diff --git a/.docker/docker-compose.yml b/.docker/docker-compose.yml index 8e4457e06cb7579e3a9b6c0a0b507c0e91e3e82e..50aab5cf449598fe961507c940dc1690cb29891e 100644 --- a/.docker/docker-compose.yml +++ b/.docker/docker-compose.yml @@ -6,7 +6,7 @@ volumes: search-db-data: identity-service-data: metric-db-data: - dashboard-service-data: + dashboard-ui-data: services: dbrepo-metadata-db: @@ -42,8 +42,10 @@ services: ports: - "3307:3306" environment: - MARIADB_ROOT_PASSWORD: "${DATA_DB_PASSWORD:-dbrepo}" MARIADB_GALERA_MARIABACKUP_PASSWORD: "${DATA_DB_BACKUP_PASSWORD:-dbrepobackup}" + MARIADB_PASSWORD: "${READONLY_PASSWORD:-user}" + MARIADB_ROOT_PASSWORD: "${DATA_DB_PASSWORD:-dbrepo}" + MARIADB_USER: "${READONLY_USERNAME:-user}" healthcheck: test: mysqladmin ping --user=root --password="${DATA_DB_PASSWORD:-dbrepo}" --silent interval: 10s @@ -115,7 +117,7 @@ services: init: true restart: "no" container_name: dbrepo-auth-service-init - image: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.7.3 + image: registry.datalab.tuwien.ac.at/dbrepo/auth-service-init:1.8.0 environment: AUTH_SERVICE_ADMIN: ${AUTH_SERVICE_ADMIN:-admin} AUTH_SERVICE_ADMIN_PASSWORD: ${AUTH_SERVICE_ADMIN_PASSWORD:-admin} @@ -123,10 +125,13 @@ services: METADATA_DB: "${METADATA_DB:-dbrepo}" METADATA_DB_PASSWORD: "${METADATA_DB_PASSWORD:-dbrepo}" METADATA_USERNAME: "root" + READONLY_USERNAME: "${READONLY_USERNAME:-user}" SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}" depends_on: dbrepo-auth-service: condition: service_healthy + dbrepo-gateway-service: + condition: service_healthy dbrepo-metadata-db: condition: service_healthy logging: @@ -136,7 +141,7 @@ services: restart: "no" container_name: dbrepo-metadata-service hostname: metadata-service - image: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.7.3 + image: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.8.0 environment: ADMIN_EMAIL: "${ADMIN_EMAIL:-noreply@localhost}" ANALYSE_SERVICE_ENDPOINT: "${ANALYSE_SERVICE_ENDPOINT:-http://analyse-service:8080}" @@ -149,12 +154,13 @@ services: BROKER_EXCHANGE_NAME: ${BROKER_EXCHANGE_NAME:-dbrepo} BROKER_QUEUE_NAME: ${BROKER_QUEUE_NAME:-dbrepo} BROKER_HOST: "${BROKER_ENDPOINT:-broker-service}" - BROKER_PASSWORD: ${BROKER_PASSWORD:-admin} + BROKER_PASSWORD: ${SYSTEM_PASSWORD:-admin} BROKER_PORT: ${BROKER_PORT:-5672} BROKER_SERVICE_ENDPOINT: ${BROKER_SERVICE_ENDPOINT:-http://broker-service:15672} - BROKER_USERNAME: ${BROKER_USERNAME:-admin} + BROKER_USERNAME: ${SYSTEM_USERNAME:-admin} BROKER_VIRTUALHOST: "${BROKER_VIRTUALHOST:-dbrepo}" CROSSREF_ENDPOINT: "${CROSSREF_ENDPOINT:-http://data.crossref.org}" + DASHBOARD_SERVICE_ENDPOINT: "${DASHBOARD_SERVICE_ENDPOINT:-http://dashboard-service:8080}" DATA_SERVICE_ENDPOINT: ${DATA_SERVICE_ENDPOINT:-http://data-service:8080} DELETED_RECORD: "${DELETED_RECORD:-persistent}" GRANULARITY: "${GRANULARITY:-YYYY-MM-DDThh:mm:ssZ}" @@ -188,6 +194,10 @@ services: condition: service_healthy dbrepo-data-service: condition: service_healthy + dbrepo-dashboard-service: + condition: service_healthy + dbrepo-search-service: + condition: service_healthy dbrepo-metadata-db: condition: service_healthy logging: @@ -197,7 +207,7 @@ services: restart: "no" container_name: dbrepo-analyse-service hostname: analyse-service - image: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.7.3 + image: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.8.0 environment: AUTH_SERVICE_CLIENT: ${AUTH_SERVICE_CLIENT:-dbrepo-client} AUTH_SERVICE_CLIENT_SECRET: ${AUTH_SERVICE_CLIENT:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG} @@ -250,23 +260,16 @@ services: restart: "no" container_name: dbrepo-search-db hostname: search-db - image: registry.datalab.tuwien.ac.at/dbrepo/search-db:1.7.3 + image: docker.io/bitnami/opensearch:2.10.0 + ports: + - "9200:9200" healthcheck: - test: curl -sSL localhost:9200/_plugins/_security/health | jq .status | grep UP + test: curl -sSL 127.0.0.1:9200 interval: 10s timeout: 5s retries: 12 - environment: - ES_JAVA_OPTS: "-Xms4g -Xmx4g" - logger.level: "WARN" - deploy: - resources: - limits: - memory: 4G - ports: - - "9200:9200" volumes: - - search-db-data:/usr/share/elasticsearch/data + - search-db-data:/bitnami/opensearch/data logging: driver: json-file @@ -274,7 +277,7 @@ services: restart: "no" container_name: dbrepo-search-service hostname: search-service - image: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.7.3 + image: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.8.0 environment: AUTH_SERVICE_CLIENT: ${AUTH_SERVICE_CLIENT:-dbrepo-client} AUTH_SERVICE_CLIENT_SECRET: ${AUTH_SERVICE_CLIENT_SECRET:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG} @@ -284,8 +287,6 @@ services: METADATA_SERVICE_ENDPOINT: ${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080} OPENSEARCH_HOST: ${OPENSEARCH_HOST:-search-db} OPENSEARCH_PORT: ${OPENSEARCH_PORT:-9200} - OPENSEARCH_USERNAME: ${SEARCH_DB_USERNAME:-admin} - OPENSEARCH_PASSWORD: ${SEARCH_DB_PASSWORD:-admin} SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}" SYSTEM_PASSWORD: "${SYSTEM_PASSWORD:-admin}" healthcheck: @@ -293,12 +294,14 @@ services: interval: 10s timeout: 5s retries: 12 + logging: + driver: json-file dbrepo-ui: restart: "no" container_name: dbrepo-ui hostname: ui - image: registry.datalab.tuwien.ac.at/dbrepo/ui:1.7.3 + image: registry.datalab.tuwien.ac.at/dbrepo/ui:1.8.0 environment: NUXT_PUBLIC_API_CLIENT: "${BASE_URL:-http://localhost}" NUXT_PUBLIC_API_SERVER: "${BASE_URL:-http://gateway-service}" @@ -315,7 +318,7 @@ services: dbrepo-search-service: condition: service_healthy healthcheck: - test: curl -fsSL http://127.0.0.1:3000 && curl -fsSL http://127.0.0.1:3000/health + test: curl -fsSL 127.0.0.1:3000 && curl -fsSL 127.0.0.1:3000/health interval: 10s timeout: 5s retries: 12 @@ -333,6 +336,11 @@ services: - "80:8080" volumes: - ./config/dbrepo.conf:/etc/nginx/conf.d/default.conf + healthcheck: + test: lsof -i TCP:80 || exit 1 + interval: 10s + timeout: 5s + retries: 12 depends_on: dbrepo-analyse-service: condition: service_healthy @@ -357,8 +365,8 @@ services: environment: LDAP_ADMIN_USERNAME: "${IDENTITY_SERVICE_ADMIN_USERNAME:-admin}" LDAP_ADMIN_PASSWORD: "${IDENTITY_SERVICE_ADMIN_PASSWORD:-admin}" - LDAP_USERS: "${SYSTEM_USERNAME:-admin}" - LDAP_PASSWORDS: "${SYSTEM_PASSWORD:-admin}" + LDAP_USERS: "${SYSTEM_USERNAME:-admin},${READONLY_USERNAME:-user}" + LDAP_PASSWORDS: "${SYSTEM_PASSWORD:-admin},${READONLY_PASSWORD:-user}" LDAP_GROUP: "${ADMIN_GROUP:-system}" LDAP_ROOT: "${IDENTITY_SERVICE_ROOT:-dc=dbrepo,dc=at}" LDAP_ADMIN_DN: "${IDENTITY_SERVICE_ADMIN_DN:-cn=admin,dc=dbrepo,dc=at}" @@ -375,14 +383,12 @@ services: init: true container_name: dbrepo-search-service-init hostname: search-service-init - image: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.7.3 + image: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.8.0 environment: LOG_LEVEL: ${LOG_LEVEL:-info} METADATA_SERVICE_ENDPOINT: ${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080} OPENSEARCH_HOST: ${OPENSEARCH_HOST:-search-db} OPENSEARCH_PORT: ${OPENSEARCH_PORT:-9200} - OPENSEARCH_USERNAME: ${SEARCH_DB_USERNAME:-admin} - OPENSEARCH_PASSWORD: ${SEARCH_DB_PASSWORD:-admin} SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}" SYSTEM_PASSWORD: "${SYSTEM_PASSWORD:-admin}" depends_on: @@ -393,6 +399,26 @@ services: logging: driver: json-file + dbrepo-dashboard-service-init: + restart: "no" + init: true + container_name: dbrepo-dashboard-service-init + hostname: search-dashboard-init + image: registry.datalab.tuwien.ac.at/dbrepo/dashboard-service-init:1.8.0 + environment: + LOG_LEVEL: ${LOG_LEVEL:-info} + DASHBOARD_UI_ENDPOINT: "${DASHBOARD_UI_ENDPOINT:-http://dashboard-ui:3000}" + METADATA_SERVICE_ENDPOINT: ${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080} + SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}" + SYSTEM_PASSWORD: "${SYSTEM_PASSWORD:-admin}" + depends_on: + dbrepo-dashboard-ui: + condition: service_healthy + dbrepo-metadata-service: + condition: service_healthy + logging: + driver: json-file + dbrepo-storage-service: restart: "no" container_name: dbrepo-storage-service @@ -428,38 +454,12 @@ services: logging: driver: json-file - dbrepo-dashboard-service: - restart: "no" - container_name: dbrepo-dashboard-service - hostname: dashboard-service - image: registry.datalab.tuwien.ac.at/dbrepo/dashboard-service:1.7.3 - ports: - - "3000:3000" - volumes: - - dashboard-service-data:/opt/bitnami/grafana/data - environment: - GF_SERVER_DOMAIN: "dashboard-service" - GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION: "true" - LDAP_ADMIN_USERNAME: "${IDENTITY_SERVICE_ADMIN_USERNAME:-admin}" - LDAP_ADMIN_PASSWORD: "${IDENTITY_SERVICE_ADMIN_PASSWORD:-admin}" - LDAP_ROOT: "${IDENTITY_SERVICE_ROOT:-dc=dbrepo,dc=at}" - healthcheck: - test: curl -fsSL --head http://127.0.0.1:3000 - interval: 10s - timeout: 5s - retries: 12 - depends_on: - dbrepo-metric-db: - condition: service_started - logging: - driver: json-file - dbrepo-storage-service-init: restart: "no" init: true container_name: dbrepo-storage-service-init hostname: storage-service-init - image: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.7.3 + image: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.8.0 environment: S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID:-seaweedfsadmin} S3_BUCKET: "${S3_BUCKET:-dbrepo}" @@ -475,7 +475,7 @@ services: restart: "no" container_name: dbrepo-data-service hostname: data-service - image: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.7.3 + image: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.8.0 environment: AUTH_SERVICE_ADMIN: "${AUTH_SERVICE_ADMIN:-admin}" AUTH_SERVICE_ADMIN_PASSWORD: "${AUTH_SERVICE_ADMIN_PASSWORD:-admin}" @@ -499,15 +499,12 @@ services: GRANT_DEFAULT_WRITE: "${GRANT_DEFAULT_WRITE:-SELECT, CREATE, CREATE VIEW, CREATE ROUTINE, CREATE TEMPORARY TABLES, LOCK TABLES, INDEX, TRIGGER, INSERT, UPDATE, DELETE}" JWT_PUBKEY: "${JWT_PUBKEY:-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB}" LOG_LEVEL: ${LOG_LEVEL:-info} - MIN_CONCURRENT_CONSUMERS: ${MIN_CONCURRENT_CONSUMERS:-1} - MAX_CONCURRENT_CONSUMERS: ${MAX_CONCURRENT_CONSUMERS:-5} QUEUE_NAME: ${QUEUE_NAME:-dbrepo} REQUEUE_REJECTED: ${REQUEUE_REJECTED:-false} ROUTING_KEY: "${ROUTING_KEY:-dbrepo.#}" S3_ACCESS_KEY_ID: "${S3_ACCESS_KEY_ID:-seaweedfsadmin}" S3_BUCKET: "${S3_BUCKET:-dbrepo}" S3_ENDPOINT: "${S3_ENDPOINT:-http://storage-service:9000}" - S3_IMPORT_BUCKET: "${S3_IMPORT_BUCKET:-dbrepo-upload}" S3_SECRET_ACCESS_KEY: "${S3_SECRET_ACCESS_KEY:-seaweedfsadmin}" SPARK_USER: "${COMPUTE_SERVICE_USERNAME:-spark}" SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}" @@ -522,3 +519,59 @@ services: condition: service_healthy logging: driver: json-file + + dbrepo-dashboard-ui: + restart: "no" + container_name: dbrepo-dashboard-ui + hostname: dashboard-ui + image: registry.datalab.tuwien.ac.at/dbrepo/dashboard-ui:1.8.0 + ports: + - "3000:3000" + volumes: + - dashboard-ui-data:/opt/bitnami/grafana/data + environment: + BASE_URL: "${BASE_URL:-http://localhost}" + GF_INSTALL_PLUGINS: "yesoreyeram-infinity-datasource" + GF_SERVER_DOMAIN: "dashboard-service" + GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION: "true" + LDAP_ADMIN_USERNAME: "${IDENTITY_SERVICE_ADMIN_USERNAME:-admin}" + LDAP_ADMIN_PASSWORD: "${IDENTITY_SERVICE_ADMIN_PASSWORD:-admin}" + LDAP_ROOT: "${IDENTITY_SERVICE_ROOT:-dc=dbrepo,dc=at}" + healthcheck: + test: curl -fsSL --head 127.0.0.1:3000 + interval: 10s + timeout: 5s + retries: 12 + depends_on: + dbrepo-metric-db: + condition: service_started + extra_hosts: + - "localhost:host-gateway" + logging: + driver: json-file + + dbrepo-dashboard-service: + restart: "no" + container_name: dbrepo-dashboard-service + hostname: dashboard-service + image: registry.datalab.tuwien.ac.at/dbrepo/dashboard-service:1.8.0 + ports: + - "4070:8080" + environment: + AUTH_SERVICE_ADMIN: ${AUTH_SERVICE_ADMIN:-admin} + AUTH_SERVICE_ADMIN_PASSWORD: ${AUTH_SERVICE_ADMIN_PASSWORD:-admin} + AUTH_SERVICE_ENDPOINT: ${AUTH_SERVICE_ENDPOINT:-http://auth-service:8080} + BASE_URL: "${BASE_URL:-http://localhost}" + DASHBOARD_UI_ENDPOINT: "${DASHBOARD_UI_ENDPOINT:-http://dashboard-ui:3000}" + SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}" + SYSTEM_PASSWORD: "${SYSTEM_PASSWORD:-admin}" + healthcheck: + test: curl -fsSL --head 127.0.0.1:8080/health + interval: 10s + timeout: 5s + retries: 12 + depends_on: + dbrepo-metric-db: + condition: service_started + logging: + driver: json-file diff --git a/.docs/.openapi/api-analyse.yaml b/.docs/.openapi/api-analyse.yaml index 25e15521d5474324eab5e43adb8baa0b90312949..b347692d4819220cf196b001ffacecf00070dcde 100644 --- a/.docs/.openapi/api-analyse.yaml +++ b/.docs/.openapi/api-analyse.yaml @@ -24,16 +24,29 @@ }, "type": "object" }, + "ApiError": { + "properties": { + "code": { + "example": "error.dashboard.create", + "type": "string" + }, + "message": { + "example": "Message", + "type": "string" + }, + "status": { + "example": "BAD_REQUEST", + "type": "string" + } + }, + "type": "object" + }, "ColumnAnalysisDto": { "properties": { "d": { "example": 4, "type": "integer" }, - "dfid": { - "example": null, - "type": "integer" - }, "enums": { "example": null, "properties": { @@ -62,19 +75,6 @@ }, "type": "object" }, - "ErrorDto": { - "properties": { - "message": { - "example": "Message", - "type": "string" - }, - "success": { - "example": false, - "type": "boolean" - } - }, - "type": "object" - }, "KeysDto": { "properties": { "keys": { @@ -111,7 +111,7 @@ }, "externalDocs": { "description": "Sourcecode Documentation", - "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.5/" + "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.8/" }, "info": { "contact": { @@ -124,7 +124,7 @@ "url": "https://www.apache.org/licenses/LICENSE-2.0" }, "title": "Database Repository Analyse Service API", - "version": "1.5" + "version": "1.8.0" }, "openapi": "3.0.0", "paths": { @@ -322,7 +322,7 @@ "servers": [ { "description": "Generated server url", - "url": "http://localhost:5000" + "url": "http://localhost" }, { "description": "Sandbox", diff --git a/.docs/.openapi/api-dashboard.yaml b/.docs/.openapi/api-dashboard.yaml new file mode 100644 index 0000000000000000000000000000000000000000..54a27444f68e0760fded5be2a5b9d1770a1d8c39 --- /dev/null +++ b/.docs/.openapi/api-dashboard.yaml @@ -0,0 +1 @@ +"<!doctype html> <html lang=en> <title>500 Internal Server Error</title> <h1>Internal Server Error</h1> <p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>" diff --git a/.docs/.openapi/api-data.yaml b/.docs/.openapi/api-data.yaml index 8a21c8aff9799682c5176f613c1a6721827b7055..b653ecb413734baa1190137bc921ef4e77c45077 100644 --- a/.docs/.openapi/api-data.yaml +++ b/.docs/.openapi/api-data.yaml @@ -1,4 +1,4 @@ -openapi: 3.0.1 +openapi: 3.1.0 info: title: Database Repository Data Service API description: Service that manages the data @@ -8,10 +8,10 @@ info: license: name: Apache 2.0 url: https://www.apache.org/licenses/LICENSE-2.0 - version: 1.7.3 + version: 1.8.0 externalDocs: description: Sourcecode Documentation - url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.7.3/system-services-metadata/ + url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.8.0/system-services-metadata/ servers: - url: http://localhost description: Development instance @@ -63,20 +63,35 @@ paths: schema: type: string responses: - "406": - description: Failed to format data + "200": + description: Retrieved view data + headers: + Access-Control-Expose-Headers: + description: Expose `X-Count` custom header + required: true + style: simple + schema: + type: string + X-Count: + description: Number of rows + required: true + style: simple + schema: + type: integer + format: int64 content: application/json: schema: - $ref: "#/components/schemas/ApiErrorDto" + type: string + text/csv: {} "400": description: Request pagination is malformed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "409": - description: View schema could not be mapped + "403": + description: Not allowed to retrieve view data content: application/json: schema: @@ -87,30 +102,20 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to establish connection with the metadata service + "406": + description: Failed to format 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 + "409": + description: View schema could not be mapped content: application/json: schema: - type: string - text/csv: {} - "403": - description: Not allowed to retrieve view data + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to establish connection with the metadata service content: application/json: schema: @@ -162,20 +167,35 @@ paths: schema: type: string responses: - "406": - description: Failed to format data + "200": + description: Retrieved view data + headers: + Access-Control-Expose-Headers: + description: Expose `X-Count` custom header + required: true + style: simple + schema: + type: string + X-Count: + description: Number of rows + required: true + style: simple + schema: + type: integer + format: int64 content: application/json: schema: - $ref: "#/components/schemas/ApiErrorDto" + type: string + text/csv: {} "400": description: Request pagination is malformed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "409": - description: View schema could not be mapped + "403": + description: Not allowed to retrieve view data content: application/json: schema: @@ -186,30 +206,20 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to establish connection with the metadata service + "406": + description: Failed to format 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 + "409": + description: View schema could not be mapped content: application/json: schema: - type: string - text/csv: {} - "403": - description: Not allowed to retrieve view data + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to establish connection with the metadata service content: application/json: schema: @@ -264,18 +274,6 @@ paths: schema: type: string responses: - "406": - description: Failed to format data - 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: @@ -283,23 +281,40 @@ paths: description: Expose `X-Count` custom header required: true style: simple + schema: + type: string X-Count: description: Number of rows required: true style: simple + schema: + type: integer + format: int64 content: application/json: schema: type: string text/csv: {} + "400": + description: Request pagination or table data select query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" "403": description: Not allowed to get table data content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Request pagination or table data select query is malformed + "404": + description: Failed to find table in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "406": + description: Failed to format data content: application/json: schema: @@ -346,22 +361,22 @@ paths: $ref: "#/components/schemas/TupleUpdateDto" required: true responses: - "403": - description: Update table data not allowed + "202": + description: Updated table data + "400": + description: Request pagination or table data select query is malformed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Failed to find table in metadata database + "403": + description: Update table data not allowed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "202": - description: Updated table data - "400": - description: Request pagination or table data select query is malformed + "404": + description: Failed to find table in metadata database content: application/json: schema: @@ -408,15 +423,16 @@ paths: $ref: "#/components/schemas/TupleDto" required: true responses: - "403": - description: Create table data not allowed + "201": + description: Created table data + "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 or - storage service + "403": + description: Create table data not allowed content: application/json: schema: @@ -428,10 +444,9 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "201": - description: Created table data - "400": - description: Request pagination or table data select query is malformed + "503": + description: Failed to establish connection with the metadata service or + storage service content: application/json: schema: @@ -472,12 +487,6 @@ paths: $ref: "#/components/schemas/TupleDeleteDto" required: true responses: - "404": - description: Failed to find table in metadata database - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "202": description: Deleted table data "400": @@ -486,14 +495,20 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to establish connection with the metadata service + "403": + description: Delete table data not allowed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Delete table data not allowed + "404": + description: Failed to find table in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to establish connection with the metadata service content: application/json: schema: @@ -547,18 +562,6 @@ paths: schema: type: string responses: - "406": - description: Failed to format data - 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: @@ -566,23 +569,40 @@ paths: description: Expose `X-Count` custom header required: true style: simple + schema: + type: string X-Count: description: Number of rows required: true style: simple + schema: + type: integer + format: int64 content: application/json: schema: type: string text/csv: {} + "400": + description: Request pagination or table data select query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" "403": description: Not allowed to get table data content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Request pagination or table data select query is malformed + "404": + description: Failed to find table in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "406": + description: Failed to format data content: application/json: schema: @@ -643,18 +663,6 @@ paths: type: integer format: int64 responses: - "403": - description: Not allowed to retrieve subset data - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "406": - description: Failed to format data - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "200": description: Retrieved subset data headers: @@ -662,29 +670,39 @@ paths: description: Reverse proxy exposing of custom headers required: true style: simple + schema: + type: string X-Count: description: Number of rows style: simple + schema: + type: string + format: uuid X-Id: description: The subset id required: true style: simple + schema: + type: string + format: uuid X-Headers: description: The list of headers separated by comma style: simple + schema: + type: string content: application/json: schema: type: string text/csv: {} - "503": - description: Failed to communicate with database + "400": + description: Invalid pagination content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Invalid pagination + "403": + description: Not allowed to retrieve subset data content: application/json: schema: @@ -696,6 +714,18 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" + "406": + description: Failed to format data + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to communicate with database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" security: - bearerAuth: [] - basicAuth: [] @@ -745,18 +775,6 @@ paths: type: integer format: int64 responses: - "403": - description: Not allowed to retrieve subset data - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "406": - description: Failed to format data - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "200": description: Retrieved subset data headers: @@ -764,29 +782,39 @@ paths: description: Reverse proxy exposing of custom headers required: true style: simple + schema: + type: string X-Count: description: Number of rows style: simple + schema: + type: string + format: uuid X-Id: description: The subset id required: true style: simple + schema: + type: string + format: uuid X-Headers: description: The list of headers separated by comma style: simple + schema: + type: string content: application/json: schema: type: string text/csv: {} - "503": - description: Failed to communicate with database + "400": + description: Invalid pagination content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Invalid pagination + "403": + description: Not allowed to retrieve subset data content: application/json: schema: @@ -798,6 +826,18 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" + "406": + description: Failed to format data + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to communicate with database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" security: - bearerAuth: [] - basicAuth: [] @@ -828,39 +868,39 @@ paths: $ref: "#/components/schemas/QueryPersistDto" required: true responses: - "400": - description: Malformed select query + "202": + description: Persisted subset content: application/json: schema: - $ref: "#/components/schemas/ApiErrorDto" - "417": - description: Failed to persist subset + $ref: "#/components/schemas/QueryDto" + "400": + description: Malformed select query content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to communicate with database + "403": + description: Not allowed to persist subset content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Not allowed to persist subset + "404": + description: Failed to find database in metadata database or query in query + store of the data database content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "202": - description: Persisted subset + "417": + description: Failed to persist subset content: application/json: schema: - $ref: "#/components/schemas/QueryDto" - "404": - description: Failed to find database in metadata database or query in query - store of the data database + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to communicate with database content: application/json: schema: @@ -880,13 +920,13 @@ paths: content: application/json: schema: - required: - - file type: object properties: file: type: string format: binary + required: + - file required: true responses: "201": @@ -939,22 +979,22 @@ paths: $ref: "#/components/schemas/ImportDto" required: true responses: + "202": + description: Imported dataset successfully "400": description: Dataset and/or query are malformed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "202": - description: Imported dataset successfully - "404": - description: Failed to find table in metadata database + "403": + description: Import table dataset not allowed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Import table dataset not allowed + "404": + description: Failed to find table in metadata database content: application/json: schema: @@ -1000,12 +1040,6 @@ paths: type: array items: $ref: "#/components/schemas/QueryDto" - "503": - description: Failed to communicate with database - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "403": description: Not allowed to find subsets content: @@ -1019,6 +1053,12 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to communicate with database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" security: - basicAuth: [] - bearerAuth: [] @@ -1063,32 +1103,39 @@ paths: $ref: "#/components/schemas/SubsetDto" required: true responses: + "201": + description: Created subset + content: + application/json: + schema: + type: string "400": description: Malformed select query content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "406": - description: Failed to format data + "403": + description: Not allowed to find subset content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "417": - description: Failed to insert query into query store of data database + "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 find subset + "406": + description: Failed to format data content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to communicate with database + "417": + description: Failed to insert query into query store of data database content: application/json: schema: @@ -1099,15 +1146,8 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "201": - description: Created subset - content: - application/json: - schema: - type: string - "404": - description: Failed to find database in metadata database or query in query - store of the data database + "503": + description: Failed to communicate with database content: application/json: schema: @@ -1144,12 +1184,6 @@ paths: type: integer format: int64 responses: - "404": - description: Failed to find table history in data database - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "200": description: Found table history content: @@ -1158,14 +1192,20 @@ paths: type: array items: $ref: "#/components/schemas/TableHistoryDto" + "400": + description: "Invalid pagination size request, must be > 0" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" "403": description: Find table history not allowed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: "Invalid pagination size request, must be > 0" + "404": + description: Failed to find table history in data database content: application/json: schema: @@ -1210,6 +1250,13 @@ paths: type: string format: date-time responses: + "200": + description: Found subset + content: + application/json: + schema: + $ref: "#/components/schemas/QueryDto" + text/csv: {} "400": description: Malformed select query content: @@ -1222,28 +1269,21 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "406": - description: Failed to find acceptable representation + "404": + description: Failed to find database in metadata database or query in query + store of the data database content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to communicate with database + "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 + "503": + description: Failed to communicate with database content: application/json: schema: @@ -1254,15 +1294,10 @@ paths: components: schemas: ApiErrorDto: - required: - - code - - message - - status type: object properties: status: type: string - example: NOT_FOUND enum: - 100 CONTINUE - 101 SWITCHING_PROTOCOLS @@ -1333,46 +1368,44 @@ components: - 509 BANDWIDTH_LIMIT_EXCEEDED - 510 NOT_EXTENDED - 511 NETWORK_AUTHENTICATION_REQUIRED + example: NOT_FOUND message: type: string example: Error message code: type: string example: error.service.code - TupleUpdateDto: required: - - data - - keys + - code + - message + - status + TupleUpdateDto: 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 + - data + - keys + QueryPersistDto: type: object properties: persist: type: boolean example: true - CreatorBriefDto: required: - - creator_name - - id + - persist + CreatorBriefDto: type: object properties: id: @@ -1387,43 +1420,35 @@ components: example: "Carberry, Josiah" name_type: type: string - example: Personal enum: - Personal - Organizational + example: Personal name_identifier: type: string example: 0000-0002-1825-0097 name_identifier_scheme: type: string - example: ORCID enum: - ORCID - ROR - ISNI - GRID + example: ORCID affiliation_identifier: type: string example: https://ror.org/05gq02987 affiliation_identifier_scheme: type: string - example: ROR enum: - ROR - GRID - ISNI - IdentifierBriefDto: + example: ROR required: - - creators - - database_id - - descriptions + - creator_name - id - - owned_by - - publication_year - - publisher - - status - - titles - - type + IdentifierBriefDto: type: object properties: id: @@ -1432,12 +1457,12 @@ components: example: b97cd56b-66ca-4354-9e6c-f47210cfaaec type: type: string - example: database enum: - database - subset - table - view + example: database creators: type: array items: @@ -1458,10 +1483,10 @@ components: example: TU Wien status: type: string - example: draft enum: - draft - published + example: draft database_id: type: string format: uuid @@ -1469,12 +1494,15 @@ components: query_id: type: string format: uuid + example: 1 table_id: type: string format: uuid + example: 1 view_id: type: string format: uuid + example: 1 publication_year: type: integer format: int32 @@ -1483,9 +1511,18 @@ components: type: string format: uuid example: 2f45ef7a-7f9b-4667-9156-152c87fe1ca5 - IdentifierDescriptionDto: required: + - creators + - database_id + - descriptions - id + - owned_by + - publication_year + - publisher + - status + - titles + - type + IdentifierDescriptionDto: type: object properties: id: @@ -1497,7 +1534,6 @@ components: example: "Air quality reports at Stephansplatz, Vienna" language: type: string - example: en enum: - ab - aa @@ -1683,9 +1719,9 @@ components: - yo - za - zu + example: en type: type: string - example: Abstract enum: - Abstract - Methods @@ -1693,9 +1729,10 @@ components: - TableOfContents - TechnicalInfo - Other - IdentifierTitleDto: + example: Abstract required: - id + IdentifierTitleDto: type: object properties: id: @@ -1707,7 +1744,6 @@ components: example: Airquality Demonstrator language: type: string - example: en enum: - ab - aa @@ -1893,6 +1929,7 @@ components: - yo - za - zu + example: en type: type: string enum: @@ -1900,17 +1937,9 @@ components: - Subtitle - TranslatedTitle - Other - QueryDto: required: - - database_id - - execution - id - - identifiers - - is_persisted - - owner - - query - - query_hash - - query_normalized + QueryDto: type: object properties: id: @@ -1928,10 +1957,10 @@ components: example: SELECT `id` FROM `air_quality` type: type: string - example: query enum: - query - view + example: query identifiers: type: array items: @@ -1956,10 +1985,17 @@ components: type: integer format: int64 example: 1 - UserBriefDto: required: + - database_id + - execution - id - - username + - identifiers + - is_persisted + - owner + - query + - query_hash + - query_normalized + UserBriefDto: type: object properties: id: @@ -1985,10 +2021,10 @@ components: family_name: type: string example: Carberry - CreatorDto: required: - - creator_name - id + - username + CreatorDto: type: object properties: id: @@ -2009,21 +2045,21 @@ components: example: "Carberry, Josiah" name_type: type: string - example: Personal enum: - Personal - Organizational + example: Personal name_identifier: type: string example: 0000-0002-1825-0097 name_identifier_scheme: type: string - example: ORCID enum: - ORCID - ROR - ISNI - GRID + example: ORCID name_identifier_scheme_uri: type: string example: https://orcid.org/ @@ -2032,33 +2068,31 @@ components: example: https://ror.org/05gq02987 affiliation_identifier_scheme: type: string - example: ROR enum: - ROR - GRID - ISNI + example: ROR affiliation_identifier_scheme_uri: type: string example: https://ror.org/ - IdentifierDto: required: - - creators - - database_id - - descriptions - - funders + - creator_name - id - - language - - licenses - - links - - owner - - publication_year - - publisher - - query - - query_hash - - query_normalized - - status - - titles - - type + EnumDto: + type: object + properties: + id: + type: string + format: uuid + example: 5343bb3d-14d3-4eb7-a86f-b8fc553cb315 + value: + type: string + example: 3 + required: + - id + - value + IdentifierDto: type: object properties: id: @@ -2069,12 +2103,12 @@ components: $ref: "#/components/schemas/LinksDto" type: type: string - example: database enum: - database - subset - table - view + example: database titles: type: array items: @@ -2300,22 +2334,26 @@ components: $ref: "#/components/schemas/CreatorDto" status: type: string - example: draft enum: - draft - published + example: draft database_id: type: string format: uuid + example: null query_id: type: string format: uuid + example: null table_id: type: string format: uuid + example: null view_id: type: string format: uuid + example: null query_normalized: type: string example: "SELECT `id`, `value`, `location` FROM `air_quality` WHERE `location`\ @@ -2346,10 +2384,25 @@ components: type: integer format: int32 example: 2022 - IdentifierFunderDto: required: - - funder_name + - creators + - database_id + - descriptions + - funders - id + - language + - licenses + - links + - owner + - publication_year + - publisher + - query + - query_hash + - query_normalized + - status + - titles + - type + IdentifierFunderDto: type: object properties: id: @@ -2364,26 +2417,26 @@ components: example: http://doi.org/10.13039/501100000780 funder_identifier_type: type: string - example: Crossref Funder ID enum: - Crossref Funder ID - ROR - GND - ISNI - Other + example: Crossref Funder ID scheme_uri: type: string example: http://doi.org/ award_number: type: string - example: "824087" + example: 824087 award_title: type: string example: EOSC-Life - LicenseDto: required: - - identifier - - uri + - funder_name + - id + LicenseDto: type: object properties: identifier: @@ -2398,10 +2451,10 @@ components: \ preservation of copyright and license notices. Licensed works, modifications,\ \ and larger works may be distributed under different terms and without\ \ source code." - LinksDto: required: - - self - - self_html + - identifier + - uri + LinksDto: type: object properties: self: @@ -2413,12 +2466,13 @@ components: self_html: type: string example: http://example.com - RelatedIdentifierDto: + dashboard_html: + type: string + example: http://example.com/d/defi2baxqawaod required: - - id - - relation - - type - - value + - self + - self_html + RelatedIdentifierDto: type: object properties: id: @@ -2430,7 +2484,6 @@ components: example: 10.70124/dc4zh-9ce78 type: type: string - example: DOI enum: - DOI - URL @@ -2450,9 +2503,9 @@ components: - PURL - UPC - w3id + example: DOI relation: type: string - example: Cites enum: - IsCitedBy - Cites @@ -2488,15 +2541,26 @@ components: - Requires - IsObsoletedBy - Obsoletes - ViewColumnDto: + example: Cites required: - - database_id - id - - internal_name - - is_null_allowed - - name - - ord + - relation - type + - value + SetDto: + type: object + properties: + id: + type: string + format: uuid + example: 7eb4eded-bacc-4a91-84db-a9ae6ddafda7 + value: + type: string + example: 3 + required: + - id + - value + ViewColumnDto: type: object properties: id: @@ -2504,10 +2568,10 @@ components: format: uuid example: 6aec3a91-2e0b-4e92-a16a-9c3c5e892da1 name: - maxLength: 64 - minLength: 0 type: string example: Given Name + maxLength: 64 + minLength: 0 size: type: integer format: int64 @@ -2517,10 +2581,20 @@ components: format: int64 example: 0 description: - maxLength: 2048 - minLength: 0 type: string example: Column comment + maxLength: 2048 + minLength: 0 + enums: + type: array + description: "enum values, only considered when type = ENUM" + items: + $ref: "#/components/schemas/EnumDto" + sets: + type: array + description: "enum values, only considered when type = ENUM" + items: + $ref: "#/components/schemas/SetDto" database_id: type: string format: uuid @@ -2530,10 +2604,10 @@ components: format: int32 example: 0 internal_name: - maxLength: 64 - minLength: 0 type: string example: given_name + maxLength: 64 + minLength: 0 index_length: type: integer format: int64 @@ -2544,7 +2618,6 @@ components: example: 255 type: type: string - example: varchar enum: - char - varchar @@ -2576,20 +2649,19 @@ components: - timestamp - time - year + example: varchar is_null_allowed: type: boolean example: false - ViewDto: required: - - columns - database_id - id - - identifiers - internal_name + - is_null_allowed - name - - owner - - query - - query_hash + - ord + - type + ViewDto: type: object properties: id: @@ -2612,9 +2684,14 @@ components: type: array items: $ref: "#/components/schemas/ViewColumnDto" + created: + type: string + format: date-time + example: 2022-01-01 08:00:00.000 last_retrieved: type: string format: date-time + example: 2025-01-23T12:09:01 database_id: type: string format: uuid @@ -2635,24 +2712,29 @@ components: query_hash: type: string example: 7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916 - TupleDto: required: - - data + - columns + - created + - database_id + - id + - identifiers + - internal_name + - name + - owner + - query + - query_hash + TupleDto: type: object properties: data: type: object additionalProperties: type: object - example: - key: value example: key: value - ImportDto: required: - - header - - location - - separator + - data + ImportDto: type: object properties: location: @@ -2672,24 +2754,23 @@ components: line_termination: type: string example: \r\n - FilterDto: required: - - column_id - - operator_id - - type - - value + - header + - location + - separator + FilterDto: type: object properties: type: type: string - example: where enum: - where - or - and + example: where value: type: string - example: "1" + example: 1 column_id: type: string format: uuid @@ -2698,25 +2779,27 @@ components: type: string format: uuid example: 67c5b54d-2eb0-4f42-8dc1-a504562e9f32 - OrderDto: required: - column_id + - operator_id + - type + - value + OrderDto: type: object properties: direction: type: string - example: asc enum: - asc - desc + example: asc column_id: type: string format: uuid example: e891ba86-0258-41a6-a8d9-ff58bc10b618 - SubsetDto: required: - - columns - - table_id + - column_id + SubsetDto: type: object properties: columns: @@ -2734,15 +2817,20 @@ components: type: array items: $ref: "#/components/schemas/OrderDto" - table_id: + datasource_id: type: string format: uuid example: f7df2a7d-4ade-4c78-97b0-7c744d0893c7 - TableHistoryDto: + datasource_type: + type: string + enum: + - table + - view required: - - event - - timestamp - - total + - columns + - datasource_id + - datasource_type + TableHistoryDto: type: object properties: timestamp: @@ -2751,27 +2839,29 @@ components: example: 2021-03-12T15:26:21Z event: type: string - example: INSERT enum: - insert - delete + example: INSERT total: type: integer format: int64 example: 1 - TupleDeleteDto: required: - - keys + - event + - timestamp + - total + TupleDeleteDto: type: object properties: keys: type: object additionalProperties: type: object - example: - id: 1 example: id: 1 + required: + - keys securitySchemes: basicAuth: type: http diff --git a/.docs/.openapi/api-metadata.yaml b/.docs/.openapi/api-metadata.yaml index 4c73fa8836ae846e20383fe509df4bea44ef7085..345b4c0efa56964b2bee6f4a4c6e1d66a4286dd4 100644 --- a/.docs/.openapi/api-metadata.yaml +++ b/.docs/.openapi/api-metadata.yaml @@ -1,4 +1,4 @@ -openapi: 3.0.1 +openapi: 3.1.0 info: title: Database Repository Metadata Service API description: Service that manages the metadata @@ -8,10 +8,10 @@ info: license: name: Apache 2.0 url: https://www.apache.org/licenses/LICENSE-2.0 - version: 1.7.3 + version: 1.8.0 externalDocs: description: Sourcecode Documentation - url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.7.3/system-services-metadata/ + url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.8.0/system-services-metadata/ servers: - url: http://localhost description: Development instance @@ -36,6 +36,12 @@ paths: type: string format: uuid responses: + "200": + description: Found user + content: + application/json: + schema: + $ref: "#/components/schemas/UserDto" "403": description: Find user is not permitted content: @@ -48,12 +54,6 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "200": - description: Found user - content: - application/json: - schema: - $ref: "#/components/schemas/UserDto" security: - bearerAuth: [] - basicAuth: [] @@ -77,18 +77,12 @@ paths: $ref: "#/components/schemas/UserUpdateDto" required: true responses: - "404": - description: Failed to find database/user in metadata database - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to modify user at auth service + "202": + description: Modified user information content: application/json: schema: - $ref: "#/components/schemas/ApiErrorDto" + $ref: "#/components/schemas/UserDto" "400": description: Modify user query is malformed content: @@ -101,12 +95,18 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "202": - description: Modified user information + "404": + description: Failed to find database/user in metadata database content: application/json: schema: - $ref: "#/components/schemas/UserDto" + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to modify user at auth service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" security: - bearerAuth: [] - basicAuth: [] @@ -127,6 +127,12 @@ paths: type: string format: uuid responses: + "200": + description: Found user + content: + application/json: + schema: + $ref: "#/components/schemas/UserDto" "403": description: Find user is not permitted content: @@ -139,12 +145,6 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "200": - description: Found user - content: - application/json: - schema: - $ref: "#/components/schemas/UserDto" security: - bearerAuth: [] - basicAuth: [] @@ -171,10 +171,15 @@ paths: description: Expose `X-Count` custom header required: true style: simple + schema: + type: string X-Count: description: Number of databases required: true style: simple + schema: + type: integer + format: int64 content: application/json: schema: @@ -186,7 +191,7 @@ paths: - database-endpoint summary: Create database description: Creates a database in the container with id. Requires roles `create-database`. - operationId: create_4 + operationId: create requestBody: content: application/json: @@ -194,33 +199,33 @@ paths: $ref: "#/components/schemas/CreateDatabaseDto" required: true responses: - "404": - description: Failed to fin container/user/database in metadata database + "201": + description: Created a new database content: application/json: schema: - $ref: "#/components/schemas/ApiErrorDto" - "409": - description: Query store could not be created + $ref: "#/components/schemas/DatabaseBriefDto" + "400": + description: Database create query is malformed or image is not supported content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "502": - description: Connection to search service failed + "403": + description: Database create permission is missing or grant permissions + at broker service failed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Database create permission is missing or grant permissions - at broker service failed + "404": + description: Failed to fin container/user/database in metadata database content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to save in search service + "409": + description: Query store could not be created content: application/json: schema: @@ -231,18 +236,18 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Database create query is malformed or image is not supported + "502": + description: Connection to search service failed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "201": - description: Created a new database + "503": + description: Failed to save in search service content: application/json: schema: - $ref: "#/components/schemas/DatabaseBriefDto" + $ref: "#/components/schemas/ApiErrorDto" security: - bearerAuth: [] - basicAuth: [] @@ -268,10 +273,15 @@ paths: description: Expose `X-Count` custom header required: true style: simple + schema: + type: string X-Count: description: Number of databases required: true style: simple + schema: + type: integer + format: int64 content: application/json: schema: @@ -303,6 +313,12 @@ paths: 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: @@ -315,12 +331,6 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "200": - description: Found database access - content: - application/json: - schema: - $ref: "#/components/schemas/DatabaseAccessDto" security: - bearerAuth: [] - basicAuth: [] @@ -330,7 +340,7 @@ paths: 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 + operationId: update parameters: - name: databaseId in: path @@ -351,13 +361,8 @@ paths: $ref: "#/components/schemas/CreateAccessDto" required: true responses: - "502": - description: Access could not be updated due to connection error in the - data service - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Modified access "400": description: Modify access query or database connection is malformed content: @@ -371,16 +376,21 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "202": - description: Modified access - "503": - description: Access could not be updated in the data service + "404": + description: Database or user not found content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Database or user not found + "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: @@ -394,7 +404,7 @@ paths: summary: Give access description: Give a user with given id access to some database with given id. Requires role `create-database-access`. - operationId: create_7 + operationId: create_1 parameters: - name: databaseId in: path @@ -415,38 +425,38 @@ paths: $ref: "#/components/schemas/CreateAccessDto" required: true responses: - "403": - description: Failed giving access + "202": + description: Granting access succeeded content: application/json: schema: - $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Database or user not found + $ref: "#/components/schemas/DatabaseAccessDto" + "400": + description: Granting access query or database connection is malformed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Access could not be created in the data service + "403": + description: Failed giving access content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "202": - description: Granting access succeeded + "404": + description: Database or user not found content: application/json: schema: - $ref: "#/components/schemas/DatabaseAccessDto" - "400": - description: Granting access query or database connection is malformed + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Access could not be created due to connection error content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "502": - description: Access could not be created due to connection error + "503": + description: Access could not be created in the data service content: application/json: schema: @@ -475,28 +485,22 @@ paths: type: string format: uuid responses: - "404": - description: "User, database with access was not 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" - "202": - description: Deleted access - "503": - description: Access could not be revoked in the data service + "403": + description: Revoke of access not permitted as no access was found content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Revoke of access not permitted as no access was found + "404": + description: "User, database with access was not found" content: application/json: schema: @@ -507,6 +511,12 @@ paths: 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: [] @@ -534,6 +544,12 @@ paths: 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: @@ -546,12 +562,6 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "200": - description: Found database access - content: - application/json: - schema: - $ref: "#/components/schemas/DatabaseAccessDto" security: - bearerAuth: [] - basicAuth: [] @@ -570,24 +580,24 @@ paths: type: string format: uuid 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" + "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 + operationId: update_1 parameters: - name: ontologyId in: path @@ -602,18 +612,18 @@ paths: $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" + "404": + description: Could not find ontology + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" security: - bearerAuth: [] - basicAuth: [] @@ -631,16 +641,16 @@ paths: type: string format: uuid responses: + "202": + description: Deleted ontology successfully + content: + application/json: {} "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: [] @@ -650,7 +660,7 @@ paths: - message-endpoint summary: Update message description: Updates a message with id. Requires role `update-maintenance-message`. - operationId: update_1 + operationId: update_2 parameters: - name: messageId in: path @@ -665,18 +675,18 @@ paths: $ref: "#/components/schemas/BannerMessageUpdateDto" required: true responses: - "404": - description: Could not find message - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "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: [] @@ -740,7 +750,7 @@ paths: summary: Update image description: Updates container image in the metadata database. Requires role `modify-image`. - operationId: update_2 + operationId: update_3 parameters: - name: imageId in: path @@ -803,7 +813,7 @@ paths: summary: Find identifier description: Finds an identifier with id. The response format depends on the HTTP `Accept` header set on the request. - operationId: find_7 + operationId: find_5 parameters: - name: identifierId in: path @@ -831,20 +841,21 @@ paths: text/bibliography; style=apa: {} text/bibliography; style=ieee: {} text/bibliography; style=bibtex: {} - "410": - description: Failed to retrieve from S3 endpoint + "400": + description: "Identifier could not be exported, the requested style is not\ + \ known" content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to find in data service + "403": + description: Not allowed to view identifier content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Not allowed to view identifier + "404": + description: Identifier could not be found content: application/json: schema: @@ -861,21 +872,20 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: "Identifier could not be exported, the requested style is not\ - \ known" + "410": + description: Failed to retrieve from S3 endpoint content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Identifier could not be found + "502": + description: Connection to data service failed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "502": - description: Connection to data service failed + "503": + description: Failed to find in data service content: application/json: schema: @@ -903,12 +913,6 @@ paths: $ref: "#/components/schemas/IdentifierSaveDto" required: true responses: - "502": - description: Connection to search service failed - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "202": description: Saved identifier content: @@ -921,8 +925,8 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to save in search service + "403": + description: Insufficient access rights or authorities content: application/json: schema: @@ -933,8 +937,14 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Insufficient access rights or authorities + "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: @@ -956,22 +966,22 @@ paths: type: string format: uuid responses: - "404": - description: Identifier or database could not be found + "202": + description: Deleted identifier + "403": + description: Deleting identifier not permitted content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "502": - description: Connection to search service failed + "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 + "502": + description: Connection to search service failed content: application/json: schema: @@ -1001,20 +1011,20 @@ paths: type: string format: uuid responses: - "502": - description: Connection to search service failed + "202": + description: Published identifier content: application/json: schema: - $ref: "#/components/schemas/ApiErrorDto" + $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 + "403": + description: Insufficient access rights or authorities content: application/json: schema: @@ -1025,14 +1035,14 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "202": - description: Published identifier + "502": + description: Connection to search service failed content: application/json: schema: - $ref: "#/components/schemas/IdentifierDto" - "403": - description: Insufficient access rights or authorities + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service content: application/json: schema: @@ -1080,14 +1090,14 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "502": - description: Connection to search service failed + "404": + description: Failed to find database in metadata database content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Failed to find database in metadata database + "502": + description: Connection to search service failed content: application/json: schema: @@ -1107,7 +1117,7 @@ paths: - view-endpoint summary: Get view description: Gets a view with id in the metadata database. - operationId: find_8 + operationId: find_6 parameters: - name: databaseId in: path @@ -1149,7 +1159,7 @@ paths: 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 + operationId: update_4 parameters: - name: databaseId in: path @@ -1170,32 +1180,32 @@ paths: $ref: "#/components/schemas/ViewUpdateDto" required: true responses: + "202": + description: Update view successfully + content: + '*/*': + schema: + $ref: "#/components/schemas/ViewBriefDto" "400": description: Update view query is malformed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Database or View could not be found + "403": + description: Update not allowed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "502": - description: Connection to search service failed + "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" - "403": - description: Update not allowed + "502": + description: Connection to search service failed content: application/json: schema: @@ -1229,12 +1239,6 @@ paths: type: string format: uuid responses: - "403": - description: Deletion not allowed - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "202": description: Delete view successfully "400": @@ -1243,8 +1247,14 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "502": - description: Connection to search service failed + "403": + description: Deletion not allowed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: "Database, view or user could not be found" content: application/json: schema: @@ -1255,14 +1265,14 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to save in search service + "502": + description: Connection to search service failed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: "Database, view or user could not be found" + "503": + description: Failed to save in search service content: application/json: schema: @@ -1279,7 +1289,7 @@ paths: \ 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 + operationId: findById_1 parameters: - name: databaseId in: path @@ -1320,7 +1330,7 @@ paths: - table-endpoint summary: Update table description: Updates a table in the database with id. Requires role `update-table`. - operationId: update_4 + operationId: update_5 parameters: - name: databaseId in: path @@ -1341,18 +1351,24 @@ paths: $ref: "#/components/schemas/TableUpdateDto" required: true responses: + "202": + description: Updated the table + content: + application/json: + schema: + $ref: "#/components/schemas/TableBriefDto" "400": description: Update table visibility payload is malformed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "202": - description: Updated the table + "403": + description: Update table visibility not permitted content: application/json: schema: - $ref: "#/components/schemas/TableBriefDto" + $ref: "#/components/schemas/ApiErrorDto" "404": description: Table could not be found content: @@ -1365,12 +1381,6 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Update table visibility not permitted - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "503": description: Failed to save in search service content: @@ -1404,14 +1414,14 @@ paths: responses: "202": description: Delete table successfully - "403": - description: Access to the database is forbidden + "400": + description: Delete table query resulted in an invalid query statement content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "502": - description: Connection to search service failed + "403": + description: Access to the database is forbidden content: application/json: schema: @@ -1422,14 +1432,14 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to save in search service + "502": + description: Connection to search service failed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Delete table query resulted in an invalid query statement + "503": + description: Failed to save in search service content: application/json: schema: @@ -1460,14 +1470,10 @@ paths: type: string format: uuid responses: - "502": - description: Connection to search service failed - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to save in search service + "202": + description: Updated table statistics successfully + "400": + description: Failed to map column statistic to known columns content: application/json: schema: @@ -1484,10 +1490,14 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "202": - description: Updated table statistics successfully - "400": - description: Failed to map column statistic to known columns + "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: @@ -1544,14 +1554,14 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Failed to find user/table/database/ontology in metadata database + "403": + description: Access to the database is forbidden content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Access to the database is forbidden + "404": + description: Failed to find user/table/database/ontology in metadata database content: application/json: schema: @@ -1593,26 +1603,26 @@ paths: $ref: "#/components/schemas/DatabaseTransferDto" required: true responses: - "404": - description: Database or user could not be found - 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 + "400": + description: Owner payload is malformed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Owner payload is malformed + "404": + description: Database or user could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Transfer of ownership is not permitted content: application/json: schema: @@ -1649,12 +1659,12 @@ paths: type: string format: uuid responses: - "502": - description: Connection to search service failed + "200": + description: Refreshed database views metadata content: application/json: schema: - $ref: "#/components/schemas/ApiErrorDto" + $ref: "#/components/schemas/DatabaseBriefDto" "403": description: Refresh view metadata is not permitted content: @@ -1667,18 +1677,18 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to save in search service + "502": + description: Connection to search service failed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "200": - description: Refreshed database views metadata + "503": + description: Failed to save in search service content: application/json: schema: - $ref: "#/components/schemas/DatabaseBriefDto" + $ref: "#/components/schemas/ApiErrorDto" security: - bearerAuth: [] - basicAuth: [] @@ -1699,14 +1709,14 @@ paths: type: string format: uuid responses: - "502": - description: Connection to search service failed + "200": + description: Refreshed database tables metadata content: application/json: schema: - $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Failed to find database in metadata database + $ref: "#/components/schemas/DatabaseBriefDto" + "400": + description: Failed to parse payload at search service content: application/json: schema: @@ -1717,24 +1727,24 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to save in search service + "404": + description: Failed to find database in metadata database content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Failed to parse payload at search service + "502": + description: Connection to search service failed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "200": - description: Refreshed database tables metadata + "503": + description: Failed to save in search service content: application/json: schema: - $ref: "#/components/schemas/DatabaseBriefDto" + $ref: "#/components/schemas/ApiErrorDto" security: - bearerAuth: [] - basicAuth: [] @@ -1753,21 +1763,19 @@ paths: type: string format: uuid responses: + "200": + description: View of image was successful + content: + '*/*': + schema: + type: string + format: byte "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: [] @@ -1792,12 +1800,24 @@ paths: $ref: "#/components/schemas/DatabaseModifyImageDto" required: true responses: + "202": + description: Modify of image was successful + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseBriefDto" "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" "410": description: File was not found in the Storage Service content: @@ -1810,24 +1830,67 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/dashboard: + put: + tags: + - database-endpoint + summary: Update database dashboard uid + description: Updates the dashboard uid for a database with given id. Only the + database owner can perform this operation. Requires role `system`. + operationId: modifyDashboard + parameters: + - name: databaseId + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseModifyDashboardDto" + required: true + responses: + "202": + description: Modify of dashboard uid was successful + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseBriefDto" + "400": + description: Malformed payload + 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 + "502": + description: Connection to search service failed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "202": - description: Modify of image was successful + "503": + description: Failed to save in search service content: application/json: schema: - $ref: "#/components/schemas/DatabaseBriefDto" + $ref: "#/components/schemas/ApiErrorDto" security: - bearerAuth: [] - basicAuth: [] @@ -1837,7 +1900,7 @@ paths: - ontology-endpoint summary: List ontologies description: Lists all ontologies known to the metadata database. - operationId: findAll_2 + operationId: findAll responses: "200": description: List ontologies @@ -1852,7 +1915,7 @@ paths: - ontology-endpoint summary: Create ontology description: Creates an ontology in the metadata database. Requires role `create-ontology`. - operationId: create + operationId: create_2 requestBody: content: application/json: @@ -1900,7 +1963,7 @@ paths: - message-endpoint summary: Create message description: Creates a message in the metadata database. Requires role `create-maintenance-message`. - operationId: create_1 + operationId: create_3 requestBody: content: application/json: @@ -1923,7 +1986,7 @@ paths: - image-endpoint summary: List images description: Lists all container images known to the metadata database. - operationId: findAll_3 + operationId: findAll_1 responses: "200": description: List images @@ -1939,7 +2002,7 @@ paths: summary: Create image description: Creates a container image in the metadata database. Requires role `create-image`. - operationId: create_2 + operationId: create_4 requestBody: content: application/json: @@ -1974,7 +2037,7 @@ paths: - identifier-endpoint summary: List identifiers description: Lists all identifiers known to the metadata database - operationId: findAll_4 + operationId: findAll_2 parameters: - name: type in: query @@ -2031,7 +2094,9 @@ paths: schema: type: array items: - type: string + type: array + items: + $ref: "#/components/schemas/IdentifierBriefDto" application/ld+json: schema: type: array @@ -2045,7 +2110,7 @@ paths: 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_3 + operationId: create_5 requestBody: content: application/json: @@ -2059,20 +2124,14 @@ paths: application/json: schema: $ref: "#/components/schemas/IdentifierDto" - "502": - description: Connection to search service failed - 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 + "403": + description: Insufficient access rights or authorities content: application/json: schema: @@ -2083,8 +2142,14 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Insufficient access rights or authorities + "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: @@ -2098,7 +2163,7 @@ paths: - view-endpoint summary: List views description: Lists views known to the metadata database. - operationId: findAll_5 + operationId: findAll_3 parameters: - name: databaseId in: path @@ -2107,12 +2172,6 @@ paths: type: string format: uuid responses: - "404": - description: Database or user could not be found - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "200": description: Find views successfully content: @@ -2121,6 +2180,12 @@ paths: 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: [] @@ -2130,7 +2195,7 @@ paths: summary: Create view description: Creates a view. This can only be performed by the database owner. Requires role `create-database-view`. - operationId: create_5 + operationId: create_6 parameters: - name: databaseId in: path @@ -2145,14 +2210,14 @@ paths: $ref: "#/components/schemas/CreateViewDto" required: true responses: - "404": - description: Failed to find database/user in metadata database. + "201": + description: Create view successfully content: application/json: schema: - $ref: "#/components/schemas/ApiErrorDto" - "409": - description: View exists with name + $ref: "#/components/schemas/ViewBriefDto" + "400": + description: Create view query is malformed content: application/json: schema: @@ -2163,26 +2228,26 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "201": - description: Create view successfully + "404": + description: Failed to find database/user in metadata database. content: application/json: schema: - $ref: "#/components/schemas/ViewBriefDto" - "423": - description: Create view resulted in an invalid query statement + $ref: "#/components/schemas/ApiErrorDto" + "409": + description: View exists with name content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "502": - description: Connection to search service failed + "423": + description: Create view resulted in an invalid query statement content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Create view query is malformed + "502": + description: Connection to search service failed content: application/json: schema: @@ -2204,7 +2269,7 @@ paths: 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 + operationId: list_3 parameters: - name: databaseId in: path @@ -2213,26 +2278,26 @@ paths: type: string format: uuid responses: - "404": - description: Database could not be found + "200": + description: List tables content: application/json: schema: - $ref: "#/components/schemas/ApiErrorDto" + type: array + items: + $ref: "#/components/schemas/TableBriefDto" "403": description: List tables not permitted content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "200": - description: List tables + "404": + description: Database could not be found content: application/json: schema: - type: array - items: - $ref: "#/components/schemas/TableBriefDto" + $ref: "#/components/schemas/ApiErrorDto" security: - bearerAuth: [] - basicAuth: [] @@ -2241,7 +2306,7 @@ paths: - table-endpoint summary: Create table description: Creates a table in the database with id. Requires role `create-table`. - operationId: create_6 + operationId: create_7 parameters: - name: databaseId in: path @@ -2256,18 +2321,18 @@ paths: $ref: "#/components/schemas/CreateTableDto" required: true responses: - "409": - description: Create table conflicts with existing table name - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "201": description: Created a new table content: application/json: schema: $ref: "#/components/schemas/TableBriefDto" + "400": + description: Create table query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" "403": description: Create table not permitted content: @@ -2280,20 +2345,20 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "502": - description: Connection to search service failed + "409": + description: Create table conflicts with existing table name content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to save in search service + "502": + description: Connection to search service failed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Create table query is malformed + "503": + description: Failed to save in search service content: application/json: schema: @@ -2307,7 +2372,7 @@ paths: - container-endpoint summary: List containers description: List all containers in the metadata database. - operationId: findAll_6 + operationId: findAll_4 parameters: - name: limit in: query @@ -2343,26 +2408,26 @@ paths: application/json: schema: $ref: "#/components/schemas/ContainerDto" - "404": - description: Container image or user could not be found + "400": + description: Container payload malformed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "409": - description: Container name already exists + "403": + description: "Create container not permitted, need authority `create-container`" content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Container payload malformed + "404": + description: Container image or user could not be found content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "403": - description: "Create container not permitted, need authority `create-container`" + "409": + description: Container name already exists content: application/json: schema: @@ -2378,7 +2443,7 @@ paths: 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 + operationId: findAll_5 parameters: - name: username in: query @@ -2400,7 +2465,7 @@ paths: - unit-endpoint summary: List units description: Lists units known to the metadata database. - operationId: findAll_1 + operationId: findAll_6 responses: "200": description: Find all semantic units @@ -2417,7 +2482,7 @@ paths: summary: Find entities description: Finds semantic entities by label or uri in an ontology with id. Requires role `execute-semantic-query`. - operationId: find_5 + operationId: find_7 parameters: - name: ontologyId in: path @@ -2436,8 +2501,16 @@ paths: schema: type: string responses: - "422": - description: Ontology does not have rdf or sparql endpoint + "200": + description: Found entities + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/EntityDto" + "400": + description: Filter params are invalid content: application/json: schema: @@ -2454,20 +2527,12 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Filter params are invalid + "422": + description: Ontology does not have rdf or sparql endpoint 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: [] @@ -2476,7 +2541,7 @@ paths: tags: - metadata-endpoint summary: Get record - operationId: identify_1_1_1_1 + operationId: identify parameters: - name: verb in: query @@ -2489,14 +2554,16 @@ paths: "200": description: List containers content: - text/xml: {} + text/xml: + schema: + type: string /api/message/message/{messageId}: get: tags: - message-endpoint summary: Find message description: Finds a message with id in the metadata database. - operationId: find_6 + operationId: find_8 parameters: - name: messageId in: path @@ -2505,25 +2572,25 @@ paths: type: string format: uuid responses: - "404": - description: Could not find message - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "200": description: Get messages content: application/json: schema: $ref: "#/components/schemas/BannerMessageDto" - /api/license: + "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 + operationId: list_4 responses: "200": description: List of licenses @@ -2566,7 +2633,7 @@ paths: - database-endpoint summary: Find database description: Finds a database with id. - operationId: findById_1 + operationId: findById_2 parameters: - name: databaseId in: path @@ -2581,24 +2648,30 @@ paths: X-Username: description: The authentication username style: simple + schema: + type: string Access-Control-Expose-Headers: description: Expose custom headers style: simple + schema: + type: string X-Password: description: The authentication password style: simple + schema: + type: string content: application/json: schema: $ref: "#/components/schemas/DatabaseBriefDto" - "404": - description: Database could not be found + "403": + description: Not allowed to view database content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Not allowed to view database + "404": + description: Database could not be found content: application/json: schema: @@ -2628,12 +2701,6 @@ paths: type: string format: uuid responses: - "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: @@ -2648,8 +2715,8 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "417": - description: Generated query is malformed + "403": + description: Not the table owner. content: application/json: schema: @@ -2660,8 +2727,14 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Not the table owner. + "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: @@ -2696,12 +2769,14 @@ paths: type: string format: uuid responses: - "422": - description: Ontology does not have rdf or sparql endpoint + "200": + description: Suggested table column semantics successfully content: application/json: schema: - $ref: "#/components/schemas/ApiErrorDto" + type: array + items: + $ref: "#/components/schemas/TableColumnEntityDto" "400": description: Generated query is malformed content: @@ -2714,14 +2789,12 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "200": - description: Suggested table column semantics successfully + "422": + description: Ontology does not have rdf or sparql endpoint content: application/json: schema: - type: array - items: - $ref: "#/components/schemas/TableColumnEntityDto" + $ref: "#/components/schemas/ApiErrorDto" security: - bearerAuth: [] - basicAuth: [] @@ -2740,18 +2813,18 @@ paths: type: string format: uuid 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" + "404": + description: Container image could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" delete: tags: - container-endpoint @@ -2801,16 +2874,65 @@ paths: $ref: "#/components/schemas/ConceptDto" components: schemas: - ApiErrorDto: + UserAttributesDto: + 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 required: - - code - - message - - status + - language + - theme + UserDto: + 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 + example: 2025-01-23T12:09:01 + qualified_name: + type: string + example: Josiah Carberry — @jcarberry + given_name: + type: string + example: Josiah + family_name: + type: string + example: Carberry + required: + - attributes + - id + - password + - username + ApiErrorDto: type: object properties: status: type: string - example: NOT_FOUND enum: - 100 CONTINUE - 101 SWITCHING_PROTOCOLS @@ -2881,69 +3003,18 @@ components: - 509 BANDWIDTH_LIMIT_EXCEEDED - 510 NOT_EXTENDED - 511 NETWORK_AUTHENTICATION_REQUIRED + example: NOT_FOUND message: type: string example: Error message code: type: string example: error.service.code - 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 + - code + - message + - status CreatorBriefDto: - required: - - creator_name - - id type: object properties: id: @@ -2958,41 +3029,35 @@ components: example: "Carberry, Josiah" name_type: type: string - example: Personal enum: - Personal - Organizational + example: Personal name_identifier: type: string example: 0000-0002-1825-0097 name_identifier_scheme: type: string - example: ORCID enum: - ORCID - ROR - ISNI - GRID + example: ORCID affiliation_identifier: type: string example: https://ror.org/05gq02987 affiliation_identifier_scheme: type: string - example: ROR enum: - ROR - GRID - ISNI - DatabaseBriefDto: + example: ROR required: - - contact + - creator_name - id - - identifiers - - internal_name - - is_public - - is_schema_public - - name - - owner_id + DatabaseBriefDto: type: object properties: id: @@ -3026,18 +3091,16 @@ components: example: 2f45ef7a-7f9b-4667-9156-152c87fe1ca5 preview_image: type: string - IdentifierBriefDto: required: - - creators - - database_id - - descriptions + - contact - id - - owned_by - - publication_year - - publisher - - status - - titles - - type + - identifiers + - internal_name + - is_public + - is_schema_public + - name + - owner_id + IdentifierBriefDto: type: object properties: id: @@ -3046,12 +3109,12 @@ components: example: b97cd56b-66ca-4354-9e6c-f47210cfaaec type: type: string - example: database enum: - database - subset - table - view + example: database creators: type: array items: @@ -3072,10 +3135,10 @@ components: example: TU Wien status: type: string - example: draft enum: - draft - published + example: draft database_id: type: string format: uuid @@ -3083,12 +3146,15 @@ components: query_id: type: string format: uuid + example: 1 table_id: type: string format: uuid + example: 1 view_id: type: string format: uuid + example: 1 publication_year: type: integer format: int32 @@ -3097,9 +3163,18 @@ components: type: string format: uuid example: 2f45ef7a-7f9b-4667-9156-152c87fe1ca5 - IdentifierDescriptionDto: required: + - creators + - database_id + - descriptions - id + - owned_by + - publication_year + - publisher + - status + - titles + - type + IdentifierDescriptionDto: type: object properties: id: @@ -3111,7 +3186,6 @@ components: example: "Air quality reports at Stephansplatz, Vienna" language: type: string - example: en enum: - ab - aa @@ -3297,9 +3371,9 @@ components: - yo - za - zu + example: en type: type: string - example: Abstract enum: - Abstract - Methods @@ -3307,9 +3381,10 @@ components: - TableOfContents - TechnicalInfo - Other - IdentifierTitleDto: + example: Abstract required: - id + IdentifierTitleDto: type: object properties: id: @@ -3321,7 +3396,6 @@ components: example: Airquality Demonstrator language: type: string - example: en enum: - ab - aa @@ -3507,6 +3581,7 @@ components: - yo - za - zu + example: en type: type: string enum: @@ -3514,10 +3589,9 @@ components: - Subtitle - TranslatedTitle - Other - UserBriefDto: required: - id - - username + UserBriefDto: type: object properties: id: @@ -3543,25 +3617,25 @@ components: family_name: type: string example: Carberry - DatabaseAccessDto: required: - - type - - user + - id + - username + DatabaseAccessDto: type: object properties: user: $ref: "#/components/schemas/UserBriefDto" type: type: string - example: read enum: - read - write_own - write_all - UserUpdateDto: + example: read required: - - language - - theme + - type + - user + UserUpdateDto: type: object properties: firstname: @@ -3582,10 +3656,10 @@ components: language: type: string example: en - OntologyModifyDto: required: - - prefix - - uri + - language + - theme + OntologyModifyDto: type: object properties: uri: @@ -3600,13 +3674,10 @@ components: rdf_path: type: string example: rdf/om-2.0.rdf - OntologyDto: required: - - id - prefix - - rdf - - sparql - uri + OntologyDto: type: object properties: id: @@ -3634,10 +3705,13 @@ components: rdf_path: type: string example: rdf/om-2.0.rdf - BannerMessageUpdateDto: required: - - message - - type + - id + - prefix + - rdf + - sparql + - uri + BannerMessageUpdateDto: type: object properties: type: @@ -3663,10 +3737,10 @@ components: type: string format: date-time example: 2021-03-12T15:26:21Z - BannerMessageBriefDto: required: - message - type + BannerMessageBriefDto: type: object properties: type: @@ -3684,23 +3758,21 @@ components: link_text: type: string example: More - ImageChangeDto: required: - - dialect - - driver_class - - jdbc_method - - registry + - message + - type + ImageChangeDto: type: object properties: registry: type: string example: docker.io/library defaultPort: - maximum: 65535 - minimum: 1024 type: integer format: int32 example: 5432 + maximum: 65535 + minimum: 1024 dialect: type: string example: Postgres @@ -3710,14 +3782,12 @@ components: jdbc_method: type: string example: postgresql - DataTypeDto: required: - - display_name - - documentation - - id - - is_buildable - - is_quoted - - value + - dialect + - driver_class + - jdbc_method + - registry + DataTypeDto: type: object properties: id: @@ -3773,14 +3843,14 @@ components: type: boolean description: frontend can build this data type example: true - ImageDto: required: - - data_types - - default + - display_name + - documentation - id - - name - - operators - - version + - is_buildable + - is_quoted + - value + ImageDto: type: object properties: id: @@ -3792,7 +3862,7 @@ components: example: mariadb version: type: string - example: "10.5" + example: 10.5 operators: type: array items: @@ -3804,12 +3874,14 @@ components: type: array items: $ref: "#/components/schemas/DataTypeDto" - OperatorDto: required: - - display_name - - documentation + - data_types + - default - id - - value + - name + - operators + - version + OperatorDto: type: object properties: id: @@ -3825,15 +3897,12 @@ components: display_name: type: string example: XOR - IdentifierSaveDto: required: - - creators - - database_id + - display_name + - documentation - id - - publication_year - - publisher - - titles - - type + - value + IdentifierSaveDto: type: object properties: id: @@ -3842,12 +3911,12 @@ components: example: 68e11675-1e0f-4d24-a6d9-887ad1c4445d type: type: string - example: database enum: - database - subset - table - view + example: database doi: type: string example: 10.1111/11111111 @@ -4064,15 +4133,19 @@ components: database_id: type: string format: uuid + example: null query_id: type: string format: uuid + example: null view_id: type: string format: uuid + example: null table_id: type: string format: uuid + example: null publication_day: type: integer format: int32 @@ -4089,10 +4162,15 @@ components: type: array items: $ref: "#/components/schemas/SaveRelatedIdentifierDto" - LicenseDto: required: - - identifier - - uri + - creators + - database_id + - id + - publication_year + - publisher + - titles + - type + LicenseDto: type: object properties: identifier: @@ -4107,10 +4185,10 @@ components: \ 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 + - identifier + - uri + SaveIdentifierCreatorDto: type: object properties: id: @@ -4131,35 +4209,35 @@ components: example: "Carberry, Josiah" name_type: type: string - example: Personal enum: - Personal - Organizational + example: Personal name_identifier: type: string example: 0000-0002-1825-0097 name_identifier_scheme: type: string - example: ORCID enum: - ORCID - ROR - ISNI - GRID + example: ORCID affiliation_identifier: type: string example: https://ror.org/04d836q62 affiliation_identifier_scheme: type: string - example: ROR enum: - ROR - GRID - ISNI - SaveIdentifierDescriptionDto: + example: ROR required: - - description + - creator_name - id + SaveIdentifierDescriptionDto: type: object properties: id: @@ -4171,7 +4249,6 @@ components: example: "Air quality reports at Stephansplatz, Vienna" language: type: string - example: en enum: - ab - aa @@ -4357,9 +4434,9 @@ components: - yo - za - zu + example: en type: type: string - example: Abstract enum: - Abstract - Methods @@ -4367,10 +4444,11 @@ components: - TableOfContents - TechnicalInfo - Other - SaveIdentifierFunderDto: + example: Abstract required: - - funder_name + - description - id + SaveIdentifierFunderDto: type: object properties: id: @@ -4385,26 +4463,26 @@ components: example: http://doi.org/10.13039/501100000780 funder_identifier_type: type: string - example: Crossref Funder ID enum: - Crossref Funder ID - ROR - GND - ISNI - Other + example: Crossref Funder ID scheme_uri: type: string example: http://doi.org/ award_number: type: string - example: "824087" + example: 824087 award_title: type: string example: EOSC-Life - SaveIdentifierTitleDto: required: + - funder_name - id - - title + SaveIdentifierTitleDto: type: object properties: id: @@ -4416,7 +4494,6 @@ components: example: Airquality Demonstrator language: type: string - example: en enum: - ab - aa @@ -4602,20 +4679,19 @@ components: - yo - za - zu + example: en type: type: string - example: Subtitle enum: - AlternativeTitle - Subtitle - TranslatedTitle - Other - SaveRelatedIdentifierDto: + example: Subtitle required: - id - - relation - - type - - value + - title + SaveRelatedIdentifierDto: type: object properties: id: @@ -4627,7 +4703,6 @@ components: example: 10.70124/dc4zh-9ce78 type: type: string - example: DOI enum: - DOI - URL @@ -4647,9 +4722,9 @@ components: - PURL - UPC - w3id + example: DOI relation: type: string - example: Cites enum: - IsCitedBy - Cites @@ -4685,10 +4760,13 @@ components: - Requires - IsObsoletedBy - Obsoletes - CreatorDto: + example: Cites required: - - creator_name - id + - relation + - type + - value + CreatorDto: type: object properties: id: @@ -4709,21 +4787,21 @@ components: example: "Carberry, Josiah" name_type: type: string - example: Personal enum: - Personal - Organizational + example: Personal name_identifier: type: string example: 0000-0002-1825-0097 name_identifier_scheme: type: string - example: ORCID enum: - ORCID - ROR - ISNI - GRID + example: ORCID name_identifier_scheme_uri: type: string example: https://orcid.org/ @@ -4732,33 +4810,18 @@ components: example: https://ror.org/05gq02987 affiliation_identifier_scheme: type: string - example: ROR enum: - ROR - GRID - ISNI + example: ROR affiliation_identifier_scheme_uri: type: string example: https://ror.org/ - IdentifierDto: required: - - creators - - database_id - - descriptions - - funders + - creator_name - id - - language - - licenses - - links - - owner - - publication_year - - publisher - - query - - query_hash - - query_normalized - - status - - titles - - type + IdentifierDto: type: object properties: id: @@ -4769,12 +4832,12 @@ components: $ref: "#/components/schemas/LinksDto" type: type: string - example: database enum: - database - subset - table - view + example: database titles: type: array items: @@ -5000,22 +5063,26 @@ components: $ref: "#/components/schemas/CreatorDto" status: type: string - example: draft enum: - draft - published + example: draft database_id: type: string format: uuid + example: null query_id: type: string format: uuid + example: null table_id: type: string format: uuid + example: null view_id: type: string format: uuid + example: null query_normalized: type: string example: "SELECT `id`, `value`, `location` FROM `air_quality` WHERE `location`\ @@ -5046,10 +5113,25 @@ components: type: integer format: int32 example: 2022 - IdentifierFunderDto: required: - - funder_name + - creators + - database_id + - descriptions + - funders - id + - language + - licenses + - links + - owner + - publication_year + - publisher + - query + - query_hash + - query_normalized + - status + - titles + - type + IdentifierFunderDto: type: object properties: id: @@ -5064,26 +5146,26 @@ components: example: http://doi.org/10.13039/501100000780 funder_identifier_type: type: string - example: Crossref Funder ID enum: - Crossref Funder ID - ROR - GND - ISNI - Other + example: Crossref Funder ID scheme_uri: type: string example: http://doi.org/ award_number: type: string - example: "824087" + example: 824087 award_title: type: string example: EOSC-Life - LinksDto: required: - - self - - self_html + - funder_name + - id + LinksDto: type: object properties: self: @@ -5095,12 +5177,13 @@ components: self_html: type: string example: http://example.com - RelatedIdentifierDto: + dashboard_html: + type: string + example: http://example.com/d/defi2baxqawaod required: - - id - - relation - - type - - value + - self + - self_html + RelatedIdentifierDto: type: object properties: id: @@ -5112,7 +5195,6 @@ components: example: 10.70124/dc4zh-9ce78 type: type: string - example: DOI enum: - DOI - URL @@ -5132,9 +5214,9 @@ components: - PURL - UPC - w3id + example: DOI relation: type: string - example: Cites enum: - IsCitedBy - Cites @@ -5170,10 +5252,13 @@ components: - Requires - IsObsoletedBy - Obsoletes - DatabaseModifyVisibilityDto: + example: Cites required: - - is_public - - is_schema_public + - id + - relation + - type + - value + DatabaseModifyVisibilityDto: type: object properties: is_public: @@ -5182,10 +5267,14 @@ components: is_schema_public: type: boolean example: true - ViewUpdateDto: + is_dashboard_enabled: + type: boolean + example: true required: + - is_dashboard_enabled - is_public - is_schema_public + ViewUpdateDto: type: object properties: is_public: @@ -5194,14 +5283,10 @@ components: is_schema_public: type: boolean example: true - ViewBriefDto: required: - - database_id - - id - - internal_name - - name - - query - - query_hash + - is_public + - is_schema_public + ViewBriefDto: type: object properties: id: @@ -5238,33 +5323,31 @@ components: type: string format: uuid example: ac750fcf-ea02-4fce-85ac-d73857e18b35 - TableUpdateDto: required: - - is_public - - is_schema_public + - database_id + - id + - internal_name + - name + - query + - query_hash + TableUpdateDto: type: object properties: description: - maxLength: 180 - minLength: 0 type: string example: Air Quality in Austria + maxLength: 180 + minLength: 0 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 + TableBriefDto: type: object properties: id: @@ -5297,6 +5380,15 @@ components: type: string format: uuid example: 78337b80-5699-45db-8111-cec86439ab6b + required: + - database_id + - id + - internal_name + - is_public + - is_schema_public + - is_versioned + - name + - owned_by ColumnSemanticsUpdateDto: type: object properties: @@ -5305,15 +5397,6 @@ components: unit_uri: type: string ColumnDto: - required: - - database_id - - id - - internal_name - - is_null_allowed - - name - - ord - - table_id - - type type: object properties: id: @@ -5321,10 +5404,10 @@ components: format: uuid example: a453e444-e00d-41ca-902c-11e9c54b39f1 name: - maxLength: 64 - minLength: 0 type: string example: Given Name + maxLength: 64 + minLength: 0 alias: type: string example: firstname @@ -5347,16 +5430,18 @@ components: unit: $ref: "#/components/schemas/UnitBriefDto" description: - maxLength: 2048 - minLength: 0 type: string example: Column comment + maxLength: 2048 + minLength: 0 enums: type: array + description: "enum values, only considered when type = ENUM" items: $ref: "#/components/schemas/EnumDto" sets: type: array + description: "enum values, only considered when type = ENUM" items: $ref: "#/components/schemas/SetDto" database_id: @@ -5372,10 +5457,10 @@ components: format: int32 example: 0 internal_name: - maxLength: 64 - minLength: 0 type: string example: given_name + maxLength: 64 + minLength: 0 index_length: type: integer format: int64 @@ -5386,7 +5471,6 @@ components: example: 255 type: type: string - example: varchar enum: - char - varchar @@ -5418,6 +5502,7 @@ components: - timestamp - time - year + example: varchar data_length: type: integer format: int64 @@ -5442,10 +5527,16 @@ components: is_null_allowed: type: boolean example: false - ConceptBriefDto: required: + - database_id - id - - uri + - internal_name + - is_null_allowed + - name + - ord + - table_id + - type + ConceptBriefDto: type: object properties: id: @@ -5462,10 +5553,10 @@ components: type: string example: "name typically used to differentiate people from the same family,\ \ clan, or other social group who have a common last name" - EnumDto: required: - id - - value + - uri + EnumDto: type: object properties: id: @@ -5474,11 +5565,11 @@ components: example: 5343bb3d-14d3-4eb7-a86f-b8fc553cb315 value: type: string - example: "3" - SetDto: + example: 3 required: - id - value + SetDto: type: object properties: id: @@ -5487,11 +5578,11 @@ components: example: 7eb4eded-bacc-4a91-84db-a9ae6ddafda7 value: type: string - example: "3" - UnitBriefDto: + example: 3 required: - id - - uri + - value + UnitBriefDto: type: object properties: id: @@ -5507,35 +5598,42 @@ components: description: type: string example: "subjective magnitude of value, meaning, or purpose" - DatabaseTransferDto: required: - id + - uri + DatabaseTransferDto: type: object properties: id: type: string format: uuid + required: + - id DatabaseModifyImageDto: type: object properties: key: type: string - CreateAccessDto: + DatabaseModifyDashboardDto: + type: object + properties: + uid: + type: string required: - - type + - uid + CreateAccessDto: type: object properties: type: type: string - example: read enum: - read - write_own - write_all - OntologyCreateDto: + example: read required: - - prefix - - uri + - type + OntologyCreateDto: type: object properties: uri: @@ -5547,10 +5645,10 @@ components: sparql_endpoint: type: string example: Ontology SPARQL endpoint - BannerMessageCreateDto: required: - - message - - type + - prefix + - uri + BannerMessageCreateDto: type: object properties: type: @@ -5576,16 +5674,10 @@ components: 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 + - message + - type + ImageCreateDto: type: object properties: registry: @@ -5606,28 +5698,30 @@ components: jdbc_method: type: string default_port: - maximum: 65535 - minimum: 1024 type: integer format: int32 - CreateIdentifierDto: + maximum: 65535 + minimum: 1024 required: - - creators - - database_id - - publication_year - - publisher - - titles - - type + - default_port + - dialect + - driver_class + - is_default + - jdbc_method + - name + - registry + - version + CreateIdentifierDto: type: object properties: type: type: string - example: database enum: - database - subset - table - view + example: database doi: type: string example: 10.1111/11111111 @@ -5848,12 +5942,15 @@ components: query_id: type: string format: uuid + example: null view_id: type: string format: uuid + example: null table_id: type: string format: uuid + example: null publication_day: type: integer format: int32 @@ -5870,12 +5967,14 @@ components: type: array items: $ref: "#/components/schemas/SaveRelatedIdentifierDto" - CreateDatabaseDto: required: - - container_id - - is_public - - is_schema_public - - name + - creators + - database_id + - publication_year + - publisher + - titles + - type + CreateDatabaseDto: type: object properties: name: @@ -5891,19 +5990,19 @@ components: is_schema_public: type: boolean example: true - CreateViewDto: required: + - container_id - is_public - is_schema_public - name - - query + CreateViewDto: type: object properties: name: - maxLength: 63 - minLength: 1 type: string example: Air Quality + maxLength: 63 + minLength: 1 query: $ref: "#/components/schemas/SubsetDto" is_public: @@ -5912,24 +6011,24 @@ components: is_schema_public: type: boolean example: true - FilterDto: required: - - column_id - - operator_id - - type - - value + - is_public + - is_schema_public + - name + - query + FilterDto: type: object properties: type: type: string - example: where enum: - where - or - and + example: where value: type: string - example: "1" + example: 1 column_id: type: string format: uuid @@ -5938,25 +6037,27 @@ components: type: string format: uuid example: 67c5b54d-2eb0-4f42-8dc1-a504562e9f32 - OrderDto: required: - column_id + - operator_id + - type + - value + OrderDto: type: object properties: direction: type: string - example: asc enum: - asc - desc + example: asc column_id: type: string format: uuid example: e891ba86-0258-41a6-a8d9-ff58bc10b618 - SubsetDto: required: - - columns - - table_id + - column_id + SubsetDto: type: object properties: columns: @@ -5974,15 +6075,20 @@ components: type: array items: $ref: "#/components/schemas/OrderDto" - table_id: + datasource_id: type: string format: uuid example: f7df2a7d-4ade-4c78-97b0-7c744d0893c7 - CreateForeignKeyDto: + datasource_type: + type: string + enum: + - table + - view required: - columns - - referenced_columns - - referenced_table + - datasource_id + - datasource_type + CreateForeignKeyDto: type: object properties: columns: @@ -5991,7 +6097,6 @@ components: - id items: type: string - example: "[\"id\"]" referenced_table: type: string example: sensor @@ -6001,30 +6106,29 @@ components: - other_id items: type: string - example: "[\"other_id\"]" on_update: type: string - example: cascade enum: - restrict - cascade - set_null - no_action - set_default + example: cascade on_delete: type: string - example: cascade enum: - restrict - cascade - set_null - no_action - set_default - CreateTableColumnDto: + example: cascade required: - - name - - null_allowed - - type + - columns + - referenced_columns + - referenced_table + CreateTableColumnDto: type: object properties: name: @@ -6032,7 +6136,6 @@ components: example: Date type: type: string - example: varchar enum: - char - varchar @@ -6064,6 +6167,7 @@ components: - timestamp - time - year + example: varchar size: type: integer format: int64 @@ -6073,22 +6177,20 @@ components: format: int64 example: 0 description: - maxLength: 2048 - minLength: 0 type: string example: Formatted as YYYY-MM-dd + maxLength: 2048 + minLength: 0 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 @@ -6099,12 +6201,11 @@ components: type: string unit_uri: type: string - CreateTableConstraintsDto: required: - - checks - - foreign_keys - - primary_key - - uniques + - name + - null_allowed + - type + CreateTableConstraintsDto: type: object properties: uniques: @@ -6114,38 +6215,37 @@ components: items: type: string checks: - uniqueItems: true type: array items: type: string + uniqueItems: true foreign_keys: type: array items: $ref: "#/components/schemas/CreateForeignKeyDto" primary_key: - uniqueItems: true type: array items: type: string - CreateTableDto: + uniqueItems: true required: - - columns - - constraints - - is_public - - is_schema_public - - name + - checks + - foreign_keys + - primary_key + - uniques + CreateTableDto: type: object properties: name: - maxLength: 64 - minLength: 1 type: string example: Air Quality + maxLength: 64 + minLength: 1 description: - maxLength: 180 - minLength: 0 type: string example: Air Quality in Austria + maxLength: 180 + minLength: 0 columns: type: array items: @@ -6158,14 +6258,13 @@ components: is_schema_public: type: boolean example: true - CreateContainerDto: required: - - host - - image_id + - columns + - constraints + - is_public + - is_schema_public - name - - privileged_password - - privileged_username - - quota + CreateContainerDto: type: object properties: name: @@ -6177,8 +6276,8 @@ components: example: data-db2 port: type: integer - description: Port of container format: int32 + description: Port of container example: 3306 quota: type: integer @@ -6186,8 +6285,8 @@ components: example: 50 image_id: type: string - description: Image ID format: uuid + description: Image ID example: 2360f3c4-85e0-4fac-a7c6-73b296b9dde2 ui_host: type: string @@ -6204,13 +6303,14 @@ components: type: string description: Password of privileged user example: dbrepo - ContainerDto: required: - - count - - id - - image - - internal_name + - host + - image_id - name + - privileged_password + - privileged_username + - quota + ContainerDto: type: object properties: id: @@ -6239,17 +6339,17 @@ components: last_retrieved: type: string format: date-time + example: 2025-01-23T12:09:01 internal_name: type: string example: air_quality - ColumnBriefDto: required: - - database_id + - count - id + - image - internal_name - name - - table_id - - type + ColumnBriefDto: type: object properties: id: @@ -6257,10 +6357,10 @@ components: format: uuid example: a453e444-e00d-41ca-902c-11e9c54b39f1 name: - maxLength: 64 - minLength: 0 type: string example: Given Name + maxLength: 64 + minLength: 0 alias: type: string example: firstname @@ -6273,13 +6373,12 @@ components: format: uuid example: bfffa915-a547-4466-9c65-ddc0d38fdb08 internal_name: - maxLength: 64 - minLength: 0 type: string example: given_name + maxLength: 64 + minLength: 0 type: type: string - example: varchar enum: - char - varchar @@ -6311,11 +6410,15 @@ components: - timestamp - time - year - UnitDto: + example: varchar required: - - columns + - database_id - id - - uri + - internal_name + - name + - table_id + - type + UnitDto: type: object properties: id: @@ -6332,13 +6435,11 @@ components: type: array items: $ref: "#/components/schemas/ColumnBriefDto" - OntologyBriefDto: required: + - columns - id - - prefix - - rdf - - sparql - uri + OntologyBriefDto: type: object properties: id: @@ -6360,10 +6461,13 @@ components: uri_pattern: type: string example: http://www.wikidata.org/entity/.* - EntityDto: required: - - label + - id + - prefix + - rdf + - sparql - uri + EntityDto: type: object properties: uri: @@ -6375,6 +6479,9 @@ components: description: type: string example: open source semantic web framework for Java + required: + - label + - uri OaiListIdentifiersParameters: type: object properties: @@ -6388,19 +6495,15 @@ 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 - - message - - type type: object properties: id: @@ -6409,11 +6512,11 @@ components: example: ae3f795b-a3da-4ebe-bdc4-21a8ce631e6f type: type: string - example: WARNING enum: - error - warning - info + example: WARNING message: type: string example: Maintenance starts on 8am on Monday @@ -6431,12 +6534,11 @@ components: type: string format: date-time example: 2021-03-12T15:26:21Z - ImageBriefDto: required: - - default - id - - name - - version + - message + - type + ImageBriefDto: type: object properties: id: @@ -6448,14 +6550,16 @@ components: example: mariadb version: type: string - example: "10.5" + example: 10.5 default: type: boolean example: false - LdCreatorDto: required: - - '@type' + - default + - id - name + - version + LdCreatorDto: type: object properties: name: @@ -6468,19 +6572,10 @@ components: type: string '@type': type: string - LdDatasetDto: required: - - '@context' - '@type' - - citation - - creator - - description - - hasPart - - identifier - name - - temporalCoverage - - url - - version + LdDatasetDto: type: object properties: name: @@ -6514,15 +6609,19 @@ components: type: string '@type': type: string - ViewColumnDto: required: - - database_id - - id - - internal_name - - is_null_allowed + - '@context' + - '@type' + - citation + - creator + - description + - hasPart + - identifier - name - - ord - - type + - temporalCoverage + - url + - version + ViewColumnDto: type: object properties: id: @@ -6530,10 +6629,10 @@ components: format: uuid example: 6aec3a91-2e0b-4e92-a16a-9c3c5e892da1 name: - maxLength: 64 - minLength: 0 type: string example: Given Name + maxLength: 64 + minLength: 0 size: type: integer format: int64 @@ -6543,10 +6642,20 @@ components: format: int64 example: 0 description: - maxLength: 2048 - minLength: 0 type: string example: Column comment + maxLength: 2048 + minLength: 0 + enums: + type: array + description: "enum values, only considered when type = ENUM" + items: + $ref: "#/components/schemas/EnumDto" + sets: + type: array + description: "enum values, only considered when type = ENUM" + items: + $ref: "#/components/schemas/SetDto" database_id: type: string format: uuid @@ -6556,10 +6665,10 @@ components: format: int32 example: 0 internal_name: - maxLength: 64 - minLength: 0 type: string example: given_name + maxLength: 64 + minLength: 0 index_length: type: integer format: int64 @@ -6570,7 +6679,6 @@ components: example: 255 type: type: string - example: varchar enum: - char - varchar @@ -6602,20 +6710,19 @@ components: - timestamp - time - year + example: varchar is_null_allowed: type: boolean example: false - ViewDto: required: - - columns - database_id - id - - identifiers - internal_name + - is_null_allowed - name - - owner - - query - - query_hash + - ord + - type + ViewDto: type: object properties: id: @@ -6638,9 +6745,14 @@ components: type: array items: $ref: "#/components/schemas/ViewColumnDto" + created: + type: string + format: date-time + example: 2022-01-01 08:00:00.000 last_retrieved: type: string format: date-time + example: 2025-01-23T12:09:01 database_id: type: string format: uuid @@ -6661,6 +6773,17 @@ components: query_hash: type: string example: 7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916 + required: + - columns + - created + - database_id + - id + - identifiers + - internal_name + - name + - owner + - query + - query_hash ConstraintsDto: type: object properties: @@ -6669,22 +6792,21 @@ components: items: $ref: "#/components/schemas/UniqueDto" checks: - uniqueItems: true type: array example: - value > 1 items: type: string - example: "[\"value > 1\"]" + uniqueItems: true foreign_keys: type: array items: $ref: "#/components/schemas/ForeignKeyDto" primary_key: - uniqueItems: true type: array items: $ref: "#/components/schemas/PrimaryKeyDto" + uniqueItems: true ForeignKeyBriefDto: type: object properties: @@ -6693,11 +6815,6 @@ components: format: uuid example: f2b740ec-0b13-4d07-88a9-529d354bba6a ForeignKeyDto: - required: - - name - - referenced_table - - references - - table type: object properties: id: @@ -6717,27 +6834,28 @@ components: $ref: "#/components/schemas/TableBriefDto" on_update: type: string - example: restrict enum: - restrict - cascade - set_null - no_action - set_default + example: restrict on_delete: type: string - example: restrict enum: - restrict - cascade - set_null - no_action - set_default - ForeignKeyReferenceDto: + example: restrict required: - - column - - foreign_key - - referenced_column + - name + - referenced_table + - references + - table + ForeignKeyReferenceDto: type: object properties: id: @@ -6750,10 +6868,11 @@ components: $ref: "#/components/schemas/ForeignKeyBriefDto" referenced_column: $ref: "#/components/schemas/ColumnBriefDto" - PrimaryKeyDto: required: - column - - table + - foreign_key + - referenced_column + PrimaryKeyDto: type: object properties: id: @@ -6764,20 +6883,10 @@ components: $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 + - column + - table + TableDto: type: object properties: id: @@ -6797,19 +6906,24 @@ components: owner: $ref: "#/components/schemas/UserBriefDto" description: - maxLength: 2048 - minLength: 0 type: string example: Air Quality in Austria + maxLength: 2048 + minLength: 0 columns: type: array items: $ref: "#/components/schemas/ColumnDto" constraints: $ref: "#/components/schemas/ConstraintsDto" + created: + type: string + format: date-time + example: 2022-01-01 08:00:00.000 last_retrieved: type: string format: date-time + example: 2025-01-23T12:09:01 database_id: type: string format: uuid @@ -6841,25 +6955,34 @@ components: example: 5 data_length: type: integer - description: in bytes format: int64 + description: in bytes example: 16384 max_data_length: type: integer - description: in bytes format: int64 + description: in bytes example: 0 avg_row_length: type: integer - description: in bytes format: int64 + description: in bytes example: 3276 - UniqueDto: required: - columns + - constraints + - created + - database_id - id + - internal_name + - is_public + - is_schema_public + - is_versioned - name - - table + - owner + - queue_name + - routing_key + UniqueDto: type: object properties: id: @@ -6875,12 +6998,12 @@ components: type: array items: $ref: "#/components/schemas/ColumnBriefDto" - TableColumnEntityDto: required: - - column_id - - database_id - - table_id - - uri + - columns + - id + - name + - table + TableColumnEntityDto: type: object properties: uri: @@ -6904,15 +7027,12 @@ components: type: string format: uuid example: 297860e3-3b29-451c-ae8a-a85ed5941018 - ContainerBriefDto: required: - - count - - hash - - id - - image - - internal_name - - name - - quota + - column_id + - database_id + - table_id + - uri + ContainerBriefDto: type: object properties: id: @@ -6938,11 +7058,15 @@ components: internal_name: type: string example: air-quality - ConceptDto: required: - - columns + - count + - hash - id - - uri + - image + - internal_name + - name + - quota + ConceptDto: type: object properties: id: @@ -6959,6 +7083,10 @@ components: type: array items: $ref: "#/components/schemas/ColumnBriefDto" + required: + - columns + - id + - uri securitySchemes: basicAuth: type: http diff --git a/.docs/.openapi/api-search.yaml b/.docs/.openapi/api-search.yaml index c47cbfb649c8e832ccbd8238ea5e574ac522900b..1a49f213871711fa78de4c38279f1f14962a435d 100644 --- a/.docs/.openapi/api-search.yaml +++ b/.docs/.openapi/api-search.yaml @@ -1,6 +1,23 @@ { "components": { "schemas": { + "ApiError": { + "properties": { + "code": { + "example": "error.dashboard.create", + "type": "string" + }, + "message": { + "example": "Message", + "type": "string" + }, + "status": { + "example": "BAD_REQUEST", + "type": "string" + } + }, + "type": "object" + }, "IndexDto": { "properties": { "results": { @@ -98,7 +115,7 @@ }, "externalDocs": { "description": "Sourcecode Documentation", - "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.5/" + "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.7/" }, "info": { "contact": { @@ -111,7 +128,7 @@ "url": "https://www.apache.org/licenses/LICENSE-2.0" }, "title": "Database Repository Search Service API", - "version": "1.5" + "version": "1.8.0" }, "openapi": "3.0.0", "paths": { diff --git a/.docs/.openapi/api.base.yaml b/.docs/.openapi/api.base.yaml index 479c27da3aca47987eb200e9f5644aa5889f065e..0000a844fae4d649e97cbdbb1a4ca15e499e656c 100644 --- a/.docs/.openapi/api.base.yaml +++ b/.docs/.openapi/api.base.yaml @@ -11,7 +11,7 @@ components: type: http externalDocs: description: Project Website - url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.7/ + url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.8/ info: contact: email: andreas.rauber@tuwien.ac.at @@ -24,7 +24,7 @@ info: name: Apache 2.0 url: https://www.apache.org/licenses/LICENSE-2.0 title: DBRepo REST API - version: 1.7.3 + version: 1.8.0 openapi: 3.1.0 servers: - description: Test Instance diff --git a/.docs/.openapi/api.yaml b/.docs/.openapi/api.yaml index a61ecbcb81f0428f43060e342bcb4b0b8bd7482a..bdbfe6909e4880c775266e2f91583a4eeaed1c74 100644 --- a/.docs/.openapi/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.7.3 + version: 1.8.0 servers: - description: Test Instance url: 'https://test.dbrepo.tuwien.ac.at' @@ -24,7 +24,7 @@ servers: url: 'http://localhost' externalDocs: description: Project Website - url: 'https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.7/' + url: 'https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.8/' paths: /api/analyse/datatypes: get: @@ -199,10 +199,15 @@ paths: description: Expose `X-Count` custom header required: true style: simple + schema: + type: string X-Count: description: Number of rows required: true style: simple + schema: + type: integer + format: int64 content: application/json: schema: @@ -299,10 +304,15 @@ paths: description: Expose `X-Count` custom header required: true style: simple + schema: + type: string X-Count: description: Number of rows required: true style: simple + schema: + type: integer + format: int64 content: application/json: schema: @@ -402,10 +412,15 @@ paths: description: Expose `X-Count` custom header required: true style: simple + schema: + type: string X-Count: description: Number of rows required: true style: simple + schema: + type: integer + format: int64 content: application/json: schema: @@ -689,10 +704,15 @@ paths: description: Expose `X-Count` custom header required: true style: simple + schema: + type: string X-Count: description: Number of rows required: true style: simple + schema: + type: integer + format: int64 content: application/json: schema: @@ -787,16 +807,26 @@ paths: description: Reverse proxy exposing of custom headers required: true style: simple + schema: + type: string X-Count: description: Number of rows style: simple + schema: + type: string + format: uuid X-Id: description: The subset id required: true style: simple + schema: + type: string + format: uuid X-Headers: description: The list of headers separated by comma style: simple + schema: + type: string content: application/json: schema: @@ -892,16 +922,26 @@ paths: description: Reverse proxy exposing of custom headers required: true style: simple + schema: + type: string X-Count: description: Number of rows style: simple + schema: + type: string + format: uuid X-Id: description: The subset id required: true style: simple + schema: + type: string + format: uuid X-Headers: description: The list of headers separated by comma style: simple + schema: + type: string content: application/json: schema: @@ -1023,13 +1063,13 @@ paths: content: application/json: schema: - required: - - file type: object properties: file: type: string format: binary + required: + - file required: true responses: '201': @@ -1558,10 +1598,15 @@ paths: description: Expose `X-Count` custom header required: true style: simple + schema: + type: string X-Count: description: Number of databases required: true style: simple + schema: + type: integer + format: int64 content: application/json: schema: @@ -1575,7 +1620,7 @@ paths: description: >- Creates a database in the container with id. Requires roles `create-database`. - operationId: create_4 + operationId: create1 requestBody: content: application/json: @@ -1659,10 +1704,15 @@ paths: description: Expose `X-Count` custom header required: true style: simple + schema: + type: string X-Count: description: Number of databases required: true style: simple + schema: + type: integer + format: int64 content: application/json: schema: @@ -1723,7 +1773,7 @@ paths: description: >- Modifies access of a user with given id to database with given id. Requires role `update-database-access`. - operationId: update_5 + operationId: update parameters: - name: databaseId in: path @@ -1790,7 +1840,7 @@ paths: description: >- Give a user with given id access to some database with given id. Requires role `create-database-access`. - operationId: create_7 + operationId: create_11 parameters: - name: databaseId in: path @@ -1985,7 +2035,7 @@ paths: - ontology-endpoint summary: Update ontology description: Updates an ontology with id. Requires role `update-ontology`. - operationId: update + operationId: update_1 parameters: - name: ontologyId in: path @@ -2048,7 +2098,7 @@ paths: - message-endpoint summary: Update message description: Updates a message with id. Requires role `update-maintenance-message`. - operationId: update_1 + operationId: update_2 parameters: - name: messageId in: path @@ -2139,7 +2189,7 @@ paths: description: >- Updates container image in the metadata database. Requires role `modify-image`. - operationId: update_2 + operationId: update_3 parameters: - name: imageId in: path @@ -2204,7 +2254,7 @@ paths: description: >- Finds an identifier with id. The response format depends on the HTTP `Accept` header set on the request. - operationId: find_7 + operationId: find_5 parameters: - name: identifierId in: path @@ -2510,7 +2560,7 @@ paths: - view-endpoint summary: Get view description: Gets a view with id in the metadata database. - operationId: find_8 + operationId: find_6 parameters: - name: databaseId in: path @@ -2553,7 +2603,7 @@ paths: 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 + operationId: update_4 parameters: - name: databaseId in: path @@ -2684,7 +2734,7 @@ paths: `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 + operationId: findById_1 parameters: - name: databaseId in: path @@ -2725,7 +2775,7 @@ paths: - table-endpoint summary: Update table description: Updates a table in the database with id. Requires role `update-table`. - operationId: update_4 + operationId: update_5 parameters: - name: databaseId in: path @@ -3170,10 +3220,8 @@ paths: content: '*/*': schema: - type: array - items: - type: string - format: byte + type: string + format: byte '404': description: Database or user could not be found content: @@ -3244,13 +3292,69 @@ paths: security: - bearerAuth: [] - basicAuth: [] + '/api/database/{databaseId}/dashboard': + put: + tags: + - database-endpoint + summary: Update database dashboard uid + description: >- + Updates the dashboard uid for a database with given id. Only the + database owner can perform this operation. Requires role `system`. + operationId: modifyDashboard + parameters: + - name: databaseId + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/DatabaseModifyDashboardDto' + required: true + responses: + '202': + description: Modify of dashboard uid was successful + content: + application/json: + schema: + $ref: '#/components/schemas/DatabaseBriefDto' + '400': + description: Malformed payload + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '404': + description: Database could not be found + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '502': + description: Connection to search service failed + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '503': + description: Failed to save in search service + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + security: + - bearerAuth: [] + - basicAuth: [] /api/ontology: get: tags: - ontology-endpoint summary: List ontologies description: Lists all ontologies known to the metadata database. - operationId: findAll_2 + operationId: findAll responses: '200': description: List ontologies @@ -3267,7 +3371,7 @@ paths: description: >- Creates an ontology in the metadata database. Requires role `create-ontology`. - operationId: create1 + operationId: create_2 requestBody: content: application/json: @@ -3318,7 +3422,7 @@ paths: description: >- Creates a message in the metadata database. Requires role `create-maintenance-message`. - operationId: create_11 + operationId: create_3 requestBody: content: application/json: @@ -3341,7 +3445,7 @@ paths: - image-endpoint summary: List images description: Lists all container images known to the metadata database. - operationId: findAll_3 + operationId: findAll_1 responses: '200': description: List images @@ -3358,7 +3462,7 @@ paths: description: >- Creates a container image in the metadata database. Requires role `create-image`. - operationId: create_2 + operationId: create_4 requestBody: content: application/json: @@ -3393,7 +3497,7 @@ paths: - identifier-endpoint summary: List identifiers description: Lists all identifiers known to the metadata database - operationId: findAll_4 + operationId: findAll_2 parameters: - name: type in: query @@ -3450,7 +3554,9 @@ paths: schema: type: array items: - type: string + type: array + items: + $ref: '#/components/schemas/IdentifierBriefDto' application/ld+json: schema: type: array @@ -3465,7 +3571,7 @@ paths: 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_3 + operationId: create_5 requestBody: content: application/json: @@ -3518,7 +3624,7 @@ paths: - view-endpoint summary: List views description: Lists views known to the metadata database. - operationId: findAll_5 + operationId: findAll_3 parameters: - name: databaseId in: path @@ -3551,7 +3657,7 @@ paths: description: >- Creates a view. This can only be performed by the database owner. Requires role `create-database-view`. - operationId: create_5 + operationId: create_6 parameters: - name: databaseId in: path @@ -3626,7 +3732,7 @@ paths: 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 + operationId: list_3 parameters: - name: databaseId in: path @@ -3663,7 +3769,7 @@ paths: - table-endpoint summary: Create table description: Creates a table in the database with id. Requires role `create-table`. - operationId: create_6 + operationId: create_7 parameters: - name: databaseId in: path @@ -3729,7 +3835,7 @@ paths: - container-endpoint summary: List containers description: List all containers in the metadata database. - operationId: findAll_6 + operationId: findAll_4 parameters: - name: limit in: query @@ -3804,7 +3910,7 @@ paths: 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 + operationId: findAll_5 parameters: - name: username in: query @@ -3826,7 +3932,7 @@ paths: - unit-endpoint summary: List units description: Lists units known to the metadata database. - operationId: findAll_1 + operationId: findAll_6 responses: '200': description: Find all semantic units @@ -3844,7 +3950,7 @@ paths: description: >- Finds semantic entities by label or uri in an ontology with id. Requires role `execute-semantic-query`. - operationId: find_5 + operationId: find_7 parameters: - name: ontologyId in: path @@ -3903,7 +4009,7 @@ paths: tags: - metadata-endpoint summary: Get record - operationId: identify_1_1_1_1 + operationId: identify parameters: - name: verb in: query @@ -3916,14 +4022,16 @@ paths: '200': description: List containers content: - text/xml: {} + text/xml: + schema: + type: string '/api/message/message/{messageId}': get: tags: - message-endpoint summary: Find message description: Finds a message with id in the metadata database. - operationId: find_6 + operationId: find_8 parameters: - name: messageId in: path @@ -3950,7 +4058,7 @@ paths: - license-endpoint summary: List licenses description: Lists licenses known to the metadata database. - operationId: list_3 + operationId: list_4 responses: '200': description: List of licenses @@ -3994,7 +4102,7 @@ paths: - database-endpoint summary: Find database description: Finds a database with id. - operationId: findById_1 + operationId: findById_2 parameters: - name: databaseId in: path @@ -4009,12 +4117,18 @@ paths: X-Username: description: The authentication username style: simple + schema: + type: string Access-Control-Expose-Headers: description: Expose custom headers style: simple + schema: + type: string X-Password: description: The authentication password style: simple + schema: + type: string content: application/json: schema: @@ -4432,14 +4546,23 @@ components: example: ',' type: string type: object + ApiError: + properties: + code: + example: error.dashboard.create + type: string + message: + example: Message + type: string + status: + example: BAD_REQUEST + type: string + type: object ColumnAnalysisDto: properties: d: example: 4 type: integer - dfid: - example: null - type: integer enums: example: null properties: @@ -4459,15 +4582,6 @@ components: example: decimal type: string type: object - ErrorDto: - properties: - message: - example: Message - type: string - success: - example: false - type: boolean - type: object KeysDto: properties: keys: @@ -4481,15 +4595,10 @@ components: - keys type: object ApiErrorDto: - required: - - code - - message - - status type: object properties: status: type: string - example: NOT_FOUND enum: - 100 CONTINUE - 101 SWITCHING_PROTOCOLS @@ -4560,46 +4669,44 @@ components: - 509 BANDWIDTH_LIMIT_EXCEEDED - 510 NOT_EXTENDED - 511 NETWORK_AUTHENTICATION_REQUIRED + example: NOT_FOUND message: type: string example: Error message code: type: string example: error.service.code - TupleUpdateDto: required: - - data - - keys + - code + - message + - status + TupleUpdateDto: 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 + - data + - keys + QueryPersistDto: type: object properties: persist: type: boolean example: true - CreatorBriefDto: required: - - creator_name - - id + - persist + CreatorBriefDto: type: object properties: id: @@ -4614,43 +4721,35 @@ components: example: 'Carberry, Josiah' name_type: type: string - example: Personal enum: - Personal - Organizational + example: Personal name_identifier: type: string example: 0000-0002-1825-0097 name_identifier_scheme: type: string - example: ORCID enum: - ORCID - ROR - ISNI - GRID + example: ORCID affiliation_identifier: type: string example: 'https://ror.org/05gq02987' affiliation_identifier_scheme: type: string - example: ROR enum: - ROR - GRID - ISNI - IdentifierBriefDto: + example: ROR required: - - creators - - database_id - - descriptions + - creator_name - id - - owned_by - - publication_year - - publisher - - status - - titles - - type + IdentifierBriefDto: type: object properties: id: @@ -4659,12 +4758,12 @@ components: example: b97cd56b-66ca-4354-9e6c-f47210cfaaec type: type: string - example: database enum: - database - subset - table - view + example: database creators: type: array items: @@ -4685,10 +4784,10 @@ components: example: TU Wien status: type: string - example: draft enum: - draft - published + example: draft database_id: type: string format: uuid @@ -4696,12 +4795,15 @@ components: query_id: type: string format: uuid + example: 1 table_id: type: string format: uuid + example: 1 view_id: type: string format: uuid + example: 1 publication_year: type: integer format: int32 @@ -4710,9 +4812,18 @@ components: type: string format: uuid example: 2f45ef7a-7f9b-4667-9156-152c87fe1ca5 - IdentifierDescriptionDto: required: + - creators + - database_id + - descriptions - id + - owned_by + - publication_year + - publisher + - status + - titles + - type + IdentifierDescriptionDto: type: object properties: id: @@ -4724,7 +4835,6 @@ components: example: 'Air quality reports at Stephansplatz, Vienna' language: type: string - example: en enum: - ab - aa @@ -4910,9 +5020,9 @@ components: - yo - za - zu + example: en type: type: string - example: Abstract enum: - Abstract - Methods @@ -4920,9 +5030,10 @@ components: - TableOfContents - TechnicalInfo - Other - IdentifierTitleDto: + example: Abstract required: - id + IdentifierTitleDto: type: object properties: id: @@ -4934,7 +5045,6 @@ components: example: Airquality Demonstrator language: type: string - example: en enum: - ab - aa @@ -5120,6 +5230,7 @@ components: - yo - za - zu + example: en type: type: string enum: @@ -5127,17 +5238,9 @@ components: - Subtitle - TranslatedTitle - Other - QueryDto: required: - - database_id - - execution - id - - identifiers - - is_persisted - - owner - - query - - query_hash - - query_normalized + QueryDto: type: object properties: id: @@ -5155,10 +5258,10 @@ components: example: SELECT `id` FROM `air_quality` type: type: string - example: query enum: - query - view + example: query identifiers: type: array items: @@ -5183,10 +5286,17 @@ components: type: integer format: int64 example: 1 - UserBriefDto: required: + - database_id + - execution - id - - username + - identifiers + - is_persisted + - owner + - query + - query_hash + - query_normalized + UserBriefDto: type: object properties: id: @@ -5212,10 +5322,10 @@ components: family_name: type: string example: Carberry - CreatorDto: required: - - creator_name - id + - username + CreatorDto: type: object properties: id: @@ -5236,21 +5346,21 @@ components: example: 'Carberry, Josiah' name_type: type: string - example: Personal enum: - Personal - Organizational + example: Personal name_identifier: type: string example: 0000-0002-1825-0097 name_identifier_scheme: type: string - example: ORCID enum: - ORCID - ROR - ISNI - GRID + example: ORCID name_identifier_scheme_uri: type: string example: 'https://orcid.org/' @@ -5259,33 +5369,31 @@ components: example: 'https://ror.org/05gq02987' affiliation_identifier_scheme: type: string - example: ROR enum: - ROR - GRID - ISNI + example: ROR affiliation_identifier_scheme_uri: type: string example: 'https://ror.org/' - IdentifierDto: required: - - creators - - database_id - - descriptions - - funders + - creator_name - id - - language - - licenses - - links - - owner - - publication_year - - publisher - - query - - query_hash - - query_normalized - - status - - titles - - type + EnumDto: + type: object + properties: + id: + type: string + format: uuid + example: 5343bb3d-14d3-4eb7-a86f-b8fc553cb315 + value: + type: string + example: 3 + required: + - id + - value + IdentifierDto: type: object properties: id: @@ -5296,12 +5404,12 @@ components: $ref: '#/components/schemas/LinksDto' type: type: string - example: database enum: - database - subset - table - view + example: database titles: type: array items: @@ -5528,22 +5636,26 @@ components: $ref: '#/components/schemas/CreatorDto' status: type: string - example: draft enum: - draft - published + example: draft database_id: type: string format: uuid + example: null query_id: type: string format: uuid + example: null table_id: type: string format: uuid + example: null view_id: type: string format: uuid + example: null query_normalized: type: string example: >- @@ -5575,10 +5687,25 @@ components: type: integer format: int32 example: 2022 - IdentifierFunderDto: required: - - funder_name + - creators + - database_id + - descriptions + - funders - id + - language + - licenses + - links + - owner + - publication_year + - publisher + - query + - query_hash + - query_normalized + - status + - titles + - type + IdentifierFunderDto: type: object properties: id: @@ -5593,26 +5720,26 @@ components: example: 'http://doi.org/10.13039/501100000780' funder_identifier_type: type: string - example: Crossref Funder ID enum: - Crossref Funder ID - ROR - GND - ISNI - Other + example: Crossref Funder ID scheme_uri: type: string example: 'http://doi.org/' award_number: type: string - example: '824087' + example: 824087 award_title: type: string example: EOSC-Life - LicenseDto: required: - - identifier - - uri + - funder_name + - id + LicenseDto: type: object properties: identifier: @@ -5628,10 +5755,10 @@ components: preservation of copyright and license notices. Licensed works, modifications, and larger works may be distributed under different terms and without source code. - LinksDto: required: - - self - - self_html + - identifier + - uri + LinksDto: type: object properties: self: @@ -5643,12 +5770,13 @@ components: self_html: type: string example: 'http://example.com' - RelatedIdentifierDto: + dashboard_html: + type: string + example: 'http://example.com/d/defi2baxqawaod' required: - - id - - relation - - type - - value + - self + - self_html + RelatedIdentifierDto: type: object properties: id: @@ -5660,7 +5788,6 @@ components: example: 10.70124/dc4zh-9ce78 type: type: string - example: DOI enum: - DOI - URL @@ -5680,9 +5807,9 @@ components: - PURL - UPC - w3id + example: DOI relation: type: string - example: Cites enum: - IsCitedBy - Cites @@ -5718,15 +5845,26 @@ components: - Requires - IsObsoletedBy - Obsoletes - ViewColumnDto: + example: Cites required: - - database_id - id - - internal_name - - is_null_allowed - - name - - ord + - relation - type + - value + SetDto: + type: object + properties: + id: + type: string + format: uuid + example: 7eb4eded-bacc-4a91-84db-a9ae6ddafda7 + value: + type: string + example: 3 + required: + - id + - value + ViewColumnDto: type: object properties: id: @@ -5734,10 +5872,10 @@ components: format: uuid example: 6aec3a91-2e0b-4e92-a16a-9c3c5e892da1 name: - maxLength: 64 - minLength: 0 type: string example: Given Name + maxLength: 64 + minLength: 0 size: type: integer format: int64 @@ -5747,10 +5885,20 @@ components: format: int64 example: 0 description: - maxLength: 2048 - minLength: 0 type: string example: Column comment + maxLength: 2048 + minLength: 0 + enums: + type: array + description: 'enum values, only considered when type = ENUM' + items: + $ref: '#/components/schemas/EnumDto' + sets: + type: array + description: 'enum values, only considered when type = ENUM' + items: + $ref: '#/components/schemas/SetDto' database_id: type: string format: uuid @@ -5760,10 +5908,10 @@ components: format: int32 example: 0 internal_name: - maxLength: 64 - minLength: 0 type: string example: given_name + maxLength: 64 + minLength: 0 index_length: type: integer format: int64 @@ -5774,7 +5922,6 @@ components: example: 255 type: type: string - example: varchar enum: - char - varchar @@ -5806,20 +5953,19 @@ components: - timestamp - time - year + example: varchar is_null_allowed: type: boolean example: false - ViewDto: required: - - columns - database_id - id - - identifiers - internal_name + - is_null_allowed - name - - owner - - query - - query_hash + - ord + - type + ViewDto: type: object properties: id: @@ -5842,9 +5988,14 @@ components: type: array items: $ref: '#/components/schemas/ViewColumnDto' + created: + type: string + format: date-time + example: '2022-01-01T08:00:00.000Z' last_retrieved: type: string format: date-time + example: '2025-01-23T12:09:01.000Z' database_id: type: string format: uuid @@ -5865,24 +6016,29 @@ components: query_hash: type: string example: 7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916 - TupleDto: required: - - data + - columns + - created + - database_id + - id + - identifiers + - internal_name + - name + - owner + - query + - query_hash + TupleDto: type: object properties: data: type: object additionalProperties: type: object - example: - key: value example: key: value - ImportDto: required: - - header - - location - - separator + - data + ImportDto: type: object properties: location: @@ -5903,24 +6059,23 @@ components: line_termination: type: string example: \r\n - FilterDto: required: - - column_id - - operator_id - - type - - value + - header + - location + - separator + FilterDto: type: object properties: type: type: string - example: where enum: - where - or - and + example: where value: type: string - example: '1' + example: 1 column_id: type: string format: uuid @@ -5929,25 +6084,27 @@ components: type: string format: uuid example: 67c5b54d-2eb0-4f42-8dc1-a504562e9f32 - OrderDto: required: - column_id + - operator_id + - type + - value + OrderDto: type: object properties: direction: type: string - example: asc enum: - asc - desc + example: asc column_id: type: string format: uuid example: e891ba86-0258-41a6-a8d9-ff58bc10b618 - SubsetDto: required: - - columns - - table_id + - column_id + SubsetDto: type: object properties: columns: @@ -5965,15 +6122,20 @@ components: type: array items: $ref: '#/components/schemas/OrderDto' - table_id: + datasource_id: type: string format: uuid example: f7df2a7d-4ade-4c78-97b0-7c744d0893c7 - TableHistoryDto: + datasource_type: + type: string + enum: + - table + - view required: - - event - - timestamp - - total + - columns + - datasource_id + - datasource_type + TableHistoryDto: type: object properties: timestamp: @@ -5982,31 +6144,30 @@ components: example: '2021-03-12T15:26:21.000Z' event: type: string - example: INSERT enum: - insert - delete + example: INSERT total: type: integer format: int64 example: 1 - TupleDeleteDto: required: - - keys + - event + - timestamp + - total + TupleDeleteDto: type: object properties: keys: type: object additionalProperties: type: object - example: - id: 1 example: id: 1 - UserAttributesDto: required: - - language - - theme + - keys + UserAttributesDto: type: object properties: theme: @@ -6021,12 +6182,10 @@ components: language: type: string example: en - UserDto: required: - - attributes - - id - - password - - username + - language + - theme + UserDto: type: object properties: id: @@ -6047,6 +6206,7 @@ components: last_retrieved: type: string format: date-time + example: '2025-01-23T12:09:01.000Z' qualified_name: type: string example: Josiah Carberry — @jcarberry @@ -6056,16 +6216,12 @@ components: family_name: type: string example: Carberry - DatabaseBriefDto: required: - - contact + - attributes - id - - identifiers - - internal_name - - is_public - - is_schema_public - - name - - owner_id + - password + - username + DatabaseBriefDto: type: object properties: id: @@ -6099,25 +6255,31 @@ components: example: 2f45ef7a-7f9b-4667-9156-152c87fe1ca5 preview_image: type: string - DatabaseAccessDto: required: - - type - - user + - contact + - id + - identifiers + - internal_name + - is_public + - is_schema_public + - name + - owner_id + DatabaseAccessDto: type: object properties: user: $ref: '#/components/schemas/UserBriefDto' type: type: string - example: read enum: - read - write_own - write_all - UserUpdateDto: + example: read required: - - language - - theme + - type + - user + UserUpdateDto: type: object properties: firstname: @@ -6138,10 +6300,10 @@ components: language: type: string example: en - OntologyModifyDto: required: - - prefix - - uri + - language + - theme + OntologyModifyDto: type: object properties: uri: @@ -6156,13 +6318,10 @@ components: rdf_path: type: string example: rdf/om-2.0.rdf - OntologyDto: required: - - id - prefix - - rdf - - sparql - uri + OntologyDto: type: object properties: id: @@ -6190,10 +6349,13 @@ components: rdf_path: type: string example: rdf/om-2.0.rdf - BannerMessageUpdateDto: required: - - message - - type + - id + - prefix + - rdf + - sparql + - uri + BannerMessageUpdateDto: type: object properties: type: @@ -6219,10 +6381,10 @@ components: type: string format: date-time example: '2021-03-12T15:26:21.000Z' - BannerMessageBriefDto: required: - message - type + BannerMessageBriefDto: type: object properties: type: @@ -6240,23 +6402,21 @@ components: link_text: type: string example: More - ImageChangeDto: required: - - dialect - - driver_class - - jdbc_method - - registry + - message + - type + ImageChangeDto: type: object properties: registry: type: string example: docker.io/library defaultPort: - maximum: 65535 - minimum: 1024 type: integer format: int32 example: 5432 + maximum: 65535 + minimum: 1024 dialect: type: string example: Postgres @@ -6266,14 +6426,12 @@ components: jdbc_method: type: string example: postgresql - DataTypeDto: required: - - display_name - - documentation - - id - - is_buildable - - is_quoted - - value + - dialect + - driver_class + - jdbc_method + - registry + DataTypeDto: type: object properties: id: @@ -6329,14 +6487,14 @@ components: type: boolean description: frontend can build this data type example: true - ImageDto: required: - - data_types - - default + - display_name + - documentation - id - - name - - operators - - version + - is_buildable + - is_quoted + - value + ImageDto: type: object properties: id: @@ -6348,7 +6506,7 @@ components: example: mariadb version: type: string - example: '10.5' + example: 10.5 operators: type: array items: @@ -6360,12 +6518,14 @@ components: type: array items: $ref: '#/components/schemas/DataTypeDto' - OperatorDto: required: - - display_name - - documentation + - data_types + - default - id - - value + - name + - operators + - version + OperatorDto: type: object properties: id: @@ -6381,15 +6541,12 @@ components: display_name: type: string example: XOR - IdentifierSaveDto: required: - - creators - - database_id + - display_name + - documentation - id - - publication_year - - publisher - - titles - - type + - value + IdentifierSaveDto: type: object properties: id: @@ -6398,12 +6555,12 @@ components: example: 68e11675-1e0f-4d24-a6d9-887ad1c4445d type: type: string - example: database enum: - database - subset - table - view + example: database doi: type: string example: 10.1111/11111111 @@ -6620,15 +6777,19 @@ components: database_id: type: string format: uuid + example: null query_id: type: string format: uuid + example: null view_id: type: string format: uuid + example: null table_id: type: string format: uuid + example: null publication_day: type: integer format: int32 @@ -6645,10 +6806,15 @@ components: type: array items: $ref: '#/components/schemas/SaveRelatedIdentifierDto' - SaveIdentifierCreatorDto: required: - - creator_name + - creators + - database_id - id + - publication_year + - publisher + - titles + - type + SaveIdentifierCreatorDto: type: object properties: id: @@ -6669,35 +6835,35 @@ components: example: 'Carberry, Josiah' name_type: type: string - example: Personal enum: - Personal - Organizational + example: Personal name_identifier: type: string example: 0000-0002-1825-0097 name_identifier_scheme: type: string - example: ORCID enum: - ORCID - ROR - ISNI - GRID + example: ORCID affiliation_identifier: type: string example: 'https://ror.org/04d836q62' affiliation_identifier_scheme: type: string - example: ROR enum: - ROR - GRID - ISNI - SaveIdentifierDescriptionDto: + example: ROR required: - - description + - creator_name - id + SaveIdentifierDescriptionDto: type: object properties: id: @@ -6709,7 +6875,6 @@ components: example: 'Air quality reports at Stephansplatz, Vienna' language: type: string - example: en enum: - ab - aa @@ -6895,9 +7060,9 @@ components: - yo - za - zu + example: en type: type: string - example: Abstract enum: - Abstract - Methods @@ -6905,10 +7070,11 @@ components: - TableOfContents - TechnicalInfo - Other - SaveIdentifierFunderDto: + example: Abstract required: - - funder_name + - description - id + SaveIdentifierFunderDto: type: object properties: id: @@ -6923,26 +7089,26 @@ components: example: 'http://doi.org/10.13039/501100000780' funder_identifier_type: type: string - example: Crossref Funder ID enum: - Crossref Funder ID - ROR - GND - ISNI - Other + example: Crossref Funder ID scheme_uri: type: string example: 'http://doi.org/' award_number: type: string - example: '824087' + example: 824087 award_title: type: string example: EOSC-Life - SaveIdentifierTitleDto: required: + - funder_name - id - - title + SaveIdentifierTitleDto: type: object properties: id: @@ -6954,7 +7120,6 @@ components: example: Airquality Demonstrator language: type: string - example: en enum: - ab - aa @@ -7140,20 +7305,19 @@ components: - yo - za - zu + example: en type: type: string - example: Subtitle enum: - AlternativeTitle - Subtitle - TranslatedTitle - Other - SaveRelatedIdentifierDto: + example: Subtitle required: - id - - relation - - type - - value + - title + SaveRelatedIdentifierDto: type: object properties: id: @@ -7165,7 +7329,6 @@ components: example: 10.70124/dc4zh-9ce78 type: type: string - example: DOI enum: - DOI - URL @@ -7185,9 +7348,9 @@ components: - PURL - UPC - w3id + example: DOI relation: type: string - example: Cites enum: - IsCitedBy - Cites @@ -7223,10 +7386,13 @@ components: - Requires - IsObsoletedBy - Obsoletes - DatabaseModifyVisibilityDto: + example: Cites required: - - is_public - - is_schema_public + - id + - relation + - type + - value + DatabaseModifyVisibilityDto: type: object properties: is_public: @@ -7235,10 +7401,14 @@ components: is_schema_public: type: boolean example: true - ViewUpdateDto: + is_dashboard_enabled: + type: boolean + example: true required: + - is_dashboard_enabled - is_public - is_schema_public + ViewUpdateDto: type: object properties: is_public: @@ -7247,14 +7417,10 @@ components: is_schema_public: type: boolean example: true - ViewBriefDto: required: - - database_id - - id - - internal_name - - name - - query - - query_hash + - is_public + - is_schema_public + ViewBriefDto: type: object properties: id: @@ -7291,33 +7457,31 @@ components: type: string format: uuid example: ac750fcf-ea02-4fce-85ac-d73857e18b35 - TableUpdateDto: required: - - is_public - - is_schema_public + - database_id + - id + - internal_name + - name + - query + - query_hash + TableUpdateDto: type: object properties: description: - maxLength: 180 - minLength: 0 type: string example: Air Quality in Austria + maxLength: 180 + minLength: 0 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 + TableBriefDto: type: object properties: id: @@ -7350,6 +7514,15 @@ components: type: string format: uuid example: 78337b80-5699-45db-8111-cec86439ab6b + required: + - database_id + - id + - internal_name + - is_public + - is_schema_public + - is_versioned + - name + - owned_by ColumnSemanticsUpdateDto: type: object properties: @@ -7358,15 +7531,6 @@ components: unit_uri: type: string ColumnDto: - required: - - database_id - - id - - internal_name - - is_null_allowed - - name - - ord - - table_id - - type type: object properties: id: @@ -7374,10 +7538,10 @@ components: format: uuid example: a453e444-e00d-41ca-902c-11e9c54b39f1 name: - maxLength: 64 - minLength: 0 type: string example: Given Name + maxLength: 64 + minLength: 0 alias: type: string example: firstname @@ -7400,16 +7564,18 @@ components: unit: $ref: '#/components/schemas/UnitBriefDto' description: - maxLength: 2048 - minLength: 0 type: string example: Column comment + maxLength: 2048 + minLength: 0 enums: type: array + description: 'enum values, only considered when type = ENUM' items: $ref: '#/components/schemas/EnumDto' sets: type: array + description: 'enum values, only considered when type = ENUM' items: $ref: '#/components/schemas/SetDto' database_id: @@ -7425,10 +7591,10 @@ components: format: int32 example: 0 internal_name: - maxLength: 64 - minLength: 0 type: string example: given_name + maxLength: 64 + minLength: 0 index_length: type: integer format: int64 @@ -7439,7 +7605,6 @@ components: example: 255 type: type: string - example: varchar enum: - char - varchar @@ -7471,6 +7636,7 @@ components: - timestamp - time - year + example: varchar data_length: type: integer format: int64 @@ -7495,10 +7661,16 @@ components: is_null_allowed: type: boolean example: false - ConceptBriefDto: required: + - database_id - id - - uri + - internal_name + - is_null_allowed + - name + - ord + - table_id + - type + ConceptBriefDto: type: object properties: id: @@ -7516,43 +7688,17 @@ components: example: >- name typically used to differentiate people from the same family, clan, or other social group who have a common last name - EnumDto: required: - id - - value + - uri + UnitBriefDto: type: object properties: id: type: string format: uuid - example: 5343bb3d-14d3-4eb7-a86f-b8fc553cb315 - value: - type: string - example: '3' - SetDto: - required: - - id - - value - type: object - properties: - id: - type: string - format: uuid - example: 7eb4eded-bacc-4a91-84db-a9ae6ddafda7 - value: - type: string - example: '3' - UnitBriefDto: - required: - - id - - uri - type: object - properties: - id: - type: string - format: uuid - example: ba1935e8-6817-488f-af0a-f54389af9000 - uri: + example: ba1935e8-6817-488f-af0a-f54389af9000 + uri: type: string example: 'http://www.wikidata.org/entity/Q1422583' name: @@ -7561,35 +7707,42 @@ components: description: type: string example: 'subjective magnitude of value, meaning, or purpose' - DatabaseTransferDto: required: - id + - uri + DatabaseTransferDto: type: object properties: id: type: string format: uuid + required: + - id DatabaseModifyImageDto: type: object properties: key: type: string - CreateAccessDto: + DatabaseModifyDashboardDto: + type: object + properties: + uid: + type: string required: - - type + - uid + CreateAccessDto: type: object properties: type: type: string - example: read enum: - read - write_own - write_all - OntologyCreateDto: + example: read required: - - prefix - - uri + - type + OntologyCreateDto: type: object properties: uri: @@ -7601,10 +7754,10 @@ components: sparql_endpoint: type: string example: Ontology SPARQL endpoint - BannerMessageCreateDto: required: - - message - - type + - prefix + - uri + BannerMessageCreateDto: type: object properties: type: @@ -7630,16 +7783,10 @@ components: type: string format: date-time example: '2021-03-12T15:26:21.000Z' - ImageCreateDto: required: - - default_port - - dialect - - driver_class - - is_default - - jdbc_method - - name - - registry - - version + - message + - type + ImageCreateDto: type: object properties: registry: @@ -7660,28 +7807,30 @@ components: jdbc_method: type: string default_port: - maximum: 65535 - minimum: 1024 type: integer format: int32 - CreateIdentifierDto: + maximum: 65535 + minimum: 1024 required: - - creators - - database_id - - publication_year - - publisher - - titles - - type + - default_port + - dialect + - driver_class + - is_default + - jdbc_method + - name + - registry + - version + CreateIdentifierDto: type: object properties: type: type: string - example: database enum: - database - subset - table - view + example: database doi: type: string example: 10.1111/11111111 @@ -7902,12 +8051,15 @@ components: query_id: type: string format: uuid + example: null view_id: type: string format: uuid + example: null table_id: type: string format: uuid + example: null publication_day: type: integer format: int32 @@ -7924,12 +8076,14 @@ components: type: array items: $ref: '#/components/schemas/SaveRelatedIdentifierDto' - CreateDatabaseDto: required: - - container_id - - is_public - - is_schema_public - - name + - creators + - database_id + - publication_year + - publisher + - titles + - type + CreateDatabaseDto: type: object properties: name: @@ -7945,19 +8099,19 @@ components: is_schema_public: type: boolean example: true - CreateViewDto: required: + - container_id - is_public - is_schema_public - name - - query + CreateViewDto: type: object properties: name: - maxLength: 63 - minLength: 1 type: string example: Air Quality + maxLength: 63 + minLength: 1 query: $ref: '#/components/schemas/SubsetDto' is_public: @@ -7966,11 +8120,12 @@ components: is_schema_public: type: boolean example: true - CreateForeignKeyDto: required: - - columns - - referenced_columns - - referenced_table + - is_public + - is_schema_public + - name + - query + CreateForeignKeyDto: type: object properties: columns: @@ -7979,7 +8134,6 @@ components: - id items: type: string - example: '["id"]' referenced_table: type: string example: sensor @@ -7989,30 +8143,29 @@ components: - other_id items: type: string - example: '["other_id"]' on_update: type: string - example: cascade enum: - restrict - cascade - set_null - no_action - set_default + example: cascade on_delete: type: string - example: cascade enum: - restrict - cascade - set_null - no_action - set_default - CreateTableColumnDto: + example: cascade required: - - name - - null_allowed - - type + - columns + - referenced_columns + - referenced_table + CreateTableColumnDto: type: object properties: name: @@ -8020,7 +8173,6 @@ components: example: Date type: type: string - example: varchar enum: - char - varchar @@ -8052,6 +8204,7 @@ components: - timestamp - time - year + example: varchar size: type: integer format: int64 @@ -8061,22 +8214,20 @@ components: format: int64 example: 0 description: - maxLength: 2048 - minLength: 0 type: string example: Formatted as YYYY-MM-dd + maxLength: 2048 + minLength: 0 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 @@ -8087,12 +8238,11 @@ components: type: string unit_uri: type: string - CreateTableConstraintsDto: required: - - checks - - foreign_keys - - primary_key - - uniques + - name + - null_allowed + - type + CreateTableConstraintsDto: type: object properties: uniques: @@ -8102,38 +8252,37 @@ components: items: type: string checks: - uniqueItems: true type: array items: type: string + uniqueItems: true foreign_keys: type: array items: $ref: '#/components/schemas/CreateForeignKeyDto' primary_key: - uniqueItems: true type: array items: type: string - CreateTableDto: + uniqueItems: true required: - - columns - - constraints - - is_public - - is_schema_public - - name + - checks + - foreign_keys + - primary_key + - uniques + CreateTableDto: type: object properties: name: - maxLength: 64 - minLength: 1 type: string example: Air Quality + maxLength: 64 + minLength: 1 description: - maxLength: 180 - minLength: 0 type: string example: Air Quality in Austria + maxLength: 180 + minLength: 0 columns: type: array items: @@ -8146,14 +8295,13 @@ components: is_schema_public: type: boolean example: true - CreateContainerDto: required: - - host - - image_id + - columns + - constraints + - is_public + - is_schema_public - name - - privileged_password - - privileged_username - - quota + CreateContainerDto: type: object properties: name: @@ -8165,8 +8313,8 @@ components: example: data-db2 port: type: integer - description: Port of container format: int32 + description: Port of container example: 3306 quota: type: integer @@ -8174,8 +8322,8 @@ components: example: 50 image_id: type: string - description: Image ID format: uuid + description: Image ID example: 2360f3c4-85e0-4fac-a7c6-73b296b9dde2 ui_host: type: string @@ -8192,13 +8340,14 @@ components: type: string description: Password of privileged user example: dbrepo - ContainerDto: required: - - count - - id - - image - - internal_name + - host + - image_id - name + - privileged_password + - privileged_username + - quota + ContainerDto: type: object properties: id: @@ -8227,17 +8376,17 @@ components: last_retrieved: type: string format: date-time + example: '2025-01-23T12:09:01.000Z' internal_name: type: string example: air_quality - ColumnBriefDto: required: - - database_id + - count - id + - image - internal_name - name - - table_id - - type + ColumnBriefDto: type: object properties: id: @@ -8245,10 +8394,10 @@ components: format: uuid example: a453e444-e00d-41ca-902c-11e9c54b39f1 name: - maxLength: 64 - minLength: 0 type: string example: Given Name + maxLength: 64 + minLength: 0 alias: type: string example: firstname @@ -8261,13 +8410,12 @@ components: format: uuid example: bfffa915-a547-4466-9c65-ddc0d38fdb08 internal_name: - maxLength: 64 - minLength: 0 type: string example: given_name + maxLength: 64 + minLength: 0 type: type: string - example: varchar enum: - char - varchar @@ -8299,11 +8447,15 @@ components: - timestamp - time - year - UnitDto: + example: varchar required: - - columns + - database_id - id - - uri + - internal_name + - name + - table_id + - type + UnitDto: type: object properties: id: @@ -8320,13 +8472,11 @@ components: type: array items: $ref: '#/components/schemas/ColumnBriefDto' - OntologyBriefDto: required: + - columns - id - - prefix - - rdf - - sparql - uri + OntologyBriefDto: type: object properties: id: @@ -8348,10 +8498,13 @@ components: uri_pattern: type: string example: 'http://www.wikidata.org/entity/.*' - EntityDto: required: - - label + - id + - prefix + - rdf + - sparql - uri + EntityDto: type: object properties: uri: @@ -8363,6 +8516,9 @@ components: description: type: string example: open source semantic web framework for Java + required: + - label + - uri OaiListIdentifiersParameters: type: object properties: @@ -8376,19 +8532,15 @@ 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 - - message - - type type: object properties: id: @@ -8397,11 +8549,11 @@ components: example: ae3f795b-a3da-4ebe-bdc4-21a8ce631e6f type: type: string - example: WARNING enum: - error - warning - info + example: WARNING message: type: string example: Maintenance starts on 8am on Monday @@ -8419,12 +8571,11 @@ components: type: string format: date-time example: '2021-03-12T15:26:21.000Z' - ImageBriefDto: required: - - default - id - - name - - version + - message + - type + ImageBriefDto: type: object properties: id: @@ -8436,14 +8587,16 @@ components: example: mariadb version: type: string - example: '10.5' + example: 10.5 default: type: boolean example: false - LdCreatorDto: required: - - '@type' + - default + - id - name + - version + LdCreatorDto: type: object properties: name: @@ -8456,19 +8609,10 @@ components: type: string '@type': type: string - LdDatasetDto: required: - - '@context' - '@type' - - citation - - creator - - description - - hasPart - - identifier - name - - temporalCoverage - - url - - version + LdDatasetDto: type: object properties: name: @@ -8502,6 +8646,18 @@ components: type: string '@type': type: string + required: + - '@context' + - '@type' + - citation + - creator + - description + - hasPart + - identifier + - name + - temporalCoverage + - url + - version ConstraintsDto: type: object properties: @@ -8510,22 +8666,21 @@ components: items: $ref: '#/components/schemas/UniqueDto' checks: - uniqueItems: true type: array example: - value > 1 items: type: string - example: '["value > 1"]' + uniqueItems: true foreign_keys: type: array items: $ref: '#/components/schemas/ForeignKeyDto' primary_key: - uniqueItems: true type: array items: $ref: '#/components/schemas/PrimaryKeyDto' + uniqueItems: true ForeignKeyBriefDto: type: object properties: @@ -8534,11 +8689,6 @@ components: format: uuid example: f2b740ec-0b13-4d07-88a9-529d354bba6a ForeignKeyDto: - required: - - name - - referenced_table - - references - - table type: object properties: id: @@ -8558,27 +8708,28 @@ components: $ref: '#/components/schemas/TableBriefDto' on_update: type: string - example: restrict enum: - restrict - cascade - set_null - no_action - set_default + example: restrict on_delete: type: string - example: restrict enum: - restrict - cascade - set_null - no_action - set_default - ForeignKeyReferenceDto: + example: restrict required: - - column - - foreign_key - - referenced_column + - name + - referenced_table + - references + - table + ForeignKeyReferenceDto: type: object properties: id: @@ -8591,10 +8742,11 @@ components: $ref: '#/components/schemas/ForeignKeyBriefDto' referenced_column: $ref: '#/components/schemas/ColumnBriefDto' - PrimaryKeyDto: required: - column - - table + - foreign_key + - referenced_column + PrimaryKeyDto: type: object properties: id: @@ -8605,20 +8757,10 @@ components: $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 + - column + - table + TableDto: type: object properties: id: @@ -8638,19 +8780,24 @@ components: owner: $ref: '#/components/schemas/UserBriefDto' description: - maxLength: 2048 - minLength: 0 type: string example: Air Quality in Austria + maxLength: 2048 + minLength: 0 columns: type: array items: $ref: '#/components/schemas/ColumnDto' constraints: $ref: '#/components/schemas/ConstraintsDto' + created: + type: string + format: date-time + example: '2022-01-01T08:00:00.000Z' last_retrieved: type: string format: date-time + example: '2025-01-23T12:09:01.000Z' database_id: type: string format: uuid @@ -8682,25 +8829,34 @@ components: example: 5 data_length: type: integer - description: in bytes format: int64 + description: in bytes example: 16384 max_data_length: type: integer - description: in bytes format: int64 + description: in bytes example: 0 avg_row_length: type: integer - description: in bytes format: int64 + description: in bytes example: 3276 - UniqueDto: required: - columns + - constraints + - created + - database_id - id + - internal_name + - is_public + - is_schema_public + - is_versioned - name - - table + - owner + - queue_name + - routing_key + UniqueDto: type: object properties: id: @@ -8716,12 +8872,12 @@ components: type: array items: $ref: '#/components/schemas/ColumnBriefDto' - TableColumnEntityDto: required: - - column_id - - database_id - - table_id - - uri + - columns + - id + - name + - table + TableColumnEntityDto: type: object properties: uri: @@ -8745,15 +8901,12 @@ components: type: string format: uuid example: 297860e3-3b29-451c-ae8a-a85ed5941018 - ContainerBriefDto: required: - - count - - hash - - id - - image - - internal_name - - name - - quota + - column_id + - database_id + - table_id + - uri + ContainerBriefDto: type: object properties: id: @@ -8779,11 +8932,15 @@ components: internal_name: type: string example: air-quality - ConceptDto: required: - - columns + - count + - hash - id - - uri + - image + - internal_name + - name + - quota + ConceptDto: type: object properties: id: @@ -8800,6 +8957,10 @@ components: type: array items: $ref: '#/components/schemas/ColumnBriefDto' + required: + - columns + - id + - uri IndexDto: properties: results: diff --git a/.docs/.openapi/openapi-generate.sh b/.docs/.openapi/openapi-generate.sh index edd927d202b42256f1da21a4415410ccee50466d..aeab907799cf93e130b1a0596cdca7e68c34116d 100644 --- a/.docs/.openapi/openapi-generate.sh +++ b/.docs/.openapi/openapi-generate.sh @@ -1,14 +1,15 @@ #!/bin/bash declare -A services -services[4000]=search -services[5000]=analyse +services[4050]=analyse +services[4060]=search +services[4070]=dashboard services[9093]=data services[9099]=metadata # requires https://github.com/mikefarah/yq/ -> v4.44.3 function retrieve () { - if [[ "$2" == analyse ]] || [[ "$2" == search ]]; then + if [[ "$2" == analyse ]] || [[ "$2" == search ]] || [[ "$2" == dashboard ]]; then echo "... retrieve json api from localhost:$1" curl -sSL "http://localhost:$1/api-$2.json" | yq -o=json - > "./.docs/.openapi/api-$2.yaml" else diff --git a/.docs/api/broker-service.md b/.docs/api/broker-service.md index 373eb35b951305cdc75d634f253c805eee95df34..18bf4fe8b449a78db5c91166830a8d29d2573e51 100644 --- a/.docs/api/broker-service.md +++ b/.docs/api/broker-service.md @@ -61,9 +61,6 @@ The consumer takes care of writing it to the correct table in the [Data Service] ## Limitations -* No support for MQTT in the [Metadata Service](../system-services-metadata) - and [Data Service](../system-services-data) because of MQTT's missing permission system. - !!! 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/dashboard-service.md b/.docs/api/dashboard-service.md deleted file mode 100644 index ea3f5650463a087a6a32552681d237a94f21d869..0000000000000000000000000000000000000000 --- a/.docs/api/dashboard-service.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -author: Martin Weise ---- - -## tl;dr - -!!! debug "Debug Information" - - Image: [`docker.io/bitnami/grafana:10.4.9-debian-12-r0`](https://hub.docker.com/r/bitnami/grafana) - - * Ports: 3000/tcp - * UI: `http://<hostname>/dashboard` - * Management UI: `http://<hostname>:3000` (see [Management](#management)) - * Prometheus: `http://<hostname>/dashboard/metrics` - - To directly access in Kubernetes (for e.g. debugging), forward the svc port to your local machine: - - ```shell - kubectl [-n namespace] port-forward svc/dashboard-service 3000:3000 - ``` - -## Overview - -The Dashboard Service is visualizing the status of DBRepo with charts. The default dashboard provisioner located in -`/etc/grafana/provisioning/dashboards/provider.yaml` checks for new `JSON` dashboard files in `/app/dashboards` every 10 -seconds and makes the available in the Dashboard Service. - -## Management - -The Dashboard Service can be accessed with admin users (see [Identity Service](../../api/identity-service)). In this -case, access the UI via the port `3000` directly to avoid UI Redirects. - -!!! bug "UI Redirects" - - It is a known bug [#460](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/460) - that when being logged-in, the UI randomly redirects when being accessed from the Gateway Service, we therefore - recommend to access port `3000` directly: `http://<hostname>:3000`. Anonmyous users are not affected. - -## Limitations - -* Unintended redirects when being logged-in (see above). - -!!! question "Do you miss functionality? Do these limitations affect you?" - - We strongly encourage you to help us implement it as we are welcoming contributors to open-source software and get - in [contact](../../contact) with us, we happily answer requests for collaboration with attached CV and your programming - experience! - -## Security - -(none) diff --git a/.docs/api/data-service.md b/.docs/api/data-service.md index bc43a5d3631f7a9b4ecd85c64472bd25095a9603..66089a1cd69492c4f47f3048de1bcb31ac53c8a3 100644 --- a/.docs/api/data-service.md +++ b/.docs/api/data-service.md @@ -45,6 +45,19 @@ cache the connection details from the [Metadata Service](../metadata-service) su everytime e.g. a sensor measurement is inserted. By default, this information is stored for 60 minutes. System administrators can disable this behavior by setting `CREDENTIAL_CACHE_TIMEOUT=0` (cache is deleted after 0 seconds). + +## Storage + +The Data Service also is capable to upload files to the S3 backend. The default limit +of [`Tomcat`](https://spring.io/guides/gs/uploading-files#_tuning_file_upload_limits) in Spring Boot is configured to be +`2GB`. You can provide your own limit with setting `MAX_UPLOAD_SIZE`. + +By default, the Data Service removes datasets older than 24 hours on a regular basis every 60 minutes. You can set the +`MAX_AGE` (in seconds) and `S3_STALE_CRON` to fit your use-case. You can disable this feature by setting `S3_STALE_CRON` +to `-`, this may lead to storage issues as no space will be available inevitably. Note +that [Spring Boot uses its own flavor](https://spring.io/blog/2020/11/10/new-in-spring-5-3-improved-cron-expressions#usage) +of cron syntax. + ## Limitations * Views in DBRepo can only have 63-character length (it is assumed only internal views have the maximum length of 64 diff --git a/.docs/api/ui.md b/.docs/api/ui.md index b82058c19bae4c4e629e0f1e06eca29985c94f67..5393c9ff790f5eaf45607f78e42cf7f418720c1e 100644 --- a/.docs/api/ui.md +++ b/.docs/api/ui.md @@ -95,13 +95,8 @@ User Interface on development. * Frontend: [Vuetify 3+](https://vuetifyjs.com/en/) * State: [Pinia](https://pinia.vuejs.org/) -### Example - -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 f2cb6b83a17dc3d9f4b09efd2c231e8cfbdac917..5f530b9f6eddc45df60b63d68b8f00333099c6d1 100644 --- a/.docs/changelog.md +++ b/.docs/changelog.md @@ -2,6 +2,25 @@ author: Martin Weise --- +## v1.8.0 (2025-??-??) + +#### Features + +* Refactored internal Java-based testing data that improves test consistency + in [#510](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/510). +* Added automated dashboard generation for all public databases where each view has an overview of its data and + schema in [#460](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/460). + +#### Changes + +* Removed OpenSearch security plugin from the Docker test deployment and changed to the `bitnami/opensearch` image + of the same version in [#515](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/515). + +#### Fixes + +* Fixed a bug where validation of missing `Principal` object in Java services caused a 400 error instead of a 401 error + in [#512](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/512). + ## v1.7.3 (2025-03-17) [:simple-gitlab: GitLab Release](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/tags/v1.7.3) diff --git a/.docs/concepts/dashboards.md b/.docs/concepts/dashboards.md new file mode 100644 index 0000000000000000000000000000000000000000..e6dd2bf22f5d8ccdbaa8bed9e3017b7f1d9407f8 --- /dev/null +++ b/.docs/concepts/dashboards.md @@ -0,0 +1,27 @@ +--- +author: Martin Weise +--- + +We use [Grafana](https://grafana.com) to display and automatically generate dashboards that describe a dataset. + +## Provisioned Dashboards + +Every provisioned dashboard consists of two areas: + +1. **Unmanaged**: this area can be modified by the database owner and is not affected by provisioning. It is the area + above the "Generated Statistics" row. +2. **Managed**: this area is affected by provisioning, any changes to this area will be overridden and deleted without + notice. Note that the dashboard links are also affected by provisioning. + +Everytime the views of the database change (e.g. a new view is added, a view is deleted) then the dashboard for this +database is provisioned. + +<figure id="fig1" markdown> + +<figcaption>Figure 1: Generated dashboard containing unmanaged (yellow) and managed (green) content.</figcaption> +</figure> + +!!! question "How do I disable managed dashboards?" + + If you prefer not to have automatically-generated dashboards, you can disable managed dashboards for a database + in the UI. Go to **your database** > **Settings** > **Visibility** > **Managed Dashboard** > **Disabled**. \ No newline at end of file diff --git a/.docs/concepts/data-versioning.md b/.docs/concepts/data-versioning.md index 8a9abc667ba2b865fa055217d388e088ea9402f3..45a7cb6e7355c85a0008e0cbdaf57c515b1a3b33 100644 --- a/.docs/concepts/data-versioning.md +++ b/.docs/concepts/data-versioning.md @@ -6,34 +6,23 @@ Data is getting bigger and so are expectations of data provisioning in regards t after quality check and not in snapshot intervals), cost-effectiveness (i.e. no duplication of data), transparent, precise citation and many more. -[System-versioned](https://mariadb.com/kb/en/system-versioned-tables/) tables in MariaDB are improved data structures -that keep track of historical data. For each entry in a system-versioned table, a time period is maintained that denotes -the validity time span of this tuple from its start to end. Tuples in system-versioned tables are not *actually* -modified, they are marked as (in-)valid in time periods. - -<figure markdown> - -| ID | Sensor | Temp | Start | End | -|----|--------|------|-------|-----| -| 1 | A | 23.1 | t1 | | -| 2 | B | 25.8 | t2 | | - +System-versioned tables in MariaDB are improved data structures that keep track of historical data. For each entry in a +system-versioned table, a time period is maintained that denotes the validity time span of this tuple from its start to +end. Tuples in system-versioned tables are not *actually* modified, they are marked as (in-)valid in time periods +(c.f. [Fig. 1](#fig1)). + +<figure id="fig1" markdown> + +<figcaption>Fig. 1: Data versioning in MariaDB system-versioned tables.</figcaption> </figure> Assuming that Sensor A was calibrated wrong and an updated measurement is passed to the system-versioned table, the table contents show that the old row with Temp 23.1 is not deleted, but marked as valid in time span (t1, t3). The updated row with Temp 22.1 is marked as valid from time span t3 onwards. -<figure markdown> - -| ID | Sensor | Temp | Start | End | -|----|--------|------|-------|-----| -| 1 | A | 23.1 | t1 | t3 | -| 2 | B | 25.8 | t2 | | -| 1 | A | 22.1 | t3 | | - -</figure> +## Further Reading -System-versioned tables are part of the SQL:2011 standard and have been adopted by many database management system -vendors: MariaDB (10.5 and higher), Google BigQuery, IBM DB2 (12 and higher), SQL Server (2016 and higher), Azure SQL, -PostgreSQL with [temporal tables extension](https://github.com/nearform/temporal_tables), etc. \ No newline at end of file +System-versioned tables are part of the current ISO/IEC 9075-2:2023 ("SQL") standard and have been adopted by many +database management system vendors, e.g. MariaDB (10.5 and higher), Google BigQuery, IBM DB2 (12 and higher), +Cockroach DB, SAP HANA, SQL Server (2016 and higher), Azure SQL, PostgreSQL +with [temporal tables extension](https://github.com/nearform/temporal_tables), etc. \ No newline at end of file diff --git a/.docs/concepts/data-visibility.md b/.docs/concepts/data-visibility.md index 31c6ca3682780c4353c6aa5baaae666047893635..e08e717fa1463b89a47f3d9b49e1c0d812ea73ee 100644 --- a/.docs/concepts/data-visibility.md +++ b/.docs/concepts/data-visibility.md @@ -2,10 +2,23 @@ author: Martin Weise --- +## Overview + There are several ways to set the visibility of (meta-)data in DBRepo. It is possible to set the data visibility to visible/hidden and the schema to be visible/hidden for each database and separately for each table, each view and each subset of a database. +<figure markdown> + +| Name | `is_public` | `is_schema_public` | UI? | Search? | Dashboard? | +|-----------------------------|-------------|--------------------|--------------------|--------------------|--------------------| +| [Visible](#visibility) | `True` | `True` | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| [Data-only](#data-only) | `True` | `False` | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| [Schema-only](#schema-only) | `False` | `True` | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| [Hidden](#hidden) | `False` | `False` | :x: | :x: | :x: | + +</figure> + ## Visibility In total there are four possible visibility settings that can be applied on database level and then at the subsequent @@ -22,6 +35,8 @@ levels (table, view, subset). We give two examples for better understanding: 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. +In any case, a Grafana dashboard will be created. + #### Visible !!! info "Possible use-case: data publication supplement to an open-access publication" @@ -40,8 +55,9 @@ Where the resource's schema visibility is hidden but the data is visible. Where the resource's data visibility is hidden but the schema is visible. -#### Draft +#### Hidden !!! 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 +Where the resource's data and schema visibility is hidden. It will not be findable even in the search. The automatically +generated Dashboard cannot be viewed anonymously (only users with read-access can view). \ No newline at end of file diff --git a/.docs/concepts/ui.md b/.docs/concepts/ui.md deleted file mode 100644 index ab6848b7ba251bde381c81af5fd8fb0b03293910..0000000000000000000000000000000000000000 --- a/.docs/concepts/ui.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -author: Martin Weise ---- - -It provides a graphical interface for a researcher to interact with the API (c.f. Figure 1). - -<figure markdown> -{ .img-border } -<figcaption>Figure 1: User Interface</figcaption> -</figure> - -For examples on how to use the User Interface, visit the [API](../api/) page to find out how to create -users, databases and how to import your data. - -## Server / Client - -TBD - -## Cache - -TBD \ No newline at end of file diff --git a/.docs/images/architecture-data-db.svg b/.docs/images/architecture-data-db.svg deleted file mode 100644 index 788750a77ea797fec5210bd3f3dbb8e20dae6ddd..0000000000000000000000000000000000000000 --- a/.docs/images/architecture-data-db.svg +++ /dev/null @@ -1,3 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="426px" height="214px" viewBox="-0.5 -0.5 426 214"><defs/><g><rect x="0" y="37" width="248" height="130" rx="3.9" ry="3.9" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 246px; height: 1px; padding-top: 164px; margin-left: 1px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-style: italic; white-space: normal; overflow-wrap: normal;">shared filesystem<br />/tmp</div></div></div></foreignObject><text x="124" y="164" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle" font-style="italic">shared filesystem...</text></switch></g><path d="M 47.5 47.63 L 47.5 31 L 47.71 7" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 47.5 52.88 L 44 45.88 L 47.5 47.63 L 51 45.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 22px; margin-left: 48px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">jdbc</div></div></div></foreignObject><text x="48" y="25" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">jdbc</text></switch></g><path d="M 22.5 62.6 C 22.5 57.85 33.69 54 47.5 54 C 54.13 54 60.49 54.91 65.18 56.52 C 69.87 58.13 72.5 60.32 72.5 62.6 L 72.5 109.4 C 72.5 114.15 61.31 118 47.5 118 C 33.69 118 22.5 114.15 22.5 109.4 Z" fill="#dae8fc" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 72.5 62.6 C 72.5 67.35 61.31 71.2 47.5 71.2 C 33.69 71.2 22.5 67.35 22.5 62.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><rect x="6.5" y="116" width="85" height="20" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 89px; height: 1px; padding-top: 126px; margin-left: 5px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">data-db</div></div></div></foreignObject><text x="49" y="130" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">data-db</text></switch></g><path d="M 160 59.63 L 160 37 L 160.1 7" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 160 64.88 L 156.5 57.88 L 160 59.63 L 163.5 57.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 23px; margin-left: 160px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">http</div></div></div></foreignObject><text x="160" y="26" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">http</text></switch></g><path d="M 231.37 86 L 288.63 86" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 226.12 86 L 233.12 82.5 L 231.37 86 L 233.12 89.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 293.88 86 L 286.88 89.5 L 288.63 86 L 286.88 82.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 86px; margin-left: 260px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">S3</div></div></div></foreignObject><text x="260" y="89" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle">S3</text></switch></g><rect x="95" y="66" width="130" height="40" rx="6" ry="6" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 86px; margin-left: 96px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Data DB Sidecar</div></div></div></foreignObject><text x="160" y="90" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Data DB Sidecar</text></switch></g><rect x="295" y="66" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 86px; margin-left: 296px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Storage Service<br style="border-color: var(--border-color);" />(SeaweedFS)</div></div></div></foreignObject><text x="360" y="90" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Storage Service...</text></switch></g><rect x="242.5" y="177" width="30" height="16" fill="#e6e6e6" stroke="rgb(0, 0, 0)" pointer-events="all"/><rect x="280" y="177" width="140" height="16" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 138px; height: 1px; padding-top: 185px; margin-left: 282px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">External images</div></div></div></foreignObject><text x="282" y="189" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">External images</text></switch></g><rect x="242.5" y="197" width="30" height="16" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><rect x="280" y="197" width="140" height="16" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 138px; height: 1px; padding-top: 205px; margin-left: 282px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Maintained images</div></div></div></foreignObject><text x="282" y="209" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">Maintained images</text></switch></g><rect x="257.5" y="177" width="15" height="16" fill="#dae8fc" stroke="#000000" pointer-events="all"/></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file diff --git a/.docs/images/architecture-docker-compose.svg b/.docs/images/architecture-docker-compose.svg index 090ac2def7a18149a6f58cfde600bc153c5b2e2e..96d6fc1256d69597f18ecb86bce81ea26b88fbc7 100644 --- a/.docs/images/architecture-docker-compose.svg +++ b/.docs/images/architecture-docker-compose.svg @@ -1,3 +1,3 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="532px" height="614px" viewBox="-0.5 -0.5 532 614" style="background-color: rgb(255, 255, 255);"><defs/><rect fill="#ffffff" width="100%" height="100%" x="0" y="0"/><g><g data-cell-id="0"><g data-cell-id="1"><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-76"><g><rect x="0" y="91" width="530" height="397" rx="7.94" ry="7.94" fill="none" stroke="rgb(0, 0, 0)" stroke-dasharray="3 3" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-77"><g><path d="M 336.37 137 L 348 137 L 348 331 L 455 331 L 455 346.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 331.12 137 L 338.12 133.5 L 336.37 137 L 338.12 140.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 455 351.88 L 451.5 344.88 L 455 346.63 L 458.5 344.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-78"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 296px; margin-left: 411px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="396.5" y="290" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-79"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 238px; margin-left: 347px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="332.5" y="232" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-80"><g><rect x="220" y="488" width="310" height="123" rx="7.38" ry="7.38" fill="none" stroke="rgb(0, 0, 0)" stroke-dasharray="3 3" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-81"><g><path d="M 265 399.37 L 265 428.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 265 394.12 L 268.5 401.12 L 265 399.37 L 261.5 401.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 265 433.88 L 261.5 426.88 L 265 428.63 L 268.5 426.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 409px; margin-left: 265px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">LDAP</div></div></div></foreignObject><image x="250.5" y="403" width="29" height="15.75" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-82"><g><rect x="32.5" y="589" width="85" height="20" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 89px; height: 1px; padding-top: 599px; margin-left: 31px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">data-db</div></div></div></foreignObject><image x="31" y="592.5" width="89" height="17" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAWQAAABECAYAAAC2wE+iAAAAAXNSR0IArs4c6QAADoFJREFUeF7tnXXQLTkRxc/i7g4Fi7u7Lla4O4W7e+Gui3vh7u5W2OK6QCG7sLgWsLi7zI9KtrJhJLl3Mnfeq9P/vHrfzXR6TmbOJJ3uzj6yGAEjYASMwCoQ2GcVVtgII2AEjIARkAnZD4ERMAJGYCUImJBXMhA2wwgYASNgQvYzYASMgBFYCQIm5JUMhM0wAkbACJiQ/QwYASNgBFaCgAl5JQNhM4yAETACJmQ/A0bACBiBlSBgQl7JQMxkxqUlHZDo+puko82k22raIfCRbtz2S9Q/sBu3x/d0dyRJ/8j+fkFJB7YzzZqXRMCEvCTa7fsyIbfHuEUPJuQWqO6BOk3Ie+CgjZhsQt4zx9OEvGeO2+xWm5Bnh3SnCtdMyDxrD5F0REm/lfT0nSK1rs5NyOsaj51ZY0LeGfRNOl4zIZ9N0kHhrn8gad8mCOyZSk3Ie+a4zW61CXl2SHeqcM2EfBtJLzIh9z4fJuSdvjbr6dyEvJ6xmMOSNRPyiyXd2oRsQp7jQd9bdZiQ966RXTMhHyzprCZkE/Le9crNezcm5Hnx3LW2tRLy8ST9Wjqs3Kt9yId/Uuyy2PWbs5L+TcgrGYgBM04o6YaSriXpjJJOFtr9ImyQvUfSKyT9Lvx9G0Im+uGSkq4u6Tyhv+NKOqakP4XIiG9I+pyk10pixjsml5f0gQp4n9H1cc+R9nPbV2FaddNLdfjcQBL/nryLKOGDBIbfk/QpSa+R9MlE6zaEfIFuzL4QdB2/6+MWkq4k6RySTiTp35J+Luk7kt4l6XWSflZ9R75gEQRMyIvAvFEnNwuhYSeYuJoQsrtJelXI9uLljlKaqXe1jnif1L2sZ6mwlI/B7SX9ZOCaOQm5hX0Vt1rcFPJ9nqRrFFwBfreSdGjIruRjGqUmU+98kr4k6ZaS+KgdZ6LvP3TZfg+W9KwCG91kYQRMyAsDXtgdM8WnFbaNze4eXsyPVxIyscGPruwrNv+lpEtIOqTn+rkIuZV9G97y4GUnDrNeVjKl8k1JF+t866+XdLkNCflcki67QVz34wIxl9rqdgsgYEJeAOTKLngxWeqnY8Oy89WS3tLNhL4f9J1CEqTHEpVZ9L8k3Sd7MadmyCyrIYNU/iLpDZ3uT0j6kaS/hlkXG3K0P3/WnqXw2SXRVypHCXbxt2uGmWP8/ceSqMGQCkt6Zm+ptLSvclgmm380uCjSht/qXBbPl/TZ4EPHpYArATfUZUJD3AhHlnTFDQn5JsFthUvnnx3Bvz88P6xc/iPptJKuLemiPXdwPUlvnrwzN1gMARPyYlAXdXSEMMtl1hMForpyN4NKZ76pMmZm+HQh8t90y1Ze+ihjhAwJQBinSdp/N+iJpN9n9P0kPSH7gRk9y+UhuVGwMf5esqm3pH1FgzPSCGJ7Y/Y7HzpcEnzg+gRSxv/PhysftxqXBX5pSPfr3Urlxh35fnmgP2x5YciUjE2+3X18SdjJCxZti4ev3xABE/KGwDW67Kph4yVVj2/w5RP9HUvS53t8wGOEDMnjx0yFWRozrCl5d7e5d5WkETPAi8xMyEvaN3W/U7+DPZtrUdj8PG9YXYxdmybLpO1qCJnr2KRjxcHKY0zwHT8ma3AdSW+dukH/vgwCJuRlcC7t5SVhVhXbM/vBJ4k7YkpYluLSSGWMkJmh3UnSSSQxy+ZZ4F+WuVOSuxKwj82kPw9cuMkMeUn7pu537HdWGPmKggSYlxYoBfMvhqiWbQj5jsE1MtXlMbrknB92G3pE70RhM5gNZMsKEDAhr2AQEhMIT4Igo1CA516FJuJD5Pr0ZZvyIaeqeRZKyJhrztSzkXe6ENbVZ+4mhJzraWlfIcS9zfioPSf5BX8/4Wa4IUqkbwO3ZoaMS4sxz334Q32/LOw7xN95ZmI4ZYm9btMQARNyQ3ArVUPEvByp1C4n8SVDflFqCLnGXAiHWOhU2OxjtteKkFvaV6M7bwsZQ8pRvtK5AM5dofDM3Zjh4kilhpDfETZNS7vEBZbP3iF0EncsO0bAhLzjAUi6z5M6+Omckr5WYeJDJT0qad+KkEl0yGeAYydXzDFDroDhf4kYNfbV6M7b5kkdRC2wyVcqrGxw9bC5F6WGkB/ZXfSI0s66CIyLhwia9BJCF9NElQp1bjonAibkOdHcTtdNJb0yU4FfNg8FG+uFECh8glFqCBlfKAkYRHiw8060xrEl4XfMnxP+nyestCbklvZtM3JEKpw+UfDUEH5Yo5NolzNsSMg8N4RElsqpQjhj2v66PfsPpfrcbkYETMgzgrmlqtwXiTrC4Er9urQnQ+ztlYRMmjQkwgx9m+ehFSG3to9UYkiqRIhiSF1CXJP7/WtnrOjA1UNURpSaGXJpZEzUTTo82Z2pEMtOCJ5lxwhs8wLu2PS9rvv7drPRJyZ3RULG0SvvkljkD1YQ8u3ChhSHZ24rLQh5CfvyGe4YDiTBpDNZ2rKpxioiygN64rSnsCXGHLfBJoRM/RGSeEqF+O6/Z43vkm1Mlupyu5kRMCHPDOgW6u6fnTRc426I3eaxu2M6iCN+Z5iFp2Z/OLg9mLUxI8Rlkr/AtT7aTXzIS9m3LSGT+JGe7D00ux17NIjjvtCGhHzhUPCp9NHrO7ma1Rk1OCw7RsCEvOMBSLq/a0/BFzZ8CKMqlTxjbIiQeSnJ7Epne7Ql06skSaA1IS9p37aETD2PNNSQTdWHlw5YaMfGLennm8yQScFOC0pNdc2+RKwOGNvW+qGn+vDvGyJgQt4QuAaX9YUj4e/7fUVfuR96iJBz1wZd3EHSCwr7OmlPCcc5XRZL21d4273NSApJ088pCnXvSoW5H7rGh0ydEELfSuWUPRl9lHdN9x5KdbndzAiYkGcGdAt1fanCRDx8tUIniST3SNoPETKVvnjpoxBTzMZW7poY6ppl8meyH+ck5KXtq4D4/5rm7gayJYlaKJW+TbYaQiZxqOYEb6rL5SFuaU3lUrvdrgECJuQGoG6oklOYSZVOpbYa18dCkfmoY4iQ2VFP02XxG6flH6duoa8k5pyEvLR9U/c79nue+Yb7gfjxUqF05oeyxjWEzMGxbH6Wys2z2ihE8VALZSjtvVSv282AgAl5BhBnUsFYsIHGCR1RKCJOneMSIW6YmS5+5ylCxk/MMjUKJ1gQw1wi7NLjdz111nhOQl7avpL7HmqTR8dAcNQE+VWh0qf0uDhqCJkSqflYjHWdHjZLu77IkULT3WxuBEzIcyO6nb63ZWmwvGwkHZSUR3xQV1f3sVn3QzPkfFb33qx629hdEJoHCeVCBhjHE/VJHmUxRSJL27fNqBEnzYkdqZQW+yHxhlVRuimInhpCpj2rG1Y5U3LUrngVpU/ZA4jyzMzNNaXDvzdEwITcENwNVOfLSVRwPNOzJ3RREY6z7oh+SGWIkImV3T9pyK47Be+nlq1UeSORgvaEeqXhXmObS/hU35T0Rz8sk4eSXpa2b4OhOtwl1JGmJnEUSJZ6FlNZlowrMcC51BLygSElemoPgP2F3N+8X3fiCK4uywoQMCGvYBASE0gw4FgfdsKj8JLhTkgJLbWa+FVIEkJg+Zmm8Q4RMps41PBNZSw6ADcF9RIgCp4ZIjLYTErP4ONMPorX9wmhWfkM7gojh6Aubd+2T0Ef0XHqC2GEfa4LZqqsZjjhBYHQqZYXZYiQqXeRV3WLxe1x81CEPg9pizrJ6COSgr6jsDHbd5LItnj4+g0RMCFvCFzDy/rC3+iOI4J4oVhy4icmKoLThTnGiRRriJsZLG6PKLg60qI1qdm4F/KXEf3PDdXHeDbwTTKDor4vm44IIVb4nzkhI40mIEGCsDuyxogcSCu/sSTHv50+b2S4kYxAHQdiYynpmW5OLWnftsPJB+ugULs61UWMMh9LPn4QJzjg4gC3mK5NHQpWCsQCR6GQPJEmuUCmZHCmcttwEgjYUqiewwwO6D6aPw3PBUR//XBsVIo/NazJ8vv0tjfv6+dDwIQ8H5ZzasKvh6uiRjgBmpM80lOgedEh6z6hgBBujnQTcao/Unw51YSl+NCHAx2QLS6JVDidhNC+IYEg0hTupe2buvep3ymjyceI0qSlcnA45JTVRfoxIrEkrdoX9TFWf8yUc9I1H8x8/2DKBp4XjnSyrAgBE/KKBiMxhXFh+f+wrE5Cn7UsUe/czTCJlGCTKE8kYYY8tCnIsUuUi8R/PCYcnkndX3y78Yw49DLzS8//izr6CBk/N7PeIcLKCRldS9o3x5PAQbCEoRHrOyV8oCjqwyw6j7QYOhGaCnu5C4QPH3izOnlywfNyaIjcyQ+3nbLXvy+AgAl5AZC36IJlLX5IZqUsPQmnYsbL8p+EkfeFJWpavQsfY+qmmCo+TgEjfI+U3mQjipeePihYTuF0fL+UBe07+BTdVDejyhynTjBzxh/KTL2vRi8ZbSzH8Wcys8NWlvL4zSH3NFklwrakfVsM1WGX8k5Rh4PDBXAJEdGACwfSZLMPFwEfz/TQ2jxCZijcERcSLqsouUuKQw5YueCfZ4XB+PChIxPwkODOgohLTzOZAw/rqEDAhFwBlpsaASNgBFoiYEJuia51GwEjYAQqEDAhV4DlpkbACBiBlgiYkFuia91GwAgYgQoETMgVYLmpETACRqAlAibkluhatxEwAkagAgETcgVYbmoEjIARaImACbklutZtBIyAEahAwIRcAZabGgEjYARaImBCbomudRsBI2AEKhAwIVeA5aZGwAgYgZYImJBbomvdRsAIGIEKBEzIFWC5qREwAkagJQIm5JboWrcRMAJGoAIBE3IFWG5qBIyAEWiJgAm5JbrWbQSMgBGoQMCEXAGWmxoBI2AEWiJgQm6JrnUbASNgBCoQMCFXgOWmRsAIGIGWCJiQW6Jr3UbACBiBCgRMyBVguakRMAJGoCUCJuSW6Fq3ETACRqACARNyBVhuagSMgBFoiYAJuSW61m0EjIARqEDgvxIi9WMJqqzcAAAAAElFTkSuQmCC"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-83"><g><path d="M 42.5 428.63 L 42.5 393" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 42.5 433.88 L 39 426.88 L 42.5 428.63 L 46 426.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-84"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 412px; margin-left: 43px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">AMQP</div></div></div></foreignObject><image x="27" y="406" width="32" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAAA/CAYAAAAoosBrAAAAAXNSR0IArs4c6QAADUhJREFUeF7tnHeQFEUUxh+ISDKAKEEBQTIUKskIAorIkXMSYwkKJhRFECQYMICgIjkntQo9wJKoYI6FoIgKCIogJgwlBlDgrF9X9VRvb5ievbkT7ub9dbfb3dP9+usXvtezBbKysrIkknyrgQIRAPLt3quFRwDI3/sfASCf738EgAgAURCYrzEQxQD5evujIDCfb38EgAgAQXmAJk2ayFtvvRWjuOXLl0u7du3SUuaXX34p1apVi+s7ceJEuf3229Ma0+y0detWqVmzZtw4L730krRt2zat8T/++GNZuXKlfPDBB7J9+3b59ttv5c8//xTCqRNPPFFKly6tnnnuuedK69atpXHjxlKwYMHAz0qmm1QDFShQQE466SQpWbKkVK1aVc4//3y1zgsuuCBht0AxwOeffy61a9eOG4jNBwTpSLJForyNGzemM2RMn2HDhsnYsWOzDYDDhw/LvHnz5IknnpAtW7YEmlfFihUVmPv37y/Fixd37psOAJINXr9+fXnyySflkksuiWkSCACDBg0STqYtxx13nHzzzTdSvnx558XphqkWuWnTJjnnnHMCj6k7cCLPOussNTdbgliAzZs3y1VXXSWffPJJ2nOhY6VKlWTatGnSqlUrp3HCBAAPxAqNGTNG7rvvPu/5zgA4ePCgnHHGGfLzzz+rzmz23r17vYEefPDBmIGdVigi9iKZ5JEjR1T3O+64QyZMmOA6VFy7devWyWWXXaY+N8flf1cALFu2THr16iV///133PiY+ubNmyuQnXbaaXL88cfLjz/+qPTy+uuvy9dffx3XBxP92GOPyeDBg33XZeuG8RcvXpyy3z///CO//fabYK1Z/2effRbX/qmnnpJbb71Vfe4MgEWLFqlToGX69OmCed23b5/6qEqVKmozWWAQsRfZqFEj+fDDD9UQKBX/ysLTkWuvvVaZbaRevXoxJ9gFAOvXr5eWLVsK5t8UNn306NFy8cUXp/TtKJ+D8dxzz6n4wBRAcPfdd6dclq2bE044QQ4cOBBIFWvXrpUbb7xRdu3a5fUrUqSIEBvhmpwBcOmll8obb7yhBilUqJB8//33cu+998rMmTO9gV955RXvxLnO0l4koHr44Ye97kuXLpUOHTq4Due1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"/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-85"><g><rect x="10" y="435" width="130" height="40" rx="6" ry="6" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 455px; margin-left: 11px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">Data Service</div></div></div></foreignObject><image x="11" y="448.5" width="128" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-86"><g><path d="M 75 481.37 L 75 500 L 74.63 518.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 75 476.12 L 78.5 483.12 L 75 481.37 L 71.5 483.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 74.52 523.88 L 71.16 516.81 L 74.63 518.63 L 78.16 516.95 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-87"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 498px; margin-left: 75px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">JDBC</div></div></div></foreignObject><image x="60.5" y="492" width="29" height="15.75" xlink:href="data:image/png;base64,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"/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-88"><g><path d="M 146.37 373 L 193.63 373" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 141.12 373 L 148.12 369.5 L 146.37 373 L 148.12 376.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 198.88 373 L 191.88 376.5 L 193.63 373 L 191.88 369.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-89"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 374px; margin-left: 171px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">LDAP</div></div></div></foreignObject><image x="156.5" y="368" width="29" height="15.75" xlink:href="data:image/png;base64,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"/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-90"><g><path d="M 75 346.63 L 75 331 L 180 331 L 180 137 L 193.63 137" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 75 351.88 L 71.5 344.88 L 75 346.63 L 78.5 344.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 198.88 137 L 191.88 140.5 L 193.63 137 L 191.88 133.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-91"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 242px; margin-left: 181px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP,<div>AMQP</div></div></div></div></foreignObject><image x="165" y="229.5" width="32" height="28.75" xlink:href="data:image/png;base64,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G9VXoOnyyy8X1OuYMWPUf1GsCYZ9b62yB7n88ssnWawIlfWVgVdDu+yyi0qKhKisYX7BLgDghC01DFH/JjHpJ554oqyyyiq5azvC58O45ZZbuhV5crnX35YNN4X99ddfXqJ46KGH1Mngzz77LHmub9++gm3E0uQMgIEDB6pqVRDFCr/99luVcMj5QU0UYtRfnCuX9iABFVW0NN11112yySabuHaXtOM+4llnnVUdjID23ntvGT58ePJ7EQD4ilk3v/vuu+QZJuCaa65RGsGHMJo33XTTioKZaDqqo+UtByEAAJ9MPoYo2kkT8hg2bJgbAGxLGssW5keNGlUxgK233lqh3YfsQaKeKIDA+g8huI6ODp8uVdsbbrhBdtxxR/VvEM/k77rrrs4AWGeddYSvRxOTP3LkSOFDqIaQ4eqrr64+HE0sHWiJySefPLXLUACg84suuqjieBh3FHzxxRduADj00EMF61cTwt1+++2VaqQjPSiEhMqeccYZnWVkD5J7c/l6qYgJof75GllvfcicwA022ECVU+OiBE15GuCFF17o5jaFcEu547etra1iOchbCkICAE02++yzV7wbzVC4BGBUYPzptX6qqaZSanGKKaZQssSYOeeccxLBAhS8BVeyB4n65xzb4osvnnThK3xAyPqmjb6rrrpK2SbcsO0CgM0220xYejThS3ONi699kyYD0y7hdzwDrrzHk7IpJADoG5tKzyN/E8coBADHizhmpIkaNea6jwrjFKom4gQ+frI9yBNOOEGGDBmiAimoTcg3JnDGGWco+wTicAQaiqqae+65ZyEAqNBJwQXT8GNZY3kLQWml3h5//PHUpSU0AOaff375+OOPk2Fw3XwhALB4YVAT15VzV61JRJlQm5oobzpgwAAnedmD1JcZ4K8CBE0+MQG0hwYh5VO4LgX/e/DgwYUAwLZhydBERA2NV60nkiYEZPP8888nPx155JFy+umn97gGYGn+8ccfK2SaCwDCnNxIrevU8u933323G6O4hES5NGFsmZWs8pBgA0DfZ8P6NO+88ybvdo0JvPzyyxVFE/TR6EsvvVR5ApqybAAmw7x6nTX7vvvucwKzayP7HRiW5kem+wmpAVgWsdc0sZxRXiYXANxDj1GmCdV6xBFHdBsnahMDQ5eCIdz5zTffqLh4EWUBgOdaW1uT265cYwKEXPEkIPMZ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"/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-92"><g><rect x="10" y="353" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 373px; margin-left: 11px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><b>Broker Service</b><div><i>rabbitmq</i></div></div></div></div></foreignObject><image x="11" y="359" width="128" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-93"><g><path d="M 336.37 373 L 383.63 373" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 331.12 373 L 338.12 369.5 L 336.37 373 L 338.12 376.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 388.88 373 L 381.88 376.5 L 383.63 373 L 381.88 369.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 373px; margin-left: 360px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">LDAP</div></div></div></foreignObject><image x="345.5" y="367" width="29" height="15.75" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-94"><g><path d="M 265 346.63 L 265 153.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 265 351.88 L 261.5 344.88 L 265 346.63 L 268.5 344.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 265 148.12 L 268.5 155.12 L 265 153.37 L 261.5 155.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-95"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 238px; margin-left: 266px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="251.5" y="232" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-96"><g><rect x="200" y="353" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 373px; margin-left: 201px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><b>Identity Service *</b><div><i>openldap</i></div></div></div></div></foreignObject><image x="201" y="359" width="128" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-97"><g><path d="M 455 428.63 L 455 411 L 342 411 L 342 376 C 345.9 376 345.9 370 342 370 L 342 370 L 342 341 L 297.5 341 L 297.5 153.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 455 433.88 L 451.5 426.88 L 455 428.63 L 458.5 426.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 297.5 148.12 L 301 155.12 L 297.5 153.37 L 294 155.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-98"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 216px; margin-left: 298px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="283.5" y="210" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-99"><g><path d="M 422.5 435 L 422.5 421 L 268 421 C 268 417.1 262 417.1 262 421 L 262 421 L 107.5 421 L 107.5 428.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 107.5 433.88 L 104 426.88 L 107.5 428.63 L 111 426.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-100"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 422px; margin-left: 206px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="191.5" y="416" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-101"><g><rect x="390" y="435" width="130" height="40" rx="6" ry="6" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 455px; margin-left: 391px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">Metadata Service</div></div></div></foreignObject><image x="391" y="448.5" width="128" height="17" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAABECAYAAAD3Lo2pAAAAAXNSR0IArs4c6QAAHOxJREFUeF7t3QOwNE2WBuAza9u2bXtnjVlzlrO2jVlz1py1bdu2bdtGPxFdERUZJ0tdfb/bt8+JuPHF/3dVVuabevMo7xMlhUAhUAgUAoVAIXB1CNzn6lpcDS4ECoFCoBAoBAqBKAJQg6AQKAQKgUKgELhCBIoAXGGnV5MLgUKgECgECoEiADUGCoFCoBAoBAqBK0SgCMAVdno1uRAoBAqBQqAQKAJQY6AQKAQKgUKgELhCBIoAXGGnV5MLgUKgECgECoEiADUGCoFCoBAoBAqBK0SgCMAVdvqVN/kNIuKLOhg8f0T8+JXjU82/bgTePCI+uwPBs0fEz183PHer9UUA7lZ/VmvmESgCMI/RvXzikSPiGQ4k7Skj4lEiwn8/bET86/HvbyLit49//3QvK3pHv10E4I52bNasaycATnvPO9PfXxARb7xxTHxmRLzFzLs/ERHPt7H8em09AkUA1mN27jeeLSJeOyLuFxFPu/Bj/xcRPxsR3xoRD46IP1z4Xj02jUARgCsaIUUA5gnA30bE40bEf68cF7D9k4h4/AsjAO8fEQ8c1fkXIsICfVfkkgjA90TES4yA/8SIeKe70hHHU/5HR8Srndim/zqqrd81Iv79xLKu/fUiAFc0AooAzBMAw+GlI+K7V44L9uQfXfDObdMA/HJEPGMRgAU9d95HkE4E8iHvKAFAbL42Ih51Rxh/LiJeKiKQ9pJtCLxuRHxM59X7RsSvbiu23rqNCBQBWEYAPj0i3mZlB37UwWb5HgveuU0E4Jki4peaOpcGYEEnnuGRt4+IT2rKvSsaABol4/5hzoDbdx0cOV82Iv73DGVXkYXAnUKgCMAyAvBnBxXjE0YEu+NS+fWF9szbRAA+LCLepwjA0i4+63M/EhEvcAcJwENEhJP6s0yg99cR8f0R8RsHk8ffH81vHAKfOiJecoFZ7f4TkR5n7bQqvBC4JASKAOQEwEbfYvOCC1X6+v/pV6jKbhMB4F3N+3ospQG4+Rn9xBHxB8kYvAsagBePiO/tQMp+z44vDI1dPxME4vUj4lOOUQLZM4jD0918t9UXC4HLQqAIQE4Afu24iY978+Mi4t0Wdu97H9SbH948+5sR8TTJ+7eFADxXRPxUUr8iAAs7fcfHjLPMDnsXCACzBvNGJm8ZEZ+1EEeRMz8wYUZ41oNz4S8uLKseKwSuEoEiADkBcAJ5QDMifjc5HfcGjU39eZofP+9wqnuTHQiAE/rLHVWhQqYeKyIeLSL+4eCn8JdHzcO3RMQ3HRZaMdNT8ufHCIe1g39JaORTHL27hVnyLXjsY0z3/0TE30XEHx+T7nxbRHzHSvPKuL6PdPwOT3Lx46IuHuqIhaQlHM2+7GDa+M/jS06PX9xp8JpEQHu2z2kV6dwixtTnz7xoLL5KREjkQjtlvMDt34598VsR8WMH58+vuoFN09h8+aS+omzU6T9WgPCpiW8OzYGQwPeMiK9ZWBZfBM6D/phdHu84r2gbzKk/PZokzCk4LRVhijBv5QNHkTYPf6zrax768cki4hEi4l+Oc4UWiDaoFXPocVY6OyLymdkFXubMsFbsGQWgjvwxOFH7trXKnz62BjCTCsX+yoj4laWgdp5DCH3nxSLiSY7fgSVzkj78yYj45kP/fufKMXZitW7360UAcgLAhviFSdctyYT1BMfNrcUWocgybC3VALB/ftBh0rzOYfGwMM3JP0cEm/6DJgb8OQiATZgD5CvOVXD0uw3obSOCA9ca8Y1P6yyS43IspHI5sCvzcv7SzkeWEIBztO9cBMBGqy8QsKUi9NBJ/HeWvrDyOQvxcyfvSOrDzr9G9IWwTuR8+PujiLBBLhERFgiU0FebxhL5wcPm9Y4LM+IZby+aFGpOvsuR8NBiPEfzDAKADAmRfPdOpd5wgsi2rzg0MO9l8o1Hcjj8tgcBsMnTgnKcfrgloB7NQu+wgQiIJvnQwyHC3F0iv3/U5C4lh0vKvNhnigDkBICd0okdIx/Lhxy8iz9gprff+rgpjR+zAVlUvz15dwkBeNXjZH/EDSNNKCKNwT8m7+5NAJxiaAecatYKvwsOiB+58EWEaqm6WJFOOq9+rNtXdL4xRwDO1b69CYB5bePvbR5zECOPxhwysLf0NkXfQXJ7G9Xe9UA2jAMn1LVCW2ED/vKZF3vaDomLjF9zxWGjlYEAOHDQImRCW/NaCytuHCATmShDWYOcSgCQGSftufwnWV3MUSTgMxa0yxi3Hr/vgmezR/iQ+NYax+6Nn7q9rxUByAmAk+UrRITNfCzUVHOnKSomqqixOPlTdVNHtzJHAJxwLBRLTv29kebU9SKJJmBPAoCJa/s4bn3LyF9ysrFoW1zXYoIEUb86gWUyRQDO2b69CYA20hadIrCiVt1qmuh9m7nijTo/Gj9MFedO5kM1jBjzE9gqtAy0cV89UYBTZpbkCPGQbEvOjWwNHgiAouGfOTTqH2a1wbQ11Q5tzU7IypBvYoz3KQTghY/r3JaDyrj+kl3xd5kS5L81067tS/4otDlXK0UAcgLwGscT4zckI4PdnUNfJpKa/NVB9f7QzY9OnlRhX5K8NEUA2Gt/+mgXbF81aTFlxIKdi73tlQ/mBxO4/b53mQPerynERKNqJIhGloYVSWBrHQt7InvoIHK1UxkLlczkh4+nDIlt5HZHrmCcCXsdlaVTaCZwRMTY4HvCC5ynuQXuSY/f813yFxN+Dz0CcO72PWZDNqmksxh59mepb8dChTt2dmNrFWaXkSObls2HGts4Za5CuFp/laF8Yyuz109AP/sTlfvnTjxlU6QJQvDOFcvv+5k/jmr9zGF8yPsxbM7w5LSYEX8Jh8xRYzYTvidIQivaxgeGVjCTMQGgcfzgznMvcyTdU6A7iZt32VoPhzdrXt5KAIxh60JvDbBeMfFRwZuLyEIbcTRUhYbF772LuWhNHIoyEbKNPCA97o/wDc9bczLZkuRtdpBfygNFAHIC8HoHu5yF1QRvF2K2rZ6a2nvtJk+txSZmc85uoZsiABZqE6EVDn9OpJl68IWOi0KrhlcPGf7Y2zOhtssmyZIogKlFQ5szNadFHinJ5K0OKkT3KGSSJcgZnrPB8SVo30XMLHZzKWd7BOAm26ctyE92iloSBcDBkaNjJtrxOc0PNDb6vqcKd/pEqPYShJOdniPilNhUOYd+38E5D4Hsjdu19TJveqYN2gkbYks8EGrq/mz8eKdHJvia8DlpxZxHHAafBwcKG5Z+d6pnehzuB2EW6R04qLF7ERXDNzOT5PAbLOA7lq0EwDx3iMjEOuauB4eJQew9b5ckuxp+d/DJfEWMG06eA6Eff4/TrzwRWSZI4aUfm1TOwcXBZ6nfyNrxdqufLwKQE4BBDS39rwE1FqFyvRMTb1Z24rE4iSqjl4O+RwB6YXnKntog/d6z+Qkt62UnPIUA9N5VFwsdb99WECsLwqMnv33dxGbdcyJTjJMzh6BMLOIcrqachXoE4Cbbp+5bCYDNnDd3ll4X1j27rIUWrplQkbYZCU9d1FyQ1SN4vbK1iwbEnyRJTodrIgaGcnt2eSdTY7VnfrDhICFU5mNRB7jyam9liox5lvqeFmAuisOaYz1ohW9R66fUPpOZJD1DA0E71pKdLQRApAInTNE3WR2ZWhxaMuHE25pah+f4YvEZGUtvbdOOZ57Jv9LrewefVrN26hi/iPeLAEwTAJ664v/HwmmEx7AJNBZqYmrVlpkOC+haAsBvwGRshbc0df+UndQpi1lAncZCPWayZmz3FAKgbYMpYfw93+ndLe653uLkxJOZIyx2v9eZWdqrX4S29USIl82jJz0CcFPtG+q1lQA4UdJCZeLUbQHMhLmA2jnz2GZr7amqJ6Cc/QkZXZpXIyvM+HeypKlDvM29OXmi4+kxW/eYx3oaqaHcLFOm32idbGStzBEARGhqfgzlZevQ8Ju0yrR0mTgt06RkJkFOgUIlW9lCAHq4KNvmPuXUx2TQrqVDnTIbPRL2VEm9HdZa36v2Mb9bc1pZ41A5N8Yu6vciANME4MmPzLbtVN6jn9z8T7bSbIG1KVl81xIAmyD1XyuDRmFuoPXMB7x02YhbOYUAzNWl93tvgaTCY1NshXbFYp/JlCp2/HwPV8/MRQGsbefa9g3lbyUAa+s3ft4inNlvOa7yYTmHUI9/wpHQnlK+k7T+l3zLqbgnmYlueJaT7A/NVKJnPmhD6YZipgiATZuX/xIvdL4a1pDMr4OPAG/4TKZuvuTb0N77oYwtBKCnlXMqd1iZy0fCYZWZtBVkf3wAo2mRkyGTKRyG5xFcfkEtIaKdoIlc0henjNNb924RgGkCoMOyZB7UUtRTY8m8Uk0MiXDIGgJgMvRONGyRPZXZuD4c97LTIBtn5oR1LwhAzyOcWjU7jVLv98J+eu1qJ92UynFvArC2fUNd7wUBoAKnEm6FHX5LqNzSxY6vAw0Ds1ZGeJeW4zlaDOX0Ej2xmTutZ+IkPUUevEN7lmUXtDlneQSmCADtR6tdnGorW70kN630bOWe60UhaEMvAmItAeBrZAPNtAxLoqbW9C/H4XHI4vhd/gSZk3VbPuKV9RVnQWaMq5IiAPMEwIbT2pWptmULo3YmmDlPW/9vLFRsQ/ztGgLAAWhNxrE1g5bmggajlb0IgJM7hx93J1hknADYpNfc/NYjACZ4T8Ut4Qqtx5xYKFrtzfDOEgJwzvYN9diLANhQ9QWfFQ6gTjnMBGtCNc9NAMb95VTKs91J2/jJHL3m+tfvPdW6PBzKP4cg7e1Jd4oA8LuweS+Vnt+EUyvNDfPeWGzMDhGZMyk/oN6Vv2sJAI2iyIlMvv5gnrjf0gYueO69DmbNj1jw3JZHaLmyMO0tZV3MO0UA5glAL0Z7fOLs2ZbHiU3WEACJe87llCJuuXVUNGBPJQAWGkRJ9q81m302WXoEQOhhL8PgUm/1qVPEFAG4ifbtRQD4StAA7RHCd5MEYDwWkBROXcgwAmOOZX4h2fgRRoZ8tnfXZym691qshQm26WynCAAixp9nqTzG0Wk2O2lndyiIOsrCmKnlnYAdWDJZSwCkT+5l8OTfgLjsJUuvWN/yPQeDNtx5SzkX9U4RgHkCoEMtJDyExzK2jQoLbB1qWjXbGgIwla721AHGCSY7BZ1CAIQuMYtIzbqH9AgAL3622kwGX4u571Nni2/PpEcAbqp9Q51O0QDYMPXx1tNzi8u9IgBZ//DAv+9RCzRnlsgcu4QzZhdyzY2ZJb8jKK3WrkcAEJRsI5/7To8A8z1qibFMptJftzLnQ7SWAEz55SwJW51r8/h3kSN7Eopx2cKSz6VdWNPGG322CMAyAsDJpk2iw5kEK2cOyC7aGF/4oVPXEADpOXvpak8dIL2ww60EwBgSp93eXT+uJ9sa710bm8VvEP4RWRhTjwD0HBuVxz7b8yYe18VCOU5iNP4tIwA32b5TCYANUua4LLRS2caqBDdwYi8fOz29Uifh1G0iAOO+EhbHJNTb0EWDMNeMo0IyIn/qfBrep7VrU333CIC1IwvVnKtLz4lRRIS2SnxDaE8kvMocad/0mOa89621BGDqsNIzN861s/f7lP/O1jKH92gXmBiuSooALCMAHIQyz3mqSYtp5pnaqgTXEACnHAtvJudKX7mVALAx93Kiw8YCgSBkstZJrhfHq+ypDI3jb8vMJkNbJhkBuMn2DXXaqgGQwY4TXCbIk/wWkqhkcq+cAE9ZcG1wNnV+Jpm0nv29lLjeReazWP5T6tcjAJzm5hIhZd9lhhLWJ5VxK+5uGFT+HJSd9FtBFJDE7F6Q4dm1BGDKXCnpVBbKvBVTUR4SsWUiSZP8ISUrECgCsIwAgFTGqDb9LMZoQrZe9VSNbf7uNQRgKjEL1R4Wv7dsJQBCoJweM8kyjY2fM2EtXK30NAC91KreXxLG5Tmmml4mx4wA3GT7Bhy2EACnPk5f2el/SIn89xODxuaXbUrn1gBYgySQkalyiwgho23LhHp6nKt/ikCKgOiRoy318s7eBECZvTkwtrcLrcxy3AuhRWinZC0BoMXrpezlx9RLwbsF06lLjdwvkd3guuU7V/NOEYDlBCBLXGJxxObbW7nYktiUxrKGAFAPWpCz/mEHz8KBTh20WwmATSVTZyJGbda0to5Sd2bhSD0CkPlaDGUuDQOcSlmaEYCbbN8pBKCnpVLmXKITG3/v9LsXAUBQJHDhS+OPv4h/EWW24q23utFq9BZ+c24cGvbxh/n6zp2JkmWdO3VOnYMAINtIaSvjUEQmNzlMWuEY2DN/Dc+uJQA0J6KhsrXKzY6nhnaO29BzbPSM+xJOvQDr1P6+uPeLACwnAFloHjuqJCTtqYt9sg2NWUMADKTeLWAIB6e0rSem3iDdQgDE6vcy79ncJTrpCdu/hSobgz0CIMd9L8bbJtC7ZW6og3BNKXHhl0lLAG66facQgClVrBNhb+PzTbj10tHuRQCmwsXYq9nyp1TTvXGUhekOz0rBPVaFT5lzxiG7ey3k5yAAnAfhlWl6kCrzqY1G0B4hihLpzK0bawmAsqd8K4Qo9pL3DDjTamSRSdY64ZWDrwpTj7Znco6Lq/YaB7e2nCIAywkArKgIpROdkl5+7rUEYMrjdQmT5wFsc6YWdhr3h6n3bljrEQB2fA52mWD/vSxfsMoSywzlcBASepOJRSoLJZy6NtcJViRA7xZB35nyWPZ7SwBuun1zBMCG4sSbCRuoxC+ZTJEjJ3Px6DQImQjx4pOyh/T8DJTNj4ST25psbNJPc8Dt3QzZqvVtRsZlllEPYc/y7Y/bza+H34+5NJ5XDgKZnIMA+E4vTTiSpz+zS2840PWSII3rvoUATCVYmkt4hNAgCFkmQE6ViO1YepEcDmIyJk5lHaTp4gM0rIfDv1OmsT3G/a0towjAcgKgEzngzd2+Rc3o5qlW1hKAqcuALHoWot5d4JKoZI53Nn+aDJeLtNKzdfMcx7yzG7YspDbrbEH1Lad8qslWhCGyD2bvDc8KY8s2855mxHvyELgQKBNmCot87wpS77QE4F60Tz2chHu3nfW0KsxC7c1uAw4WTafDjPxNZVf0/pKNcekCN5fIxSnO/OJvMyfMCa6E7UWf9Oo9dbETDUEv1bT6IEPi3ltRZuYHcy4C0HPygx9/iiwnfhammGG8hQBIMiW6JBMaNwmeeplNkRZrZiZuWWw1UwhFL4kRJ1h5SHrS0xYhAtaqqXtE5sbjRf5eBGAdAZBtrr2dqu14my9v41bWEgDvu7imt8DJsuWU396yxa4qDjzTVMh13oujn8qyJ0GGhTk7nVE39uL/LYwY93BCcjmROF4nlOGEr8xsHFpos2tbp+5Ht8FZUGgXxnWlwRBWOXUTILwzH4Cbbp96SNLiNJNJb5Ni1ujdS68cjnLCWQdcPG/zH+Kqe/1gUUQApzQrSxc/2encxTClRUM4zTF/bpF0ohtMQk6JTAXIjk1wikBmyXHUs3chjN+MU/i2d3o4VfNA792k2ZoaBjzORQC0G7Fux4gwQHOpvQococou0NmLACgHoW9P60P5UqLLtDcO01VPzswuCspuEdQ+dW4POUwffssyHPqe9cHlRC3Z9X3XM2eaxQdOOJIuHdsX+VwRgHUEwMSTcrMXduQ3asZso9xCAGRCM3myvPgGnMUREeBsQx3qeV63WapXE4kdNrMPKivLdTAe1C4OcapSF+0frkmWz9xtZT1xApB7wHu+P7a/O1GZqFliIqYUp3maBxN+yMFOjae9WYzzUAcLng3EpuXET4U9THwnFarcTF440ZzcdPvUC1F7oU4djS1t00ZY+nfQOOkfGPfEhqofOWeKNBlvFPJcOCG1m4ey2NGpeYlkN+N73dcufDB2c9up2SKnvstRFkHomROmyK5yEW8Yy9SHrDjd98xZyjK3MzkXAfCtKYfGti5rNrgtGgDfg49Q6V4OCusPfxLj1ebtMNXL4aDfYN67vfIBB/Lj7pWeWB84Oxqn1ipjrneFu/wkHJGv7vQPvCIA6wgAzLJLf4aBOGVn20IAlLvl7vR2YphQ2PbUveNTKuS2PI44w70HJr5T3doFnT/Ccx5OuyZzm2Sp/V7r4bsVE0SCCrGXZCkLW7wX7ZsKbWux0RZaFjKV42Bqw7ThDWrlHvEY3t/DW17UDL+E9rrqtWQie94mJAXyFEmRhhcpbUN1136fo6t507vr/pwEYCpUuG2HjdZGt0S2EgBl800Sdrkly+G4btT41PlT4jQvx8gpwvav/3rXKZ9S9kW8WwRgPQFwWm0zfg2d3VMF+n0rAfAu73e5BtZust6V/MPtgVOb/1D/pbnSxwTAu5LPzE3Y8YQw8aRy9T0mC1qJqbGYhfj0Yp17E49dnVmBujEz0XjPxpGlCb7p9vHWdlq3Uc3JmAB4dipXQlYWzQq1OPPBknbuQQDUg6ZCXfdKzYvkOo3bPJbk2OfgSXvmdLhFaGmolXu2bWWekwAo36Y+p9of30i6pJ2nEADlI9GcUbckOrJWIehLcvLTxloD5nyyem12GNB/mT/UEpzuxDNFANYTAOzWYtkOcOp4qlU2zExOIQDKo95ns8Wyl4rNjN2y56DTlsMRhlp+blFpCYByxOGzvWcq5PF3bL58F8Ynkqn4fu9mBMDYZe+Hydw3ndTuf1R/i0umscjEybR33ehNtw9BUhemnSlpCYDx+aDjRjg1v22YSKGEMcOG6V3q/iktwF4EQJuQMeRWP/aup50b61S37M9yb/RupeuVgVAjx7LLzeWsGMqgufItuQt6c3149twEgGq/5/Q61MHNn73bLzNcTiUAyuRzw+dEeGlm38++S92vrmuv5GUqYL5cOn6YIh589BWYihiYG3d34vciAOsJgI7nfWxDGYsTuk2iJ6cSgKFcDndOqpg2+zbHKB7uHIDYy8Xk2mSp4pwi1wrvc6co13g6nUs7SsUpzI4Tj6xf7KNZqmL2Nup5J0rvIkkmHLbtPSc+DoqZWCy8i+gM3+S97luwZdfLROif0LjBTgsPJwnhXti90whnxMEezP7Yc2iby5N+0+1DyGyOfBiYIvh26Ad/CJR+tvlld9Tzc2BeYWv17hBVAUfRAjb/zB8E9kijkEnhdUOGQb4DyKHFs6fyXjvWxs+rIycyCznVvLarMwJkE+Ggp9+0HYEzzm34xuGQA3/r97UZ4aIhktlOP/Mx0XaaI2MJiYS1v6X24nMTAHOsvfFwjIF7N/gkTTmHtpjtQQCGMhEBaxVcrVvmJs2LetGcWJ9oUqxVonu2in2Mc7N54l9t9i0HA2OGOcj4RW5d4rYGj611uoj3rp0AXEQnVSULgUKgECgECoG9ESgCsDeiVV4hUAgUAoVAIXABCBQBuIBOqioWAoVAIVAIFAJ7I1AEYG9Eq7xCoBAoBAqBQuACECgCcAGdVFUsBAqBQqAQKAT2RqAIwN6IVnmFQCFQCBQChcAFIFAE4AI6qapYCBQChUAhUAjsjUARgL0RrfIKgUKgECgECoELQKAIwAV0UlWxECgECoFCoBDYG4EiAHsjWuUVAoVAIVAIFAIXgEARgAvopKpiIVAIFAKFQCGwNwJFAPZGtMorBAqBQqAQKAQuAIEiABfQSVXFQqAQKAQKgUJgbwSKAOyNaJVXCBQChUAhUAhcAAJFAC6gk6qKhUAhUAgUAoXA3ggUAdgb0SqvECgECoFCoBC4AASKAFxAJ1UVC4FCoBAoBAqBvREoArA3olVeIVAIFAKFQCFwAQgUAbiATqoqFgKFQCFQCBQCeyNQBGBvRKu8QqAQKAQKgULgAhAoAnABnVRVLAQKgUKgECgE9kagCMDeiFZ5hUAhUAgUAoXABSBQBOACOqmqWAgUAoVAIVAI7I1AEYC9Ea3yCoFCoBAoBAqBC0Dg/wGnnVmfYLYuGgAAAABJRU5ErkJggg=="/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-102"><g><path d="M 336.37 465 L 383.63 465" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 331.12 465 L 338.12 461.5 L 336.37 465 L 338.12 468.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 388.88 465 L 381.88 468.5 L 383.63 465 L 381.88 461.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-103"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 466px; margin-left: 361px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="346.5" y="460" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-104"><g><rect x="200" y="435" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 455px; margin-left: 201px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><b>Auth Service</b><br /><i>keycloak</i></div></div></div></foreignObject><image x="201" y="441" width="128" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-105"><g><rect x="390" y="107" width="130" height="40" rx="6" ry="6" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 127px; margin-left: 391px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">Search Service</div></div></div></foreignObject><image x="391" y="120.5" width="128" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-106"><g><path d="M 430 195.6 C 430 190.85 441.19 187 455 187 C 461.63 187 467.99 187.91 472.68 189.52 C 477.37 191.13 480 193.32 480 195.6 L 480 242.4 C 480 247.15 468.81 251 455 251 C 441.19 251 430 247.15 430 242.4 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 480 195.6 C 480 200.35 468.81 204.2 455 204.2 C 441.19 204.2 430 200.35 430 195.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-107"><g><rect x="412.5" y="251.5" width="85" height="17" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 89px; height: 1px; padding-top: 260px; margin-left: 411px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">search-db</div></div></div></foreignObject><image x="411" y="253.5" width="89" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-108"><g><rect x="390" y="353" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 373px; margin-left: 391px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><b>Dashboard Service</b><div><i>grafana</i></div></div></div></div></foreignObject><image x="391" y="359" width="128" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-109"><g><path d="M 75 147 L 75 168 L 74.65 182.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 74.53 187.88 L 71.19 180.8 L 74.65 182.63 L 78.19 180.97 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-110"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 166px; margin-left: 75px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">S3</div></div></div></foreignObject><image x="68.5" y="160" width="13" height="15.75" xlink:href="data:image/png;base64,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"/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-111"><g><path d="M 240 523.6 C 240 518.85 251.19 515 265 515 C 271.63 515 277.99 515.91 282.68 517.52 C 287.37 519.13 290 521.32 290 523.6 L 290 570.4 C 290 575.15 278.81 579 265 579 C 251.19 579 240 575.15 240 570.4 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 290 523.6 C 290 528.35 278.81 532.2 265 532.2 C 251.19 532.2 240 528.35 240 523.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-112"><g><rect x="222.5" y="579" width="85" height="20" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 89px; height: 1px; padding-top: 589px; margin-left: 221px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">auth-db</div></div></div></foreignObject><image x="221" y="582.5" width="89" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-113"><g><path d="M 430 523.6 C 430 518.85 441.19 515 455 515 C 461.63 515 467.99 515.91 472.68 517.52 C 477.37 519.13 480 521.32 480 523.6 L 480 570.4 C 480 575.15 468.81 579 455 579 C 441.19 579 430 575.15 430 570.4 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 480 523.6 C 480 528.35 468.81 532.2 455 532.2 C 441.19 532.2 430 528.35 430 523.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-114"><g><rect x="412.5" y="580" width="85" height="17" fill="rgb(255, 255, 255)" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 89px; height: 1px; padding-top: 589px; margin-left: 411px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">metadata-db</div></div></div></foreignObject><image x="411" y="582.5" width="89" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-115"><g><path d="M 336.37 117 L 383.63 117" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 331.12 117 L 338.12 113.5 L 336.37 117 L 338.12 120.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 388.88 117 L 381.88 120.5 L 383.63 117 L 381.88 113.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 117px; margin-left: 360px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="345.5" y="111" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-116"><g><path d="M 200 117 L 170 117 L 146.37 117" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 141.12 117 L 148.12 113.5 L 146.37 117 L 148.12 120.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 117px; margin-left: 170px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="155.5" y="111" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-117"><g><path d="M 193.63 127 L 160 127 L 160 291 L 146.37 291" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 198.88 127 L 191.88 130.5 L 193.63 127 L 191.88 123.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 141.12 291 L 148.12 287.5 L 146.37 291 L 148.12 294.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-118"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 198px; margin-left: 161px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="146.5" y="192" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-119"><g><rect x="200" y="107" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 127px; margin-left: 201px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><b>Gateway Service</b><div><i>nginx</i></div></div></div></div></foreignObject><image x="201" y="113" width="128" height="32" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAACACAYAAAB9V9ELAAAAAXNSR0IArs4c6QAAIABJREFUeF7tnQWU9biRhSucCTMzZ8LMzMyMG6YJ8wY3MGHcMPNkwszMzMyMG2Zcf1krq64pyfIDd7/nW+f0+c//LMvSlWxdFelgJhECQkAICAEhIARmh8DBZtdjdVgICAEhIASEgBAwEQBNAiEgBISAEBACM0RABGCGg64uCwEhIASEgBAQAdAcEAJCQAgIASEwQwREAGY46OqyEBACQkAICAERAM0BISAEhIAQEAIzREAEYIaDri4LASEgBISAEBAB0BwQAkJACAgBITBDBEQAZjjo6rIQEAJCwMxeaGbXC5D4tZkdRQhtPwIiAMuN8THN7HRmdgIzO4aZ7WNmBzez35nZb83se2b2ZTP7vpn9c7lH6W4hsHUIHLt/f05oZkcwsyOa2SHM7Pf934/M7Otm9k0z+8vW9X73OyQCsPtjsKstEAEYBz94XdzMrm5mlzKzEzfe/gsze4uZvdbMXqmPWSNqKrZtCPD+8N7w/lzBzI7V2ME/m9l7+/fnuT3BbrxVxSoIiADMfHqIALRNAHC6breLv7+ZnbLtlmKpH5jZIzuNwX+b2d+XrGvdt7+j+/BeNHvI483sjut+qOrfSgSYR48ys7Ms2TvI9P3M7ElL1qPbZQKY/RwQARieAqj3n29mFxkuOqrEh3r727dG3TVdYdSzkBVUsklEAKbDf5uedFcze4TZSlOPowm4iUxrS02TJ5jZVYMa8AHAtCnZcgREAOoDzG7lDWZ23DXNgx/2xOKra6p/mWr3MzM+ELmIACyD6Dzvvc0ad+toAh40T1jVayGwPAIiAGUMT2VmH+id+8YgjVo/3zUP3YuD4JnMDNXmXhL6fl4RgL00JBvXFnxkvtCZvA5fafk3zOx9ZoYmDMdZnGiPZman781POAeW5G9mdureSXDjwFGDhcBuIyACEI/AYc3s4w1qMDyUDzCzt/Xeyj8zs7+a2ZH6D9OFu9+v3zn+nXFgoA80s2vt9mTIno9X9ncCla00AHtokDagKQ/s7fVRU4mQQYX/9ko/WPzvbWb3rJgPnm5mt9wALNREIbDnEBABiIfkwd1C/p+V0SJM6S5m9iwzYxcyJHg947RU83q+QBdh8P6hiia6js0WR0UvIgATDcCWPOazZnaGoC9oySDFX2zs5527EMFHF8r+T/9e/aOxLhUTAkKgR0AE4KBTAec31JHE9EfyczO7TK8hGDORTmpm76qEDhIieKURFZ6sd+A5V68uJScBcdR8XH/Z5x74sJm9qQ9BrOUhOE2ngfjSiGfnRf/DzHDIqsmh+/BJQigxKxynN62g7v2pmeEL8W4ze10XJoZzZEkO1/eN+rygCq75UjCe4HKYQuWEpb1+oB+RWYRbGDfGryTn7MvgU3LaPskKu9s/9m36Wt/vl3VjyqJZk9ubGUQskv/qI1Vah/KZXa6KmxYK4/TKmCwj5MOI1P8QXQhvq/CdAhfMArlAxHlXwZ9cAS2CeYH3l7nIePDeHN3MCDX8iZl9u39fXtNr9VrqROOH41wkF+pDGLmGZg2/hUv2fkWH6n2MXm1mzyjc/1gzgwC1ylX6UOOo/GP6jUu6tsowQN6/S/e4nrzH9ch9yCYk7dO9SfXF/Tvf2h9fbh3jt2hbNv4+EYCDDuF9Ko5FLKJM8rcuOPJn6z4+H8l8BH5sZm/uF2nMCCxQQ7JvR04e3hGQyw8VzK6zwNy2N1VEt62LAOALAUG4r5mdqLG9xHvfof9gRLdgLz5/cOEGfWaz0mP44INxSfzH0ZfjY/0bM8M8lAs7TxaQXwUVX7YfK79w1aAg9BKVNrbxSI7aEybfDspC4pgfLcK7T6IdCK8XzD8Q1mWSV0HWWKAjgehdsaWRWRkWebQGLPTpjwW7Vchsd7fO1wYCVfMrSPUxrhBbTBBDzwFLiHf0PU3kkDnA3Gb8csHJGDMhz4iILfPgFK2dNLMX9PVFt5y1I0ufyi6sggAQLYAjJsSjRUjoRBvvPtLvaZ3j19LurSwjAnDQYeUjyoIYyXN6u+UykwF7Jjtfduaw4jEf2Wt0H+bnVbQTtXbxHD5mDwsKrYMAsCt6aU+YxuKFWYUFHf8KL3xsIGlenth/3EvP2r+3JZeu82HkA1mSc5jZR4OL+IpwLRfeK0gaC84iws75yt0uGTIQCbuo6xSu8UFuUa2fu6JtwQQGaVtGmOP4w/CvFwgGu8Sp8mAwv9Hu8MyxwsJ8sd6ZsXYvZAfS44XFHc3O5ws5RCAAkHk0DiVS1DqmkFQ0alEaX+aED+1blgDcqNdc8NyxQjshR2gph2SK8Rtqw1ZeFwHYOazsemqqRHYgn9ulmUAiFTQPYyIMoqZGO+VVEwA+hB/soxsWhYvF4dqd2vflrgJwiBZGPiTnqTyMxdsv1Hlxdnykcy5pYaKwSO7HV4LdTC4kjHrAoh3v70PbwCIdmWZKGHArz8YUMCQ1QkQEDFqjZQV1eilb5lhzxaJtYdHD5LBMbnvMfucbMDGh5kY97eXW/Q9PKXQgEQCcgCPCy233KhB3XyWmBTKORgL5Z8xzWYYA1PwyWscK0kSb+VaUZKrxa23zVpUTAdg5nOyq2F1F8snORo0KfzcEuzWqwOMXHs4Hjl0GiXvwA7hcn241Kg7zZifELjMJKuz0oeI3dn+ROhL7/Btdpdi+vd362b3qP3r+Jzq1Mx9DdkTMP0gVi2ukJic0Eps5bU6C6ht1u7fl/6mPvmDX6QVbJB/onDyhEfHzHzUm9thIXtRng/TXsCdjxklCf9AmRDtfSA1aEVTBRIwcr9d04CMQCVoizAheaDf+DpFqGII6FHVCfYTnReYCxtiHfxaaN/gz2qobVkphCsAmjiZsHYLfx8cq0Tyk5eZ9h6jgq3DB3vwEEfSC6Ql7fkljhzkF3xYvkEOiHUpaxUQAIM1oGyLzROuYPLUQEUGb2dygecllUQIAGXpPZTPC3Ca6g3/JoYIGJSJHtIVoEMKgI+I95fitY/7t+TpFAHYOUW1XNKRiXudg36ziJIQ9LfrIwvgfUmjUrboX82mVBpect1qiAGq7U2yqOJ15j21UiOx+oqxk3IMfQS58fPhYezl7l2MeguEFVaNf2FlcWbxzIfER/geRQMBwvMwFUwU23ZxMlT6q3Mc4EjmSC6QE9TS+JZGwcHwluMCu8KGFe4YcIiGAhLBGAhFkIVmFsFC0RLbQP3auOB2yGxyyube2DS1DyZTBPISoeoGU4ayLFsTLjXsTXPR8HFmjhGH4nVyiv4GFmMU8EWaexX2JfJdIJu8L5IIFtSR8y6krIiEQTsiLl0UIwCF78gmhiIQU50RI5Yc3Qa743kQnD1IHKaIjc9mU49c6p7aqnAjAzuEsvYCUqr38654ULBDs6iNhh8yJg17YweNk6J2OKPeqwmKb6liGALCjiXat7LJoKzv1SNBcoHb2Tml4Z/NhzXcIqNdRdXsh61ykamVhR8uQy9X63V+uSSjtnvEUz7UQqR4WKxa5JCzmaBrQOHhhLEoZJUv+BdQBIfEZGfmdur5rZnyQvRDCWiIHlC2pbyOsC8PV/HPNX6FUCZ79LJT8sfNmwRzjK0O9aIrYXUa7echmyYeCe0vjgTahpK0hoVdJQ0edXCccGCfgkvCOlyJR0CLgg1QStDZEqURyi8IGYhECUNOS4seA70okfI/o+5mDiySAIuU6Zq8kU49f84TepoIiADtHExt7Yut+nFnU2DXuhuBIFKkGUSmXwodoZ6k/qI/ZJZZkUQLAS8yiFM0rHPdKGonUDq6jufBCBMOTsx9JsMQuzUvJSRNzg3eAYlHHnJH7BbDIQED8TosQwSjMj/bmDok4PnJoVCQsRpCjSDAXYA+NPPtriW5KjmNDDo0lDQr+FjiarlLY/dHvaAfa+px0mibEFbNBiUTm9bHbZIGLhCiS0mKZypdCPjFVYT7xUiMAECu0U8zDmqAJw5SASc4LGqyapz2+KOTv8MKz0QpEUSqLEIASLjwXk1ItnLg2Jmj/GN8kU49f61zcqnIiADuHsxRiRikYdi1GPa8JhzTi88cK6mHUxKuS0gvOBzX6yKTnLkoAWPzQokSCyh58a1IyH/gcCeza+aD5BZMPs/clYEFn951LIkAkZ0JrkMs1e3+K/LcSMcG2+c4VDVZpAcFOjbYikhIxoSxq/sihFVss2ozImRQvdBbYVQsLG1obVMOlPAytz8Qhj5BNTHK56cXfD3G6eVApCyLapshXJC9eUj+jPSE230uNANRMS76ekh0fgog2o0R+MOlEUQ61+TOWAIAbmrho7qClwZZfE7SRpbMb2KzkJHvq8Wudf1tVTgRg53Bir8xVuvlVFvQoDCyaEHuFAGA/J1THCx/BaLeZyi1KALD/sVuPBNWfd0Ly5UiUEiXCYffs8wiw8PoTGrGVpuQjqe6IlCS/AnwncFTLBROCJwX+WGTKgyGe5S270ZaPRsljHtt4yT+ADzGYRqrne/Qn8PlnR32mTHJKbMls2dKfqAxjiEmDOVkjoC31Q24ga5HPB/dHWh9+Z6GOshP6Z6LqzrVO6XrJ56ZGAEq+KVE/0ZSUEjARLhhpkehPKYGU31nnzxxLANCOlnKgQKZv1zJwjWWmHr/GZm1XMRGAneOJ5yq7ukguNSIB0DoJAB9OQoYgKjBu0guz6EVe+6XZui4CgDc8OK1D2P1gX0+C9zi55r34DHZRtrvkjBeFfeJPga9CEtTzaBvY/eTCR3roiOhT9mOF3RgTBDsgzARjQjlrBID2lNJWl+zVqPkjjUKLg+eqxhW/BTIBsqCAIdE1i8SSQ1TRLOXJbVIbIWbLahui/pb8REoEgDYy5q0+DHyTMaNhTvOCIx0OvF5K7wK7ddT/uUNefu9YAlAL/btjJUPlIvNm6vFbpI0bf48IwM4hJJQOR51IiEknhKtF1kEAsKXysWd3Omaxj9q7LgKAk0/JSaoFt1oZb3tlAcG72QthV/k5BjiUncQVwpuf35Fo5413NrZYpLS7qsXb8zx2RJEz5FgchggAJIYIhehdJgafxSQJCyIq9MifhEWYUNfdEMK9mDf8oWmD3Ebe7FHbGEciJfJFjvr+sKaOgB/+I15KBGCR8GG84jGXeMHLH2LgyQTPIK2xl6GDksYSgNoZKdjsSyHUY4diN8ZvbBu3orwIwM5hxLYHk40Er+raAUH5PasmAHxw2HG2pnkdmpzrIgCEc0XhU0PtabnufTAgQezM/ZkNuSMbC71PqcuCn4cw4ThIhEcumA1e0v+AHZkPqZfS4U0k70FN6jUGLX2MygwRAO4paa5YRLCXJyklikHd2qIWX7QPi9yHkyoEihDQobZ5J1EiJFgs1yEQjUizUCIAjE3JsbjUPsgYGSYjwWk1vwbJY05HMuR3M5YARD4z6bm1HBpjx2E3xm9sG7eivAjAzmEkB3spBhqbc8k84CcDLL1mYyf+ODoMJXICZIzwTaglZ8EeSggd6sbchstuyu9+aeu6CADpRnP1+SpfEp9wp7TwseNN2eei/Algnx+AQ2bE57uGEllB6BTCmBCClQu7S+z/3pEMh0O8oKPQS+4naoPFlsUCp658J4dDX5RKtoUAlLLIoZGBkCQpeYp7rckqx23Zupj/aN9Qf5dIFVENRIYkwSy2qlwCUfshnd73o0QAxh7ylZ5XItM40aHyT8KGJXJKbDnPYSwBYAzSe+FxwayEw+EqZDfGbxXt3rg6RAB2DlmNecP8cVKL4sHHDnzJVh4RgFqKUD46OCuVkq1M7QRIXHwpHS/e5y2HHY3BEo0MakkvqI9ZANjFs3jkQkhlHqkAWcPJMBc8qrHfI1HGPHb4ka8DDoSRjZZ6MFdANnKVfP7MRZwA0/1oQ9jxesc6CAb9S7thMu55T21ICc5569oxjxnPWll2s2jBom8WRAzCnRJMgQckN5IWb/VF2lwiALXY+NpzSrkuGMNc3V8K6WzRWI4lAJxv4dNepz4MHcY1BtPdGL8x7duasiIAO4cShy8Wjih5CCWHEqy0TowxBIAdBLvDSAibi+LhU1niaqPEHOvSAJSSANEeb49uxapWrpRpLh3tG2Vny+37qW60Jz6tLmSPxCSQFp/WlwOd+BjmgmMfnvTR7p966H8Ui53q4DlRvvoWDQB1lMxXKesjuyrCIf0731r/KsYLRz80VK0Ocf6ZEIBSPgHMZNjnk5QO58FnwGd0XEXfVk0AMIFECb5oK1EfifDxvYqcSodi8qlnLAEgsiQ6TIy6Vq1Fmnr8VjEHNq4OEYCDDhnq31IsPmd+Y4/0O8axAz+GALBoRJnl0ERER7nmbYl2fFxfFwHA3nynAhirOF/eV82CwsLpz5xHTYr3vw879B7+qb4o5hjNCgtKdIRwFBJKmGPkjc4zcC4lZK0kLPwl7UjrAk2UQZRoJu1ASzkaVum8lfqHKYMFDHMQC1H6F5KFXb92LHPtXYrMMak8mg7OwkhScoyDgNC+oTwAY9/pVRMAnk+IY3RCZUpjXArpbHU8HEsAsPOX1Py8b1HehbE47tb4LdrOjb5PBOCgw1dLy0ppVLmof5eJ/y4lHPImANSafyzMMK8K9MWw/eMbEI3xughAzVxRiktf9gVigcS5LRd+44PEwpsLcd1RnoIovSk7agiAz17Ibh5zhj/KFh8Ff1BSevbjKsSIMsTFY66JpJUAcC+JqnKbP7+RZhXTACTHOzvSF8wlpTm26NjUwsUgv/4MhtbnQBwuHhRG9Y9jXu7/UjPHjMnp0dq2dRAAMvvlES2pLQf24aX8G2VuLCUr8n0ZSwBqtnm0aC0OwGguqMcLCajyTIdTj1/rOG9VORGAeDj5kNc+UizgHDAz1qbNosxiwL2ReALAQpPHvuf35M5uUV1kSisl5mD3UwslLCUC4oOBra8kqCZpV3QSHrsZEqLUhFA/QsHQbqBO51/+UAeWJDoUh0yHLHio6nMhxPMVQUUsginsL11mjMHem1DI1R6ZZEi4EtVNfTgZRgmZuIb6Fq/uKEc611n0PMEpYYGzoj9siLKozfF78LHl3iFyVR+3oWO1FzlwiBMO2dlG6u5IrV/LWY+mKgqzy/sP5mjY0hxMc7IUU78OAlBKrc38xlMe9b83G0FMuc9nv4zGdiwBoI5Sgh6uDSU8wnehFGrqzWpTj9+q5v5G1SMCEA8XccWoc2ue/CwOOKDxEc0PsfA1kgSEDzCqVjxlo8Nb0j2eALCQslhHCyq7HghFZI5AQwGJie5Lz8KjupRKlf5EHtdDWgfqrh1chIaAXUtJSju80qJLPex4oxTNpPvNdyTYnbETlwgV3vv5ka1gAw74DORS2l2VzifgXjy6UYX7UxC5Vout5noLcUrtwxQCkfFjhyYk2ikyL6NcCqv4iNWSQjEWj+77jlltSNj1k7HRj0W6j7p8HvzaYTJEcWAyKYXPgR/mo8ifg+fwPC/rIAA8o+Tkh6kt8v4vOahGGC9CANCgkfEzEkIeIU4lH4/S2RW8F7yrecju1OM3NAe38roIQHlYcZ6KTpbzd6B25IAMQuDYJbBgs3PHkRCPa3wGagtxqg+1PB9pn4u9dG4797Ew4uWedsioQQnTIZFI2uFH595zLx9VUtxGgi219LEdWsRr6UJpJ/f7dKbs6vBaLnkY13LuQ6jQxETJbfK+DZEXzAPpWNbay84uJjq/vnRiYKqLxEH4JqSPI+VZ/FNYVWmcUM+jMq3lvc/bG/kzRHWz+OEMt6hD3tAHkbnPbq829zFPQBQgcEReQAbYwWKjZ4fLIg2ZreWY5/1DexId0FM6w4G2Q8rQxPmjlvG3wc6Ng60X2od2I9L8rYsAlL5DENkonTJ+AaQrbpFFCABjAzkqOUqzIYIk5CZSwiYhTaX3iwRrPlqH9k85fi14bV0ZEYD6kOLxiu163YIqjxcgygHOi8OusySo+oj3hjHjMJRnKWNHDbuOQtZ4iTkrHXUiWoQ8l3jtUCQWDNoJW+dZ/OvVqbVjlekHhIk60jGgqNRT7L7vJ3URulcTTmks5ctP9w2pfSFfNe0E9YAVH77Solly2kptwAmRVLKolvE1yZMYcaogUSY+sRH3koMi7bpYLGvqXUwotSNnU1t8PPk65njNa3xVz+PQnuhoaOpHIwIJKdmmUedDRpPzJofpYMop5RvAyQ3fkkjWRQBY5NHqtKRKRrPB3Goli4sQAPoOceJ0wpJATvBdYZ7SHr4/JcIAmWKTlDtwpnqnHL9VzceNqkcEYHi42JWyOx2Tv3241v8vwW4DZlzKL8DCiDp7bPpfHNjIa8BHKz+yNmobOfWJO05SikGO7o3YO2YPFqFcpT4Gk1SWnTaq9SE1MWPkw/L880oHqaRykBmIWO2dqJ2sRj2QuJRBcEx/IURESbDQc1RtTVqiKT7T7WKxmdeEPAfsutcttciQZZ+NbwUe8bUDjCDFqNGHNERDbSkdNZ3uWxcBoP5aeG3eblLxYmpslUUJAPWvYnPEBgBNZO2QtanGrxWzrSonAtA2nGThIwuWP2q27e64FPH7ZPQqJfHJ72o1R6R7CB1kR8wiTAgW6tHaWHsCgPqV3SoL+ZCU1HeYQdglRBkPh+rkOloIfCZwBhySoV0vCwTt4YNTE3bntTHGqZJ0qDWJkg/VyqN5wWwCAWwZ5xYCsF/XX46gLQkJm0qnXg5hvch1FiU0GFGeg0XqY6eL+WT/xpsxEWAui05NbKkC89Dtg8iP/N51EgA0YC1qfUIs0Ya1yjIEgGfgDwHxbjFx+jYRDQBhHjoinPumGL9WzLaqnAhA+3AyyZmwHMaz6McTuyvJeXD2i2yWtdaw08GzP1IR5/fxcSfci7CcJENs3RMA7oNA4Dw2tHMqEQDqQGuBdgNP/aGcBamtaC74sHM6nQ+1K+GDdgb1fImwcDZDKUNhXieLJotnSbBJ4+tRE1S1OGcxT2rvF2YEQv84HjcRE+4d0gK0EACc1/jAlpxYSXkdnW/Q/jaML8niT1/RSC26EEOSMNMwP8ZmLsSP4t6dOp2+15x7857xjjJ3vV9O1Pt1EgDeQbRTUaro1BawAdcxxzkvSwB4Nk64kLHWNOn4SEGi2fwMEfIc53WP3/gZvQV3iAAsNoiE2WDXSse8kjUOWx0fFj7sOLuxILHgo2blaFYW5rGLvm8dLwFOY+wY2dnzUcWOiQ2fRY7dZ+m8bsLQuBd7Gx8S1Oo4QGGLx3EnUgcTZYC3MZ69mCJYaLHZ8QfBoE9EG5TOIk/t53kQCtR9xGDTD/CiPjztCR1E3U9d/C0Sl16LPmhJi0pba4lO+AC3nlBHXWgSWOzwtAe7FHUBzmh/WPyj+QBWmDTwScBJL2UYRDuBTwc26CGTCM8vZZDE2ZR+1LISLvZWtN+FWpe5AKHCTITDKYtcSuiEDZs/tD9EZ4ATZhK0ZVEkRfuT/6/vl+ufz7uAbRrtEAsnmDCv8eVAezXmeeskAPQPol1LJgV5hWCNkVUQgPQ8dum84zhP8t0AVwg57zI+DMxf5j0Ebpl06usavzG4bU1ZEYCtGUp1RAj8GwEiI1iQIq3LUFZCwSgEhMBMEBABmMlAq5uzQqDmjIg2Z9FUvLMCUZ0VAtuOgAjAto+w+jc3BDAZENaGetsLWdyi3+eGkforBITAgJOSABICQmDzECC+vxT2iXMoGfUkQkAICIGql7LgEQJCYO8igPYuT0iEBzj51EvnP+BIR0a91siKvdtztUwICIGVICATwEpgVCVCYHIE2Onj9U3YJJEDRFbU3mc8tMnOJhECQkAI/AsBEQBNBCGwmQgMHSKU94qYf+LfJUJACAiBfyMgAqDJIAQ2E4FWAkDsNUdbE/8vEQJCQAiIAGgOCIENR6CFAJBxkhS2pM6VCAEhIAR2ICANgCaEENhMBMjsSJZGnP/IoMdR0KRWJasih9+QMZBDgSRCQAgIgRABEQBNDCEgBISAEBACM0RABGCGg64uCwEhIASEgBAQAdAcEAJCQAgIASEwQwREAGY46OqyEBACQkAICAERAM0BISAEhIAQEAIzREAEYIaDri4LASEgBISAEBAB0BwQAkJACAgBITBDBEQAZjjo6rIQEAJCQAgIAREAzQEhIASEgBAQAjNEQARghoOuLgsBISAEhIAQEAHQHBACQkAICAEhMEMERABmOOjqshAoIPAEM9svu/YSM7uu0BICQmA7ERAB2M5xVa+EwCIIvN/MzpfdeDcze9QiFekeISAE9j4CIgB7f4zUQiEwBQIH704X/HW34B8he9jFzOydUzxczxACQmB6BEQApsdcTxQCexGB05jZl1zDjmpmv9qLjVWbhIAQWB4BEYDlMVQNQmAbEDik2/3/s9cIbEPf1AchIAQCBEQANC2EgBAQAkJACMwQARGAGQ66uiwEhIAQEAJCQARAc0AICAEhIASEwAwREAGY4aCry0JACAgBISAERAA0B4TAOATeZGaXzm65vJm9of//IczsSmZ2NTM7u5kd38wO03vSf9nM3mJmTzOzn4175L9Kn9zMrmdmFzGzU5vZ0fo6fmJmnzSzl5rZy8zs71nd/P/q2f9va2ZPDp59czN7evb7583sDIU2rrv/fJM+a2anz57/JDO73QjM6DN9z+WeZvbwEXWoqBDYegREALZ+iNXBFSPw9X4xTtWezsy+aGZnNbPnuYUrevQvzew6PRloaRoL/WPM7AZmRqx+TT5nZtfu20M5iMYxshvObGafCSpggb1N9vsLzOyGhQdN0X/6QBbCJH8wsxOa2S8aADujmX3QzA6flYV03arhXhURArNCQARgVsOt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aBsH3mDPj4SdP1oCnP2S/KOPGIhy+u9+L9UCISAE9hQCIgB7ajjUmBkjQErf67r+E/L37P7oW9LiclDOifskPhx8c2hXfmyWwhnDra4LASEgAqA5IAT2BgIkwnmvmZ15geaQH+A+HUF42AL36hYhIARmioAIwEwHXt3ekwgc3swe0x1wc1MzIw1vi5D7nlS++ZHFLfepjBAQAjNHQARg5hNA3d+TCJy0PxaYdLb7mtkxei9/8v6Txhevfxb813bHAHNcrkQICAEhMBoBEYDRkOkGISAEhIAQEAKbj4AIwOaPoXogBISAEBACQmA0AiIAoyHTDUJACAgBISAENh8BEYDNH0P1QAgIASEgBITAaAREAEZDphuEgBAQAkJACGw+AiIAmz+G6oEQEAJCQAgIgdEIiACMhkw3CAEhIASEgBDYfAREADZ/DNUDISAEhIAQEAKjERABGA2ZbhACQkAICAEhsPkIiABs/hiqB0JACAgBISAERiMgAjAaMt0gBISAEBACQmDzERAB2PwxVA+EgBAQAkJACIxGQARgNGS6QQgIASEgBITA5iMgArD5Y6geCAEhIASEgBAYjYAIwGjIdIMQEAJCQAgIgc1HQARg88dQPRACQkAICAEhMBoBEYDRkOkGISAEhIAQEAKbj4AIwOaPoXogBISAEBACQmA0Av8LQdNQ+dOiFboAAAAASUVORK5CYII="/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-120"><g><rect x="9.5" y="189" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 209px; margin-left: 11px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><b>Storage Service</b><div><i>seaweedfs</i></div></div></div></div></foreignObject><image x="11" y="195" width="128" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-121"><g><path d="M 75 264.63 L 75 250 L 74.65 235.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 75 269.88 L 71.5 262.88 L 75 264.63 L 78.5 262.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 74.53 230.12 L 78.19 237.03 L 74.65 235.37 L 71.19 237.2 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-122"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 251px; margin-left: 75px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">S3</div></div></div></foreignObject><image x="68.5" y="245" width="13" height="15.75" xlink:href="data:image/png;base64,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"/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-123"><g><rect x="10" y="271" width="130" height="40" rx="6" ry="6" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 291px; margin-left: 11px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">Analyse Service</div></div></div></foreignObject><image x="11" y="284.5" width="128" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-124"><g><rect x="10" y="107" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 127px; margin-left: 11px;"><div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><b>Upload Service</b><div><i>tusd</i></div></div></div></div></foreignObject><image x="11" y="113" width="128" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-125"><g><path d="M 455 153.37 L 455 180.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 455 148.12 L 458.5 155.12 L 455 153.37 L 451.5 155.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 455 185.88 L 451.5 178.88 L 455 180.63 L 458.5 178.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-126"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 167px; margin-left: 457px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="442.5" y="161" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-127"><g><path d="M 236.37 41 L 265 41 L 265 100.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 231.12 41 L 238.12 37.5 L 236.37 41 L 238.12 44.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 265 105.88 L 261.5 98.88 L 265 100.63 L 268.5 98.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-128"><g><ellipse cx="215" cy="7.5" rx="7.5" ry="7.5" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 215 15 L 215 40 M 215 20 L 200 20 M 215 20 L 230 20 M 215 40 L 200 60 M 215 40 L 230 60" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 67px; margin-left: 215px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">Researcher</div></div></div></foreignObject><image x="184" y="67.5" width="62" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-129"><g><ellipse cx="185" cy="524.5" rx="7.5" ry="7.5" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 185 532 L 185 557 M 185 537 L 170 537 M 185 537 L 200 537 M 185 557 L 170 577 M 185 557 L 200 577" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 584px; margin-left: 185px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">Database<div>Engineer</div></div></div></div></foreignObject><image x="159.5" y="584.5" width="51" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-130"><g><rect x="220" y="481" width="310" height="14" fill="rgb(255, 255, 255)" stroke="none" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-131"><g><path d="M 455 481.37 L 455 508.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 455 476.12 L 458.5 483.12 L 455 481.37 L 451.5 483.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 455 513.88 L 451.5 506.88 L 455 508.63 L 458.5 506.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-132"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 496px; margin-left: 456px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="441.5" y="490" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-133"><g><path d="M 265 481.37 L 265 508.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 265 476.12 L 268.5 483.12 L 265 481.37 L 261.5 483.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 265 513.88 L 261.5 506.88 L 265 508.63 L 268.5 506.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 495px; margin-left: 265px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">JDBC</div></div></div></foreignObject><image x="250.5" y="489" width="29" height="15.75" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-134"><g><ellipse cx="357" cy="509.5" rx="7.5" ry="7.5" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 357 517 L 357 542 M 357 522 L 342 522 M 357 522 L 372 522 M 357 542 L 342 562 M 357 542 L 372 562" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 569px; margin-left: 357px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">System<div>Engineer</div></div></div></div></foreignObject><image x="333" y="569.5" width="48" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-135"><g><path d="M 19.5 523.6 C 19.5 518.85 30.69 515 44.5 515 C 51.13 515 57.49 515.91 62.18 517.52 C 66.87 519.13 69.5 521.32 69.5 523.6 L 69.5 570.4 C 69.5 575.15 58.31 579 44.5 579 C 30.69 579 19.5 575.15 19.5 570.4 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 69.5 523.6 C 69.5 528.35 58.31 532.2 44.5 532.2 C 30.69 532.2 19.5 528.35 19.5 523.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-136"><g><path d="M 79.5 523.6 C 79.5 518.85 90.69 515 104.5 515 C 111.13 515 117.49 515.91 122.18 517.52 C 126.87 519.13 129.5 521.32 129.5 523.6 L 129.5 570.4 C 129.5 575.15 118.31 579 104.5 579 C 90.69 579 79.5 575.15 79.5 570.4 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 129.5 523.6 C 129.5 528.35 118.31 532.2 104.5 532.2 C 90.69 532.2 79.5 528.35 79.5 523.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-137"><g><path d="M 49.5 533.6 C 49.5 528.85 60.69 525 74.5 525 C 81.13 525 87.49 525.91 92.18 527.52 C 96.87 529.13 99.5 531.32 99.5 533.6 L 99.5 580.4 C 99.5 585.15 88.31 589 74.5 589 C 60.69 589 49.5 585.15 49.5 580.4 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/><path d="M 99.5 533.6 C 99.5 538.35 88.31 542.2 74.5 542.2 C 60.69 542.2 49.5 538.35 49.5 533.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-138"><g><rect x="0" y="506" width="150" height="105" rx="6.3" ry="6.3" fill="none" stroke="rgb(0, 0, 0)" stroke-dasharray="3 3" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-139"><g><path d="M 170 547 L 156.37 547" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 151.12 547 L 158.12 543.5 L 156.37 547 L 158.12 550.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-140"><g><rect x="390" y="271" width="130" height="40" rx="6" ry="6" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 291px; margin-left: 391px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">User Interface</div></div></div></foreignObject><image x="391" y="284.5" width="128" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-141"><g><path d="M 293.63 41 L 265 41 L 265 100.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 298.88 41 L 291.88 44.5 L 293.63 41 L 291.88 37.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 265 105.88 L 261.5 98.88 L 265 100.63 L 268.5 98.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-142"><g><ellipse cx="315" cy="7.5" rx="7.5" ry="7.5" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 315 15 L 315 40 M 315 20 L 300 20 M 315 20 L 330 20 M 315 40 L 300 60 M 315 40 L 330 60" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 67px; margin-left: 315px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">Machine</div></div></div></foreignObject><image x="292.5" y="67.5" width="45" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-143"><g><path d="M 75 428.63 L 75 411 L 186 411 L 186 376 C 189.9 376 189.9 370 186 370 L 186 370 L 186 341 L 232.5 341 L 232.5 153.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 75 433.88 L 71.5 426.88 L 75 428.63 L 78.5 426.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 232.5 148.12 L 236 155.12 L 232.5 153.37 L 229 155.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-144"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 221px; margin-left: 232px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="217.5" y="215" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-145"><g><path d="M 530 497.35 L 530 478.47" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-146"><g><path d="M 220 502.88 L 220 488" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-147"><g><path d="M 336.37 127 L 363 127 L 363 291 L 383.63 291" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 331.12 127 L 338.12 123.5 L 336.37 127 L 338.12 130.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 388.88 291 L 381.88 294.5 L 383.63 291 L 381.88 287.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-148"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 217px; margin-left: 364px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="349.5" y="211" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-149"><g><path d="M 383.63 137 L 377 137 L 377 288 C 380.9 288 380.9 294 377 294 L 377 294 L 377 328 C 380.9 328 380.9 334 377 334 L 377 334 L 377 370 C 380.9 370 380.9 376 377 376 L 377 376 L 377 408 C 380.9 408 380.9 414 377 414 L 377 414 L 377 418 C 380.9 418 380.9 424 377 424 L 377 424 L 377 445 L 390 445" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 388.88 137 L 381.88 140.5 L 383.63 137 L 381.88 133.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-150"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 238px; margin-left: 381px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">HTTP</div></div></div></foreignObject><image x="366.5" y="232" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g></g></g></g></svg> \ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="611px" height="614px" viewBox="-0.5 -0.5 611 614"><defs/><g><g data-cell-id="0"><g data-cell-id="1"><g data-cell-id="uDJ2bVtIrgoZBCZFZmDG-26"><g><rect x="420" y="505.61" width="150" height="105" rx="6.3" ry="6.3" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all" style="stroke: rgb(0, 0, 0);"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-97"><g><path d="M 495 428.63 L 495 411 L 380 411 L 380 171 L 337.5 171 L 337.5 153.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 495 433.88 L 491.5 426.88 L 495 428.63 L 498.5 426.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/><path d="M 337.5 148.12 L 341 155.12 L 337.5 153.37 L 334 155.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-98"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 173px; margin-left: 362px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; background-color: #ffffff; "><div style="display: inline-block; font-size: 11px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">HTTP</div></div></div></foreignObject><image x="347.5" y="167" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-143"><g><path d="M 115 428.63 L 115 411 L 220 411 L 220 171 L 272.5 171 L 272.5 153.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 115 433.88 L 111.5 426.88 L 115 428.63 L 118.5 426.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/><path d="M 272.5 148.12 L 276 155.12 L 272.5 153.37 L 269 155.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-144"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 172px; margin-left: 241px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; background-color: #ffffff; "><div style="display: inline-block; font-size: 11px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">HTTP</div></div></div></foreignObject><image x="226.5" y="166" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-77"><g><path d="M 376.37 137 L 388 137 L 388 331 L 495 331 L 495 346.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 371.12 137 L 378.12 133.5 L 376.37 137 L 378.12 140.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/><path d="M 495 351.88 L 491.5 344.88 L 495 346.63 L 498.5 344.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-78"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 296px; margin-left: 451px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; background-color: #ffffff; "><div style="display: inline-block; font-size: 11px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">HTTP</div></div></div></foreignObject><image x="436.5" y="290" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-79"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 332px; margin-left: 451px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; background-color: #ffffff; "><div style="display: inline-block; font-size: 11px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">HTTP</div></div></div></foreignObject><image x="436.5" y="326" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-81"><g><path d="M 305 399.37 L 305 428.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 305 394.12 L 308.5 401.12 L 305 399.37 L 301.5 401.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/><path d="M 305 433.88 L 301.5 426.88 L 305 428.63 L 308.5 426.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 409px; margin-left: 305px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; background-color: #ffffff; "><div style="display: inline-block; font-size: 11px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">LDAP</div></div></div></foreignObject><image x="290.5" y="403" width="29" height="15.75" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-82"><g><rect x="72.5" y="589" width="85" height="20" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 89px; height: 1px; padding-top: 599px; margin-left: 71px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">data-db</div></div></div></foreignObject><image x="71" y="592.5" width="89" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-83"><g><path d="M 82.5 428.63 L 82.5 393" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 82.5 433.88 L 79 426.88 L 82.5 428.63 L 86 426.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-84"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 412px; margin-left: 83px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; background-color: #ffffff; "><div style="display: inline-block; font-size: 11px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">AMQP</div></div></div></foreignObject><image x="67" y="406" width="32" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAAA/CAYAAAAoosBrAAAAAXNSR0IArs4c6QAADUhJREFUeF7tnHeQFEUUxh+ISDKAKEEBQTIUKskIAorIkXMSYwkKJhRFECQYMICgIjkntQo9wJKoYI6FoIgKCIogJgwlBlDgrF9X9VRvb5ievbkT7ub9dbfb3dP9+usXvtezBbKysrIkknyrgQIRAPLt3quFRwDI3/sfASCf738EgAgAURCYrzEQxQD5evujIDCfb38EgAgAQXmAJk2ayFtvvRWjuOXLl0u7du3SUuaXX34p1apVi+s7ceJEuf3229Ma0+y0detWqVmzZtw4L730krRt2zat8T/++GNZuXKlfPDBB7J9+3b59ttv5c8//xTCqRNPPFFKly6tnnnuuedK69atpXHjxlKwYMHAz0qmm1QDFShQQE466SQpWbKkVK1aVc4//3y1zgsuuCBht0AxwOeffy61a9eOG4jNBwTpSLJForyNGzemM2RMn2HDhsnYsWOzDYDDhw/LvHnz5IknnpAtW7YEmlfFihUVmPv37y/Fixd37psOAJINXr9+fXnyySflkksuiWkSCACDBg0STqYtxx13nHzzzTdSvnx558XphqkWuWnTJjnnnHMCj6k7cCLPOussNTdbgliAzZs3y1VXXSWffPJJ2nOhY6VKlWTatGnSqlUrp3HCBAAPxAqNGTNG7rvvPu/5zgA4ePCgnHHGGfLzzz+rzmz23r17vYEefPDBmIGdVigi9iKZ5JEjR1T3O+64QyZMmOA6VFy7devWyWWXXaY+N8flf1cALFu2THr16iV///133PiY+ubNmyuQnXbaaXL88cfLjz/+qPTy+uuvy9dffx3XBxP92GOPyeDBg33XZeuG8RcvXpyy3z///CO//fabYK1Z/2effRbX/qmnnpJbb71Vfe4MgEWLFqlToGX69OmCed23b5/6qEqVKmozWWAQsRfZqFEj+fDDD9UQKBX/ysLTkWuvvVaZbaRevXoxJ9gFAOvXr5eWLVsK5t8UNn306NFy8cUXp/TtKJ+D8dxzz6n4wBRAcPfdd6dclq2bE044QQ4cOBBIFWvXrpUbb7xRdu3a5fUrUqSIEBvhmpwBcOmll8obb7yhBilUqJB8//33cu+998rMmTO9gV955RXvxLnO0l4koHr44Ye97kuXLpUOHTq4Due1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"/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-85"><g><rect x="50" y="435" width="130" height="40" rx="6" ry="6" fill="#ffffff" stroke="#000000" pointer-events="all" style="fill: rgb(255, 255, 255); stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 455px; margin-left: 51px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; word-wrap: normal; ">Data Service</div></div></div></foreignObject><image x="51" y="448.5" width="128" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-86"><g><path d="M 115 481.37 L 115 500 L 114.63 518.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 115 476.12 L 118.5 483.12 L 115 481.37 L 111.5 483.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/><path d="M 114.52 523.88 L 111.16 516.81 L 114.63 518.63 L 118.16 516.95 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-87"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 498px; margin-left: 115px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; background-color: #ffffff; "><div style="display: inline-block; font-size: 11px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">JDBC</div></div></div></foreignObject><image x="100.5" y="492" width="29" height="15.75" xlink:href="data:image/png;base64,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"/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-88"><g><path d="M 186.37 373 L 233.63 373" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 181.12 373 L 188.12 369.5 L 186.37 373 L 188.12 376.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/><path d="M 238.88 373 L 231.88 376.5 L 233.63 373 L 231.88 369.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-89"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 374px; margin-left: 211px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; background-color: #ffffff; "><div style="display: inline-block; font-size: 11px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">LDAP</div></div></div></foreignObject><image x="196.5" y="368" width="29" height="15.75" xlink:href="data:image/png;base64,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"/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-90"><g><path d="M 115 346.63 L 115 331 L 210 331 L 210 137 L 233.63 137" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 115 351.88 L 111.5 344.88 L 115 346.63 L 118.5 344.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/><path d="M 238.88 137 L 231.88 140.5 L 233.63 137 L 231.88 133.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-91"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 332px; margin-left: 191px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; background-color: #ffffff; "><div style="display: inline-block; font-size: 11px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; "><div>AMQP,<br />MQTT</div></div></div></div></foreignObject><image x="174" y="319.5" width="34" height="28.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIgAAABzCAYAAABD70qIAAAAAXNSR0IArs4c6QAAFVpJREFUeF7tnQW0XTXThnNxp7gVd3cv7sXdXYsXd3coUqC4Fddixd0pXgoUdy9eoEDhfv+Tv3PWnNwtyd776sms9a2P3rMje/LuZPLOZNLU3NzcbKJEDaRooCkCJGIjSwMRIBEfmRqIAIkAiQCJGCiugTiDFNddQ5SMAGmIYS7+khEgxXXXECUjQBpimIu/ZDBAlltuOfPMM8/UtXj33Xebddddt1AvPvjgAzP77LO3KHvuueea/fbbr1CdutC7775r5pprrhb13HPPPWadddYpVP8bb7xh7r//fjNo0CDz/vvvmy+//NL8/vvvBs5xwgknNJNPPrltc6GFFjJrrbWWWWKJJcxoo40W3FaabjJ5i6YmM9FEE5lJJpnEzDbbbGbJJZe077nUUksFt0+BIIC88847Zp555mnREOAAJEUkTQko97XXXitSZV2ZI444wpx66qmlAfLvv/+aa665xpx99tnmrbfeCurXDDPMYMG+++67m/HHH9+7bBGApFW+yCKLmPPOO8/06NHDu/1ggPTu3dvwZbsy+uijm88++8xMO+20QY3zcJYSXn/9dbPgggsG1ykF+KJnmmkm2zdXQmaQN99802yzzTZm8ODBhftCwRlnnNFccsklZo011vCqp0qA0CCz2AknnGCOPPJIr/aDAPLXX3+Z6aabzvzwww+2csDw1Vdf1Ro66aSTghqWgq4SeIn//vvP/rz//vubc845x/tl3Acfe+wxs8oqq9g/63r5ty9A7rrrLrPllluaP//8s0U/WEpWWmklC8IpppjCjDnmmOa7776zennyySfNJ5980qJMU1OTOeOMM8xBBx2U+16ubqj/hhtuyCz3999/m59//tkw2/P+b7/9dovn+/bta/bZZ5/c9oMAcv3119uvSOTSSy81TN/Dhg2zf5plllnsbIACQsRVwuKLL25eeuklWwVKZ31HMUVkhx12sMsCssACC9TNAD4Aefzxx81qq61mWF60AIrjjz/eLLvsspm2BYPDh3PTTTdZ+0QLIDn44IMzX8vVzdhjj21GjBgRpIqHH37Y7LrrrubTTz+tlRtnnHEMthlLX5542yArrLCCeeqpp2x9Y4wxhvnmm2/MYYcdZi6//PJaG4888kjti81rWH53lQDoTjnllFrxO++806y//vq+1dWe++OPP8xUU01lhg8fbv/Wq1cvc9FFF9V+zwMIswDr9rffflsrwwBdddVVdkYJEYz6DTbYoDb7UpYZ7b777stcbqoACG0BDgxlZjcR9NGvX7/c1/ACiLsTwDLn5R566KG6F9x8883t1xIirhKY/q688kqD/YGg2AEDBoRUaZ+97rrrzLbbbmv/my8GcOy4447eAFl99dUNX58I4HjwwQcNH0oRQYcrrrii/bBEWJqYZcYdd9zEKqsCCJWff/75Zt9996210717d/P555/nvooXQA488EBrvYug/K233tpOvTQkL40SWRImm2yy3IblAVcJZ511luHrP+aYY+wjLC98zaz3IaIHeO211zabbbaZ2X777b0A8uKLL7bYFlax7X7ggQdMz54965abrKWmSoAwE04zzTR1bTOz5C0zuQDB6ME4FVtjggkmsNPueOONZ5WNsdWnT5+a4gESux1fcZXA8rLeeuuZ+eabr1ZF6OAAUl5cjN0rrrjC2kY77bSTF0A23HBDw9ImApfw/PPPB9tXSTrQdhG/s7P58MMPDTtBV6oECHVj08k48m94HGy+LMkFyI033mi22mqrWh0777xznd3BFDnvvPPWfocnCeEJXCUcd9xx5thjj7VEE9MyEsqJnH766dY+QsYaayw7w912221mt912ywXIr7/+aiaddNI6w5Rlk+WzCmHLjMGs5YknnkhcuqoGyKyzzmo++uijWtOPPvqoWXnllcsBBIudFxB59tlnzTLLLFNXKSwd07LIc889Z5ZeemkvfbpKOOqoo8yJJ55o9+sARSSEE2H2EZButNFG5vbbb7f8wx577JELEGwrliQRGElmzKI7qSQloJsXXnih9tOhhx5qTjvttFafQVj6f/zxxyCdZs4g0Mhzzjlnbd3iv4cOHdriRdjywhKKYAxiaPqICxBIHLaGrI8zzzxzrW1fTuSVV14xiy22WK1peAyWrIsvvtjuZETSdjEMFnaBCDbDwIEDfV7F+xm3DQxf/RFKRVXOICy72IsiLLnff/99rr2YCRD26RiNIkzdhxxySAtFMC1jAGFcItDJX3/9tfVL5EkaQCjH9AcXgfhyIlDa7ITcMr4AwW+hAcFMdvTRR+e9RtDv2DfYOSJsx/XupjUAAuF4wAEH1Nr0XbZTAYJxCuJAGQL3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"/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-92"><g><rect x="50" y="353" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all" style="fill: rgb(230, 230, 230); stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 373px; margin-left: 51px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>Broker Service</b><div><i>rabbitmq</i></div></div></div></div></foreignObject><image x="51" y="359" width="128" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-96"><g><rect x="240" y="353" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all" style="fill: rgb(230, 230, 230); stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 373px; margin-left: 241px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>Identity Service</b><div><i>openldap</i></div></div></div></div></foreignObject><image x="241" y="359" width="128" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-99"><g><path d="M 462.5 435 L 462.5 421 L 308 421 C 308 417.1 302 417.1 302 421 L 302 421 L 147.5 421 L 147.5 428.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 147.5 433.88 L 144 426.88 L 147.5 428.63 L 151 426.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-100"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 422px; margin-left: 246px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; background-color: #ffffff; "><div style="display: inline-block; font-size: 11px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">HTTP</div></div></div></foreignObject><image x="231.5" y="416" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-101"><g><rect x="430" y="435" width="130" height="40" rx="6" ry="6" fill="#ffffff" stroke="#000000" pointer-events="all" style="fill: rgb(255, 255, 255); stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 455px; margin-left: 431px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; word-wrap: normal; ">Metadata Service</div></div></div></foreignObject><image x="431" y="448.5" width="128" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-102"><g><path d="M 376.37 465 L 423.63 465" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 371.12 465 L 378.12 461.5 L 376.37 465 L 378.12 468.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/><path d="M 428.88 465 L 421.88 468.5 L 423.63 465 L 421.88 461.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-103"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 466px; margin-left: 401px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; background-color: #ffffff; "><div style="display: inline-block; font-size: 11px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">HTTP</div></div></div></foreignObject><image x="386.5" y="460" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-106"><g><path d="M 470 195.6 C 470 190.85 481.19 187 495 187 C 501.63 187 507.99 187.91 512.68 189.52 C 517.37 191.13 520 193.32 520 195.6 L 520 242.4 C 520 247.15 508.81 251 495 251 C 481.19 251 470 247.15 470 242.4 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(230, 230, 230); stroke: rgb(0, 0, 0);"/><path d="M 520 195.6 C 520 200.35 508.81 204.2 495 204.2 C 481.19 204.2 470 200.35 470 195.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="stroke: rgb(0, 0, 0);"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-107"><g><rect x="452.5" y="251.5" width="85" height="17" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 89px; height: 1px; padding-top: 260px; margin-left: 451px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">search-db</div></div></div></foreignObject><image x="451" y="253.5" width="89" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-111"><g><path d="M 280 523.6 C 280 518.85 291.19 515 305 515 C 311.63 515 317.99 515.91 322.68 517.52 C 327.37 519.13 330 521.32 330 523.6 L 330 570.4 C 330 575.15 318.81 579 305 579 C 291.19 579 280 575.15 280 570.4 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(230, 230, 230); stroke: rgb(0, 0, 0);"/><path d="M 330 523.6 C 330 528.35 318.81 532.2 305 532.2 C 291.19 532.2 280 528.35 280 523.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="stroke: rgb(0, 0, 0);"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-112"><g><rect x="262.5" y="579" width="85" height="20" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 89px; height: 1px; padding-top: 589px; margin-left: 261px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">auth-db</div></div></div></foreignObject><image x="261" y="582.5" width="89" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-115"><g><path d="M 376.37 117 L 423.63 117" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 371.12 117 L 378.12 113.5 L 376.37 117 L 378.12 120.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/><path d="M 428.88 117 L 421.88 120.5 L 423.63 117 L 421.88 113.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 117px; margin-left: 400px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; background-color: #ffffff; "><div style="display: inline-block; font-size: 11px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">HTTP</div></div></div></foreignObject><image x="385.5" y="111" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-117"><g><path d="M 233.63 127 L 200 127 L 200 291 L 186.37 291" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 238.88 127 L 231.88 130.5 L 233.63 127 L 231.88 123.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/><path d="M 181.12 291 L 188.12 287.5 L 186.37 291 L 188.12 294.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-118"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 242px; margin-left: 191px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; background-color: #ffffff; "><div style="display: inline-block; font-size: 11px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">HTTP</div></div></div></foreignObject><image x="176.5" y="236" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="uDJ2bVtIrgoZBCZFZmDG-13"><g><path d="M 305 147 L 305 182.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 305 187.88 L 301.5 180.88 L 305 182.63 L 308.5 180.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-119"><g><rect x="240" y="107" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all" style="fill: rgb(230, 230, 230); stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 127px; margin-left: 241px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>Gateway Service</b><div><i>nginx</i></div></div></div></div></foreignObject><image x="241" y="113" width="128" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-121"><g><path d="M 115 264.63 L 115 250 L 114.65 235.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 115 269.88 L 111.5 262.88 L 115 264.63 L 118.5 262.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/><path d="M 114.53 230.12 L 118.19 237.03 L 114.65 235.37 L 111.19 237.2 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-122"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 251px; margin-left: 115px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; background-color: #ffffff; "><div style="display: inline-block; font-size: 11px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">S3</div></div></div></foreignObject><image x="108.5" y="245" width="13" height="15.75" xlink:href="data:image/png;base64,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"/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-123"><g><rect x="50" y="271" width="130" height="40" rx="6" ry="6" fill="#ffffff" stroke="#000000" pointer-events="all" style="fill: rgb(255, 255, 255); stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 291px; margin-left: 51px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; word-wrap: normal; ">Analyse Service</div></div></div></foreignObject><image x="51" y="284.5" width="128" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-125"><g><path d="M 495 153.37 L 495 180.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 495 148.12 L 498.5 155.12 L 495 153.37 L 491.5 155.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/><path d="M 495 185.88 L 491.5 178.88 L 495 180.63 L 498.5 178.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-126"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 167px; margin-left: 497px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; background-color: #ffffff; "><div style="display: inline-block; font-size: 11px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">HTTP</div></div></div></foreignObject><image x="482.5" y="161" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-127"><g><path d="M 276.37 41 L 305 41 L 305 100.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 271.12 41 L 278.12 37.5 L 276.37 41 L 278.12 44.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/><path d="M 305 105.88 L 301.5 98.88 L 305 100.63 L 308.5 98.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-128"><g><ellipse cx="255" cy="7.5" rx="7.5" ry="7.5" fill="#ffffff" stroke="#000000" pointer-events="all" style="fill: rgb(255, 255, 255); stroke: rgb(0, 0, 0);"/><path d="M 255 15 L 255 40 M 255 20 L 240 20 M 255 20 L 270 20 M 255 40 L 240 60 M 255 40 L 270 60" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 67px; margin-left: 255px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; ">Researcher</div></div></div></foreignObject><image x="224" y="67.5" width="62" height="17" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPgAAABECAYAAACs2fgFAAAAAXNSR0IArs4c6QAAEqFJREFUeF7t3QOQLc2SB/B8y7e2bdu2bdvet36rt7Zt27Zt27bt3f5FdG1k5NeonnNm3pz5KiMm7r3T1V1VWfVPV937xKDBgcGBO8uB+9zZmY2JDQ4MDsQA+NgEgwN3mAMD4Hd4ccfUBgcGwMceGBy4wxwYAL/DizumNjgwAD72wODAHebAAPgdXtwxtcGBAfCxBwYH7jAHBsDv8OLey6f2VxHxKIkHLxcR33Rv48kA+L1txe898x0Aj7hHocsjRsTfnrAH/ici/jEi/i4i/jAifjoifjgivjEi/u2E745XBweOcmAA/BoAvrYIhMZnRMQHRMS/HF2p0X5w4AocGAC/QYC39fndiHjliPi5KyzYeGVw4AgHBsA7Af6jEfErnZx9iIh4hIh4soh48oh40IX3/joiXjAifqnzm6PZ4MBVODAA3gnwt4uIT7oCh0UwXzsi3iciHq28//OTX/4s07P/vsJ3xyuDAz0cGAC/ZoC3RQDu74iIZyyr8oYR8fk9KzXaDA5cgQMD4DcEcGvzJLNJft+0UN8cES97hYUbrwwO9HBgAPwGAW5BvnIC+aumlfmniHi4npVKbZ49Il4qIl44Ih53Nv35/X8ZEX8REeIF3z5bDP9+8NuaP8wsdF48Ip4uIh5/HuNDRsQ/R4RN8xtzP18fEVyNq5B0JOH2ErNlw8p55DnFqI/fjojvnAszfvMqHczvmA9+6edpJ4vpieb54Nk/RMTfzHOQyvzimYc93T3sPNbW9u8jwpyQuMtbTnN4vYh46rm//Hzt+w8eES85j/e5IuIx5kIV6VXrK+Vqbb+sMxNTAY4P3zZ3/iBzsNd+5Co+VkTgSUvv/tBsXf5MDzMW2jxYRNhD+P4881weNSL+a57LH09xqO+LiG+d2v3IgT4+auL7O6f295v4/nHzv59qSkW/R0S8UEQ8ZkTg5/1qoctSHvyqPngd97tMAPrI8ksAB/Q9eraI+PB58HttPf+9iHivKdD3JT2Np/SdBccs8QJBwl76ngkUbx0Rv975AgvmnaYN+m6d/agr+MJ5LjZFL5mPfu4/C46e9/5jEpifHBHv2VGzAMQ2a6P/nAHi91+3YJntAfzl570hMLtHUq428mdGxP9uNK4Af5GIsF5PM++Lp9/raOb9W0TEv3a0bU1eIyI+KCKetPOdH5wwABs/0dHed+3rRv7+IXPQmrDIFrI2NwrwN58k5aeXSTx2RPzpzsTeYNLWnzUxjVQ8Sp82Scy3iQhAWSPfpRVe5ejH5/YE1EtHhIXaIkFHpZLPeYV+WCc0Qo/FQBN97TymK3QVPz5bSHv1CkCd18Tf3zEiaJlKWwB/vwmoD7jCQAm+N9oI1FaAP+8M1O9O1kZPt3gptbtHhJtgNOvlKBGWbzwLlK13ARrIG/n7R0TEr011JrBU6UYB/t6T+faBZQQkzpYpbQE/p7xD03xBRHzLrKltNCaWBXyTSbI/TmlPK73tBtdogw8tz2nkL58BBVz6oNlpGKYeU5KWbCT19xQR4c8lYiqT0EzWTL8wzwWovPvwk7B5yqlO4BUj4hWKC8V8ZMn81s7u+ZSIeKvS5k9mIcbkNB8bisB55tmU5u5k+qL591tdEWzm1YhZ+Mul/hvI8ImlyAWpVDes59wG7o+x4gkr75kigmZ8pPKBT5zav/3KICvAX2zeS483a34aj8mv4pI5CyAE9YsuuK7W4ht2+P55EUEZZcJryok5TpERvk8wVXcai7YPnRqzRl5z2iNfsdFPtYI/enYb8/7l0hCo9uv9b9JE/65JyzGTGil6eeKNyTBxFMTkTSQfz5zjoy4RgUGKAnomPvv3LrxgYS1C8x81+YTZXN/S+vw2kt1mafRhs0m8NC6WBFOvkcVkPnNZ1vrhu31NRDx6es9GMZc105RwALIsfAQzX33Db32oyZwE6KylfB/4twqSbCICqRFBiQc0PzPfhtcGWUMxjExAS7BZg0Y2Nw24VC5tjcQJgDATnxNfKlWAW39tuW+vNrkRP7W0UJNQf6U5XpRrOCiTl1lp79eA+aXluZiTfah0e4kIFHtIXKmRMfOl/blE3MiPSQ8+deYHocEywfefnPcHbN/3pgD+rLMGy/3xoZjta0SKA3MjPqhU29rk83fqu784gWXJ53r+adG/P734Z3Pwric/D+SY2eZk4whiVQIUAaJMFqJaDUt8sPgCPhkEXAnAXyJxCv59I6ASKKQVt4gm+f1JOAoENfItoF0j38waVfDxCWd/ULBzjwBOwVMjIKXZsm9fv0GA/+xs5bRngpHcl0oV4J4T5tZjL55RrSB8JMyWhLEA7B8UQcw6EETdUhLGQ2hxu6xRoy2rhLXy8aktnrMqxT3si3v0dxMAN3ggsviZgHXNpySRfqdoIhqGxOshmtX72UcEFoDM9LrF72Fl2GS9pLYeATeA2LSVyZ89+1ftm7Qi4bC3+K29uEUWhFva5INn0ND6fgSVaKQeqpv6xyYTVjR7jZYAJOCTg0Br76p0tDkzcT/WtOrWmuGjuVb3aGl8NPdXdTDjOSY3zPwzsY6WgqmyBVzGRlxOgn4vttTav1YJBrNeuJxLritXkwDIxEKArUUhfp0AJ/H4Ge+/4DvxS95sg9Gi2Q08mgErk30ralo/R6rxnRotScZqWtl0fOlzEeluwZjBjY4W+BCEtFYj1oUNIHW0R9a3l2c1CEorEbRrVAF0ZFz2xPumDwMOAPUQX54gBuj2I1VU04l1fFxCe6hHsLJoqkvxApN79AMLA2Qac5sacU3EjnqJEmI55rPra1baEsC5lO+w1lkPwJlOPdFbfRhsq0W3MW3wSvwuvnhlYG7HxBHIakS7iIYfIYEm7zWivbO/4/e0Rk1P2Ojch3NQ1QTAJhjFVOwla0QbyAs34g/S5OckOWF+YyOaIfvYta8KIK7E83UOSHArm9VXWd+9rur4jvZh/vL9jbiLjj1n4qeLM+Q4kXhH5uPeOD0X0PVeI7GZ7Gq13y8BXFCQkFmkHoD3DLC3Dd+YSbMWeGjfIZlz1JW2p/WPEPMyFxGILorIZh/P/AXusvYAQiaXCCXf/RSqPhPfr0ase75fASEjwRw/J4ncZxeIAM4bvPZVAfSxc+69Z0z1XRqIJjon1T6OCm5COJ+hWDLvxXWq8uN+7GU66jwFXLk3jdZcxSWAU6iKlh6oAOfPkEprwaE8OAOWEsrErztS8eNdJk/1t5aYz7xS4ZQDWa1vrgFrAsPFEY5ehmHTyw03YkZuBRbX1kn1Ui7rFU0WP9gjwU0SXlWeudPIhNySZSWFkysLjwKchZUtprWxGUOLrrc2PWmovbnW5xXgLJSvPvARZnO2mpYAbtxcwUysq70agjoMFi2h3WhNEVSAc9NyluUe07tuDa6AQQoGUHqJ3ydodR20Fshhfjn4ktNltX++G1+YNmWJ9FQefe40Fz73uWmvjt9mpuF7KsPWxnYU4IJFCob2SNBVQDLTWhpz71tbz0+tRe8BuBgTn/vctMb7CvDd2EUPwHtLVZnUOsypFppRYcgRWjJ7jry/1baVKy61sfEE9mxU2myP5OKlLOS4FcIsEYulN4q9119+rmpOiq+S/DdX5kiQZ63fowDv1cKsCQU+mVT3ic2ck24C4NUFO+f4xbNqurYCnMKR9lulcwJcJ0uVZ3xuWryXVHsp1rgO6tmETHsakE8qcpoj4EtjItSk8JYuxVC4wbQ7N60trEKTdy+diTmoyWd1uGSDZmJC1nzzqT54762lSwBX1HPUBdvj6U0A3DkElZLXQUu+dQW4+gpu2I0BnMCQSlA22kjATHVOT1rHO0pN/6iMeC1FcR2Mzd9UWGHz8WNpf/nrXCXW2vLNRcxrqkY0/k3TB+XJc0rlnOPnYxOMOZYg1SUb8asdHd0UwJdMdLUH4hznpJsA+OsU5cWNo3l7U5NH5/tAB7gBO5ZIw+QiE74Z07eHpBzqCbOlFEXPt87dhvshR+mkVvVvCTaCKJPAovrhRuqrCYnrIHX+OVBjs1mLHnAbj1rv7EMfNdF7NfhSELXXfz/Ct5sAuIBavWtdEHEvS3RkHrntrQC4ATnh8q5lFr0bwGsORyjmaMTXqRU8V2XSOd6jJUWMs3b2XfGDnFqrxSOsmRyjOMdY2jeYuLnyzOGIXOiz1xfTnonf6LoA7vs1DSoYmwub9sba8/wmAE7I1+q2ugd6xtrb5tYAnBamOfJhDGa3s7irObs0y1pLLsJ9HdHoXsYutWOhWNx8YIZP5gBAIwcq6qUByhivI0vAHM/8VilWT+9tzbceBrpOgLvCK5cESzUdCUaKk2RXhMashVM3AXAuqRLRnH0Rh7qOyLq1uzUANxgLVvPeIs71KOPSpqvahMR3+sZR0esgfrXI+dH/nMFR1hyxrqAiBGyAnF+W084ngs41H3GAvNGOFHaIkQjA5fjCdQKctlaO3IhLxrLpvYXnz0v+ly9cL/e4CYAbf626VO2WD0mda31vHcANiH+Sj9kJPjhBtFTTmxkh0CZXmo/sMYcd3OglpZCqg2gLuWsmbE5nqTmXApRmeIbZ5K5uxV5fNlWOLSylFOtRUek1lkzvZm58BDhz8eMMcyVWQa4dJyS5SntECCniee7SkDBdKohpzU4BEN67pCCTY6L1QpClsSs3rik1VpRa80ynjM93evLg2tXzDLITMgV1flvrwEURzG3rW9OI7d1bpcENijkqsptTTQ50ANSetqw5ZFpcgKoWSSwxTk5e9ZzIcqMKvhrNBSDjWjtrXvvhhijgyZVESwUbvlnPVSuDzcG3rcU37lzGqS4dkGvuXc2BO8AarR2jzH0xMX3bxrGh1cln2iqDPBVAhHyuXde/9RV/WSPjBQJZjUZrNQGnjq8X4Cw/7lGuenPHnaxLjxCX5lLHn4Xpmh9/6wBuEZx9rnXTW5cjtIVzEytg5HrovcP63hU5dvjen40sADO0lhBW88r3mXt7OVkb35VBAoeNAI8PvHSWnF9er/JxtREzdU3Q8TFpYeZsrlewyEu516U776S+xDOWiB+r5t4FCoSFgqSaqto61HIqgFQVOjeerTTKwKGLpZoC0WnWUM3GSAOy0CqdOr5egOvXmB0YyUTAqnTbOjbKjWWV5nP1yqvXaiduJcBJOAX5+UAHM4aplY9BLm1CgTXlnpmkf/g5fmhQARY+ru9bbDXb2Ze0eZnrS7d+KKpxyixfnaMvAKcpBApZDr5BY9P6xq2wpZa1SjOtXbfj+/qpVzYRPMx8/fErjVusQR9Mv3pc05jMcSnPymph3WSBiM80tNNNgpzy+u3aKZuvxQZaXECtQo7ys2YIJn9axxwxPhVA+Fx9cb/Da4KXhnfgA99pdunJemUTk37tDrRTx3cE4Ma9VJYstiD1COwsExodf2lo8yHkMqlB5zKunTa8lQA3AVfluHwgk+iy4pCtGzy0f/25/HLpMMiKcvr/X9PYNHI9EJDfo4VJ372KtbW+gI2mrTfG1vY0JqG0dYnC1nxoVxp565jtVWqjnaV2FRBaulesjanWv58KoPbdpeq7vXX1nGC0N9Zu3zl1fEcBzhKRyu0JIi/Nj3CmiOpFGLntrQW4QTJp6wkoVwK5GmiPSHAbIftee+/QAk5ybTGsfYM57+TXke97lwuh6GXpvrel8dGgxuSsb9VGa/MhzQULbZ6eywpEz2ntrQCZvpzoMg7/62sjMQvlj0v31V8XwPVNm9kH3LI9kpXg9u0F5G4a4G3czGvpyd6LQ7hozHRz2ksh32qAC0KILGbT1uSYK72X+wM6X5FFwHx1XpcJR1MDgu8LcDjXfCSK2RaHCc3Ed/jBAgk6+b5IM3PL5vJd1geroOeKoaUNy5/k38oFm5N50PCsAYssIsyt4VsC1l5AsvbBzGe6CvQwyfGc6csNEKEVkHPkdGlDiQC7ccVhFuPkokih2YS50u1UANUxs9CsrR9WjuAlnjBr8398IL7Scxzz1PEd1eB5PrQ5ZUEjK9u2j6xx20dMcfEGVq191HsByMkA35Oe4/ngwODABXGgnia7oKGPoQ4ODA7scWAAfI9D4/ngwAVzYAD8ghdvDH1wYI8DA+B7HBrPBwcumAMD4Be8eGPogwN7HBgA3+PQeD44cMEcGAC/4MUbQx8c2OPAAPgeh8bzwYEL5sAA+AUv3hj64MAeBwbA9zg0ng8OXDAHBsAvePHG0AcH9jgwAL7HofF8cOCCOTAAfsGLN4Y+OLDHgQHwPQ6N54MDF8yBAfALXrwx9MGBPQ4MgO9xaDwfHLhgDgyAX/DijaEPDuxxYAB8j0Pj+eDABXNgAPyCF28MfXBgjwMD4HscGs8HBy6YAwPgF7x4Y+iDA3scGADf49B4PjhwwRwYAL/gxRtDHxzY48D/AbTWH0p48Qc9AAAAAElFTkSuQmCC"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-129"><g><ellipse cx="225" cy="524.5" rx="7.5" ry="7.5" fill="#ffffff" stroke="#000000" pointer-events="all" style="fill: rgb(255, 255, 255); stroke: rgb(0, 0, 0);"/><path d="M 225 532 L 225 557 M 225 537 L 210 537 M 225 537 L 240 537 M 225 557 L 210 577 M 225 557 L 240 577" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 584px; margin-left: 225px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; ">Database<div>Engineer</div></div></div></div></foreignObject><image x="199.5" y="584.5" width="51" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-133"><g><path d="M 305 481.37 L 305 508.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 305 476.12 L 308.5 483.12 L 305 481.37 L 301.5 483.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/><path d="M 305 513.88 L 301.5 506.88 L 305 508.63 L 308.5 506.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 495px; margin-left: 305px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; background-color: #ffffff; "><div style="display: inline-block; font-size: 11px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">JDBC</div></div></div></foreignObject><image x="290.5" y="489" width="29" height="15.75" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-134"><g><ellipse cx="385" cy="524.5" rx="7.5" ry="7.5" fill="#ffffff" stroke="#000000" pointer-events="all" style="fill: rgb(255, 255, 255); stroke: rgb(0, 0, 0);"/><path d="M 385 532 L 385 557 M 385 537 L 370 537 M 385 537 L 400 537 M 385 557 L 370 577 M 385 557 L 400 577" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 584px; margin-left: 385px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; ">System<div>Engineer</div></div></div></div></foreignObject><image x="361" y="584.5" width="48" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-135"><g><path d="M 59.5 523.6 C 59.5 518.85 70.69 515 84.5 515 C 91.13 515 97.49 515.91 102.18 517.52 C 106.87 519.13 109.5 521.32 109.5 523.6 L 109.5 570.4 C 109.5 575.15 98.31 579 84.5 579 C 70.69 579 59.5 575.15 59.5 570.4 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(230, 230, 230); stroke: rgb(0, 0, 0);"/><path d="M 109.5 523.6 C 109.5 528.35 98.31 532.2 84.5 532.2 C 70.69 532.2 59.5 528.35 59.5 523.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="stroke: rgb(0, 0, 0);"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-136"><g><path d="M 119.5 523.6 C 119.5 518.85 130.69 515 144.5 515 C 151.13 515 157.49 515.91 162.18 517.52 C 166.87 519.13 169.5 521.32 169.5 523.6 L 169.5 570.4 C 169.5 575.15 158.31 579 144.5 579 C 130.69 579 119.5 575.15 119.5 570.4 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(230, 230, 230); stroke: rgb(0, 0, 0);"/><path d="M 169.5 523.6 C 169.5 528.35 158.31 532.2 144.5 532.2 C 130.69 532.2 119.5 528.35 119.5 523.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="stroke: rgb(0, 0, 0);"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-137"><g><path d="M 89.5 533.6 C 89.5 528.85 100.69 525 114.5 525 C 121.13 525 127.49 525.91 132.18 527.52 C 136.87 529.13 139.5 531.32 139.5 533.6 L 139.5 580.4 C 139.5 585.15 128.31 589 114.5 589 C 100.69 589 89.5 585.15 89.5 580.4 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(230, 230, 230); stroke: rgb(0, 0, 0);"/><path d="M 139.5 533.6 C 139.5 538.35 128.31 542.2 114.5 542.2 C 100.69 542.2 89.5 538.35 89.5 533.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="stroke: rgb(0, 0, 0);"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-138"><g><rect x="40" y="506" width="150" height="105" rx="6.3" ry="6.3" fill="none" stroke="#000000" stroke-dasharray="3 3" pointer-events="all" style="stroke: rgb(0, 0, 0);"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-139"><g><path d="M 210 547 L 196.37 547" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 191.12 547 L 198.12 543.5 L 196.37 547 L 198.12 550.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-140"><g><rect x="430" y="271" width="130" height="40" rx="6" ry="6" fill="#ffffff" stroke="#000000" pointer-events="all" style="fill: rgb(255, 255, 255); stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 291px; margin-left: 431px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; word-wrap: normal; ">User Interface</div></div></div></foreignObject><image x="431" y="284.5" width="128" height="17" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAABECAYAAAD3Lo2pAAAAAXNSR0IArs4c6QAAFX9JREFUeF7tnQXwLTcVxk8p7lBKcadAi7u7FCjuxYpTvDgtpbi7U9ytuFuR4u4U12IFirvdH7M7sy+ck81md+/b+/7fmXnz2neTbPZLsvlyLDuZRAgIASEgBISAENhyCOy05d5YLywEhIAQEAJCQAiYCIAmgRAQAkJACAiBLYiACMAWHHS9shAQAkJACAgBEQDNASEgBISAEBACWxABEYAtOOh6ZSEgBISAEBACIgCaA0JACAgBISAEtiACIgBbcND1ykJACAgBISAERAA0B4SAEBACQkAIbEEERAC24KDrlYWAEChC4Gxmdlszu6yZ7W5mJzGz/5jZH83sZ2b2fTPbp/n/ogZVSAgsCQERgCWNhvoiBITAUhB4oJk93MyO1dOhXc3sV0vptPohBIYgIAIwBK15y57OzH4cPOJzZnbhysef28y+EtT9gJldubJdVRuOwCfN7GJBtTOb2Q+GN6kaMyBwBzM7pLBdEYBCoFRseQiIACxnTEQAljMWc/VkEwnAQc1JuMXkS2Z2/rkAWkC7x26I+CkL+yICUAiUii0PARGA5YyJCMByxmKunmwiAfiqme3ZAWRHJwCXMbOPZCbAu8zss2b2FzM7tZkdIB+AuZaL2p0bARGAuREub18EoByrTS25aQTAMx/t6ATgjquN/XnBBMMn4OBNnXzqtxBIERABWM6cEAFYzljM1ZNNIwCPak64XTx2dAJwPzN7fDABMH3w/hIhsEMgIAKwnGEUAVjOWMzVk00jAN8xs7MmYOzoBADv/8cEEwCV/8/nmhxqVwisGwERgHUjHj9PBGA5YzFXTzaJABB18hkHCBGAuWaH2hUCa0ZABGDNgGcet3QCcEEzu07jAb6HmZ3MzE7UJEb5vZn91My+ZmYfWpV5s5kdNQJaPLEJT+TPJc3sVGZ2ipU3+jHM7JfNs3jO28zsEwOe83kzu4BTHrsu9l3keCsHrwes3uVGZnamlTr4+Gb2JzM74YDnREVrCMCTzOzeToMfXDmrXTH590usQgn3NbNLm9kZmhh2YtSPMLN3m9kLzOy3mffgdLtbxXu+tHluX9WLm9lVVnPk8k3/GFPwpY+M66dX4a5vX435e83sb32NNb8/2cz2L8Dn1qt5g32fuXvSpvxFzOyvmTDZki7kogCYx7zv1c3svI02hTXDHPuDmf2mMSl83MxeOYF2gciFvZpn8jzw5Q9YHt3MA+bg65q1WvJ+Xpm51mdtf1SvEgERgErgZqi2VALAB+UJZoZDWKn8Y/WBf1HjMPWL0kpmtrOZ3cbMCD1jAysRPLbvaWZfLCgMabicU+4pzSbLJv9hM4PsdGV7EgDIyUOdPvO+LZkhQx2b+w17MGDDuYuZvTYoNxcBgKg80swgKCVCPoT7mtkbCgqDjeeY94XOOBLTT2x/KnMRgGM2ODOP2YBLhDXz4hUxuE9FVAHPeFDzzOOWPGyV3fCwFQG5x0AiMPf6LOy6ik2FgAjAVEiOb2dpBIC5wcbPB6lW2FBuYGaccPrkxM3GBOEYKv80s1ua2Wt6Kr5jdcq8hlOGzZMNgpPsrZzftycBAP8nOn36XnOi5DQLCTpPIWiksiW97Uuc8lMTAObQI8zswMK+pcWe2WxS9DmSyGkP/4WzN4QSMurJHASA8TjUzK5U+c70Gw3JkYX1IatoTfBPGCqQDkjAcwsqrmN9FnRDRaZEQARgSjTHtbU0AvAQM3vYuFf6X21Uzqjxv5FpCzUwJOF8I573r5WK86bNxzdqhhPl9Z0fORFjAiDm3VsT25MA3HV1imQjTAW1Oernt5rZtQbi9ucGazabrkxNAKKT95DuPr3R8ER17m5mlEkFzdPpV4QOosTa8mRqAoCJCvNF7ebf9pHMnWSMJNdATshZQF6CEwwB1Cl7r5VJ72kLWJ8jX0PVhyIgAjAUsfnKL4kAkJb2m0EedOz92JPZ0Nnc+ehhN0a9ywfJk8ObC1Ui9Dihofr3hDTIz+lsztg2+eh7JglU3Odq7MleW69uSEL6G5qBn6wueLlT0IftSQDok3dCw66LtiJS5/fNVDC/XVKIjaD1dbiFmZ3DaQSS8Kzk33EMxB+jK/QNjYonXKTDhgPpg4wQaUD5awblsaO/P/gtwocxu/3qHRjzSCAAP0zGnTl81aDC4xz1PD4a7UYdkTWaY92gafpy08Y5Vzb/O2fICX4oUTgi7e3S+A+cNugrvg3va9JL43fAe6URHW1VNGj8jn+AJ+tan31zVr9PjIAIwMSAjmhuSQTgwY3qNn0dPth8pCNHsr0buy1OQqngmPYx59+xD3MngSeoqdmk/p38yAUtqPu90zx1IjLxqhWxuZnzoE81xAE1J/KtZnPi1jdO2TgD4sA2VmqcANnEnh88mBM8N9ax2aFqZ7NDdYzTJO+JfTw6HbLx8m787QlqZW9DLokCQA3+o8ZJNG0b3wVOyJC1VCJzx3cbMoKWJ5UocQ9zBp+P1lESjQkkAmdDfCbYgKnLhtyV2jBAiDC3A3q+K2zGRFXgJNsVnPZwTPU2cUjSaTIT7uVmBknzBJPQTRKnQr71dwu0JbRBdkMIUSrrXJ+Z19VPcyAgAjAHqnVtLokA4MWPx38qbLhv6nm9xzZe9N1ieDyzGeGxnUpkl8cRjNM8H09PONV82/Fa52SMPRSv51Resapz80z//96cBj37eN2obltragJA62CLYyNOb6mw0XIKjNY519yinfFkDAGI7PJsyvgqfD0DZjQfICPvdOrlCFJbHBMKToUlkQW1BCAKm6QPaGkwT3mSSzyESSwlKLTRmjZwNkwFjQb1fhc879lmtl/w2xUa0tT9eZ3rc4o1pjYGICACMACsmYsuiQBw0vc8tgmlelkPDrwHGxInUUID+ZsTqieU5aTozUO0EGSiy4mXqY7yqGL50KXSRwA4EUan7SmGfw4CgPMiquVIIr8HyuMA9oyg4hgCADFDM5EKJ3DU+Tnhd+zoqbx+RRxu7Px7HwFA65MjfWmTtQQAjQLOe56gYfIIGmXxj/E0Y/y2T2DCiOY9ddjcc059aBswd3mS+luse31OscbUxgAERAAGgDVz0SURAE6N3jXBqDg5VfL3FMIHjvhnT3Kn07Z8pJ7EMc7TYOQIAKptwupyHudj33lqAsBp7yyOiaTbTzbNyE+A0DxC1TypJQBoXyB+nuBYiqkiJ4SxYS/HzNMVTrTknkjHJ0cAOPHjz4I6vVRqCUBp+2k5iBKEyZOIoJEvwVPXo2HBrPDrns6gjfPCE1nX+DS0su71WYuh6lUiIAJQCdwM1ZZEAAj/Q2XqCaFDqAVxBCQJD3ZNzzZbAhGqWU7rnpB3nQ0uJ6hCPRXpjwNbbI4A8L7dj19J/4eWmZoA0N9onNq+5TYYTv9sMp7UEgByEXBa9wQbdET4uuUhY54tHSc2vPq7kiMAvMPQCIl1EwD8SyJCTWw/JrWukEQIMpQSJMqwFofk6+ibv+ten3390e8TIyACMDGgI5pbEgHAhojKsmR+4CiHA9FHV6p/stNBCvrCl1qYIBFXG4FZrionnPQklCMAnKh4jzllagKAoxdZ3XKCQ2Zk++bWOzzRPaklALkNdCy25JR44wACgH3dy6GQ68cUBIB1g1c9Wii0SpAwHA/xWylZU23/PAJA3D+RMZ7gu3O9sSB36q97fU7YdTVVgsCQyVjSnsrUI7AkAsBbPLrJLjb0jfAqx1kLj3Q+SKkHf7c9bKMXHfqAwvKchFKv6xwBIAIAh7o5ZWoCEEVWpO+Ac6N3YpyDABAqd/+ZQESDkIYg5jQA13bCE/u6NpYAYJaij/gEjBWPAGCaw0TnCf4r+LFMJeten1P1W+0UIiACUAjUGorNRQCIm4+uMCX8zrP1t6/bZgKsnSdswKj4Sa/rCbkGdp8JW5yr0nsCIgJAHLS3QU7dtakJAKfLkhTIRFIcx3mZOQgAbU65CXW7fYBzU1+OAJQSpO4zxhAA8iiQVnoq8QgAd1REWh9yK9CHqWTd63OqfqudQgRqP+yFzavYAASI3Y6clViItScKnOmiDfgtqw3kuj19ZCMlIcmlBrxLtyibK57qXmgd4WCE+s0hXMCCCrMrEQHA6QwV7dyyFQhALsxsLL5oF9igu5IjAKjLI+/7qC+1BIAU0/jGRIKpDLJGhkJMMq0zI3kaojXoEQDyOxDZ4EnOp6MG+3Wvz5o+qs4IBEQARoA3cdWcrRZbdumlImm3iD+OsqG1OfBLXoWscKhUsdkTIkj63lJBBc1pLL1eNgo3pN2TB7H8pc/0ykUEAKeq9oa4Me331d0KBCBnOirJI9GHYfp7jgCUaki6bdYQAL6jZMb0MifSNs50mEU835ihToAQWy8fAs95YZP9cCiGUfl1r8+p+q12ChEQASgEak3FOIniKOQJH4o+r3ivHrG9pM715DFmhlp1qKAu5+OK/R7nObLk9anySRULgehKlGSEMmdscgQM7VuuvAjAtujMYQLIJbYpySMxdLyXQABySYDIyufdQNm+J9EukZbC0wBwR0CUshdiEKVTHoor5de9Pmv6qDojEBABGAHeDFX5EPBB8CSXtCXqCloFMupFN4URslVy5WrJq7Jhk7aXdK6edoBQQRztuqlno7vceZ6XlaykHyIA/4/AOn0AIHmYljzhcinvauMx47oEArB/kOWS9+L6Ze6yiASv/TSyoS3rEQA0Y6Q19r7d7Q2IY/Ds1l33+pyq32qnEAERgEKg1lQsF39P/DOe7aUhdnQ5yq3Ob9jmMStEKUNrX5nwJ049nuDHgD9DK4SxRVf49l2GUtM/aQC2RW0ODQCJaLBze8LNdd51zDVj2dZZAgHIRT5g348IEe8QXUHNbx4B4N9ztnky/UWJmFrMMAniTJgK3wK+Ca1/wrrX55h5oLoVCIgAVIA2YxWy7EW3nvFYNrB9CxPv7NVcFRt5txNKFN16xrwgKgG1Pneq84fTGyaKEuEyHeqkcqHm8pP23/lYkQqYi1RSIdYZ1WpOIESYIbjg5ajmb/47Sj0sArAtmjUEgDSyJGDKSeQ9ji8IF9zkMtXhi4HfCuPY/RNdQLUEAoD3fZRQCa0Yt+l5gtaMzTzypzmwCcdN6+YS9PQltOJ7AEHwfIpwmsXHYHutz5Jvi8pMiIAIwIRgTtAU48HtYJEZgEcQuofKkTvDPSFdKh8BTtA7Z/qEI59nS8STmI8qKVm7wjOfWvCOXFDCCRBVZSpEOqSnwyjhDHX7Et1EKYujDHAiANuOSI4AkE7Zy6KHKYdTvnebX9s68w9tlieow1GLR8KmR4riVCAD+MGkGrAlEICDV52NTBuRoy3rCxt7e1uhh0eU6XHP5npsrw7XNRP6CyH2JGeu4BbNNFpnneuz4POiIlMiIAIwJZrTtNUXTsRTUNER20+cOxsq6nw2XDL4Ea6Xbt5pz3K3k3FxChtlKpyqyWwWXd1LeTZ/Qgb5yKRyRBDyF13+Qn2eCQlIw6sgNnibRwln0KQc5vRBBGBbUHIEgJS95IL3hEQ3OJZG9yZAQknHHF1FzJ0AXGiTJoki0x8hbt510g9fPY+NNpUlEIBc+mPWJqfqrmaPDZwLe4iMadez9y0muyYmNU9w+Oue1rtluCsALLuX/tD+bZvnercIMl5kLERL05V1rs/gVfXPcyEgAjAXsuPa5aR9z3FNhLVRrXNrGXHJnqAiJL9+lHeA7GCEB/HBwKGPOYTaFnMBJgXvbnOek3NizG021OW2NO52J1MfpglOpqhPPaGt6J50EYBtEcsRAC7t4UbGSNBAMZcgm2gEIF1dIffDIZn6OKwRGcKJlfpsdFFWSC7Lgdx6/i9LIAC7NLdeesmWgACihLaNDZnLm8hP0H57+Q0im9OYcAonOqh7qRPzH6dhyJYnbOTvMbPvNkSMSIQoUoc+sKaiPAbrWp8zffLUbISACMAy5wY2cRx1vOtPx/QYrQGbNOrUnJD8hxN09EEb2gfa4iQRpQUmOgBiUZvsqO0PiVYgN5FjowhAOQEAR+52KBG0UJh3UuE0T+KaMYLtn75E2SyXQAB4v9oESGz8mA8wqfStt/R7TcTFoRNkseyLVFjX+hwzT1S3AgERgArQ1lSFseHUjIdx34ehr0tsvIT0YF9NVXxR3b2bm9tY/GOE+wAwK3TD/7z2MGFQNlJ59vXh8EbtGdk+qS8CUE4AKFmaCz4iABBZtFlRHoq+MUXLhCo7TSDVrbcUAlCzSXadeomGwdyVE+97jQ8Bobw1iawID8VfI71fYXutz775oN8nRkAEYGJAZ2gOuxzmAJKoREmCosey6aK+w7EvchrMdRl1JbZaQoZyDoVeG9j8sfVGV8N6dbD97teEP+1WiCUx0SQ0whO771piEYBhBACnOxwtmYM5iQhAWwf1MiYF1PglAknFeY7503e3/VIIAO+FKYONnBwWOcG3hVM/Tn6tHwXXH3Mb5a6ZitH3mqgM/CP4Rnj2fa9J1P0cMNLrlXP9nnt9lswNlZkQARGACcGcuSk2f9g+WfewlWILh/WTw56PCKpS/hy5irXGCQgHQeLxp4jzJ5EQYYWczrEjsjFw4uFucjZdbPN8qAlpQlWLbZdohlohLIrncVERmc/4sGJnhYQQikjoIOp+HKH4U5obQQRgGAGgNPMOFTEJa7i3gbFhTh3d2LSxbeOfgb05J3xruJcCExR/4ytCKBpzCH8UfAEgqZiLSIzTZ6Zqn7UkAtD2iXTZaL2ItME0gp8EeHE5FqF2hAV6mipIwEENRqw51hbrGV8L5jk5A3ICEcCJmHWzR4MvmjUcEXkepBxNGWYDUhfXylzrs7Y/qleJgAhAJXCqJgSEgBAQAkJgkxEQAdjk0VPfhYAQEAJCQAhUIiACUAmcqgkBISAEhIAQ2GQERAA2efTUdyEgBISAEBAClQiIAFQCp2pCQAgIASEgBDYZARGATR499V0ICAEhIASEQCUCIgCVwKmaEBACQkAICIFNRkAEYJNHT30XAkJACAgBIVCJgAhAJXCqJgSEgBAQAkJgkxEQAdjk0VPfhYAQEAJCQAhUIiACUAmcqgkBISAEhIAQ2GQERAA2efTUdyEgBISAEBAClQiIAFQCp2pCQAgIASEgBDYZARGATR499V0ICAEhIASEQCUCIgCVwKmaEBACQkAICIFNRkAEYJNHT30XAkJACAgBIVCJgAhAJXCqJgSEgBAQAkJgkxEQAdjk0VPfhYAQEAJCQAhUIiACUAmcqgkBISAEhIAQ2GQERAA2efTUdyEgBISAEBAClQiIAFQCp2pCQAgIASEgBDYZARGATR499V0ICAEhIASEQCUCIgCVwKmaEBACQkAICIFNRkAEYJNHT30XAkJACAgBIVCJwH8BXdfFgQPDC+AAAAAASUVORK5CYII="/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-141"><g><path d="M 333.63 41 L 305 41 L 305 100.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 338.88 41 L 331.88 44.5 L 333.63 41 L 331.88 37.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/><path d="M 305 105.88 L 301.5 98.88 L 305 100.63 L 308.5 98.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-142"><g><ellipse cx="355" cy="7.5" rx="7.5" ry="7.5" fill="#ffffff" stroke="#000000" pointer-events="all" style="fill: rgb(255, 255, 255); stroke: rgb(0, 0, 0);"/><path d="M 355 15 L 355 40 M 355 20 L 340 20 M 355 20 L 370 20 M 355 40 L 340 60 M 355 40 L 370 60" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 67px; margin-left: 355px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; ">Machine</div></div></div></foreignObject><image x="332.5" y="67.5" width="45" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-147"><g><path d="M 376.37 127 L 403 127 L 403 291 L 423.63 291" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 371.12 127 L 378.12 123.5 L 376.37 127 L 378.12 130.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/><path d="M 428.88 291 L 421.88 294.5 L 423.63 291 L 421.88 287.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-148"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 217px; margin-left: 404px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; background-color: #ffffff; "><div style="display: inline-block; font-size: 11px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">HTTP</div></div></div></foreignObject><image x="389.5" y="211" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-149"><g><path d="M 423.63 137 L 417 137 L 417 288 C 420.9 288 420.9 294 417 294 L 417 294 L 417 328 C 420.9 328 420.9 334 417 334 L 417 334 L 417 408 C 420.9 408 420.9 414 417 414 L 417 414 L 417 418 C 420.9 418 420.9 424 417 424 L 417 424 L 417 445 L 430 445" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 428.88 137 L 421.88 140.5 L 423.63 137 L 421.88 133.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-150"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 238px; margin-left: 421px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; background-color: #ffffff; "><div style="display: inline-block; font-size: 11px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">HTTP</div></div></div></foreignObject><image x="406.5" y="232" width="29" height="15.75" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAA/CAYAAAAxBeyIAAAAAXNSR0IArs4c6QAAA/xJREFUeF7tm78vNEEYx78rEoUG0VGJHxGJSIiIQuFHkKAglCRErVKQUChIUPgDRChPUIqCwu9EQSHRiEgkNKIhUQg5mXvf2/f23tubW7Nr5jbf7dzMPM8z388882uXFY1Go+ATGgUsAg0Ny1hHCDRcPAk0ZDwJlEDDpkDI+sM1lEBDpkDIusMMDTPQ1dVVjI+P213s7OzE3t6eUpeLi4vx8vJi27i6ukJdXZ399/7+Pjo6OpR8yBqPjIxgfX0dv+krMabS0lI8Pj7KwnSU5+fno6CgAKJtY2MjWltb0dPTg9zc3LR2HBlKoJ40T1k5PnhUgaYyLuDOzs46ki65HoGqM3RYCBJo3FFfXx82NzeRl5f3X/TagT49PWF3dzcjWaenp/H8/GzXnZqaQllZmbRtZWUlWlpa8Ju+0mXo/Pw8KioqXOP++vrC6+sr7u/vcXZ2hqOjIyRfuQ8MDGBra8s8oFIaCRXKy8txd3dn/3J+fo6mpiYvJjKu66ev5DXUa9y3t7exafbw8NARfyQSwdDQkOM37RmascIA/BRZ5tdPX6pARawfHx9ob2/H8fGxHXp1dTVubm4IVAZTlJsGVMR0fX2N2tpaR/gie0Ws8YcZ6kLXRKAi1JqaGkdWbmxsYHh4mEBlWWoq0MHBQcdmaHFxEZOTkwSarUDHxsawtrZmhz8zM4O5uTkCzVag4riys7Njh7+ysoKJiQkCzVagyUvB9vY2+vv7CTQbgV5eXqK+vt4OPScnJ3bRUlRUlBlQcZuRuIOSiZCqfGFhAe/v73ZR8uW8F5t+blRkfv305dc5tK2tDScnJ3boqV6epD22yDr9k3ICBbzeFD08PGB0dBQHBwf/MtGycHFxgYaGhswvFn4CTNaGQIHl5WVUVVW5SiXubd/e3iBAnp6exl5hfn5+OuqLna3Y4SY/zFANFwuyQS8rF+dOcf5M9fCmKIuAiqxeWlpCb2+vK3MCNRSoeNdZWFiIkpISNDc3o6urC93d3bAsK20CE6gGoF43RbIpOLGcQAnUy3gBZB+JebHm59lQ5tdPX36cQ2XxxsuZoczQTMfKn3rMUMQ+xUz8jJNr6N8x5Oc0KBuWfvoi0F+YBglUpoBLOadcTrmuQ8fPaVA2Pv30xSmXU65svPHqz6tCzFCuoa5jRtuU63UUs755CvAffs1johQRgSrJZ15jAjWPiVJEBKokn3mNCdQ8JkoREaiSfOY1JlDzmChFRKBK8pnXmEDNY6IUEYEqyWdeYwI1j4lSROm/2lUyzcY6FCBQHaoH6JNAAxRXh2kC1aF6gD4JNEBxdZgmUB2qB+iTQAMUV4dpAtWheoA+CTRAcXWYJlAdqgfok0ADFFeH6W97Qt2suZ3FFgAAAABJRU5ErkJggg=="/></switch></g></g></g></g><g data-cell-id="a_cl7nsyDpLQFaXOHeFD-3"><g><path d="M 279.5 257.6 C 279.5 252.85 290.69 249 304.5 249 C 311.13 249 317.49 249.91 322.18 251.52 C 326.87 253.13 329.5 255.32 329.5 257.6 L 329.5 304.4 C 329.5 309.15 318.31 313 304.5 313 C 290.69 313 279.5 309.15 279.5 304.4 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(230, 230, 230); stroke: rgb(0, 0, 0);"/><path d="M 329.5 257.6 C 329.5 262.35 318.31 266.2 304.5 266.2 C 290.69 266.2 279.5 262.35 279.5 257.6" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="stroke: rgb(0, 0, 0);"/></g></g><g data-cell-id="a_cl7nsyDpLQFaXOHeFD-4"><g><rect x="262" y="313" width="85" height="17" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 89px; height: 1px; padding-top: 322px; margin-left: 260px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">metric-db</div></div></div></foreignObject><image x="260" y="315.5" width="89" height="17" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAWQAAABECAYAAAC2wE+iAAAAAXNSR0IArs4c6QAAD95JREFUeF7tnWWw7LgRhc9mAxtmZk4qzMzMzMzMzBtmhgpVmJk2nGyYK8zMFWZmf3lybZfKM5bGmrm+d07/2X13RD6Wj1qt7tZ+shgBI2AEjMAsENhvFqPwIIyAETACRkAmZE8CI2AEjMBMEDAhz+RFeBhGwAgYAROy54ARMAJGYCYImJBn8iI8DCNgBIyACdlzwAgYASMwEwRMyDN5ER6GETACRsCE7DlgBIyAEZgJAibkmbwID2MSAp+QdJ7Qwt0kPWVSi7uz8kUlHRyG/ndJByx4lEdIekD47SBJV9ydj713Rm1C3jvvcpufxIS87+2bkHf5V2BC3uUv0MP/PwImZBPynvgUTMh74jXO7iEuIuliaVRvkvT5NY/QhGxCXvMU20zzJuTN4LxtvbxG0rXSQ99M0ovWDMCRJB069PFXSdhPt01sstjlb9yEvMtf4EyH/yNJJ9ogIc8Uho0Py4S8ccjbdmhCbounW9tHxBByL5vQkI27TRZ7Yg6YkPfEa5zVQ1xb0qtNyDvyTqwh7wjs7To1IbfD0i3tQ+DJku5qQt6R6WBC3hHY23VqQm6D5ccknS80dW5Jn07/PqykG0m6hqSzSjqWpH9J+lnniP8ZSS+X9OYFwziVpFtJuoQk/v+Ikn4v6QeS3i/pWZK+t+IjnFzSlSRdqhvDqSUdW9KRJf1G0q8kfbF7pndJepukX4/08RFJF6gYx9E70v5dKA8O5wj/PlvwzLhsN6Y7SzqXpGNIOlSHV/ydalO8LBjLlSVdTtKZOkyP0wWVHE3SHyT9uPv7JyW9MWHxn4pnbFH0mJKu02Fx1fSOjpca/WV3aPoVSW+X9JI0J/hpCiHznpkPveApcz1J55XEXDmCpN9K+rkk3jeYvLvFQ7qNQxAwIbeZDRDXpUNTF08RU2eQ9AZJpxnphol9TUl/TOUgnYdJuq+k/ZfU/Wf3MRKV9syKxzhBavumI233TTKmx0t6giS8F4ZkKiHn9SF3Frn7dJFmjxnosAUhHyYR/QMTAY9B+HVJt5H0obGCjX5nESfakEVombCw3albsF/WzTlI9AOhcE2k3lskXUUSpP/ibD4v6h+lAIXhu42eeeubMSG3mQJvzcJOCUH9atLc0LhKBI3j6qng8zrt7JYllVIZtG+If0zOnrSq444VHPgdLfTySUvKf55KyO/ptK5Lhkb5fzRU+mRxymUqIR++04Zfn7TiGij+K+n2HWk9u6bSCmUx+WD6qRF2EZ/rdlMfXpGQmT8sOB9Pu7HSvn+adkffL63gcosRMCG3mR2QKdvKXjjYQnPFjPEXSa9KmhXmAEwDaNDXHdBQ0XDQpiFk5BvJpIF2hpnjFB3R0zYmkSg/TNvKZVtqtuNonfjsRnmHJPyGv5Y0dDSyc0q6QfpvLMsHzxb2H1kb1ME0g0AImFd6gVziIR9/Z9sLufXCdvkK4d9sne/YkcNlwt8gaPrFnID5Igab1JgsmPPsaDDVRPlOZ1IiiOWbCQfe0wXTe0WbjsJuBkJfh2CeYoGK3ybvFdMWpNkTHzsdFq6bJC36392475Hl8KjRkF+R5gbmGwSzGM/4pWTGwnxCvhBMKLyDKF+QxGK/aZPOOvDf0TZNyG3g50O5WmgKEwQmDOx8TPChLR32Pj68GNCALfnCkrBrPi4lf4GIc3l6Iqz4995MMvREkCU27TNnBAe5Q06L5LaS6CuO8aFd4QOX1GHxOG34vcTtjefuiYCq95P06NQG5hjMJT0R8SyQOeaaXmoIGaLnmaLQH2YZSC2X03f2bXZApww/YEtlcYx28BYzid0Ai158T39OmnzUfGNfLByvTOcMjIu500sNIXMWga0YwVxG8qGIcd8mJg2I+vzZA99c0gtbgLDNbZiQ27z916VDu9gaH8cZJbGlWyREsKHh5MJBzdDf+3IcsODrG+2LkCRkOSRo608KP0A8LAiYGsbk7t1h3xNDIbTUk6ZDyaG6qxByvqChpbJTQOOL41401lJCZnfA++DwsheI50EjIJwuaeSHC+XIlPaoMfAqf2eXwG4hCrZ+bLrLhOdiwWWcUWoIuQYPtOUvJ3tzX49D4LNUPq+LZwiYkNtMiSFCLkkBiZkDc0eUv0k6iSRO0pcJZhC2j70whj5cOdbjHUNw0YzwtM4WfJfCR6c+5oyo9d47aZRDTaxCyEP4fTSZDEqGWUrIHEA9NzT4i6QVYlYak+d3i+AtQqF1ENALOlMBO4pe0FrxgBnS3PPxskPLzxFqCRnTF/3lJqkhbJgDj81+YI5h+rGsiIAJeUXgsmo5obDVO36BuxhaIHbiKGwHsVGOyYMzjZjTf2zQuVxowDOArWnNIUx+yIRdMW6rY5+tCJkDznyxWoRJKSF/MJmE+nae02n6mGVKBHv2w9M7xS2QBRNSGjIplbQ3VAbbejwExsuChb1E8MahPtprL7WEzE6BHUOJnGzA5fJ2GzjwLBnbri1jQm7z6nJC/mzmV7uoF7bOHFZFQXNFgx2TXNtb1GfuOob3B+54NYIdlXq9YMM9iqQ/DTTSgpAhEogF+2mJlBAyhAXWmHt6wYb+2pIONlAGIoZQo9QsStTDlsxhcS+1hMzBHDbsUmFRx3zVC7Z5vD0sKyJgQl4RuKxaTsgv7Q7yblzQNCSRa1gcBnLYNyZ4QeB72gsHiNisc8nts5zW33Cs8ex35gnb+nj7BB4ImBVyaUHIkALkUColhIyXCWaGKNg887+V9tm6XB7UQfuMGVttqaDhciDXSw0hMw9ZrIYO8hb1n7srvnfAe6V07C6XudYYkNURyAm5xkYb3b8YQYzyWzYiNCE0ol4WETLkRoRgL2iERPjVCotMn8GNumjo2FVzaUHIjBHttVRKCBkvjjwi8qgDO5TSPluXY5EE4yjsQvpgoZL+8kW6hpC/nezHJf30ZXK7+jJTVk27W1vWGnKbV58TMocdRNmVSE7IpVpRKSFzMIS9r7XcK7mjrYOQa2y79F9CyOxYcm8FdiitfGfZ2WDXLxU02Rh6jP01Xyhxg8vnx7L280WnhpAJCMld2caeJc9bwlzDHdCyIgIm5BWBy6rNmZAJRom+qW2eeN8B1xABtdCQ+dBxtyuVEkImvDja5vFmIWKvlQxpuMvaJjQ6mpxY4PA972WV8RFUgtmglxpCfl8WLVmCyyM7j4z7h4IcdJZGppa0v3VlTMhtXvmcCRnXLoIHWssi0mxByPg937NiwKsQMrbSPrqwoquFRacScn74uoxMFw2CBEkkHFqFkInYJDS+RvKbqzmU7BMg1bTjsgkBE3KbqTBnQv5W5oP8kOzgpw0Ch7QyV0IeMlkQEt3KbW0qIQ9FENaaVHCXjF4jNRoyLoEcLNYIQTvRLW8VO3RNf3u+rAm5zSueMyETwUVuil74iIiAW5fMlZDJZEauiij4ipMGdQ5CRF4eelx76JjboWsIudazBczyJFjkFyHxk2VFBEzIKwKXVZszIZM0hry2veAGR3a4dclcCZlAFpLgRCGQZlPpNMfwzs0NlGfMeC6UCoEkMQKzhpDJs50nDRrrl0PJmKQpz6k8Vt+/ZwiYkNtMiTkTcp7Hgixe6/C66JGcKyGz/ceFLB7kEYH41MIpwLeSpy0lcX+N3+6yroYi32qzyrG4EJnZSw0hUwe3xp8U4kExkmb1CYn4N4eS2MItKyJgQl4RuKzanAmZlIkcekXhdg4i+9YhcyVknjUnLAIb4sUCy/DIoxUpe8KR5FE1+PItsmBwK0wvNZFveNLg5RAvNKglZHJ1kE+jRE4sidwXUXLPkZJ2XCYgYEJuMx3mTMg8IcmBYiYw3K34eEqFrHLcREFkHttUbopgizskOSGXfOQ5fuvwsmCsJGCPyeXxQSa6EXzGJE+ms46dBjZubN29kNGPtJ8lWjjuZ7ihRaklZFJ8kv61RPL8JiRAwiY/lhSrpO2tLWNCbvPq507I5BfIt+YEEZDnd0wITiDBfEx4tCwBEjbPGMJNgEyeFSzvc1OETOQb6TejFsriQuKgZd4W3INIJGT0sV3khz2G57LfhzxB8J9+xkijZGj71IANuJaQ6abk9hlysIAHWnIvB6eLF6Y8/9bXNSG3mQJzJ2T8bflgY75aAg+4JorcFouEBD9EzcVDQIgrv7Ej1s8zqpFzGa1rWcTZpgiZceb5nfkbB51gQQ7rXCA7XMkidpTDhJEnA5o6m8glQapUTCG9kAqTkGgwGhJC7UnFii2X1Jcxkf4yQiaXM4n5e+mT25PQiTSu+CUPCbmX6S/e8EI5DiXfORWAba9vQm4zA+ZOyDwlWivhsfkVTrjFcYUTmi2HVCQQ4uOGRMm3HJO5085YYnY08TzjF1thLtHkYyfXM4tDTK25SUJG40crzlOVcvsHmj+uW/w/wTQckHE/Yn6F0/WzPCJtZtG+Vobc3/g7Cx25ODCVYCfmAI4bubnGiWeCuMn/EV37lgW/cCNLDO/HjEWbvS8yASbggTkHPFicSSh16+wgj7FBxBCyZSICJuSJAKbqu4GQGSoZ1A6aEE3FDdBRqxpCb+gQMS+X593dJCEzFhYliItQ4xrB5sxiU3PLd037fVlCvDFV1AhEybuNXhLsSoYuiaVdrqyK0ZDshLhxhkU7ptQcGwPZ6Fi8h3YXY3X9e4aACbnNlNgthMzTcvDCdU/cgRbvyluGBNozh1qlW9IhLTm2v9OEzFgw42C+YIHBtjwmHFaS4a7k2quxtsZ+57sEb3KFxPzNQ/U4XOUmbPzNh/Jr85xDh4I56XNvIfk00JIxY5Uc7jHv79D1T3i+pQECJuQGICb7XrSzzinb26InxHTAdhzHfjwwOLjCdQq7I9oOIdeYM9C6cBeryTpGn9wJCIER3IAZBOIgKg6TANpYJLZNa8gREzxI8Gxg+0+mPQ7uiJDDBQ1tE40RUwFb+FoMps4uyJGgHuy1ZFHDjILGiycDiyQLJBns4mWrvL+YowNTAwmmcsmvi8pNUbgDYgLhlnHmCgsD84JDUTxuOOjlFnNLQwRMyA3BdFNGwAgYgSkImJCnoOe6RsAIGIGGCJiQG4LppoyAETACUxAwIU9Bz3WNgBEwAg0RMCE3BNNNGQEjYASmIGBCnoKe6xoBI2AEGiJgQm4IppsyAkbACExBwIQ8BT3XNQJGwAg0RMCE3BBMN2UEjIARmIKACXkKeq5rBIyAEWiIgAm5IZhuyggYASMwBQET8hT0XNcIGAEj0BABE3JDMN2UETACRmAKAibkKei5rhEwAkagIQIm5IZguikjYASMwBQETMhT0HNdI2AEjEBDBEzIDcF0U0bACBiBKQiYkKeg57pGwAgYgYYImJAbgummjIARMAJTEDAhT0HPdY2AETACDREwITcE000ZASNgBKYgYEKegp7rGgEjYAQaImBCbgimmzICRsAITEHAhDwFPdc1AkbACDRE4H/y1m9yS92XTAAAAABJRU5ErkJggg=="/></switch></g></g></g><g data-cell-id="uDJ2bVtIrgoZBCZFZmDG-6"><g><path d="M 570 127 L 550 127 L 580 127 L 564.87 127" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 561.12 127 L 566.12 124.5 L 564.87 127 L 566.12 129.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g></g><g data-cell-id="uDJ2bVtIrgoZBCZFZmDG-5"><g><rect x="570" y="120" width="40" height="14" rx="2.1" ry="2.1" fill="#ffffff" stroke="#000000" pointer-events="all" style="fill: rgb(255, 255, 255); stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 127px; margin-left: 571px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; word-wrap: normal; ">init</div></div></div></foreignObject><image x="571" y="120.5" width="38" height="17" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJgAAABECAYAAAB9Pvx1AAAAAXNSR0IArs4c6QAABCZJREFUeF7tnFmoTVEYx3/3wRTiRaYi05Mk4kFE8UYKGZJIhkylDK8iPFJCIWMSUQpRSiHyJFEeCIlCkVmEhP1p37qd1h7O8J17jv3fdbt1z1rfXv3Wb39r7bXWuS3oEgFHAi2OsRVaBJBgksCVgARzxavgEkwOuBKQYK54FVyCyQFXAhLMFa+CSzA54Eqg2QQ7ASwIEPkE9HQlVX7wF0D/QLXzwIzywzVnDQnm128SDJpuoVUZzO+BcImsDOaC9V/QajJYF+AN0K1N82YC5/ya6xO52QTbDcxKmIMN90FUcdTbQN9A7cuRfMsyos4BzpSUkWAVd4UqlhI4G3iQJJg8qQmB7vHw2FkZrCY8FaSEwELgeICKMphUqQmBi8A0CVYTlmUHqWSZYiewPnCna8Dkkr+PAxYDE4ABQAfgLfAQsMn5IeBjzlbnfYtcCezLGbO02KCovc8qrFuXas32FlmJYJsjklsCNO8Bo+K/94jlmZ1B/X00P1oNnM7ROxKsIAutG6L1pB0BIZ4CQ+ItphvAiBzSWJE/wBLgWEZ5CVYQwdYAewMy2NDXC7gATM8pV2uxb8BI4ElKPQlWEMFWAPsDIvwAFuUc7kIeHQGW1kCw0cDUOE4/YFVCzJPAg5LP9gC20d+wVxHmYLZqfjChBywDDQW+AtuAU8DLSMg+wPx47tY1oa5lMcuA9jt05c1gbeuOid4gbQcgdGmZog6PUSWT/DTBrMlfgEnA3UD7pwBXUjL9ROCmBEvu+aJnMCOzPH6DTKIU2rZpLbsWsGFKGSwBQtEFex6tmg8Gfqdk37kp87TtwCYJpgyWNAezRdiNGUO7zdEeJ5Sx7GVZTBlMGSxIYF7gWExpwY6AvXGGrgOArcRLMAkWJGBbQrcyMph9/DPeNiotKsEy4BV9DmZbRbZllHV9BzoFCkkwCfbv9GjSHEyCZT1aVX6uDKYMVqVC6dUlmASTYG0I1HolX0Okq17F+F6k5mDOEqWF1xDZPEOkPSiH29GVim4twRpLMDu6cyehJ3dFR3PWVdTL7VhJgjWWYMOARwk+2LmvsSnbVu2oUfKtJVhjCWbfhfycsGtgvWjn1q5GhxJfAwOjn6PxGbaGlMsaJcEaSzDrk+vx+bQ80tjp19Bp3Tx161JGgjWeYHZ8+lLO3pdgOUHlLfa/r4O1crAzZltzQJFgOSCVU6QoghmT8YB9I8pOfPQGfgEfgHfA/fgUiP23xFflAKx32WYbIuvNR/erkoAEqxKgqqcTkGAyxJWABHPFq+ASTA64EpBgrngVXILJAVcCEswVr4JLMDngSkCCueJVcAkmB1wJSDBXvAouweSAKwEJ5opXwSWYHHAlIMFc8Sq4BJMDrgQkmCteBZdgcsCVgARzxavgEkwOuBKQYK54FVyCyQFXAhLMFa+C/wVRVztUleCmzgAAAABJRU5ErkJggg=="/></switch></g></g></g><g data-cell-id="uDJ2bVtIrgoZBCZFZmDG-9"><g><path d="M 570 373 L 550 373 L 580 373 L 564.87 373" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 561.12 373 L 566.12 370.5 L 564.87 373 L 566.12 375.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g></g><g data-cell-id="uDJ2bVtIrgoZBCZFZmDG-8"><g><rect x="570" y="366.5" width="40" height="13" rx="1.95" ry="1.95" fill="#ffffff" stroke="#000000" pointer-events="all" style="fill: rgb(255, 255, 255); stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 373px; margin-left: 571px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; word-wrap: normal; ">init</div></div></div></foreignObject><image x="571" y="366.5" width="38" height="17" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJgAAABECAYAAAB9Pvx1AAAAAXNSR0IArs4c6QAABCZJREFUeF7tnFmoTVEYx3/3wRTiRaYi05Mk4kFE8UYKGZJIhkylDK8iPFJCIWMSUQpRSiHyJFEeCIlCkVmEhP1p37qd1h7O8J17jv3fdbt1z1rfXv3Wb39r7bXWuS3oEgFHAi2OsRVaBJBgksCVgARzxavgEkwOuBKQYK54FVyCyQFXAhLMFa+CSzA54Eqg2QQ7ASwIEPkE9HQlVX7wF0D/QLXzwIzywzVnDQnm128SDJpuoVUZzO+BcImsDOaC9V/QajJYF+AN0K1N82YC5/ya6xO52QTbDcxKmIMN90FUcdTbQN9A7cuRfMsyos4BzpSUkWAVd4UqlhI4G3iQJJg8qQmB7vHw2FkZrCY8FaSEwELgeICKMphUqQmBi8A0CVYTlmUHqWSZYiewPnCna8Dkkr+PAxYDE4ABQAfgLfAQsMn5IeBjzlbnfYtcCezLGbO02KCovc8qrFuXas32FlmJYJsjklsCNO8Bo+K/94jlmZ1B/X00P1oNnM7ROxKsIAutG6L1pB0BIZ4CQ+ItphvAiBzSWJE/wBLgWEZ5CVYQwdYAewMy2NDXC7gATM8pV2uxb8BI4ElKPQlWEMFWAPsDIvwAFuUc7kIeHQGW1kCw0cDUOE4/YFVCzJPAg5LP9gC20d+wVxHmYLZqfjChBywDDQW+AtuAU8DLSMg+wPx47tY1oa5lMcuA9jt05c1gbeuOid4gbQcgdGmZog6PUSWT/DTBrMlfgEnA3UD7pwBXUjL9ROCmBEvu+aJnMCOzPH6DTKIU2rZpLbsWsGFKGSwBQtEFex6tmg8Gfqdk37kp87TtwCYJpgyWNAezRdiNGUO7zdEeJ5Sx7GVZTBlMGSxIYF7gWExpwY6AvXGGrgOArcRLMAkWJGBbQrcyMph9/DPeNiotKsEy4BV9DmZbRbZllHV9BzoFCkkwCfbv9GjSHEyCZT1aVX6uDKYMVqVC6dUlmASTYG0I1HolX0Okq17F+F6k5mDOEqWF1xDZPEOkPSiH29GVim4twRpLMDu6cyehJ3dFR3PWVdTL7VhJgjWWYMOARwk+2LmvsSnbVu2oUfKtJVhjCWbfhfycsGtgvWjn1q5GhxJfAwOjn6PxGbaGlMsaJcEaSzDrk+vx+bQ80tjp19Bp3Tx161JGgjWeYHZ8+lLO3pdgOUHlLfa/r4O1crAzZltzQJFgOSCVU6QoghmT8YB9I8pOfPQGfgEfgHfA/fgUiP23xFflAKx32WYbIuvNR/erkoAEqxKgqqcTkGAyxJWABHPFq+ASTA64EpBgrngVXILJAVcCEswVr4JLMDngSkCCueJVcAkmB1wJSDBXvAouweSAKwEJ5opXwSWYHHAlIMFc8Sq4BJMDrgQkmCteBZdgcsCVgARzxavgEkwOuBKQYK54FVyCyQFXAhLMFa+C/wVRVztUleCmzgAAAABJRU5ErkJggg=="/></switch></g></g></g><g data-cell-id="uDJ2bVtIrgoZBCZFZmDG-11"><g><path d="M 40 209 L 60 209 L 29.5 209 L 44.63 209" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 48.38 209 L 43.38 211.5 L 44.63 209 L 43.38 206.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g></g><g data-cell-id="uDJ2bVtIrgoZBCZFZmDG-10"><g><rect x="0" y="203" width="40" height="12" rx="1.8" ry="1.8" fill="#ffffff" stroke="#000000" pointer-events="all" style="fill: rgb(255, 255, 255); stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 209px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; word-wrap: normal; ">init</div></div></div></foreignObject><image x="1" y="202.5" width="38" height="17" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJgAAABECAYAAAB9Pvx1AAAAAXNSR0IArs4c6QAABCZJREFUeF7tnFmoTVEYx3/3wRTiRaYi05Mk4kFE8UYKGZJIhkylDK8iPFJCIWMSUQpRSiHyJFEeCIlCkVmEhP1p37qd1h7O8J17jv3fdbt1z1rfXv3Wb39r7bXWuS3oEgFHAi2OsRVaBJBgksCVgARzxavgEkwOuBKQYK54FVyCyQFXAhLMFa+CSzA54Eqg2QQ7ASwIEPkE9HQlVX7wF0D/QLXzwIzywzVnDQnm128SDJpuoVUZzO+BcImsDOaC9V/QajJYF+AN0K1N82YC5/ya6xO52QTbDcxKmIMN90FUcdTbQN9A7cuRfMsyos4BzpSUkWAVd4UqlhI4G3iQJJg8qQmB7vHw2FkZrCY8FaSEwELgeICKMphUqQmBi8A0CVYTlmUHqWSZYiewPnCna8Dkkr+PAxYDE4ABQAfgLfAQsMn5IeBjzlbnfYtcCezLGbO02KCovc8qrFuXas32FlmJYJsjklsCNO8Bo+K/94jlmZ1B/X00P1oNnM7ROxKsIAutG6L1pB0BIZ4CQ+ItphvAiBzSWJE/wBLgWEZ5CVYQwdYAewMy2NDXC7gATM8pV2uxb8BI4ElKPQlWEMFWAPsDIvwAFuUc7kIeHQGW1kCw0cDUOE4/YFVCzJPAg5LP9gC20d+wVxHmYLZqfjChBywDDQW+AtuAU8DLSMg+wPx47tY1oa5lMcuA9jt05c1gbeuOid4gbQcgdGmZog6PUSWT/DTBrMlfgEnA3UD7pwBXUjL9ROCmBEvu+aJnMCOzPH6DTKIU2rZpLbsWsGFKGSwBQtEFex6tmg8Gfqdk37kp87TtwCYJpgyWNAezRdiNGUO7zdEeJ5Sx7GVZTBlMGSxIYF7gWExpwY6AvXGGrgOArcRLMAkWJGBbQrcyMph9/DPeNiotKsEy4BV9DmZbRbZllHV9BzoFCkkwCfbv9GjSHEyCZT1aVX6uDKYMVqVC6dUlmASTYG0I1HolX0Okq17F+F6k5mDOEqWF1xDZPEOkPSiH29GVim4twRpLMDu6cyehJ3dFR3PWVdTL7VhJgjWWYMOARwk+2LmvsSnbVu2oUfKtJVhjCWbfhfycsGtgvWjn1q5GhxJfAwOjn6PxGbaGlMsaJcEaSzDrk+vx+bQ80tjp19Bp3Tx161JGgjWeYHZ8+lLO3pdgOUHlLfa/r4O1crAzZltzQJFgOSCVU6QoghmT8YB9I8pOfPQGfgEfgHfA/fgUiP23xFflAKx32WYbIuvNR/erkoAEqxKgqqcTkGAyxJWABHPFq+ASTA64EpBgrngVXILJAVcCEswVr4JLMDngSkCCueJVcAkmB1wJSDBXvAouweSAKwEJ5opXwSWYHHAlIMFc8Sq4BJMDrgQkmCteBZdgcsCVgARzxavgEkwOuBKQYK54FVyCyQFXAhLMFa+C/wVRVztUleCmzgAAAABJRU5ErkJggg=="/></switch></g></g></g><g data-cell-id="uDJ2bVtIrgoZBCZFZmDG-12"><g><rect x="240" y="189" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all" style="fill: rgb(230, 230, 230); stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 209px; margin-left: 241px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>Dashboard UI</b><div><i>grafana</i></div></div></div></div></foreignObject><image x="241" y="195" width="128" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="uDJ2bVtIrgoZBCZFZmDG-17"><g><path d="M 230 455 L 250 455 L 220 455 L 235.13 455" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 238.88 455 L 233.88 457.5 L 235.13 455 L 233.88 452.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g></g><g data-cell-id="uDJ2bVtIrgoZBCZFZmDG-18"><g><path d="M 230 455 L 250 455 L 220 455 L 238.13 455" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 238.88 455 L 237.88 455.5 L 238.13 455 L 237.88 454.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g></g><g data-cell-id="uDJ2bVtIrgoZBCZFZmDG-14"><g><rect x="190" y="448.5" width="40" height="13" rx="1.95" ry="1.95" fill="#ffffff" stroke="#000000" pointer-events="all" style="fill: rgb(255, 255, 255); stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 455px; margin-left: 191px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; word-wrap: normal; ">init</div></div></div></foreignObject><image x="191" y="448.5" width="38" height="17" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJgAAABECAYAAAB9Pvx1AAAAAXNSR0IArs4c6QAABCZJREFUeF7tnFmoTVEYx3/3wRTiRaYi05Mk4kFE8UYKGZJIhkylDK8iPFJCIWMSUQpRSiHyJFEeCIlCkVmEhP1p37qd1h7O8J17jv3fdbt1z1rfXv3Wb39r7bXWuS3oEgFHAi2OsRVaBJBgksCVgARzxavgEkwOuBKQYK54FVyCyQFXAhLMFa+CSzA54Eqg2QQ7ASwIEPkE9HQlVX7wF0D/QLXzwIzywzVnDQnm128SDJpuoVUZzO+BcImsDOaC9V/QajJYF+AN0K1N82YC5/ya6xO52QTbDcxKmIMN90FUcdTbQN9A7cuRfMsyos4BzpSUkWAVd4UqlhI4G3iQJJg8qQmB7vHw2FkZrCY8FaSEwELgeICKMphUqQmBi8A0CVYTlmUHqWSZYiewPnCna8Dkkr+PAxYDE4ABQAfgLfAQsMn5IeBjzlbnfYtcCezLGbO02KCovc8qrFuXas32FlmJYJsjklsCNO8Bo+K/94jlmZ1B/X00P1oNnM7ROxKsIAutG6L1pB0BIZ4CQ+ItphvAiBzSWJE/wBLgWEZ5CVYQwdYAewMy2NDXC7gATM8pV2uxb8BI4ElKPQlWEMFWAPsDIvwAFuUc7kIeHQGW1kCw0cDUOE4/YFVCzJPAg5LP9gC20d+wVxHmYLZqfjChBywDDQW+AtuAU8DLSMg+wPx47tY1oa5lMcuA9jt05c1gbeuOid4gbQcgdGmZog6PUSWT/DTBrMlfgEnA3UD7pwBXUjL9ROCmBEvu+aJnMCOzPH6DTKIU2rZpLbsWsGFKGSwBQtEFex6tmg8Gfqdk37kp87TtwCYJpgyWNAezRdiNGUO7zdEeJ5Sx7GVZTBlMGSxIYF7gWExpwY6AvXGGrgOArcRLMAkWJGBbQrcyMph9/DPeNiotKsEy4BV9DmZbRbZllHV9BzoFCkkwCfbv9GjSHEyCZT1aVX6uDKYMVqVC6dUlmASTYG0I1HolX0Okq17F+F6k5mDOEqWF1xDZPEOkPSiH29GVim4twRpLMDu6cyehJ3dFR3PWVdTL7VhJgjWWYMOARwk+2LmvsSnbVu2oUfKtJVhjCWbfhfycsGtgvWjn1q5GhxJfAwOjn6PxGbaGlMsaJcEaSzDrk+vx+bQ80tjp19Bp3Tx161JGgjWeYHZ8+lLO3pdgOUHlLfa/r4O1crAzZltzQJFgOSCVU6QoghmT8YB9I8pOfPQGfgEfgHfA/fgUiP23xFflAKx32WYbIuvNR/erkoAEqxKgqqcTkGAyxJWABHPFq+ASTA64EpBgrngVXILJAVcCEswVr4JLMDngSkCCueJVcAkmB1wJSDBXvAouweSAKwEJ5opXwSWYHHAlIMFc8Sq4BJMDrgQkmCteBZdgcsCVgARzxavgEkwOuBKQYK54FVyCyQFXAhLMFa+C/wVRVztUleCmzgAAAABJRU5ErkJggg=="/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-104"><g><rect x="240" y="435" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all" style="fill: rgb(230, 230, 230); stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 455px; margin-left: 241px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>Auth Service</b><br /><i>keycloak</i></div></div></div></foreignObject><image x="241" y="441" width="128" height="32" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-120"><g><rect x="49.5" y="189" width="130" height="40" rx="6" ry="6" fill="#e6e6e6" stroke="#000000" pointer-events="all" style="fill: rgb(230, 230, 230); stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 209px; margin-left: 51px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>Storage Service</b><div><i>seaweedfs</i></div></div></div></div></foreignObject><image x="51" y="195" width="128" height="32" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAACACAYAAAB9V9ELAAAAAXNSR0IArs4c6QAAIABJREFUeF7t3QW4dU1VB/Bld3cnNhZ2K9iBXdjdKKIYYCuKYic2dqFiYhcWWGCLYisqFnafn+zxGeeb2XHuuefe9+61nud94Ltn9uyZ/8ye+c+qeZxISQQSgUQgEUgEEoHdIfA4u+txdjgRSAQSgUQgEUgEIglAToJEIBFIBBKBRGCHCCQB2OGgZ5cTgUQgEUgEEoEkADkHEoFEIBFIBBKBHSKQBGCHg55dTgQSgUQgEUgEkgDkHEgEEoFEIBFIBHaIQBKAHQ56djkRSAQSgUQgEUgCkHMgEUgEEoFEIBHYIQJJAHY46NnlRCARuPEI/HFEPFunl98ZEW9643ufHVyFQBKAVTBtLvSEEfECEfFCEfE0EfEUEfGkEfGvEfGPEfH3EfF7EfGIiPiLzbXnA4nA9UYg5//Vj08SgKsfg2vfgiQApxsibPttI+ItIuJlI+LxV1b9yIj4voi4f0T83MpnslgicN0QyPl/vUYkCcD1Go9r2ZokABcflqeMiHtGxAdGxBNfsLofjIj3iIg/3FDPvSLiE6ryvxIRL7nh+SyaCFwEgaue/xdp+01+NgnATR7dE/UtCcDFgHzOiPjeiHjRi1Xz/57+q4h4g4h4yMo6f7V5fxKAlcBlsQsjcB3m/4U7cUMrsH48S6dv3z8dMm5ot7NbWxBIArAFrf9f9skjwmb7vMdXMXzyTyLiZSLizxfqfrGDyeHhTZkkAJcwIFnlbRC4DvM/hyURSAQugEASgOPB+/yIeP+Zx/8lIn5i2qA5+nEA5Aj43BHxShFh856Tr4iId18o88kR8VFJAI4fxHzyaASuw/w/uvH5YCKQCETeBnjkJHiyyXvfht6TL4wItvm/nqn/FSPCJi9SoCf/ERHPt+APIIpAmVpSA3DkoOZjqxG4LvN/dYOzYCKQCNwWgdQAHDcr3jwivm3w6DdExNuvrPbpJlv/8wzK3zUiPnfwGxNBz08gCcBK8LPY0Qhch/l/dOPzwUQgEXgsAkkAjpsJH3ZQ599n8OidIuKHN1T7VhHxzU35/46IPz2c7r/mYDr4yOo3PgHPtKHuUvSrI+JdVjzHrnvHg+nitQ6hiS8fEc8YEU8fEU80aTNoNGgdmDZ+JCJ+aUWddZFfjIiX6jzzsVUkw5NExD0iAi7MJbQscido25zwxbAxaTfzyjNM+Rf+MyL+5uD4xCv6Z6eQywdFBIyPETkdvMe/F54crZ7gYA76y8PfHnbon0Qrxu2fq8rlffBcK2/TGfu5Nr1CRLx2RLzGQXvEAc/YwIfjKDPTzx98R777YGL6gcnkdEz/1jxzVfN/qW20Ya8/zeEXnPB56oj4uwmfXz+E6H5PRHzXIWrn0UuVTb9/5uH5D+mU/dHpOyk/vfPhm32vw3i+SER4JxEO/MERcZfBu+4cEQ9c2Q7FPufwHX7QoPybTP0qP58qCsD3aE0z78w/a4Jv63Gn7+oPpvBl8866d+x3pd2XMX4b4N1f0SQAx425zd8i2JM7RISNbq1ImsKW70OSHMg/uQH4DLRyWQRAKJeFxUL3tGsbflgYfmpqO8/iNfJjEfHqnYKfdUiOdLdpk//xw6L40k2ZOQJgwf20iHijNQ2YyvzO5L8h7HKL2PQ/LyKedeEh5M2G8ENTnx6zctEeVYuQfVJEMButkd+PiLvPaKnW1DFX5qrm/6hNtzv88HFTHg4b05L8wzRvzbved1Y/r14EtRXkt8zT+0XEe3bKIAA2TKSjJ1++0SPfGoH4tYLM8Pj/9+qHixIA65I+CXF+5iVAp999V+bdFlLj0cscv5VN32exJADHjftoUVCbj+bLjqt28anLIAAvMZ1an2vx7eMCFkB5EP5toQ4LoRDHVuAFN5qKd+r8PiIAtASecUrZKk4qHCg/deWDCJIT2FqxGEsKxSRj4e7JkrbI9/mJh4X9o9e+tCnHUU+7L3Iq6736quZ/ry3S2n5tRPBL2Co/PWkMaGhGMtJ20ITZuN518uXpPY8A/HJE/NmkjWjLPGrauNeMj7poeHrC56h1SL4IAaBZosnirHyMfOWkDeHHtCSXPX5L79/170kAjht+6nSTvCd/dFCFverMon/cGx/71KkJgA3Ihz5yZtzSVirR121OIe3z/Cacolv5pskEIKdBb072CIBTMVX3421pZKfsO04byFw1VLXffoTJjOpZdkiZHntCG8KcMpLRyXJLl/mQ8CU5pVzV/G/78A4TAVxz6h/136b6ajOaAMS254dj836OSWP37IPKbdoPPZjtvujw7b7PoAytDtPUknxKYw6sy9uof6ap4FgCQGPx4MM38fxLDVr4/QER8ZYL5PMc43fBbtzsx5MAHDe+nPao6kfCJvvxE0mweZ1K2BOLLdzHw87ZCpLwBc0fnULZPWthX/+FBZU/NSe7NhU2tbdNt9g3e3367IG9tJTlIGlDbIVmwIL13gOgWgLAJ+F3B5edqIJp4lsOWgX5FNje33BajHrVs52zPVIL94R24TcHqtdSXh3MG3wN4AonfgEEqRmFfL7KtNj23ksTQrvREydK2ggn2H+a2q+8fvaE/ZY54lRyVfO/bj//C5trj7wKwf3iiXj5Fm1qbOSybJZxqetigqPq7ok5qa5WzEn1mdMjKQQAwWDa6sm9O6G8vXK/MYgY8h30NutjCID9wLfIj6InNBXIQSHq/Hlebqb/zAH3Hfx+rvE71Zy/kfUkATh+WNmPnaDnxCLBWY5zzE9Om+katdiaVnG66S34a6MAfMgjFd+vTU6DFthabLwfs7Bg0X7YgHvy9RHxdp0f3IFgQeCLQH572txsyhyObKockIpYeL908A4OeD0zAnW/hb4nTmdfMvgN6WIrHgkVvVTM9bjKi29jgMWcjE5/SJZ00D3HQSpljpq9ENMPPRDEz+i80CaBLHKIPJVc9fynOenhS+uCgPX8cBAuWqPWZMRcI5snG3YrHPt6c+O/JtLnXQTRQLKQwaeaNmvPItDWWWYgGoNWbKa3XxgU3wYHxp6Yez0fhWMIgLwjI/Ol+pi0WjMELdZ3DA4GHGGZFjnItnKu8TvVfL+R9SQBOH5YfbQ2SM4ya8Vpzambus4GjBQ4NR4jFyEAr3NwKOMJ3xMLFVY/d0sh7QYi0BMniJFDHlvtyCNaXXwInLi+agGQUd89ZrF0Ym/FONGOuJ2xFer9nmlCOePVOiWW59nYqYh7YvO2WI7yPHhmRABGdmebjnk32gzUOfKzQBalrT6VXOX8H4XA6tscmfP7CNtPP2hTPrwDzhzZrOeB0+6cQ6H6lemJCBaOvyOZI69uHe0Rl60EwF5gXvXmK+Iousa30JO3Pnx3zHg9sVbwGanlnON3qvl+I+tJAnCxYbVpOOltIQH1Gy3oTio2NB9Qb+MatfAiBMApiFp49DFTn8+J/v7WdDJvy1ETUkn2TCRLBMCJaXSyr9/D/NELC7RQzT0/6jeNQ8+cMqfqpp3gkT1H4N54wSN6RAAs6D21rhPmaNwKPn7Xz1aMqYX6lHJV898Y25hbYaqi7mcCGIl547ROm1ULs4oTeqslWSIAtFpzpLa8A4kcbaC0THMOpvJ92DRbQTBtzD3ZSgBG80bd1qae6a5+72jO0oBwNK7lnON3yvl+4+pKAnDxIfVhy+jXTvJjarZwY8xsu0tyLAGg/vzbAWmhqhNOtEZV3EtDXNpMlQiTVuYIANMFm+Iaj+glbEa/j95PnS4pUytzJxu5G8Txz4nvi1Mok0BPegQA/sIIe0LrwuQwJ26k5NXe2rqpxmk/To3vVcx/hI0HfivMbcwjSzJSP+tLm9tijgA48SOJyMMaQfB7RHOu3UjJ6HZQER7CUnuylQDMhXYierRkc4IE9cJUHXKYpuoQxXOO35px2W2ZJACnGXo48nj9gMkueRFcLdCSj0gAVH80bUuPJQAWyJFD2NcdEv04Xa+R15z8G3plqfCFR7UyRwDmHIbWtGdNGe0Sn9+Khbx3lbPY+1EI3vsOnMPausV6v9ugcT0CYB6NNDDmlzFaEmSqFy/O2XHOeXWp3tHv55z/QtR6NmVt+8aIMC5Lwkm2l62zR1znCIBvkJZnrbDVt+pwz/If4euCmLcyikLwDGI5MtVtJQBzPkHaRmtyCjn3+J2izTe2jotsVDcWlAt2TEjQ600nEQ4yvSs517xiaTM+lgBI9oNg9IStkVfyGpEcZHTyEdbUOw3MEYDiMb3m3XUZC4qT+CtPWhiLFSesLWaZEQGYay8i5eS2JHN49wjAR2wYg6V3t79z4hKedZly2fOfM2gb8naq/jhNt5n25ggAf4Ke0+WoPez1TGc94RyLwLRijiHbrfDnGEV9KLuVAIyyVSIlPb+ZYzE/9/gd285dPJcE4PKHmYOPhd4Gx+uemvvxV752ziZ+LAGYO9XynudFv0bEXo9MBSOb+tyGKgJglDGv1x5OdswQnAa3bPa9ukYEQOjkyKFx5GzY1t9L9VzK9AiArIY9Z7Q1Y7JUhgahDRFdeuaiv596/gtRO6UzY92/b51SUNd/myMAbfrdNVhxHJYttJXeHSKycso30FsvaDDmQhC3EAD1j7SNbPuIy6nk3ON3qnbfyHqSAJx/WGUsoxlwGmM3a52R6haxBQuB632cxxKAuaQka2x9dfuEOfbisKkLncRbGREA6sxefPZodNyHIK66Z089ZkRHBGCUutg7qNjZ95dkbsHrEQAhZ4jfZcgWDc9lvF+dF53/Tsoc7y5D+OBIZlXLHAGYy+Mwat8oVNNJ2zdTh5MyV/UiYjig+gZEFY1kCwHw3pEpYW1Y8drxOPf4rW3XLsslAbjaYZdcx4I/l8ee+s9G1MqxBEDa0JGddCsBEOfbs51bTHqXFo0IAPUjtf0aMWepgEfez+qggXBysVDWC6oN14m0lREBGDmLeZ5zlkV2SYxtm4SpPNMjAHPjs/Supd9pF5gYroscM//nHDMv2i/5KOp8E+qbIwA9p8GlNrDbc+rrZS9szUri62WhbOX+A1+WutwWAjDnePrwg9noxZc6teH3c4/fhqbtr2gSgKsfcwuBy3RG4V0jz+9jCcCpTABS8I6SGsla5pKeVkYEgIf6XIbBuh6qz5EjnEXPAjOyEW91AhzF1GsP7QOisST8E3q2Xc/1CMBcytetBG2pbdfh963zfy6HxWWkPZ4jAMx5EjNtlZFmqc6kWW557N1zAYOli6y2EAAkvr69su7PKNPg1j6X8ucev2PbuYvnkgCcbpip8pduFhu9zfWucun3hM2W7baVYwnAXGa7LSpiGb7cOtcTmQB7WdpOQQDmkgDJyjbCUTtHJ6qRBsDGPQr1k95VIqclYc938u5JjwDMXbVLJez0dx3lXPN/7lIc93OMIi6OxewyCMAovXBtb3dJTi/0bpSvoO3fFgLg2ZE2b81V3FuwPff4bWnb7somAdg+5LycnW45gflX/r/TIE/0Y2Qu1rfclHcqAjAXvrc2qYm28EC2GfdkRFpOQQBoC0rK4PrdI7NDXYY9s6fOHBGAuexta299HN1wqF09AsCxzAVNPellVTtmvl3kmaue/0xFki/11i5+Icj0KeUyCADnPlkpe34vJVRTHo1eKK0IHn4ES7KVAIy+De8x5u7VOIWce/xO0eYbW0cSgG1Dy1uWV64PuCfsh+yIWwVxGOXPl/ill3b3WA0AdR+Ho57zofhq4X2SdyyJTf79BoV4vvOobuWiBIA6dOT4RBVLJTuSuax+IwIwdyGPvrhJcE58X05sPX8Iz/UIgEx25lhP3CrYu055aaxO9ft1mf+ji3GQQw5tc/kztmJxGQRAG0bfr2/K5UOjebPW72ArAZjzPeGsvOR4KQWz1Ng9ceqvEyydc/y2jveuyicB2D7ccyc6E9tmvjW/v6xyNs2ejNS+owXEh9+7dKSu20YiV0FP1sSKY/Fsg73sedKwcnTqXVZzUQIgHrlXr37wyO8lvyl9nCMsNoxeKKFb/DhB9QSJYgaZu0uezd4VyCMZpQIWK94LvXJXAse5R8/UyZdC2lYakfpfL8nM9tn/2BsKe5ctqetc838uUmJNaJ7rjKm8Ed6CkciVHvG9LAJgU/U9tEL7g/S3F3EpJ1e/S4vWyFYCMJeAak3CI+2GfSu+D6TM3C1yzvFbg9VuyyQB2D70S4ks2PGoh0fXf9ZvtFizD4/CvmxMTuS9Te+BgyxkYvOdIkcbpffPZQN8xHQZ0ByJmctuN3dBzkUJAIcxmPQ8qC3eQiZ7oXlCu8SOz90bL69A70rgUY5zOM6pY5Eki/jcveojAiArIvNDT4RxjjQvystcyNGzFRsdfEbOXmu/hOsw/+cuk6HKdplVveHUfRtp28wffZN3v5bLIgDCIY1JG0ZrwzSvehkDt/jobCUAzBF8ehDMVmQnZVoRFdMT40Hz2fu+EEaEq5Zzjt/aeb3LckkAjht2p7rR7XGlRpdg8O533Sd1HtW1U6aNQSiaxYY6t3epTamjlxyk/MYTvpfO1O9Ou1KIzuV9Z3IY+SxYBJ1Q2lvGnMAtTu0HXdqkj/wiRrnLL0oAvAeeo1MQr31OexyXCDMHciVbWznhw6Q3713t7NrmVly3eq+ZaWKh5rlfq52ZG6hM25CytpoRAYAzImOT6AmTkCRI7YmV9sZ7e9qM0bWxx3wB12H+z6Wu5expjjIJ1GJuivVn026FQyfHzlYuiwB4z8jJlIan1a6Zt+aV2zrXyFYCoM45h1VkxfxqTZXmMHNfjzg4jLgjxfXirZxr/NZgtdsySQCOG3onbIzXieqyhErSRjdK0EFNeM+Zl1Ndu32MzV9720tStN3vI38GHy8tBrWuxQdp4WXfi/svzXCPwFyu+lMQgDnHPO3gXGVstJO9tE5IJHTKptkme/GchdVGT3Ni80XgiIUYEZpLh0qVbANxerNISxAjTJK4AGZ0JfCIAHiOFul+M+NLUyO/gP4aX1EXTr490X4L8UVP/6Xu6zD/XUfsNrzRfLSJIgJwQrKV57haxqXGibbAXOltVJdJAOYcPttxdPqWQGytHEMAaAHM47kcGzZuWhbrA8zmHJ9dMHSPQYPPNX5r8dpluSQAxw+7zdkJv3eaOL7Wxz5p8XLJyFzO87nQwfb9nMqYElpx6mW762Xz29oHp+DRxTmlrlMQAP4NNrS5DIq9tiNUUrDaWOeIk2dbb3sq92NS6CJvTlW9bG7eM0cA/O40L3PaRYTt31yxaJ9Srnr+6wvtDnvyRQS5FTo4GqPLJAA0NQjcmlz7a6/KLlgcQwA8i8C6jbS3XmzBmXaDFnHOofgc47elzbsrmwTgYkPudMnGJd3rqcTplePf6NKQ+j3Kjk59dbkRAVCG5zwSsOQ4OOofD3qZBcVgL8kpCIB3LJ2O23bYBDk9wosa2Elvbu73wu0kmWFWWSvMEOaFxX0U1rdEANhUJYfZ8t66fTQZ1LatXXttH5bKXfX81z6bjJC5Y+6D4LBq7o42f/VfJgFQvzBftxDOiW/MhrzFkfNYAqAdnGmZ0zjBHiPWApv7KFFYXedlj98x7d/NM0kATjPUVHOu76VmX3vRT/1mLBnrtsmMroLttZQan1p7ztHMc3MEwO+cEd1ad9cNKXl93NT9bNGtr8AI1VMRAPWz8TqVL2kv4Kps3cZPnVFNqrtHAHwrd5s8tHvZ2eo+81PgKS/0aZTQRfm1YaO0QUw+1PhrhErbxsJXYC5iYE1da8pc1fwvbaNO5vjY80IftV8kDO2MsZqTyyYAzGo935O6TW5wROS2yEUIgPfwP5E0TM6BNRoKz4hSkLRsLhlXrw+XOX5bMNtd2SQApx1yGyn7slM5u+/tpg2VDbKk2+Rpzlb8yOkkytZsMRrFfi+1kPc6FfWbTadbGyLnJ178FgFX80o9+qCliqYEO1ISIzL6wNbLBu4kaiPxT3t94OrbmhzklARAd5xAnTSkF3Wyh7/Nz8lXvzlRcvrqCS2LZy0+BTNaF1g5UbId94SmhK+DTRkB0wYnNO900uYgxzZfVJ9ztwF699IGVNrgW+Wkpq/+V6ilq5CREXOKKpnfh+tjbRgj35EV0+DoIlcx/+vGSsrFsdamKqEOfDjdck7l22GDQgg5rfHNWCOXTQB8W77TuWvDj0kBfVECULCRdIv2jLlQPL/5bk3gS2GNEQ7sWzPnfTtzjsdLeF/G+C29c9e/JwHY9fBn58+AwJyd06Jv405JBBKBRODsCCQBODvk+cKdIXDfyXTQdlvYIDXrKbPW7Qza7G4ikAhcBIEkABdBL5/dEwJUtVL6MgH45/9LyrOk8qSW7zlTjS5M2hOm2ddEIBG4QgSSAFwh+PnqWwIBzp3U+Gzu7eUt4splGBwJ2yn/jp5IIMTZMCURSAQSgStBIAnAlcCeL72FEJBZUExzTzjacZosSYPqMnIOIAccKVuRkEdipbT/30ITIZuaCNw0BJIA3LQRzf6cGgFhnbzHRXT0REY0cf6y0skIKLOirHxvNHP3gDBEmoWURCARSASuDIEkAFcGfb74FkJAulOx2luzD/a6KCyR6WBNkpRbCKJsaiKQCNxqCCQBuNVGLNt7VQiIL5f4SKz7seLaZ3Hljzm2gnwuEUgEEoFTIZAE4FRIZj17QECKVBn5pC/tXSozwkCyn3tPuf33gFP2MRFIBG4BBJIA3AKDlE28dggIAbzzlJHPpTgiBGRk5C9QsjDKJChDGtNBe4XqtetQNigRSAT2h0ASgP2NefY4EUgEEoFEIBGYvREt4UkEEoFEIBFIBBKBG4pAagBu6MBmtxKBRCARSAQSgTkEkgDk/EgEEoFEIBFIBHaIQBKAHQ56djkRSAQSgUQgEUgCkHMgEUgEEoFEIBHYIQJJAHY46NnlRCARSAQSgUQgCUDOgUQgEUgEEoFEYIcIJAHY4aBnlxOBRCARSAQSgSQAOQcSgUQgEUgEEoEdIpAEYIeDnl1OBBKBRCARSASSAOQcSAQSgURgGYH7RcR7VsW+MiLebeExd0O8Q0S8aUS8ZEQ8fUQ8YUT8Q0T84uGOiDstvzZLJAKXh0ASgMvDNmtOBBKBm4PAQyPiDlV3PigiPm+me88dEQ+MiNsPyvxERLz6zYEne3IrIpAE4FYctWxzIpAInBOBJ4iIxxyudH6i6qWvEhEPHjTiqSLiFyLi+WYa+TkR8cHn7ES+KxFoEUgCkHMiEUgEEoF5BKjvf6kq8l8RYZOnyu/JJ0XERzc//MzBDPAdEfFnE5H4lYh4SAKfCFwlAkkArhL9fHcikAjcCgiw9X951dDfiogXGjT8cSPijyPiWarfvzEi3u5W6Gi2cV8IJAHY13hnbxOBRGA7Ap8fEe+/ckN/mc7J/gUi4ne2vzafSAQuF4EkAJeLb9aeCCQCtz4CPx0Rr1h148Mj4tMH3bprRHx29dtvRMSL3PoQZA9uIgJJAG7iqGafEoFE4FQIUOn//WHDf7KqwteOiB8avOBrptC/8vOXRsR7naoxWU8icEoEkgCcEs2sKxFIBG4aAk7vv9Z0Sjz/owcd/fWIeOHqt/do/AduGj7Zn1sYgSQAt/DgXeOmi5e+85T8xGL4tBHx5BHx35Pn9B9GxK9GxPdPsdIjb+qlLj5vRLz94TQmJOtFD3HZTxcR5vTfTI5YP3dQ3T4oIr43InhuHytPEhGvO/17sYjw3qeMCH/X9r+YErt836Ed3xIR/7Twooc18eFvc1ATf/OKxglHe2REPFtVlm2ZjXmNcET7+qrgT0XEq848eC58NeEVDhvtW02qduFzTxMR/zKN5SMO2POi//YpvG5NX3tlJOZ5k4h4o4h4+Yh45mkcjRdcxeZ/WUQYnyJ3iYivrf7b3H2u6r/bBEFr2qZ/v9cUfOqpXa85zeXnjIinmOaY9v31wZGQ86E5/YBDcqFfXvOiLJMIzCGQBCDnxykRsEl+2mGhfokNlTpJfWxEfMGGZyygbLAyrK2ZwxbbD5nIxobXBPWv5+5xaN8zrHzwrw6bFjtwvdG2j1If37H6owxzNp4lkVWOirkW5OOZlh6cfv/5iHjZqqyN8Hs6z54LX69+rcNGd9+JLK7phk36fSPCSXuLvPEhEx9nPhvrnCCKnxsRHxYR/xER95n+f3lGKN+bVRW0CYKW2vS3E7kp5RCde05OhnWegaV6ENv3jog/WCqYvycCIwTWLJ6JXiKwBoFPiIh7rSk4KPOFjaf1qCohWcjCEx/xLqSBA9caedKJMNQb9ZrnShlx4J8yeOAbIuJtq9/udogr/6wVlUsf+1JNuX9dicUrH1LPOvEXefjhJPninXeeC1/aDH2uvetXQPC/Rf45It7xoEX5tpUP9OLylx5FyBAz2qPXrwojq+Y66SUIWqr3RyryR3Oj/rmEQXP1IZuvFhEcDVMSgc0IJAHYDFk+0EHg3Tsn2N+OiK+aVLfUptSYTjvUrq8zLeC1Klu1VNRipkfy8QdV/sc0PzpR3f+wEFpYveffphhsaVY5Xz1jU/5DD2rfz1wxik56zBi1PGpS1Uvg8ueTSYM6+JWm/tgQaqHO/bHOu5wwP7D6+8cdNBn6NidOyj88FYAlglIEGUIE5sRm+eZVAartVktxLnyddL/rkEmPM10tzBlfN2XYgy+V/fNMG/A7NZn49BcmPPTnBBFDAGr5u4MZhXPeD0bEHx02dJoem/BbHML14PJ4U+HXm+b1s1cP0yR89/Tfnqvnl3Flxihi/n9k827kxfuNH0L3gtXv/37wH/imSStDw0E75h2+GeWYu2jZ/K2Icojcfy7gkD8nArdBIAlAToqLImCR/pPOQuhUO7co8aq22VNDF5kLmfqATu51yVm8h5d2T2RrY5OvNxp25eef2jzqO5t8S0TkdUdQRvZ9G8iPHhy+nqOq1H/bpFqhKSmnSL9Rgd99YSBsOm84lXE65VxWhAmAKWAkNlGba9nY2Ltv14zPOfH91mmzLe1F2qjcaXZGc4YvCR+L2v4umx6NCN+SntB6/HgRry4/AAAQ20lEQVTVb2X891tGhNNzT/hEICfmjux/rcYFGTDfe8IuX5u/3udARr9kUNZdAtIBF0F4zFO+MXOCACCntQZsrQ/JQtX5894QSAKwtxE/fX+dcp2+i/zu5JS2xunOIqs8570iPQcpiyr7tZvUitAEfOKK7nDWs6jWG/OSKaBdyDmg0Sg4oc1J6zBmM9PHf2weYrv94upvS6Fiss456fle1cmO7/RYxGbOUW4k4tL5JRShdmdyKXJOfNnv63fb/BGbUVhd3aeXnpLs1Cdgz1KjtwIr+fjrDRzBfLmZFL6ljh4B9Nucv0W55a/WAnFs5LTXE0SE+r7IO0+arJlh/L+fWq0GvxAakpREYBMCSQA2wZWFOwi0aVKd7mo16BJo1NK8nZkMeDnzdm7lZyev7fJ3HvMW6bXidF0nbhHWxZu/J1SzTqNUrv6x03I2LOr3uXdK//qnTYFeFjh9ru3X1L61T0D7jtrT3OmUMyA1chHZ52x2PUGApKaFMbGJOUXThBQ5F74cKTlkiggp8n4HJ8YvWjuQk/q9aEI8RmtAe9GKOdhGViBxnAiXxLqILNTqec9wvGMW6AmiUZMyBBjmI40Rc1VNSs3HNtxw1E6E+V2m78U3Q6PDYTElEdiEQBKATXBl4Q4CFiJ3oxdxem7VphcBjh2eyrOIsDtagjmVd/u+9jIXvwvhqzfBi7SxPGuzrTdmf+8RAGrmeiNygq03tbotNk2bRVH5UgE7PdZt56hYa2Hq55lImBiKfNTBln7v6r/PiS+nv/oGPKdjGfZGKvzemHi+dphEXuosfeUZeNBOFRmZY0bj3vppKAc3+PXkXQ8RBl9R/bCUAfD3G3MGkvmdp5iEWUcisBaBJABrkcpyIwSoVFs159qwtjWoOnnXdnQLc63OXlOHE1Nr83X6cjI+pVClt/HZ3t1qNaj0a8/tuXh8XuecBIln5DsgtYmFRkGMfCts/kwD7qYnfCWEwdUk5Vz40qy4CQ9JKjJq99yYcNSjZSrChMSnoxYaDqfien2jYaFpWSvCP1tn0beefEp6dbSEQaQHp72RtNEFzFRMAnJYpCQCZ0EgCcBZYL7xL+Es5ZRdi9OQE9OcbXoJGJuVk1I9T72H89cW6Z3MqXeZHU4pbZw+L25Z41qRGKnOJKc/LX6e4S3v9F88zWunMhqAEjfu9MnjvBXObpwgi8jR8BHVf58T3x42nBe3eq9L5FOflJGKZ2063jo0ihgwDlsSTrW+Cl6BaCAcPaHRqZMqzd0X4Hkn/pa0GWvjwzzENyIlEbhUBJIAXCq8u6lcGNKDG9tu6bwwLScvanwL3BYRxld7UTvBtqF5a+qz+NcboWfY63lezwn1/Z2m1K4Ig3As0Qv+2Xzb78ffau9smwK7cyues8CLoCBOq7LutcLTn4MgoUWgtSg25b+syAWNiBNoK/UlNjZBmoC6z+fEV8hhfSUubGg3torx4ARXpHc1Lz+JOrqElsNzW6R1tKM1EcbaM1cYT+GotXZDqKswwzlB2jj/tYIcIgH+MV0sOZ9u6VeWTQT+D4EkADkZToUARzSbbFE39+rlyS/OW2rVnrNf+0y7aZyqreoZ+QDYlG28wrTqnO7HvFuYV23zruuwEZcMfj1NgW+TWrjcJNee3jnTCe8jvYgIqW7Zx4sgUjQItZwTX86RSNeppecDYG7ZrItIyFSThjVtaP0V+F28xuBBPimtpovWBkmbExEDnFPnTFpMAjQFyMJPrml4lkkE1iKQBGAtUlluDQJOQFSfwszkNh+JU6yTrTC+0aUqnpWtbuStv6Y9ozLSp/aIChWveP+LbvzlvXOhXXXfaAPaNLBvUKXp5eFts699FpgNSia/Xh4BeQxKpAQ1Ow1Gq74+F76tyeMiY9c++9WTR3z5O01K20+pe2tH0jXv5/HvFF9EKCW/gJ60fgnyBNTJg5beh1jICzF3L4M6mNrkkOilb156R/6eCNwGgSQAOSkuAwEqcg5T0rVSgddx2/X7LJQ2KeaDVsxN8fNO6qcWKmK25FrE0jthtXn1qX5pNlxcJEzLyV27WrUs8iDZTi1zoV2tl3qbza++L8BmXqvPvUNbXYJEStra8m6mAhqCYmLoPX9OfMXDy6VwGdJmdmx9BLxTxsk2PHOpLbWGRllx9u09DKWONtWwDbo2QSy9q/zOiVRYrW+HuWkkwkJpqJayP659b5bbKQJJAHY68Gfstg3VCYwTmMxsrdAG2MicbmoRQ91m+BNeeBm3oPkOqHjbE5hMgzaYNrSvBx+Pb+aNIlK+6sPIya0+oXtGuF+JVGijCXoJZWov8jYvAnNBfedBD7dz4it9Ls1KEXjOaYguMj2lWK79IXralaX6RRFwPq3l9jNZ+uosjZ755OmCn6X3jH5HmM1FuQwQPxqUVpaiDI59dz63IwSSAOxosK9BV4WwCWnjnV6Lk7UFtnaw6iXVOeYkt6bbVL1UvrW4X6DnoDWqr822N4pPL89/XpPAps6A6N20J2RUT00g6gQ1tC/y2xcbOM1FfZlNef858W2vId5yhfGa8avLiDypIx16UQJLdTJhuTmwiIgLyYtGZI5ppr7Xwvxee1HRUluYhuTacE9Dq53KFMBL6OXvswgkAcgJchUI9PLOtxfn9DYop8Y1p/GtfWrvdHdqFFo255/QvqO1p48y1JXnOO7VFwCVU7r3igooaY9H8et8KMp9ADVJaDevUfa7c+LbEoBTJ4uqx8LGXd8wOLr1cG6OIE0SLhXhvMqpsiciTFpnv7lwwa1zs5SnIRI5IYdEkTnHxGPfk8/tCIEkADsa7GvW1fZuejZNp+IiTj5tpr65i1gu0r22Lezv7U11c/VzsPvNpoAbEuvMcO3zbZy5JDDs+jzWyw1yTpac/3ppXiWpKU5pJeuc71k7hC8Sdnc3FfbknPjaTG2qRXjM87m4DOEPAfsi0vPeYcOLYAfP2m/FvQ3GqyfmyQ9UPzBbIapbshuubV7tGOoZ0Q71PRpr68lyicD/IpAEICfCVSEgfTDVZhFhWja/WupYd3+XEVBc9BbhTLUU7y8qQFKcIkuX87TvZ49tc/kvJSxqPcflmHeio74vyYPucbg29j6DzjKllDh6z2g/xzMOjkXkTKht721V58KX6ae+5Y6GxSVJW1Ix25Btdkuhda0GQO6J+gbBpbnTzkvlXd5ES9QTvhZ8LoogcfUlP0vv2/J765twjH/Dlvdl2RuOQBKAGz7Al9g9Gw7PaB7L1Pdb1OWaJUlKnZyll82uvcNebLbc9mtFeJXTPI97zzqF9k5mbV72LQTAxu2a2lp4Z3Oym0vgYpOw4RfhKGlTLBn9OEfSeIxSw3JO/Izp4XISrCMHen4VLW7nwtc64+6GOiviEjlp28pkIg8/R0v+FlT7PWlNK8ab+nzN/HSaN0faqBW3Lz508L42lwItFm1WT0RlmC/mutsdhfRtEU600kYXGYWzbqkzy+4YgSQAOx78C3RdQhk27rJQOjUJX1or1L8WwBKm5rnelbYIhjjvIo+ZYt9bD+3ee506qWbrNLGjq2Pbq1lHqXnb90h+hFxI6FJnAHTa5dQ4J3INwKCIKAJJg9ytQFyZW9uy27rqLH5O0japelOcC1srdZ0LX+9jDrHxFXF7oUt81mS541TH6dHdBkQYpnj/3oVQHB7b64Fb81JvXKj+haO2qZuZX5C5kbbCGNZ5I3wH9eVY5V3mCOfHoo0QJeJ649Z0NDdnfAv1tb/IkOialETgKASSABwF2+4f4uRk4SoLMkDYpHlfLy3oFktJWYqd2rMjZ6Z20VTWgivWe5ST3Zy2KLpilkd8EafdNvqg/OZkKXSrFir6B8yMNDuzk6jTvox/ErkUWYoAUK51HrPhuxqXOLVy9pq7q4DJgemB2KRoDopToJOhMVq6IvZc+Gqj/tBK1Kdr+Iq0GOXolwOCo6TrmWsR6ld76de/uXSI70SdCZCGhDNkbYYoz5gvvOllSpTICsksVycr87BDJj5hmT3RPuXr78Cm3oa0lmfb1L/MEzQhS6GtiLI5WjuNqrN1nJ2ZrvlTInBbBJIA5Kw4FgG26XZh5r3ulOIk5ZROje1kTAXrRM6JySUo9YKpDA/40WZHLUvFXj/D9ul+AWYE73GasqE6kdsYy415pW8WZCr30UbDtoxQUMEXUefdp9Oc/0+8Q0y707fYfGRHn4TwcRQrok9+H6mplfPteb70yzM2LzJ3PXB5B22G+PO6vSVp0twG2Y73OfAt70SSWrW33AfCHqm2hey55ZDpQ24IWpE29I0tnk1+TmyUTAG1OMGXdLrmAd8QJIkJq5zKzVsE022WRdpMg3Wdbbpl4ylccHSRD22U+ut5JrRQql++GggKUwUMkBAOoLQkcGjvimiTPy1Akj8nArdFIAlAzopjEXAqcapuM+ptqc/ib0Otc9b3nneydaKvTQZr3+MiGKf5pfBBV9O6Zrb9JizmnAiRhFqjYEO5y6QluOPka1C3ySJuQ7OQS+TSiyF/VHXTX/2sTZk9f05aH4JSlpOcDa2QljU4nQNf7YCt5Eq1KWBN+0oZPg+c7pY87IVQCpkbhe713iligvlA1sc6AqTNNFg/i4jUxG+N6YhfikyBhext6X8pi8ggKUsanmPqzmd2hEASgB0N9iV0lTqXFkDYWn2qWXqVzdNG4KS25NVd6pIZjd/Bkm29lJdmWIpWqt2lDaM8QzthcV3qi5OaTaw4hlGl+/8lN3/dfxqKcmlPi4t6Wm3FGv8B9Ygy6KmanbD1e6ucA9/SJhsnbUC55niprUL5aGO2RIBQ57t0CsGcE0SNOQGxYM6hiapDFJGCOoSxrsvmX2sj5rQF9XPMYJ7dGi1gboiWmYvsWMIyf08E/g+BJAA5GU6BgFMuL3YnYfnvnUCpQp3YqVvZSZkHLGDCpKiu/W2rmK9iyqm/eURTqTpdW8Sd8OW/tykyGVi0l/wReu9XHydH72C3RgacptlrHzJpPZzgvLMW+ff5EcDAxmYzQUKod+vMdPUzNrT2hjknO+rdJendQAdT2I8iB5bqPAe+pQ1MQ2zvIkE4MDITwRpubPY2YpohYY1LGqK5fgkdlVXRfJH8iMmFRoefgHHkxS+Mskh7k2DPObWU1a5ayyAvA7+QtSI/AQ0aNT+fGFommgFaJ2NJQ8ZkQLMAhyVfgbXvzXKJwP8ikAQgJ0IikAgkAolAIrBDBJIA7HDQs8uJQCKQCCQCiUASgJwDiUAikAgkAonADhFIArDDQc8uJwKJQCKQCCQCSQByDiQCiUAikAgkAjtEIAnADgc9u5wIJAKJQCKQCCQByDmQCCQCiUAikAjsEIEkADsc9OxyIpAIJAKJQCKQBCDnQCKQCCQCiUAisEMEkgDscNCzy4lAIpAIJAKJQBKAnAOJQCKQCCQCicAOEUgCsMNBzy4nAolAIpAIJAJJAHIOJAKJQCKQCCQCO0QgCcAOBz27nAgkAolAIpAIJAHIOZAIJAKJQCKQCOwQgSQAOxz07HIikAgkAolAIpAEIOdAIpAIJAKJQCKwQwSSAOxw0LPLiUAikAgkAolAEoCcA4lAIpAIJAKJwA4RSAKww0HPLicCiUAikAgkAkkAcg4kAolAIpAIJAI7RCAJwA4HPbucCCQCiUAikAgkAcg5kAgkAolAIpAI7BCBJAA7HPTsciKQCCQCiUAikAQg50AikAgkAolAIrBDBJIA7HDQs8uJQCKQCCQCiUASgJwDiUAikAgkAonADhFIArDDQc8uJwKJQCKQCCQC/wPLH9oIOYaqjgAAAABJRU5ErkJggg=="/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-105"><g><rect x="430" y="107" width="130" height="40" rx="6" ry="6" fill="#ffffff" stroke="#000000" pointer-events="all" style="fill: rgb(255, 255, 255); stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 127px; margin-left: 431px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; word-wrap: normal; ">Search Service</div></div></div></foreignObject><image x="431" y="120.5" width="128" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="FWEJ_FGA9GBXbfwohBE8-108"><g><rect x="430" y="353" width="130" height="40" rx="6" ry="6" fill="#ffffff" stroke="#000000" pointer-events="all" style="fill: rgb(255, 255, 255); stroke: rgb(0, 0, 0);"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 373px; margin-left: 431px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "><b>Dashboard Service</b></div></div></div></foreignObject><image x="431" y="366.5" width="128" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="uDJ2bVtIrgoZBCZFZmDG-21"><g><rect x="452.5" y="588.61" width="85" height="20" fill="none" stroke="none" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 89px; height: 1px; padding-top: 599px; margin-left: 451px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; "><div style="display: inline-block; font-size: 12px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">data-db</div></div></div></foreignObject><image x="451" y="592.5" width="89" height="17" xlink:href="data:image/png;base64,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"/></switch></g></g></g><g data-cell-id="uDJ2bVtIrgoZBCZFZmDG-23"><g><path d="M 439.5 523.21 C 439.5 518.46 450.69 514.61 464.5 514.61 C 471.13 514.61 477.49 515.52 482.18 517.13 C 486.87 518.74 489.5 520.93 489.5 523.21 L 489.5 570.01 C 489.5 574.76 478.31 578.61 464.5 578.61 C 450.69 578.61 439.5 574.76 439.5 570.01 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(230, 230, 230); stroke: rgb(0, 0, 0);"/><path d="M 489.5 523.21 C 489.5 527.96 478.31 531.81 464.5 531.81 C 450.69 531.81 439.5 527.96 439.5 523.21" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="stroke: rgb(0, 0, 0);"/></g></g><g data-cell-id="uDJ2bVtIrgoZBCZFZmDG-24"><g><path d="M 499.5 523.21 C 499.5 518.46 510.69 514.61 524.5 514.61 C 531.13 514.61 537.49 515.52 542.18 517.13 C 546.87 518.74 549.5 520.93 549.5 523.21 L 549.5 570.01 C 549.5 574.76 538.31 578.61 524.5 578.61 C 510.69 578.61 499.5 574.76 499.5 570.01 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(230, 230, 230); stroke: rgb(0, 0, 0);"/><path d="M 549.5 523.21 C 549.5 527.96 538.31 531.81 524.5 531.81 C 510.69 531.81 499.5 527.96 499.5 523.21" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="stroke: rgb(0, 0, 0);"/></g></g><g data-cell-id="uDJ2bVtIrgoZBCZFZmDG-25"><g><path d="M 470.5 533.21 C 470.5 528.46 481.69 524.61 495.5 524.61 C 502.13 524.61 508.49 525.52 513.18 527.13 C 517.87 528.74 520.5 530.93 520.5 533.21 L 520.5 580.01 C 520.5 584.76 509.31 588.61 495.5 588.61 C 481.69 588.61 470.5 584.76 470.5 580.01 Z" fill="#e6e6e6" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(230, 230, 230); stroke: rgb(0, 0, 0);"/><path d="M 520.5 533.21 C 520.5 537.96 509.31 541.81 495.5 541.81 C 481.69 541.81 470.5 537.96 470.5 533.21" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="stroke: rgb(0, 0, 0);"/></g></g><g data-cell-id="uDJ2bVtIrgoZBCZFZmDG-29"><g><path d="M 494.86 481.37 L 494.86 518.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke" style="stroke: rgb(0, 0, 0);"/><path d="M 494.86 476.12 L 498.36 483.12 L 494.86 481.37 L 491.36 483.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/><path d="M 494.86 523.88 L 491.36 516.88 L 494.86 518.63 L 498.36 516.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all" style="fill: rgb(0, 0, 0); stroke: rgb(0, 0, 0);"/></g><g data-cell-id="uDJ2bVtIrgoZBCZFZmDG-30"><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 498px; margin-left: 496px;"><div style="box-sizing: border-box; font-size: 0; text-align: center; color: #000000; background-color: #ffffff; "><div style="display: inline-block; font-size: 11px; font-family: "Helvetica"; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">JDBC</div></div></div></foreignObject><image x="481.5" y="492" width="29" height="15.75" xlink:href="data:image/png;base64,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"/></switch></g></g></g></g></g></g></g></svg> \ No newline at end of file diff --git a/.docs/images/architecture.drawio b/.docs/images/architecture.drawio index b1aed4cb4035dfa1cbc08818c44ca5d7fac5a803..4343db2e4a0483a162a38cd87ac13b3674f79761 100644 --- a/.docs/images/architecture.drawio +++ b/.docs/images/architecture.drawio @@ -1,11 +1,41 @@ -<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"> +<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/26.2.2 Chrome/134.0.6998.178 Electron/35.1.2 Safari/537.36" version="26.2.2" 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"> + <mxGraphModel dx="819" dy="330" 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="FWEJ_FGA9GBXbfwohBE8-76" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;arcSize=2;" parent="1" vertex="1"> - <mxGeometry x="320" y="160" width="640" height="397" as="geometry" /> + <mxCell id="uDJ2bVtIrgoZBCZFZmDG-26" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;arcSize=6;" vertex="1" parent="1"> + <mxGeometry x="700" y="574.61" width="150" height="105" as="geometry" /> + </mxCell> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-97" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;jumpStyle=arc;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-101" target="FWEJ_FGA9GBXbfwohBE8-119" edge="1"> + <mxGeometry relative="1" as="geometry"> + <Array as="points"> + <mxPoint x="775" y="480" /> + <mxPoint x="660" y="480" /> + <mxPoint x="660" y="240" /> + <mxPoint x="618" y="240" /> + </Array> + </mxGeometry> + </mxCell> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-98" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-97" vertex="1" connectable="0"> + <mxGeometry x="0.7012" y="1" relative="1" as="geometry"> + <mxPoint x="-19" as="offset" /> + </mxGeometry> + </mxCell> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-143" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.25;entryY=1;entryDx=0;entryDy=0;jumpStyle=arc;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-85" target="FWEJ_FGA9GBXbfwohBE8-119" edge="1"> + <mxGeometry relative="1" as="geometry"> + <Array as="points"> + <mxPoint x="395" y="480" /> + <mxPoint x="500" y="480" /> + <mxPoint x="500" y="240" /> + <mxPoint x="553" y="240" /> + </Array> + </mxGeometry> + </mxCell> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-144" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-143" vertex="1" connectable="0"> + <mxGeometry x="0.6707" relative="1" as="geometry"> + <mxPoint x="17" as="offset" /> + </mxGeometry> </mxCell> <mxCell id="FWEJ_FGA9GBXbfwohBE8-77" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.75;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;startArrow=classic;startFill=1;endArrow=classic;endFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-119" target="FWEJ_FGA9GBXbfwohBE8-108" edge="1"> <mxGeometry relative="1" as="geometry"> @@ -23,12 +53,9 @@ </mxCell> <mxCell id="FWEJ_FGA9GBXbfwohBE8-79" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-77" vertex="1" connectable="0"> <mxGeometry x="-0.3724" relative="1" as="geometry"> - <mxPoint x="-2" y="11" as="offset" /> + <mxPoint x="62" y="105" as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-80" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;arcSize=6;" parent="1" vertex="1"> - <mxGeometry x="540" y="557" width="420" height="123" as="geometry" /> - </mxCell> <mxCell id="FWEJ_FGA9GBXbfwohBE8-81" value="LDAP" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-96" target="FWEJ_FGA9GBXbfwohBE8-104" edge="1"> <mxGeometry x="-0.2381" relative="1" as="geometry"> <mxPoint as="offset" /> @@ -68,50 +95,22 @@ <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="395" y="400" /> - <mxPoint x="500" y="400" /> - <mxPoint x="500" y="206" /> + <mxPoint x="490" y="400" /> + <mxPoint x="490" y="206" /> </Array> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-91" value="HTTP,<div>AMQP</div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-90" vertex="1" connectable="0"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-91" value="<div>AMQP,<br>MQTT</div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-90" vertex="1" connectable="0"> <mxGeometry x="-0.1797" y="2" relative="1" as="geometry"> - <mxPoint x="2" y="-77" as="offset" /> + <mxPoint x="-18" y="23" as="offset" /> </mxGeometry> </mxCell> <mxCell id="FWEJ_FGA9GBXbfwohBE8-92" value="<b>Broker Service</b><div><i>rabbitmq</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> <mxGeometry x="330" y="422" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-93" value="LDAP" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-96" target="FWEJ_FGA9GBXbfwohBE8-108" edge="1"> - <mxGeometry relative="1" as="geometry"> - <mxPoint as="offset" /> - </mxGeometry> - </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-94" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-96" target="FWEJ_FGA9GBXbfwohBE8-119" edge="1"> - <mxGeometry relative="1" as="geometry" /> - </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-95" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-94" vertex="1" connectable="0"> - <mxGeometry x="0.125" relative="1" as="geometry"> - <mxPoint as="offset" /> - </mxGeometry> - </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-96" value="<b>Identity Service *</b><div><i>openldap</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-96" value="<b>Identity Service</b><div><i>openldap</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> <mxGeometry x="520" y="422" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-97" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;jumpStyle=arc;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-101" target="FWEJ_FGA9GBXbfwohBE8-119" edge="1"> - <mxGeometry relative="1" as="geometry"> - <Array as="points"> - <mxPoint x="775" y="480" /> - <mxPoint x="662" y="480" /> - <mxPoint x="662" y="410" /> - <mxPoint x="617" y="410" /> - </Array> - </mxGeometry> - </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-98" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-97" vertex="1" connectable="0"> - <mxGeometry x="0.7012" y="1" relative="1" as="geometry"> - <mxPoint x="1" y="2" as="offset" /> - </mxGeometry> - </mxCell> <mxCell id="FWEJ_FGA9GBXbfwohBE8-99" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.25;exitY=0;exitDx=0;exitDy=0;entryX=0.75;entryY=0;entryDx=0;entryDy=0;jumpStyle=arc;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-101" target="FWEJ_FGA9GBXbfwohBE8-85" edge="1"> <mxGeometry relative="1" as="geometry"> <Array as="points"> @@ -136,55 +135,23 @@ <mxPoint x="3" as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-104" value="<b>Auth Service</b><br><i>keycloak</i>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> - <mxGeometry x="520" y="504" width="130" height="40" as="geometry" /> - </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-105" value="Search Service" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" parent="1" vertex="1"> - <mxGeometry x="710" y="176" width="130" height="40" as="geometry" /> - </mxCell> <mxCell id="FWEJ_FGA9GBXbfwohBE8-106" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" parent="1" vertex="1"> <mxGeometry x="750" y="256" width="50" height="64" as="geometry" /> </mxCell> <mxCell id="FWEJ_FGA9GBXbfwohBE8-107" value="search-db" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" parent="1" vertex="1"> <mxGeometry x="732.5" y="320.5" width="85" height="17" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-108" value="<b>Dashboard Service</b><div><i>grafana</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> - <mxGeometry x="710" y="422" width="130" height="40" as="geometry" /> - </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-109" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-124" target="FWEJ_FGA9GBXbfwohBE8-120" edge="1"> - <mxGeometry relative="1" as="geometry" /> - </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-110" value="S3" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-109" vertex="1" connectable="0"> - <mxGeometry x="0.2961" y="-3" relative="1" as="geometry"> - <mxPoint x="3" y="-9" as="offset" /> - </mxGeometry> - </mxCell> <mxCell id="FWEJ_FGA9GBXbfwohBE8-111" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" parent="1" vertex="1"> <mxGeometry x="560" y="584" width="50" height="64" as="geometry" /> </mxCell> <mxCell id="FWEJ_FGA9GBXbfwohBE8-112" value="auth-db" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" parent="1" vertex="1"> <mxGeometry x="542.5" y="648" width="85" height="20" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-113" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" parent="1" vertex="1"> - <mxGeometry x="750" y="584" width="50" height="64" as="geometry" /> - </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-114" value="metadata-db" style="text;html=1;strokeColor=none;fillColor=default;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" parent="1" vertex="1"> - <mxGeometry x="732.5" y="649" width="85" height="17" as="geometry" /> - </mxCell> <mxCell id="FWEJ_FGA9GBXbfwohBE8-115" value="HTTP" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0;entryY=0.25;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-119" target="FWEJ_FGA9GBXbfwohBE8-105" edge="1"> <mxGeometry relative="1" as="geometry"> <mxPoint as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-116" value="HTTP" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;entryX=1;entryY=0.25;entryDx=0;entryDy=0;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-119" target="FWEJ_FGA9GBXbfwohBE8-124" edge="1"> - <mxGeometry relative="1" as="geometry"> - <Array as="points"> - <mxPoint x="490" y="186" /> - <mxPoint x="490" y="186" /> - </Array> - <mxPoint as="offset" /> - </mxGeometry> - </mxCell> <mxCell id="FWEJ_FGA9GBXbfwohBE8-117" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-119" target="FWEJ_FGA9GBXbfwohBE8-123" edge="1"> <mxGeometry relative="1" as="geometry"> <Array as="points"> @@ -195,15 +162,15 @@ </mxCell> <mxCell id="FWEJ_FGA9GBXbfwohBE8-118" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-117" vertex="1" connectable="0"> <mxGeometry x="0.5551" y="-1" relative="1" as="geometry"> - <mxPoint x="1" y="-64" as="offset" /> + <mxPoint x="-9" y="-20" as="offset" /> </mxGeometry> </mxCell> + <mxCell id="uDJ2bVtIrgoZBCZFZmDG-13" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-119" target="uDJ2bVtIrgoZBCZFZmDG-12"> + <mxGeometry relative="1" as="geometry" /> + </mxCell> <mxCell id="FWEJ_FGA9GBXbfwohBE8-119" value="<b>Gateway Service</b><div><i>nginx</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> <mxGeometry x="520" y="176" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-120" value="<b>Storage Service</b><div><i>seaweedfs</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> - <mxGeometry x="329.5" y="258" width="130" height="40" as="geometry" /> - </mxCell> <mxCell id="FWEJ_FGA9GBXbfwohBE8-121" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-123" target="FWEJ_FGA9GBXbfwohBE8-120" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> @@ -215,9 +182,6 @@ <mxCell id="FWEJ_FGA9GBXbfwohBE8-123" value="Analyse Service" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" parent="1" vertex="1"> <mxGeometry x="330" y="340" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-124" value="<b>Upload Service</b><div><i>tusd</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> - <mxGeometry x="330" y="176" width="130" height="40" as="geometry" /> - </mxCell> <mxCell id="FWEJ_FGA9GBXbfwohBE8-125" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-105" target="FWEJ_FGA9GBXbfwohBE8-106" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> @@ -239,24 +203,11 @@ <mxCell id="FWEJ_FGA9GBXbfwohBE8-129" value="Database<div>Engineer</div>" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1"> <mxGeometry x="490" y="586" width="30" height="60" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-130" value="" style="rounded=0;whiteSpace=wrap;html=1;strokeColor=none;" parent="1" vertex="1"> - <mxGeometry x="540" y="550" width="420" height="14" as="geometry" /> - </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-131" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-101" target="FWEJ_FGA9GBXbfwohBE8-113" edge="1"> - <mxGeometry relative="1" as="geometry"> - <mxPoint x="840" y="524" as="sourcePoint" /> - </mxGeometry> - </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-132" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-131" vertex="1" connectable="0"> - <mxGeometry x="-0.0169" y="-1" relative="1" as="geometry"> - <mxPoint x="1" as="offset" /> - </mxGeometry> - </mxCell> <mxCell id="FWEJ_FGA9GBXbfwohBE8-133" value="JDBC" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-104" target="FWEJ_FGA9GBXbfwohBE8-111" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="FWEJ_FGA9GBXbfwohBE8-134" value="System<div>Engineer</div>" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1"> - <mxGeometry x="662" y="571" width="30" height="60" as="geometry" /> + <mxGeometry x="650" y="586" width="30" height="60" as="geometry" /> </mxCell> <mxCell id="FWEJ_FGA9GBXbfwohBE8-135" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" parent="1" vertex="1"> <mxGeometry x="339.5" y="584" width="50" height="64" as="geometry" /> @@ -288,33 +239,6 @@ <mxCell id="FWEJ_FGA9GBXbfwohBE8-142" value="Machine" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1"> <mxGeometry x="620" y="69" width="30" height="60" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-143" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.25;entryY=1;entryDx=0;entryDy=0;jumpStyle=arc;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-85" target="FWEJ_FGA9GBXbfwohBE8-119" edge="1"> - <mxGeometry relative="1" as="geometry"> - <Array as="points"> - <mxPoint x="395" y="480" /> - <mxPoint x="506" y="480" /> - <mxPoint x="506" y="410" /> - <mxPoint x="553" y="410" /> - </Array> - </mxGeometry> - </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-144" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-143" vertex="1" connectable="0"> - <mxGeometry x="0.6707" relative="1" as="geometry"> - <mxPoint x="-1" as="offset" /> - </mxGeometry> - </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-145" value="" style="endArrow=none;dashed=1;html=1;rounded=0;entryX=1;entryY=0.976;entryDx=0;entryDy=0;entryPerimeter=0;exitX=1;exitY=0.076;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-80" target="FWEJ_FGA9GBXbfwohBE8-76" edge="1"> - <mxGeometry width="50" height="50" relative="1" as="geometry"> - <mxPoint x="810" y="570" as="sourcePoint" /> - <mxPoint x="860" y="520" as="targetPoint" /> - </mxGeometry> - </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-146" value="" style="endArrow=none;dashed=1;html=1;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=0;exitY=0.121;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-80" target="FWEJ_FGA9GBXbfwohBE8-130" edge="1"> - <mxGeometry width="50" height="50" relative="1" as="geometry"> - <mxPoint x="540" y="590" as="sourcePoint" /> - <mxPoint x="590" y="540" as="targetPoint" /> - </mxGeometry> - </mxCell> <mxCell id="FWEJ_FGA9GBXbfwohBE8-147" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-119" target="FWEJ_FGA9GBXbfwohBE8-140" edge="1"> <mxGeometry relative="1" as="geometry"> <Array as="points"> @@ -341,22 +265,76 @@ <mxPoint x="4" y="34" as="offset" /> </mxGeometry> </mxCell> - <mxCell id="a_cl7nsyDpLQFaXOHeFD-5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="a_cl7nsyDpLQFaXOHeFD-3" target="FWEJ_FGA9GBXbfwohBE8-108"> + <mxCell id="a_cl7nsyDpLQFaXOHeFD-3" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" parent="1" vertex="1"> + <mxGeometry x="559.5" y="318" width="50" height="64" as="geometry" /> + </mxCell> + <mxCell id="a_cl7nsyDpLQFaXOHeFD-4" value="metric-db" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" parent="1" vertex="1"> + <mxGeometry x="542" y="382" width="85" height="17" as="geometry" /> + </mxCell> + <mxCell id="uDJ2bVtIrgoZBCZFZmDG-6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;endSize=4;" edge="1" parent="1" source="uDJ2bVtIrgoZBCZFZmDG-5" target="FWEJ_FGA9GBXbfwohBE8-105"> <mxGeometry relative="1" as="geometry" /> </mxCell> - <mxCell id="a_cl7nsyDpLQFaXOHeFD-6" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="a_cl7nsyDpLQFaXOHeFD-5"> - <mxGeometry x="-0.1222" relative="1" as="geometry"> - <mxPoint as="offset" /> - </mxGeometry> + <mxCell id="uDJ2bVtIrgoZBCZFZmDG-5" value="init" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" vertex="1" parent="1"> + <mxGeometry x="850" y="189" width="40" height="14" as="geometry" /> + </mxCell> + <mxCell id="uDJ2bVtIrgoZBCZFZmDG-9" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;endSize=4;" edge="1" parent="1" source="uDJ2bVtIrgoZBCZFZmDG-8" target="FWEJ_FGA9GBXbfwohBE8-108"> + <mxGeometry relative="1" as="geometry" /> + </mxCell> + <mxCell id="uDJ2bVtIrgoZBCZFZmDG-8" value="init" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" vertex="1" parent="1"> + <mxGeometry x="850" y="435.5" width="40" height="13" as="geometry" /> </mxCell> - <mxCell id="a_cl7nsyDpLQFaXOHeFD-3" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" vertex="1" parent="1"> - <mxGeometry x="900" y="410" width="50" height="64" as="geometry" /> + <mxCell id="uDJ2bVtIrgoZBCZFZmDG-11" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;endSize=4;" edge="1" parent="1" source="uDJ2bVtIrgoZBCZFZmDG-10" target="FWEJ_FGA9GBXbfwohBE8-120"> + <mxGeometry relative="1" as="geometry" /> + </mxCell> + <mxCell id="uDJ2bVtIrgoZBCZFZmDG-10" value="init" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" vertex="1" parent="1"> + <mxGeometry x="280" y="272" width="40" height="12" as="geometry" /> </mxCell> - <mxCell id="a_cl7nsyDpLQFaXOHeFD-4" value="metric-db" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" vertex="1" parent="1"> - <mxGeometry x="882.5" y="474" width="85" height="17" as="geometry" /> + <mxCell id="uDJ2bVtIrgoZBCZFZmDG-12" value="<b>Dashboard UI</b><div><i>grafana</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" vertex="1" parent="1"> + <mxGeometry x="520" y="258" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="a_cl7nsyDpLQFaXOHeFD-7" value="* omitted edges for all services to metric-db" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> - <mxGeometry x="727" y="683" width="233" height="11" as="geometry" /> + <mxCell id="uDJ2bVtIrgoZBCZFZmDG-17" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;endSize=4;" edge="1" parent="1" source="uDJ2bVtIrgoZBCZFZmDG-14" target="FWEJ_FGA9GBXbfwohBE8-104"> + <mxGeometry relative="1" as="geometry" /> + </mxCell> + <mxCell id="uDJ2bVtIrgoZBCZFZmDG-18" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endSize=0;startSize=0;jumpSize=3;" edge="1" parent="1" source="uDJ2bVtIrgoZBCZFZmDG-14" target="FWEJ_FGA9GBXbfwohBE8-104"> + <mxGeometry relative="1" as="geometry" /> + </mxCell> + <mxCell id="uDJ2bVtIrgoZBCZFZmDG-14" value="init" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" vertex="1" parent="1"> + <mxGeometry x="470" y="517.5" width="40" height="13" as="geometry" /> + </mxCell> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-104" value="<b>Auth Service</b><br><i>keycloak</i>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> + <mxGeometry x="520" y="504" width="130" height="40" as="geometry" /> + </mxCell> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-120" value="<b>Storage Service</b><div><i>seaweedfs</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> + <mxGeometry x="329.5" y="258" width="130" height="40" as="geometry" /> + </mxCell> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-105" value="Search Service" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" parent="1" vertex="1"> + <mxGeometry x="710" y="176" width="130" height="40" as="geometry" /> + </mxCell> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-108" value="<b>Dashboard Service</b>" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1"> + <mxGeometry x="710" y="422" width="130" height="40" as="geometry" /> + </mxCell> + <mxCell id="uDJ2bVtIrgoZBCZFZmDG-21" value="data-db" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" vertex="1" parent="1"> + <mxGeometry x="732.5" y="657.61" width="85" height="20" as="geometry" /> + </mxCell> + <mxCell id="uDJ2bVtIrgoZBCZFZmDG-23" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" vertex="1" parent="1"> + <mxGeometry x="719.5" y="583.61" width="50" height="64" as="geometry" /> + </mxCell> + <mxCell id="uDJ2bVtIrgoZBCZFZmDG-24" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" vertex="1" parent="1"> + <mxGeometry x="779.5" y="583.61" width="50" height="64" as="geometry" /> + </mxCell> + <mxCell id="uDJ2bVtIrgoZBCZFZmDG-25" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" vertex="1" parent="1"> + <mxGeometry x="750.5" y="593.61" width="50" height="64" as="geometry" /> + </mxCell> + <mxCell id="uDJ2bVtIrgoZBCZFZmDG-29" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;startArrow=classic;startFill=1;" edge="1" parent="1"> + <mxGeometry relative="1" as="geometry"> + <mxPoint x="774.86" y="544" as="sourcePoint" /> + <mxPoint x="774.86" y="594" as="targetPoint" /> + </mxGeometry> + </mxCell> + <mxCell id="uDJ2bVtIrgoZBCZFZmDG-30" value="JDBC" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="uDJ2bVtIrgoZBCZFZmDG-29"> + <mxGeometry x="0.3566" relative="1" as="geometry"> + <mxPoint x="1" y="-12" as="offset" /> + </mxGeometry> </mxCell> </root> </mxGraphModel> @@ -1108,11 +1086,33 @@ </root> </mxGraphModel> </diagram> - <diagram id="7HywRA3nQAgvNxZjCRq2" name="private-embargo"> - <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"> + <diagram id="7HywRA3nQAgvNxZjCRq2" name="data-versioning"> + <mxGraphModel dx="988" dy="563" 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="795Xv0Ka93fOG331V9Xn-7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="795Xv0Ka93fOG331V9Xn-4" edge="1"> + <mxGeometry relative="1" as="geometry"> + <mxPoint x="622" y="141" as="targetPoint" /> + </mxGeometry> + </mxCell> + <mxCell id="795Xv0Ka93fOG331V9Xn-8" value="t3:<b> UPDATE</b>&nbsp;tbl<br><b>SET</b> `Temp` = <font style="color: light-dark(rgb(251, 35, 108), rgb(251, 35, 108));">22.1</font><br><b>WHERE</b> `ID` = 1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=default;fontSize=17;" parent="795Xv0Ka93fOG331V9Xn-7" vertex="1" connectable="0"> + <mxGeometry x="-0.1405" y="3" relative="1" as="geometry"> + <mxPoint x="22" y="3" as="offset" /> + </mxGeometry> + </mxCell> + <mxCell id="795Xv0Ka93fOG331V9Xn-4" value="" style="rounded=1;whiteSpace=wrap;html=1;arcSize=4;" parent="1" vertex="1"> + <mxGeometry x="120" y="80" width="284" height="122" as="geometry" /> + </mxCell> + <mxCell id="795Xv0Ka93fOG331V9Xn-18" value="" style="shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/png,iVBORw0KGgoAAAANSUhEUgAABJEAAAHoCAYAAAD5W34cAACAAElEQVR4XuydB5iV1bWGTTP2buyxRGNFNHYMEcUGoiiKgg0RFOzYqWIHLIiKPYiKEkWxoCioFCsR0RhbTJPYk1yvN7m5aQbcl3fBd7LPP2eQGc4MM+b7nmc95y9773//ex+G2e+stfZSybIsy7Isy7Isy7Isy7K+REsVL1iWZTVV/eMf/7DZbHU0y7Isy7Isy6qWDJEsy2o2YkH8y1/+0mazLaL99a9/Lf4zsizLsizLsqx6yxDJsqxmI0Mkm61uZohkWZZlWZZlVVOGSJZlNRsZItlsdTNDJMuyLMuyLKuaMkSyLKvZyBDJZqubGSJZlmVZlmVZ1ZQhkmVZzUaGSDZb3cwQybIsy7Isy6qmDJEsy2o2MkSy2epmhkiWZVmWZVlWNWWIZFlWs5Ehks1WNzNEsizLsizLsqopQyTLspqNDJFstrqZIZJlWZZlWZZVTRkiWZbVbGSIZLPVzQyRLMuyLMuyrGrKEMmyrGYjQySbrW5miGRZlmVZlmVVU4ZIlmU1Gxki2Wx1M0Mky7Isy7Isq5oyRLIsq9nIEMlmq5sZIlmWZVmWZVnVlCGSZVnNRg0FkV5//fX09ttv17huszWWvfnmm2HF64trhkiWZVmWZVlWNWWIZFlWs1FDQKRRo0alXXbZJb322mtxvvvuu6fvf//7DQaVZsyYkdZaa63UtWvXGvdqs2KdcePGpY4dO6allloqXXnllTXKyyZNmpROOOGEtOKKK6bWrVvXuF8ta+gx+0+wmTNnpl133TWNHTu2xr3FMUMky7Isy7Isq5oyRLIsq9mo2hBpwIABaeutt04vv/xy6RpA6Xvf+16DAZEXX3wxrbHGGqlz58417tVmleqMHz/+SyGSbOONN25QiNTQY/afYsBCYNzQoUNr3KuvGSJZlmVZlmVZ1ZQhkmVZzUbVhEgjR45M3/72t9O0adNq3GsOJoh01VVX1bhXtGpBJMKtttxyyxrXm5o1l35WsokTJ6ZvfetbacyYMTXu1ccMkSzLsizLsqxqyhDJsqxmo2pBpDfeeCM8e4444oga95qLCSJdffXVNe4VrVoQ6bLLLkurrLJKjetNzZpLP2uz9u3bpw033DD94he/qHGvrmaIZFmWZVmWZVVThkiWZTUbVQsi4b0DgCEfUn6d8DaAyze+8Y3StWuuuSatu+66Uf7kk09OW221VVpmmWXS6quvnvr16xdlpk+fnvbaa68os9lmm6W+ffuW6g8aNCi8Ylq2bBn5bo4//vjIUbTbbruVPfvyyy+P0LqddtopQppatWoV13/+859XrCOIdMghh0Sfll122bTaaqulww47rCw8D6sEkV566aXUqVOntNFGG8VzseJ45Na/f/+05pprxtjwLoSwcb3SmPXo0SOtsMIKAUJ69uwZz2DM+Bw+fHi6+eab0z777BOgZ+WVV069evUqexbw5Iwzzoh2W7RoEZ8aa4ywue7du0efd9hhh7TJJpuk3r17L7SfGDmlGFvGgs999903xoF7hAWut956MaZnnnlmPJd3oC36x3h36dIlvguMNfP9s5/9LOoOGzYsoORyyy2XjjzyyCiz9NJLp8033zzeNX+32uY5txEjRlT8ftbHDJEsy7Isy7KsasoQybKsZqNqQSRAC4t0ctAU7x111FFlQATr06dPlL/22mvTk08+mZ544omAE1//+tfT1KlTowyJuQEiQKRim9tss0168MEHS+eUyYHQfffdl772ta9F25wDSYrQp1hHEOmss85Kr776asAm4AOAA0CR1y1CpHfeeSdtt912AV8EnE4//fQAH0899VRZ3dwOPPDAih4+lcaM5wFWbrzxxvTII48EEFl77bWj3JAhQ9L9998fY9KmTZt4jwkTJpTqkgycvlCP87vvvrss/9M555yTvvvd78auepyTM4q+fVk/mTPGiuMXXnghffOb3wwYpftnn312POeiiy5KDzzwQPSROlwDhtEP+nnSSSfFtYEDB5bqduvWLa5Nnjw55o8wScaA933ssceizKLMM0YbembxXl3NEMmyLMuyLMuqpgyRLMtqNqoWRNp2221rQA9ZJSAiiPTTn/60dO2mm26Ka7feemvpGot+rt15552la4CS7bffvqy9IhC6+OKLA0gBQ3Qtf1alOrUl1j722GPjeg6tihAJjyjK4LWja88991xcwwMoby+32uBMpTHjeTw3v4YnF8/IPaUEiABgnBNqCAhr27ZtWV28mNi9jOMOHTqEFw8wTPfz8aqtn+xql59vsMEGaY899iidCyIBmHTtjjvuiGvk0NI14A/vm++wJ4iUt//MM89EObzFOF+UecbwcKKtSoCprmaIZFmWZVmWZVVThkiW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pTb79ttv0913350222yztMEGG6Sddtop7nmyiBCmhx56aNpoo41CDg0cODCkgn4j9AVZRv379499+/btm84555wQRtdcc0065ZRT0lZbbZVWWmmltMMOO6THH388ff3113EtOkYxM0r3BEHGCxlNyKPVV189ruHoo49OTzzxROm3pu9UnAZXabqqRMprGUko8TviPfIHGdivX7902mmnpRdffLE0yJdYQiLxmX6m7Q888MC05pprpkUWWSRtuOGG8Xt8+umnm53X4SgXlkjGGGOMMaZSjFaJpAGoptEMHTo0ps3wP/DHHntsDKLJhpl44oljEMZgS4Wf82NaIrWPltqN9//617/SnXfemQ477LC04oorpummmy6tv/76IfYYwIty+5tG8vbN2ygXSUgHxOiUU06ZVllllRA/CAUyhIgnn3wy7bXXXmmyySZLW2+9dbrxxhtLv5dPPvkkDR48OG288cZpoYUWCoH09ttvx3oKZr/66qshnshsWnTRRdOFF14Yx+Y6inIrD35/SBD6n/1322231KtXrzTjjDOmQw45JGSU9tc+lkiNoZpIKphNO5JhxHKmJSKCVl111ZCFNTU1sQ/bqNYR8fzzz8cUUoTRLrvsEr+/qaaaKq2wwgqRCWaJ5GhrWCIZY4wxxphKUTWJpKyFfKBJ1gt1jjTgZnB8/PHHx/Se5557LmohkZHBQAqJRIYEmUoamEs+mfZDu/F0tuKUJjJWTj/99HTUUUeFyGM62/LLL5+uuOKKGBAL9mffooSyVGpEwiZ/gqDah/udzBPaeeqpp46MIuQD/aFtmCp2wQUXxL1P+7Mtx2Lfzz77LF1++eVpm222CdFK3STkkfrzq6++iho6a6yxRlpwwQVDQCCW2JdtlIVUFEBcE78zppA+/PDDUQOJqYyIRKbG3X///U2+W7XEUU5XlUjIIGUV8TmXSkjxZZZZJi2xxBJp2223TY8++miTqWu1tbXxZx+y78gjj4xsJUQeGUlzzjlnyKSTTz45ss+K53U4yoUlkjHGGGOMqRRVkUiSRMpgECruy2CWoO4LUz/IRmKgzCsigzovyKU333yzySPoi1LKtA31h9qPoC8QDAx6yZZAbNTU1MR0q+WWWy716dMnxJ6knY6R92ee5dJdkWDRvV6uTVhOxhcFyxEH1DwiC4jtEDO6x5E5k046aUzpJDNIy9kW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Y8wYgyWSw9F6WCIZY4wxxphKYYlkjBljsERyOFoPSyRjjDHGGFMpLJFMh2loaCguMl2Iurq69L///S/997//jfedzejo/zFdIjGoLy5zODo7LJGMMcYYY0ylqJpEqq+vT3/88Ue8CgahfCZ4n38uLmMQXNx32LBhTZaZtkP70aZqY/qmKBqKkkD9ArQ9giLvAx2ruF93pHgv634WeVtqe6AP6Iv83qedWab91E+80v75cfP2ZxD51FNPpfvuuy999NFHZfslP4+uh+Pq3tA2nJ9zCbatlJwaGV1ZIjFg//DDD+OVtqfNeWUd7z/44IP07rvvxvt//vOfTYSS3ueDf46Vf9Z69uc963W+fF+d09F9wxLJGGOMMcZUiqpIJAahGhxrMK3BsOSQBqXff/99DIyee+659OCDD6Y77rgj3XLLLemee+6JATGDr59++im2t0TqGHn7v/POO+n+++9PN910U7r55pvTbbfdlm699dYmceedd6YHHnggPfPMM9E3//73v6OvJBbyPlT/dmfUBrmcURtpOZ//85//pB9//DEGey+++GJ6+OGHo63ph9tvvz09/vjj6b333ks//PBDiKT8OPDmm2+mG2+8MX4f6ive6/Npp52Wjj322HTmmWem1157rXRu9U8ui3Rs+hRJQV8jn/j96dj8Hl9++eX0+eefp6FDh8Y9oN9gftxK0lUlEoN1iR8+FyUSr0gk+pM/wySRcpH09ttvp2effTb+rLv22mvTJZdcki688MJ0wQUXxHvuCf4M5DiSR/n+uUAqrnN0r7BEMsYYY4wxlaIqEkkD6fwzg2JlsjD45PVf//pXeumll2LQtP3226eePXumaaedNk088cRprrnmSptuumm6+OKLQ3woW8O0n7w/BgwYkHr06JEmn3zyaOdJJpkkTTTRRKX3vNIH888/f9pqq63SueeeG4PjX3/9tcnx6A/1Z3eGe7KYcaflyhzSK3LojTfeSBdddFHaddddU+/evdMss8ySpphiijT11FOn1VdfPZ1xxhkxEGQfiSRxzDHHRF+1FBNOOGFaZJFF0vHHH59eeeWVJlKL90ggjim4buQQAmO77bZL88wzT5pqqqniPuAeWGqppVKfPn1CZnzyySel7ySZWPzOlaCrSqRiBhKSSEKJ5e+//36813Jtq/fs8/TTT6dLL7007bLLLmnFFVdMc845Z/wuib/85S9pyy23TGeddVZ64YUXIqOJY3388cclWZBnIClLqXidju4RlkjGGGOMMaZSjDaJlGcxAP/gJRtm5513jsHSnnvumQYNGpTOP//8dM4556Tddtstrb322mmVVVaJgRbZEL/99lvVp9OMDUja0X5klpx66qlpttlmi6B9aferrroqXXnllSHtkBUIvOWWWy6tv/76MZB96623SsfJM5Hy7JbuiESNMnNyUapg/XfffRfZXTvttFPaZJNNQtogjLi3kagHHHBA2mijjdIKK6yQ/va3v6VXX301joOwkfw54ogjQvLwuzjyyCOjv4grrrgijsMrmWX0MeeT9NH1qe/g999/j+04DkJr9913T6effnoIrssuuyzkIde06qqrpq233jp+l2RRcS25mKo0XV0i5cs0kCeri77ld0SbkhUm+VNbWxtC6LHHHksHH3xwWnPNNeM3uO+++8bv8KSTTor33AtIvG222SZdfvnl6fnnnw+JpKltOncuD4rX4+g+YYlkjDHGGGMqRdUkUj7A5LOyKggGxgy0GGSR/bDWWmvFIJXpHWQnEVdffXXaYostIiuCwSwZSwxiu3vmS0egL2hzpqXRD2RAkI204IILhqxjECLhgWhi2tR5552XlllmmRBN2267bRoyZEjpOBIREiTVykrpquSyiClreY0jLUcAIOOmm266yDo57rjjQib8/PPPMV3zySefTHvttVdkgm2++ebpuuuuK2UjcUzkDcKH/jjkkEPSE088Ufqd6fcloZf3R/5b1O+PQDKRgTT33HOn9dZbLw0cODDEiKatMc0UyYtMXGihhdIOO+wQg9RffvmlyXerNF1RIjFQZ4qZMop4pe00bY1pgfzZtdJKK4WA4886JBL7fvrppyGVmJbI+llnnTVtuOGGMX2NwT+/PfZHJi2wwAJp0UUXTQcddFB66KGHmgkjSSPOWbxGR/cKSyRjjDHGGFMpqiKRijDYVEYEA2wGzfxPPANp/rf9hBNOKGU5aBDMQIvlU045ZUgMarUwoHQmUvuh3fPsoZqampB38847b2TGMCCWbKB/mLpGf9DuM888c2TOUEdJx8rlhTORmhZ8V9vonldQG+eUU06JqUrULWLAh7BTphGC7+9//3tMSeM3QVZKMaOJ3wvShwwWpB5ySeeTcCJa6gv9ttiGwSa1k/h9HXbYYZH5xDUo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e8VVV12Vttlmm9ju8MMPb7a+M6Ij38fRPK6//vq0zjrrpJqammbrOiOaSSQGZoihP/74I/6X/5tvvmkWX3/9dfryyy/TZ599lr744ot473A4HNWO9957Lz333HMOh6NMPP/88+mll16K12eeeSY99dRT6ZFHHmnyl74xxhjTnaiUROLv2QUXXDCddtpppWUvvPBCmmGGGdLWW2/dbPvOiquvvjpNOumk6Ywzzmi2rqU46KCD0pRTTpkeeuih0rJ+/fq1KpEI/k1RSYnUke/jKB+33nprmmOOOdJdd93VbN2oRlmJRIbRd999l4466qi03nrrhcVae+21S7H++uunDTbYoNlyh8PhqGasuuqqaYUVVnA4HGVixRVXTCuttFK88nn55ZdPyy23XJO/9I0xxpjuRCUk0vvvv5969epV0YyjSockEjKsuC6PzpRIDzzwQHiF4vKuFmPKdZaLAQMGhMhEaBbXjUo0k0hkISGR+F9+JNH444+fxhtvvDTuuOPGDUNMOOGEaeKJJ451LHc4HI7REfozyeFwtBz8VvT3OH9vG2OMMd2VSkikY489Nv6ebU3AdOWQRCKTubguj86USJtuumkkrBSXd7UYU66zXPCUXqZUbrXVVs3WjUo0k0h66hpT1viffv7BOcEEE8SrhBKfEUn67HA4HA6Ho2sGf2dPNNFE8fc2YYwxxnRXKiGR5pprrrTEEks0Wfb222+nPfbYI6aNkQ3MMh5usdZaa4WEWX311UNMkCXC39HUJFL9moEDB6bpppsuttt2223T/fffH8uZfrbjjjvGGJwpaXzecsstYzvqHOncyKx11103romYd9550wUXXBDrLrvssshMZp+bbrqptI8kEtfMFCiuafbZZ0+HHnpo6eEcREsS6fzzz0+LLLJI6tmzZ5p77rnTdtttF22Qb6OgHAVZW/ybZOqpp069e/eO85b7PhQpp834jzDabPPNN0+zzDJLTHlbfPHFY8rWySefnJZZZplYNuuss8a15Oe777770sorr5zmn3/+CGYyPPbYY6X1t9xyS1pyySXjGFz/QgstlB5//PEWr5N97rzzzvi+tC/9O88885TqOI3qNe+6666RsMPxOc7000+fJplkksguf/jhh0vbjayf8+A7cLxXX3212bqORjOJpIK1v/32WzTejTfeGEFxJuKGG25o8t7hcDgcDkfXDf2dTVx55ZVN/tI3xhhjuhOdLZGoIYT02GGHHZqtIxZYYIGSRFIggVZZZZUQEYgj5AP/6YNA0TbIG4573nnnNdn30ksvTWuuuWbpM7UPixKJY2+yySZN9jnmmGNKnxEWLUkk/q3w7rvvppdffjntv//+sYxXbVdOIl1xxRWxjKlTfFYtqNayX8iQKWb4lPs+BFJr2WWXTYMHDw4pNGjQoGhHhBXf5+67745rn3POOaNoOE+mZT8yq6aaaqq00UYbxTIyc5Ax7Md7xB6C6NRTTy2dC1F0zz33jPQ6aVNEnj7vvPPO8Z92r7zyyihfM4HIWnjhheP6uc477rgjpN5ss80W/cM2rfWzAmFFm9JPxXUdjWYS6ffffw+BRPBekS/T++I2DofD4XA4ulbkf2cTxhhjTHelsyWSBEpReihakkhkFOXLyDpZdNFFS5+ROGSfLL300k22W2ONNeIpafpcTrrMOOOMaaeddip9Rk5wPH0emUQqFtamWDgSRtlI5SQS3w8JguzQMp7iRvYL9aLy4+VRTs6U+z4EQobspnwZ2VtcX77s4IMPjv1VA4jj8DmXQkg7lpEowwNHeJ9nAr355pshl/S53HXSTvn0xTPPPDOOg+zRso5eM4FEQkDl25111lmxnYq3t9bPCuRSsc9GNZpJpCafjDHGGGOMMcaYsYDOlkgSEtRFKq4j2iqRmE6FOMiXMZUtFyA8ZZXpWHnGSjnpsvHGG8dUqr/+9a8hSvLtifZIJF3DE088EZ/LSSQk02KLLdZkP4mRfNpYMcrJmXLfhygnZMjEYRpZvqz4PSjPw+d8ah1Z2ixj2iDii+lkU0wxRWRcDRkypMnxiHLXWYyzzz47jslUNS3r6DUT5SQSWWtst9tuu8Xn1vpZQbYT++25557N1nU0LJGMMcYYY4wxxoz1dLZEYhoUA/Tjjjuu2TpiVCTSgw8+GMfWtDAkx/HHH99km3LShUwa6uowTYt1SIv8Me/tkUiIB5ZzLXwuJ5H4PpwL6aFgKhZTr8j0yY+XRzk5U+77EB0VMrQ9oiW/NuoScW1nnHFGbPPoo4/GdVD7iH05LtcxsutkKuIWW2yRVltttXhqPTWJKi2RXn/99dgOecTn1vpZIWmWZy2NalgiGWOMMcYYY4wZ6+lsiXTOOefEAP3II49sto4YFYlEUBCaaW1MdaJwMkWb8/UtSReCqWQXXnhh1CeiWLaWt0cikeXC8hdffDE+l5NISIzid2xLlJMzLX2fjgoZPW0+36aleO2112J/ts/rORWvkzagT8gIUvZPNTKRyAZju+K901I/K5j+yH777LNPs3UdDUskY4wxxhhjjDFjPZ0tka699toYoOfFp/MYVYmkmks8yatcJkk56XL55Zc32aZ///6xjer8tEciITzmm2++0udyEmm55ZYLgZHXRGpL8MSySkskTat74IEHmmynePbZZ9O9997bZBmFy8lW0ufidfKQEo7Jq5ZVQyKp36iNxOfW+rm4X7mi2x0NSyRjjDHGGGOMMWM9nS2ReGw606U23XTTZuuIUZVIZLqQgcQ5ytXrKSddevToEbJHn7feeuso3K3PbZVIJ554Ypw3LzpdTiKRBcMysnd4mhjLqEFEDR9tUy4oMI1Qeeutt0qPny/3fYiOChnqSE022WRRswmRRHuSucO1Ib2oN0Wxcj3x7L333ou6U6o7VO46Nc2Q6+EzdZ94Ol8lJRJT2Xr27Bn3E9fIstb6uXh86iYV13U0LJGMMcYYY4wxxoz1dLZEIqiHg3jIlz388MNpl112SVNOOWVk6ey+++4hG/r06RNihuweCjuzLcJk+umnj2lh5abFDRgwIB5LX1xOltLmm28egoAaRGRDIUl4nD2iguwl5NRaa61VKnBNTSUyh9gHeaInfSFTmLrGOp4gxuPke/funS655JLS+ZgWhShiX6TMYYcdVlpHJg6SgyeyTTvttJHJc8oppzS75jyYCsh35slu1BYis6b4fRA3tNl4440X3wl5hfzZb7/90kwzzRQFsanbxHS7QYMGxXVJaEnKUCcIecO2k08+ecgXjomMYRtkDXKG796rV6/I+MoLcRevkzbed999YxmCiswlFVin7W6//fZRvmYkEvfE6quvnpZffvk011xzpc0226yJNBpZP+dBDSWuvZihNCphiWSMMcYYY4wxZqynEhJJmT0tTZlyONobSKQVV1yx2fL2BhIOkdnSdMuOhiWSMcYYY4wxxpixnkpIJIKaOWSNFJc7HB2J4nS2jgYZU2RedWYWEmGJZIwxxhhjjDFmrKdSEonpTzwJjFo67S0w7XAUozMkElPlmJ6XT4HrrLBEMsYYY4wxxhgz1lMpiUR8+OGH6aSTTopCxsV1Dkdbg6lnU001VZpuuunSzjvvnB59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41XT1DiG2pjjsC39q6ev5cdXX0lMcT1sL8mEONp8883TXHPNFX0088wzp6WWWioNGDAgffnll6X7g304rqZFSlqpwDrbFSUjwfkQh8cde2zq2bNnmnHGGSOmnXbatOOOO8Z+o9IflkjGGGOMMcYYY8ZqKiWRFAzchwwZkk477bR08MEHp9122y1Ey0477ZR23nnndMABB0S2jgQFYuKxxx4LcbD77ruXtmVfslKee+650vQqZaZIQEnSKEuIZZJOZJogcxZYYIE03njjpXHHHTdtvPHGkZGE6JIYeuaZZ9LZZ5+ddthhhzgv75VVkwsYzsln3it76emnn05XXHFFWmONNdI000yTxhlnnJAVfMcXX3yxtK8Eko5XbLNKhASPxJGWaT3XTnZO37590y677BLtTtBfe+21V3yvF154oZRFhKQ79dRT0z777FPq00MOOSSde+650X+cg/Opb/J+0nnVrpI+ZAhxzCWXXDLEzqSTTpp69+6djj/++JIQUvYX5+G89NHf/va39OSTTzaRXPpe+fdFVpF5huxDVs0///xpsskmS+OPP37acsstS2Kto31iiWSMMcYYY4wxZqymUhKJ40jy3HfffWnfffeNTKCJJpooBA5Btg6ZJgMHDixljCB0mBJGltCss84awmfqqadOK6ywQoiDRx55JLJZOIfEhDJ7lOXCMokaHRdBxHGXXXbZkDscd6ONNgqJRBYR2yCw7r777rTddtuFWOAat91221KWC8dHYChDin1Yh3TgMzKJ4s3IDbJp2H+hhRZK++23X3r11Vdje7WLpFe1RBLnJDuI95JfeV8z5Q6BQ/vQ3uqjKaaYIs0777zpuOOOC9GkjC9kzB577BEiRtvRl4cddli64447YjtlGOXZQJxLGWV8b9qU7CFleHGvbLjhhmm22WYLicQxkUiSglw7/UXmEAKIfkQA3X777XEezqnsJLWr2lgZUzU1Nemoo45KK664YppkkklKx9A15RKqPWGJZIwxxhgzFtHwxQ/FRcYY0+2plERSRgcZJgiFJ554Igbq0003XZpggglCJs0333zp6KOPTvfff39J9Kig8jnnnJM22GCDNOGEE6ZVVlklnXjiiZFtgkBACnAOtlONHgmAPJNE7/WdyDJCHEgikYmEmGI6G8ekXg4ZS0gkSRTeS4AQOrbeS1Yo4wlZhDDr0aNH7M8r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LcvybL8lx6Ns27KCSKVSqVQqlUqlrU4c4J///OcNJEXe//KXv5w4yL/61a8mjnLa33DDDcNPf/rT9pr3N954Y9su7UvzUw8HelhgTH/yk59Mxrq3LPf6ox/9qL3/xS9+MWvOAhMs64FDaf0yVu6F3AOub+P84x//eNb177N1c0Efc2de+vnz+Yc//GFbdtlllw3vete7htNOO2245JJLZsEh2wbw9lAo96d92jcQNb4uXAP9vbsUmrnm+lkQ6fq/OWviCI+d46UyECggqIdFPlseOPTVr351Fkj6yle+0l6vvPLKBvm0s8x2y5cvn7QB/770pS9NzHx+/vOfb+az7S6//PJ2LNnefsfHWVY2lxVEKpVKpVKpVCptdQoo4pjGxpEVef+DH/ygOUdvf/vbh+OPP3448MADh8c//vHDfvvtNxx66KHDK17xiuEjH/nI8P3vf38CnJYyCmJ71cc+9rHhkEMOGZ7whCcMj33sY2fZ4x73uGbWmYMTTzxxOPfcc5ujCjL0MGoMOErrl7ECY6655pphampqOOOMM4bjjjtuOPjgg9vYP+lJTxqOPvro4eyzzx6+8IUvNLjaQzrbf/SjHx323nvvYZ999mk2nr8999yz2bHHHjtcfPHFc953AUq5L+3nM5/5zPDqV796eMYznjEccMABbf71/9SnPrXdh5deeunwne98px3/UoHDMUS69pTzJo7w2DneGixRQQE7YBHgY1lA09VXX93agkzWJSrpqquuanPwtre9bXjpS186PP3pTx/22muv4RGPeMTwyEc+cth///2Hk046aXjPe94zfO5zn2t9BFqNj6OsbF1WEKlUKpVKpVKptFUpzir1IKmHP145sFJtOLkvfOELh8MOO6w50IEaHKcHPOD/t3cmcFfPaf9/nmeesa/zGLswY4nKLoqUFjOy7yFlGSJKaJGQFgppoUKhlJIplRIhrXRLyb7MDBqyC+NvbKPb99/7quv4nt85d/c5932rc+4+79frep1zfts59+93fofvu+u6vvXD0UcfHdq3bx+ef/55y4bgWJIWuZMUPTxyDhER5557bthll13CRhttFH7/+9+HBg0apMQEkoIBbMOGDcORRx5pYm/s2LE24M2WHSNyA1mDWLjvvvtM8rRs2dKuA4+c9yZNmoTGjRubxLv77rtNPLi48/N+zz33hPXWWy/suuuu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;clipPath=inset(0.4% 57.33% 56.4% 0%);" parent="1" vertex="1"> + <mxGeometry x="122" y="82" width="279.7" height="118" as="geometry" /> + </mxCell> + <mxCell id="795Xv0Ka93fOG331V9Xn-20" value="" style="rounded=1;whiteSpace=wrap;html=1;arcSize=4;" parent="1" vertex="1"> + <mxGeometry x="621" y="79.5" width="284" height="151" as="geometry" /> + </mxCell> + <mxCell id="795Xv0Ka93fOG331V9Xn-2" value="" style="shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/png,iVBORw0KGgoAAAANSUhEUgAABJEAAAHoCAYAAAD5W34cAACAAElEQVR4XuydB5iV1bWGTTP2buyxRGNFNHYMEcUGoiiKgg0RFOzYqWIHLIiKPYiKEkWxoCioFCsR0RhbTJPYk1yvN7m5aQbcl3fBd7LPP2eQGc4MM+b7nmc95y9773//ex+G2e+stfZSybIsy7Isy7Isy7Isy7K+REsVL1iWZTVV/eMf/7DZbHU0y7Isy7Isy6qWDJEsy2o2YkH8y1/+0mazLaL99a9/Lf4zsizLsizLsqx6yxDJsqxmI0Mkm61uZohkWZZlWZZlVVOGSJZlNRsZItlsdTNDJMuyLMuyLKuaMkSyLKvZyBDJZqubGSJZlmVZlmVZ1ZQhkmVZzUaGSDZb3cwQybIsy7Isy6qmDJEsy2o2MkSy2epmhkiWZVmWZVlWNWWIZFlWs5Ehks1WNzNEsizLsizLsqopQyTLspqNDJFstrqZIZJlWZZlWZZVTRkiWZbVbGSIZLPVzQyRLMuyLMuyrGrKEMmyrGYjQySbrW5miGRZlmVZlmVVU4ZIlmU1Gxki2Wx1M0Mky7Isy7Isq5oyRLIsq9nIEMlmq5sZIlmWZVmWZVnVlCGSZVnNRg0FkV5//fX09ttv17huszWWvfnmm2HF64trhkiWZVmWZVlWNWWIZFlWs1FDQKRRo0alXXbZJb322mtxvvvuu6fvf//7DQaVZsyYkdZaa63UtWvXGvdqs2KdcePGpY4dO6allloqXXnllTXKyyZNmpROOOGEtOKKK6bWrVvXuF8ta+gx+0+wmTNnpl133TWNHTu2xr3FMUMky7Isy7Isq5oyRLIsq9mo2hBpwIABaeutt04vv/xy6RpA6Xvf+16DAZEXX3wxrbHGGqlz58417tVmleqMHz/+SyGSbOONN25QiNTQY/afYsBCYNzQoUNr3KuvGSJZlmVZlmVZ1ZQhkmVZzUbVhEgjR45M3/72t9O0adNq3GsOJoh01VVX1bhXtGpBJMKtttxyyxrXm5o1l35WsokTJ6ZvfetbacyYMTXu1ccMkSzLsizLsqxqyhDJsqxmo2pBpDfeeCM8e4444oga95qLCSJdffXVNe4VrVoQ6bLLLkurrLJKjetNzZpLP2uz9u3bpw033DD94he/qHGvrmaIZFmWZVmWZVVThkiWZTUbVQsi4b0DgCEfUn6d8DaAyze+8Y3StWuuuSatu+66Uf7kk09OW221VVpmmWXS6quvnvr16xdlpk+fnvbaa68os9lmm6W+ffuW6g8aNCi8Ylq2bBn5bo4//vjIUbTbbruVPfvyyy+P0LqddtopQppatWoV13/+859XrCOIdMghh0Sfll122bTaaqulww47rCw8D6sEkV566aXUqVOntNFGG8VzseJ45Na/f/+05pprxtjwLoSwcb3SmPXo0SOtsMIKAUJ69uwZz2DM+Bw+fHi6+eab0z777BOgZ+WVV069evUqexbw5Iwzzoh2W7RoEZ8aa4ywue7du0efd9hhh7TJJpuk3r17L7SfGDmlGFvGgs999903xoF7hAWut956MaZnnnlmPJd3oC36x3h36dIlvguMNfP9s5/9LOoOGzYsoORyyy2XjjzyyCiz9NJLp8033zzeNX+32uY5txEjRlT8ftbHDJEsy7Isy7KsasoQybKsZqNqQSRAC4t0ctAU7x111FFlQATr06dPlL/22mvTk08+mZ544omAE1//+tfT1KlTowyJuQEiQKRim9tss0168MEHS+eUyYHQfffdl772ta9F25wDSYrQp1hHEOmss85Kr776asAm4AOAA0CR1y1CpHfeeSdtt912AV8EnE4//fQAH0899VRZ3dwOPPDAih4+lcaM5wFWbrzxxvTII48EEFl77bWj3JAhQ9L9998fY9KmTZt4jwkTJpTqkgycvlCP87vvvrss/9M555yTvvvd78auepyTM4q+fVk/mTPGiuMXXnghffOb3wwYpftnn312POeiiy5KDzzwQPSROlwDhtEP+nnSSSfFtYEDB5bqduvWLa5Nnjw55o8wScaA933ssceizKLMM0YbembxXl3NEMmyLMuyLMuqpgyRLMtqNqoWRNp2221rQA9ZJSAiiPTTn/60dO2mm26Ka7feemvpGot+rt15552la4CS7bffvqy9IhC6+OKLA0gBQ3Qtf1alOrUl1j722GPjeg6tihAJjyjK4LWja88991xcwwMoby+32uBMpTHjeTw3v4YnF8/IPaUEiABgnBNqCAhr27ZtWV28mNi9jOMOHTqEFw8wTPfz8aqtn+xql59vsMEGaY899iidCyIBmHTtjjvuiGvk0NI14A/vm++wJ4iUt//MM89EObzFOF+UecbwcKKtSoCprmaIZFmWZVmWZVVThkiW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pTb79ttv0913350222yztMEGG6Sddtop7nmyiBCmhx56aNpoo41CDg0cODCkgn4j9AVZRv379499+/btm84555wQRtdcc0065ZRT0lZbbZVWWmmltMMOO6THH388ff3113EtOkYxM0r3BEHGCxlNyKPVV189ruHoo49OTzzxROm3pu9UnAZXabqqRMprGUko8TviPfIHGdivX7902mmnpRdffLE0yJdYQiLxmX6m7Q888MC05pprpkUWWSRtuOGG8Xt8+umnm53X4SgXlkjGGGOMMaZSjFaJpAGoptEMHTo0ps3wP/DHHntsDKLJhpl44oljEMZgS4Wf82NaIrWPltqN9//617/SnXfemQ477LC04oorpummmy6tv/76IfYYwIty+5tG8vbN2ygXSUgHxOiUU06ZVllllRA/CAUyhIgnn3wy7bXXXmmyySZLW2+9dbrxxhtLv5dPPvkkDR48OG288cZpoYUWCoH09ttvx3oKZr/66qshnshsWnTRRdOFF14Yx+Y6inIrD35/SBD6n/1322231KtXrzTjjDOmQw45JGSU9tc+lkiNoZpIKphNO5JhxHKmJSKCVl111ZCFNTU1sQ/bqNYR8fzzz8cUUoTRLrvsEr+/qaaaKq2wwgqRCWaJ5GhrWCIZY4wxxphKUTWJpKyFfKBJ1gt1jjTgZnB8/PHHx/Se5557LmohkZHBQAqJRIYEmUoamEs+mfZDu/F0tuKUJjJWTj/99HTUUUeFyGM62/LLL5+uuOKKGBAL9mffooSyVGpEwiZ/gqDah/udzBPaeeqpp46MIuQD/aFtmCp2wQUXxL1P+7Mtx2Lfzz77LF1++eVpm222CdFK3STkkfrzq6++iho6a6yxRlpwwQVDQCCW2JdtlIVUFEBcE78zppA+/PDDUQOJqYyIRKbG3X///U2+W7XEUU5XlUjIIGUV8TmXSkjxZZZZJi2xxBJp2223TY8++miTqWu1tbXxZx+y78gjj4xsJUQeGUlzzjlnyKSTTz45ss+K53U4yoUlkjHGGGOMqRRVkUiSRMpgECruy2CWoO4LUz/IRmKgzCsigzovyKU333yzySPoi1LKtA31h9qPoC8QDAx6yZZAbNTU1MR0q+WWWy716dMnxJ6knY6R92ee5dJdkWDRvV6uTVhOxhcFyxEH1DwiC4jtEDO6x5E5k046aUzpJDNIy9kW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Y8wYgyWSw9F6WCIZY4wxxphKYYlkjBljsERyOFoPSyRjjDHGGFMpLJFMh2loaCguMl2Iurq69L///S/997//jfedzejo/zFdIjGoLy5zODo7LJGMMcYYY0ylqJpEqq+vT3/88Ue8CgahfCZ4n38uLmMQXNx32LBhTZaZtkP70aZqY/qmKBqKkkD9ArQ9giLvAx2ruF93pHgv634WeVtqe6AP6Iv83qedWab91E+80v75cfP2ZxD51FNPpfvuuy999NFHZfslP4+uh+Pq3tA2nJ9zCbatlJwaGV1ZIjFg//DDD+OVtqfNeWUd7z/44IP07rvvxvt//vOfTYSS3ueDf46Vf9Z69uc963W+fF+d09F9wxLJGGOMMcZUiqpIJAahGhxrMK3BsOSQBqXff/99DIyee+659OCDD6Y77rgj3XLLLemee+6JATGDr59++im2t0TqGHn7v/POO+n+++9PN910U7r55pvTbbfdlm699dYmceedd6YHHnggPfPMM9E3//73v6OvJBbyPlT/dmfUBrmcURtpOZ//85//pB9//DEGey+++GJ6+OGHo63ph9tvvz09/vjj6b333ks//PBDiKT8OPDmm2+mG2+8MX4f6ive6/Npp52Wjj322HTmmWem1157rXRu9U8ui3Rs+hRJQV8jn/j96dj8Hl9++eX0+eefp6FDh8Y9oN9gftxK0lUlEoN1iR8+FyUSr0gk+pM/wySRcpH09ttvp2effTb+rLv22mvTJZdcki688MJ0wQUXxHvuCf4M5DiSR/n+uUAqrnN0r7BEMsYYY4wxlaIqEkkD6fwzg2JlsjD45PVf//pXeumll2LQtP3226eePXumaaedNk088cRprrnmSptuumm6+OKLQ3woW8O0n7w/BgwYkHr06JEmn3zyaOdJJpkkTTTRRKX3vNIH888/f9pqq63SueeeG4PjX3/9tcnx6A/1Z3eGe7KYcaflyhzSK3LojTfeSBdddFHaddddU+/evdMss8ySpphiijT11FOn1VdfPZ1xxhkxEGQfiSRxzDHHRF+1FBNOOGFaZJFF0vHHH59eeeWVJlKL90ggjim4buQQAmO77bZL88wzT5pqqqniPuAeWGqppVKfPn1CZnzyySel7ySZWPzOlaCrSqRiBhKSSEKJ5e+//36813Jtq/fs8/TTT6dLL7007bLLLmnFFVdMc845Z/wuib/85S9pyy23TGeddVZ64YUXIqOJY3388cclWZBnIClLqXidju4RlkjGGGOMMaZSjDaJlGcxAP/gJRtm5513jsHSnnvumQYNGpTOP//8dM4556Tddtstrb322mmVVVaJgRbZEL/99lvVp9OMDUja0X5klpx66qlpttlmi6B9aferrroqXXnllSHtkBUIvOWWWy6tv/76MZB96623SsfJM5Hy7JbuiESNMnNyUapg/XfffRfZXTvttFPaZJNNQtogjLi3kagHHHBA2mijjdIKK6yQ/va3v6VXX301joOwkfw54ogjQvLwuzjyyCOjv4grrrgijsMrmWX0MeeT9NH1qe/g999/j+04DkJr9913T6effnoIrssuuyzkIde06qqrpq233jp+l2RRcS25mKo0XV0i5cs0kCeri77ld0SbkhUm+VNbWxtC6LHHHksHH3xwWnPNNeM3uO+++8bv8KSTTor33AtIvG222SZdfvnl6fnnnw+JpKltOncuD4rX4+g+YYlkjDHGGGMqRdUkUj7A5LOyKggGxgy0GGSR/bDWWmvFIJXpHWQnEVdffXXaYostIiuCwSwZSwxiu3vmS0egL2hzpqXRD2RAkI204IILhqxjECLhgWhi2tR5552XlllmmRBN2267bRoyZEjpOBIREiTVykrpquSyiClreY0jLUcAIOOmm266yDo57rjjQib8/PPPMV3zySefTHvttVdkgm2++ebpuuuuK2UjcUzkDcKH/jjkkEPSE088Ufqd6fcloZf3R/5b1O+PQDKRgTT33HOn9dZbLw0cODDEiKatMc0UyYtMXGihhdIOO+wQg9RffvmlyXerNF1RIjFQZ4qZMop4pe00bY1pgfzZtdJKK4WA4886JBL7fvrppyGVmJbI+llnnTVtuOGGMX2NwT+/PfZHJi2wwAJp0UUXTQcddFB66KGHmgkjSSPOWbxGR/cKSyRjjDHGGFMpqiKRijDYVEYEA2wGzfxPPANp/rf9hBNOKGU5aBDMQIvlU045ZUgMarUwoHQmUvuh3fPsoZqampB38847b2TGMCCWbKB/mLpGf9DuM888c2TOUEdJx8rlhTORmhZ8V9vonldQG+eUU06JqUrULWLAh7BTphGC7+9//3tMSeM3QVZKMaOJ3wvShwwWpB5ySeeTcCJa6gv9ttiGwSa1k/h9HXbYYZH5xDUo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e8VVV12Vttlmm9ju8MMPb7a+M6Ij38fRPK6//vq0zjrrpJqammbrOiOaSSQGZoihP/74I/6X/5tvvmkWX3/9dfryyy/TZ599lr744ot473A4HNWO9957Lz333HMOh6NMPP/88+mll16K12eeeSY99dRT6ZFHHmnyl74xxhjTnaiUROLv2QUXXDCddtpppWUvvPBCmmGGGdLWW2/dbPvOiquvvjpNOumk6Ywzzmi2rqU46KCD0pRTTpkeeuih0rJ+/fq1KpEI/k1RSYnUke/jKB+33nprmmOOOdJdd93VbN2oRlmJRIbRd999l4466qi03nrrhcVae+21S7H++uunDTbYoNlyh8PhqGasuuqqaYUVVnA4HGVixRVXTCuttFK88nn55ZdPyy23XJO/9I0xxpjuRCUk0vvvv5969epV0YyjSockEjKsuC6PzpRIDzzwQHiF4vKuFmPKdZaLAQMGhMhEaBbXjUo0k0hkISGR+F9+JNH444+fxhtvvDTuuOPGDUNMOOGEaeKJJ451LHc4HI7REfozyeFwtBz8VvT3OH9vG2OMMd2VSkikY489Nv6ebU3AdOWQRCKTubguj86USJtuumkkrBSXd7UYU66zXPCUXqZUbrXVVs3WjUo0k0h66hpT1viffv7BOcEEE8SrhBKfEUn67HA4HA6Ho2sGf2dPNNFE8fc2YYwxxnRXKiGR5pprrrTEEks0Wfb222+nPfbYI6aNkQ3MMh5usdZaa4WEWX311UNMkCXC39HUJFL9moEDB6bpppsuttt2223T/fffH8uZfrbjjjvGGJwpaXzecsstYzvqHOncyKx11103romYd9550wUXXBDrLrvssshMZp+bbrqptI8kEtfMFCiuafbZZ0+HHnpo6eEcREsS6fzzz0+LLLJI6tmzZ5p77rnTdtttF22Qb6OgHAVZW/ybZOqpp069e/eO85b7PhQpp834jzDabPPNN0+zzDJLTHlbfPHFY8rWySefnJZZZplYNuuss8a15Oe777770sorr5zmn3/+CGYyPPbYY6X1t9xyS1pyySXjGFz/QgstlB5//PEWr5N97rzzzvi+tC/9O88885TqOI3qNe+6666RsMPxOc7000+fJplkksguf/jhh0vbjayf8+A7cLxXX3212bqORjOJpIK1v/32WzTejTfeGEFxJuKGG25o8t7hcDgcDkfXDf2dTVx55ZVN/tI3xhhjuhOdLZGoIYT02GGHHZqtIxZYYIGSRFIggVZZZZUQEYgj5AP/6YNA0TbIG4573nnnNdn30ksvTWuuuWbpM7UPixKJY2+yySZN9jnmmGNKnxEWLUkk/q3w7rvvppdffjntv//+sYxXbVdOIl1xxRWxjKlTfFYtqNayX8iQKWb4lPs+BFJr2WWXTYMHDw4pNGjQoGhHhBXf5+67745rn3POOaNoOE+mZT8yq6aaaqq00UYbxTIyc5Ax7Md7xB6C6NRTTy2dC1F0zz33jPQ6aVNEnj7vvPPO8Z92r7zyyihfM4HIWnjhheP6uc477rgjpN5ss80W/cM2rfWzAmFFm9JPxXUdjWYS6ffffw+BRPBekS/T++I2DofD4XA4ulbkf2cTxhhjTHelsyWSBEpReihakkhkFOXLyDpZdNFFS5+ROGSfLL300k22W2ONNeIpafpcTrrMOOOMaaeddip9Rk5wPH0emUQqFtamWDgSRtlI5SQS3w8JguzQMp7iRvYL9aLy4+VRTs6U+z4EQobspnwZ2VtcX77s4IMPjv1VA4jj8DmXQkg7lpEowwNHeJ9nAr355pshl/S53HXSTvn0xTPPPDOOg+zRso5eM4FEQkDl25111lmxnYq3t9bPCuRSsc9GNZpJpCafjDHGGGOMMcaYsYDOlkgSEtRFKq4j2iqRmE6FOMiXMZUtFyA8ZZXpWHnGSjnpsvHGG8dUqr/+9a8hSvLtifZIJF3DE088EZ/LSSQk02KLLdZkP4mRfNpYMcrJmXLfhygnZMjEYRpZvqz4PSjPw+d8ah1Z2ixj2iDii+lkU0wxRWRcDRkypMnxiHLXWYyzzz47jslUNS3r6DUT5SQSWWtst9tuu8Xn1vpZQbYT++25557N1nU0LJGMMcYYY4wxxoz1dLZEYhoUA/Tjjjuu2TpiVCTSgw8+GMfWtDAkx/HHH99km3LShUwa6uowTYt1SIv8Me/tkUiIB5ZzLXwuJ5H4PpwL6aFgKhZTr8j0yY+XRzk5U+77EB0VMrQ9oiW/NuoScW1nnHFGbPPoo4/GdVD7iH05LtcxsutkKuIWW2yRVltttXhqPTWJKi2RXn/99dgOecTn1vpZIWmWZy2NalgiGWOMMcYYY4wZ6+lsiXTOOefEAP3II49sto4YFYlEUBCaaW1MdaJwMkWb8/UtSReCqWQXXnhh1CeiWLaWt0cikeXC8hdffDE+l5NISIzid2xLlJMzLX2fjgoZPW0+36aleO2112J/ts/rORWvkzagT8gIUvZPNTKRyAZju+K901I/K5j+yH777LNPs3UdDUskY4wxxhhjjDFjPZ0tka699toYoOfFp/MYVYmkmks8yatcJkk56XL55Zc32aZ///6xjer8tEciITzmm2++0udyEmm55ZYLgZHXRGpL8MSySkskTat74IEHmmynePbZZ9O9997bZBmFy8lW0ufidfKQEo7Jq5ZVQyKp36iNxOfW+rm4X7mi2x0NSyRjjDHGGGOMMWM9nS2ReGw606U23XTTZuuIUZVIZLqQgcQ5ytXrKSddevToEbJHn7feeuso3K3PbZVIJ554Ypw3LzpdTiKRBcMysnd4mhjLqEFEDR9tUy4oMI1Qeeutt0qPny/3fYiOChnqSE022WRRswmRRHuSucO1Ib2oN0Wxcj3x7L333ou6U6o7VO46Nc2Q6+EzdZ94Ol8lJRJT2Xr27Bn3E9fIstb6uXh86iYV13U0LJGMMcYYY4wxxoz1dLZEIqiHg3jIlz388MNpl112SVNOOWVk6ey+++4hG/r06RNihuweCjuzLcJk+umnj2lh5abFDRgwIB5LX1xOltLmm28egoAaRGRDIUl4nD2iguwl5NRaa61VKnBNTSUyh9gHeaInfSFTmLrGOp4gxuPke/funS655JLS+ZgWhShiX6TMYYcdVlpHJg6SgyeyTTvttJHJc8oppzS75jyYCsh35slu1BYis6b4fRA3tNl4440X3wl5hfzZb7/90kwzzRQFsanbxHS7QYMGxXVJaEnKUCcIecO2k08+ecgXjomMYRtkDXKG796rV6/I+MoLcRevkzbed999YxmCiswlFVin7W6//fZRvmYkEvfE6quvnpZffvk011xzpc0226yJNBpZP+dBDSWuvZihNCphiWSMMcYYY4wxZqynEhJJmT0tTZlyONobSKQVV1yx2fL2BhIOkdnSdMuOhiWSMcYYY4wxxpixnkpIJIKaOWSNFJc7HB2J4nS2jgYZU2RedWYWEmGJZIwxxhhjjDFmrKdSEonpTzwJjFo67S0w7XAUozMkElPlmJ6XT4HrrLBEMsYYY4wxxhgz1lMpiUR8+OGH6aSTTopCxsV1Dkdbg6lnU001VZpuuunSzjvvnB59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41XT1DiG2pjjsC39q6ev5cdXX0lMcT1sL8mEONp8883TXHPNFX0088wzp6WWWioNGDAgffnll6X7g304rqZFSlqpwDrbFSUjwfkQh8cde2zq2bNnmnHGGSOmnXbatOOOO8Z+o9IflkjGGGOMMcYYY8ZqKiWRFAzchwwZkk477bR08MEHp9122y1Ey0477ZR23nnndMABB0S2jgQFYuKxxx4LcbD77ruXtmVfslKee+650vQqZaZIQEnSKEuIZZJOZJogcxZYYIE03njjpXHHHTdtvPHGkZGE6JIYeuaZZ9LZZ5+ddthhhzgv75VVkwsYzsln3it76emnn05XXHFFWmONNdI000yTxhlnnJAVfMcXX3yxtK8Eko5XbLNKhASPxJGWaT3XTnZO37590y677BLtTtBfe+21V3yvF154oZRFhKQ79dRT0z777FPq00MOOSSde+650X+cg/Opb/J+0nnVrpI+ZAhxzCWXXDLEzqSTTpp69+6djj/++JIQUvYX5+G89NHf/va39OSTTzaRXPpe+fdFVpF5huxDVs0///xpsskmS+OPP37acsstS2Kto31iiWSMMcYYY4wxZqymUhKJ40jy3HfffWnfffeNTKCJJpooBA5Btg6ZJgMHDixljCB0mBJGltCss84awmfqqadOK6ywQoiDRx55JLJZOIfEhDJ7lOXCMokaHRdBxHGXXXbZkDscd6ONNgqJRBYR2yCw7r777rTddtuFWOAat91221KWC8dHYChDin1Yh3TgMzKJ4s3IDbJp2H+hhRZK++23X3r11Vdje7WLpFe1RBLnJDuI95JfeV8z5Q6BQ/vQ3uqjKaaYIs0777zpuOOOC9GkjC9kzB577BEiRtvRl4cddli64447YjtlGOXZQJxLGWV8b9qU7CFleHGvbLjhhmm22WYLicQxkUiSglw7/UXmEAKIfkQA3X777XEezqnsJLWr2lgZUzU1Nemoo45KK664YppkkklKx9A15RKqPWGJZIwxxhgzFtHwxQ/FRcYY0+2plERSRgcZJgiFJ554Igbq0003XZpggglCJs0333zp6KOPTvfff39J9Kig8jnnnJM22GCDNOGEE6ZVVlklnXjiiZFtgkBACnAOtlONHgmAPJNE7/WdyDJCHEgikYmEmGI6G8ekXg4ZS0gkSRTeS4AQOrbeS1Yo4wlZhDDr0aNH7M8r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LcvybL8lx6Ns27KCSKVSqVQqlUqlrU4c4J///OcNJEXe//KXv5w4yL/61a8mjnLa33DDDcNPf/rT9pr3N954Y9su7UvzUw8HelhgTH/yk59Mxrq3LPf6ox/9qL3/xS9+MWvOAhMs64FDaf0yVu6F3AOub+P84x//eNb177N1c0Efc2de+vnz+Yc//GFbdtlllw3vete7htNOO2245JJLZsEh2wbw9lAo96d92jcQNb4uXAP9vbsUmrnm+lkQ6fq/OWviCI+d46UyECggqIdFPlseOPTVr351Fkj6yle+0l6vvPLKBvm0s8x2y5cvn7QB/770pS9NzHx+/vOfb+az7S6//PJ2LNnefsfHWVY2lxVEKpVKpVKpVCptdQoo4pjGxpEVef+DH/ygOUdvf/vbh+OPP3448MADh8c//vHDfvvtNxx66KHDK17xiuEjH/nI8P3vf38CnJYyCmJ71cc+9rHhkEMOGZ7whCcMj33sY2fZ4x73uGbWmYMTTzxxOPfcc5ujCjL0MGoMOErrl7ECY6655pphampqOOOMM4bjjjtuOPjgg9vYP+lJTxqOPvro4eyzzx6+8IUvNLjaQzrbf/SjHx323nvvYZ999mk2nr8999yz2bHHHjtcfPHFc953AUq5L+3nM5/5zPDqV796eMYznjEccMABbf71/9SnPrXdh5deeunwne98px3/UoHDMUS69pTzJo7w2DneGixRQQE7YBHgY1lA09VXX93agkzWJSrpqquuanPwtre9bXjpS186PP3pTx/22muv4RGPeMTwyEc+cth///2Hk046aXjPe94zfO5zn2t9BFqNj6OsbF1WEKlUKpVKpVKptFUpzir1IKmHP145sFJtOLkvfOELh8MOO6w50IEaHKcHPOD/t3cmcFfPaf9/nmeesa/zGLswY4nKLoqUFjOy7yFlGSJKaJGQFgppoUKhlJIplRIhrXRLyb7MDBqyC+NvbKPb99/7quv4nt85d/c5932rc+4+79frep1zfts59+93fofvu+u6vvXD0UcfHdq3bx+ef/55y4bgWJIWuZMUPTxyDhER5557bthll13CRhttFH7/+9+HBg0apMQEkoIBbMOGDcORRx5pYm/s2LE24M2WHSNyA1mDWLjvvvtM8rRs2dKuA4+c9yZNmoTGjRubxLv77rtNPLi48/N+zz33hPXWWy/suuuu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;clipPath=inset(42% 0.33% 0% 56.33%);" parent="1" vertex="1"> + <mxGeometry x="623.13" y="82.5" width="279.73" height="156" as="geometry" /> + </mxCell> </root> </mxGraphModel> </diagram> diff --git a/.docs/images/data-versioning.png b/.docs/images/data-versioning.png new file mode 100644 index 0000000000000000000000000000000000000000..01fe62af37e22534cca302ae9d184b215b31692b Binary files /dev/null and b/.docs/images/data-versioning.png differ diff --git a/.docs/images/screenshots/dashboard-managed.png b/.docs/images/screenshots/dashboard-managed.png new file mode 100644 index 0000000000000000000000000000000000000000..d5a0086672021d5b85c47f1d31f9952f38943b9d Binary files /dev/null and b/.docs/images/screenshots/dashboard-managed.png differ diff --git a/.docs/index.md b/.docs/index.md index 12f027bd103d4b8f595a2e10d261fd4b332c6673..6b4674bf5d8fd2d24ab48fb57fb767d8fcae0f2c 100644 --- a/.docs/index.md +++ b/.docs/index.md @@ -14,18 +14,18 @@ author: Martin Weise   -Documentation for version: [v1.7.2](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/releases). +Documentation for version: [v1.7.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 -[RDA WGDC](https://doi.org/10.1162/99608f92.be565013) on precisely identifying arbitrary subsets of data. +DBRepo is a repository for data in databases that cover the entire data life cycle supporting data evolution, -citation +and -versioning. It implements the query store of the [RDA WGDC](https://doi.org/10.1162/99608f92.be565013) on precisely +identifying arbitrary subsets of data. ## Why use DBRepo? -* **Built-in search** makes your dataset searchable without extra effort: most metadata is generated - automatically for data in your databases. +* **Built-in search** makes your dataset searchable without extra effort: metadata is generated automatically for data + in your databases. * **Citable datasets** adopting the recommendations of the RDA-WGDC, arbitrary subsets can be precisely, persistently - identified using system-versioned tables of MariaDB and the DataCite schema for minting DOIs. + identified using [data versioning](concepts/data-versioning) of MariaDB and the DataCite schema for minting DOIs. * **Powerful API for Data Scientists** with our strongly typed Python Library, Data Scientists can import, export and work with data from Jupyter Notebook or Python script, optionally using Pandas DataFrames. * **Cloud Native** our lightweight Helm chart allows for installations on any cloud provider or private-cloud setting diff --git a/.docs/kubernetes.md b/.docs/kubernetes.md index 0881fe7ca36f98701ac76f979f321d404fd3ef04..d551be901df071a59a10f39476ef85c65f6df12c 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.7.3" \ + --version "1.8.0" \ --create-namespace \ --cleanup-on-fail ``` diff --git a/.gitignore b/.gitignore index c7f9e185567df07cec5926685711393fa7bfa55d..7aac91c7e1b3e9cfbee5f51bf91d490b5b36c71b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ target/ !**/src/main/**/target/ !**/src/test/**/target/ +# TODO +.docker/ # generated ready schema.xsd diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 92270eee737c7a8dcdf4ee62d2184a260b29f300..e9aad03603c178c81758e50530ba956af53f608f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,18 +2,19 @@ variables: BUILD_VERSION: "" HOSTALIASES: "./hosts" DOCKER_HOST: "unix:///var/run/dind/docker.sock" + TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE: "/var/run/dind/docker.sock" DOCKER_VERSION: "27" - TESTCONTAINERS_RYUK_DISABLED: "false" ALPINE_VERSION: "3.21" PYTHON_VERSION: "3.11" JAVA_VERSION: "17" NODE_VERSION: "18" SONARQUBE_VERSION: "10.0" BUN_VERSION: "1.1.40" - DOC_VERSION: "1.7" - APP_VERSION: "1.7.3" - CHART_VERSION: "1.7.3" - SUPPORTED_VERSIONS: "[\"1.7.0\",\"1.7.1\",\"1.7.2\",\"1.7.3\"]" + DOC_VERSION: "1.8" + APP_VERSION: "1.8.0" + CHART_VERSION: "1.8.0" + SUPPORTED_VERSIONS: "1.7.3, 1.8.0" + MAINTAINED_SERVICES: "analyse-service, auth-service-init, dashboard-service, dashboard-service-init, data-service, metadata-service, search-db, search-service, search-service-init, storage-service-init, ui" 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. @@ -74,13 +75,13 @@ lint-docker-compose: - "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 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-metric-db'" - - "IGNORE_IMAGE=1 bash .scripts/check-service.sh 'dbrepo-search-db'" + - "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 IGNORE_IMAGE=1 bash .scripts/check-service.sh 'dbrepo-storage-service-init'" + - "IGNORE_IMAGE=1 bash .scripts/check-service.sh 'dbrepo-dashboard-service-init'" - "IGNORE_IMAGE=1 bash .scripts/check-service.sh 'dbrepo-ui'" - - "IGNORE_VOLUMES=1 bash .scripts/check-service.sh 'dbrepo-upload-service'" lint-helm-chart: image: docker.io/alpine:${ALPINE_VERSION} @@ -149,19 +150,20 @@ build-metadata-service: only: - merge_requests - master + needs: + - build-java-lib + dependencies: + - build-java-lib script: - - "mvn -f ./dbrepo-metadata-service/pom.xml clean install $MAVEN_OPTS -DskipTests" + - "mvn -f ./dbrepo-metadata-service/pom.xml clean package $MAVEN_OPTS -DskipTests" # Compiled classes are needed for SonarQube in later stages artifacts: when: always paths: - - ./dbrepo-metadata-service/test/target/classes - - ./dbrepo-metadata-service/services/target/classes + - ./dbrepo-metadata-service/oai/target/classes - ./dbrepo-metadata-service/repositories/target/classes - ./dbrepo-metadata-service/rest-service/target/classes - - ./dbrepo-metadata-service/api/target/classes - - ./dbrepo-metadata-service/oai/target/classes - - ./dbrepo-metadata-service/entities/target/classes + - ./dbrepo-metadata-service/services/target/classes expire_in: 1 days build-analyse-service: @@ -176,7 +178,7 @@ build-analyse-service: - "pip install pipenv" - "pipenv install gunicorn && pipenv install --dev --system --deploy" -build-lib: +build-python-lib: image: docker.io/python:${PYTHON_VERSION}-alpine${ALPINE_VERSION} stage: build only: @@ -188,6 +190,19 @@ build-lib: - "pip install pipenv" - "pipenv install gunicorn && pipenv install --dev --system --deploy" +build-java-lib: + image: maven:3-openjdk-${JAVA_VERSION} + stage: build + only: + - merge_requests + - master + script: + - "mvn -f ./lib/java/dbrepo-core/pom.xml clean install $MAVEN_OPTS -DskipTests" + artifacts: + when: always + paths: + - ./lib/java/dbrepo-core/target/classes + build-data-service: image: maven:3-openjdk-${JAVA_VERSION} stage: build @@ -195,11 +210,9 @@ build-data-service: - merge_requests - master needs: - - build-metadata-service + - build-java-lib dependencies: - - build-metadata-service - before_script: - - "mvn -f ./dbrepo-metadata-service/pom.xml clean install $MAVEN_OPTS -DskipTests" + - build-java-lib script: - "mvn -f ./dbrepo-data-service/pom.xml clean package $MAVEN_OPTS -DskipTests" # Compiled classes are needed for SonarQube in later stages @@ -231,6 +244,17 @@ build-search-service: script: - "cd dbrepo-search-service && pipenv install --system --deploy" +build-dashboard-service: + image: docker.io/python:${PYTHON_VERSION}-alpine${ALPINE_VERSION} + stage: build + only: + - merge_requests + - master + before_script: + - "pip install pipenv" + script: + - "cd dbrepo-dashboard-service && pipenv install --system --deploy" + build-images: image: docker.io/docker:${DOCKER_VERSION}-dind stage: build @@ -241,8 +265,9 @@ build-images: - "apk add --no-cache make" - echo "$CI_REGISTRY_PASSWORD" | docker login --username "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY_URL script: - - docker build -q --network=host -t dbrepo-metadata-service:build --target build dbrepo-metadata-service - - docker build -q --network=host -t dbrepo-data-service:build --target build dbrepo-data-service + - docker build --network=host -t dbrepo-core:build --target build ./lib/java/dbrepo-core + - docker build --network=host -t dbrepo-data-service:build --target build dbrepo-data-service + - docker build --network=host -t dbrepo-metadata-service:build --target build dbrepo-metadata-service - docker compose build -q --parallel build-helm: @@ -266,9 +291,9 @@ test-metadata-service: - merge_requests - master needs: - - build-metadata-service + - build-java-lib dependencies: - - build-metadata-service + - build-java-lib script: - "mvn -f ./dbrepo-metadata-service/pom.xml clean test verify $MAVEN_OPTS" - "cat ./dbrepo-metadata-service/report/target/site/jacoco-aggregate/index.html | grep -o 'Total[^%]*%' | sed 's/<.*>/ /; s/Total/Jacoco Coverage Total:/'" @@ -321,7 +346,7 @@ test-analyse-service: script: - "pip install pipenv" - "pipenv install gunicorn && pipenv install --dev --system --deploy" - - cd ./dbrepo-analyse-service/ && coverage run --rcfile=.coveragerc -m pytest tests/test_determine_dt.py tests/test_determine_pk.py tests/test_s3_client.py && coverage html && coverage xml && coverage report > ./coverage.txt + - cd ./dbrepo-analyse-service/ && coverage run --rcfile=.coveragerc -m pytest tests/test_determine_dt.py tests/test_determine_pk.py && coverage html && coverage xml && coverage report > ./coverage.txt - "cat ./coverage.txt | grep -o 'TOTAL[^%]*%'" artifacts: when: always @@ -370,17 +395,10 @@ test-search-service: - build-search-service dependencies: - build-search-service - before_script: - - "cp -r ./dbrepo-search-service/init/clients ./dbrepo-search-service" - - "cp -r ./dbrepo-search-service/init/omlib ./dbrepo-search-service" - - "cp -r ./dbrepo-search-service/init/tests/rsa ./dbrepo-search-service/tests" - - "cp ./dbrepo-search-service/init/tests/test_keycloak_client.py ./dbrepo-search-service/tests" - - "cp ./dbrepo-search-service/init/tests/test_opensearch_client.py ./dbrepo-search-service/tests" - - "cp ./dbrepo-search-service/init/friendly_names_overrides.json ./dbrepo-search-service/friendly_names_overrides.json" script: - "pip install pipenv" - "pipenv install gunicorn && pipenv install --dev --system --deploy" - - cd ./dbrepo-search-service/ && coverage run --rcfile=.coveragerc -m pytest tests/test_app.py tests/test_jwt.py tests/test_opensearch_client.py tests/test_keycloak_client.py && coverage html && coverage xml && coverage report > ./coverage.txt + - cd ./dbrepo-search-service/ && coverage run --rcfile=.coveragerc -m pytest tests/test_app.py && coverage html && coverage xml && coverage report > ./coverage.txt - "cat ./coverage.txt | grep -o 'TOTAL[^%]*%'" artifacts: when: always @@ -392,6 +410,60 @@ test-search-service: junit: ./dbrepo-search-service/coverage.xml coverage: '/TOTAL.*?([0-9]{1,3})%/' +test-dashboard-service: + image: docker.io/python:${PYTHON_VERSION}-alpine${ALPINE_VERSION} + stage: test + only: + - merge_requests + - master + variables: + PIPENV_PIPFILE: "./dbrepo-dashboard-service/Pipfile" + needs: + - build-dashboard-service + dependencies: + - build-dashboard-service + script: + - "pip install pipenv" + - "pipenv install gunicorn && pipenv install --dev --system --deploy" + - cd ./dbrepo-dashboard-service/ && coverage run --rcfile=.coveragerc -m pytest tests/test_integration_app.py && coverage html && coverage xml && coverage report > ./coverage.txt + - "cat ./coverage.txt | grep -o 'TOTAL[^%]*%'" + artifacts: + when: always + paths: + - ./dbrepo-dashboard-service/coverage.xml + - ./dbrepo-dashboard-service/coverage.txt + expire_in: 1 days + reports: + junit: ./dbrepo-dashboard-service/coverage.xml + coverage: '/TOTAL.*?([0-9]{1,3})%/' + +test-dashboard-service-init: + image: docker.io/python:${PYTHON_VERSION}-alpine${ALPINE_VERSION} + stage: test + only: + - merge_requests + - master + variables: + PIPENV_PIPFILE: "./dbrepo-dashboard-service/init/Pipfile" + needs: + - build-dashboard-service + dependencies: + - build-dashboard-service + script: + - "pip install pipenv" + - "pipenv install gunicorn && pipenv install --dev --system --deploy" + - cd ./dbrepo-dashboard-service/init/ && coverage run --rcfile=.coveragerc -m pytest tests/test_app.py && coverage html && coverage xml && coverage report > ./coverage.txt + - "cat ./coverage.txt | grep -o 'TOTAL[^%]*%'" + artifacts: + when: always + paths: + - ./dbrepo-dashboard-service/init/coverage.xml + - ./dbrepo-dashboard-service/init/coverage.txt + expire_in: 1 days + reports: + junit: ./dbrepo-dashboard-service/init/coverage.xml + coverage: '/TOTAL.*?([0-9]{1,3})%/' + test-search-service-init: image: docker.io/python:${PYTHON_VERSION}-alpine${ALPINE_VERSION} stage: test @@ -407,7 +479,7 @@ test-search-service-init: script: - "pip install pipenv" - "pipenv install gunicorn && pipenv install --dev --system --deploy" - - cd ./dbrepo-search-service/init/ && coverage run --rcfile=.coveragerc -m pytest tests/test_app.py tests/test_keycloak_client.py tests/test_opensearch_client.py && coverage html && coverage xml && coverage report > ./coverage.txt + - cd ./dbrepo-search-service/init/ && coverage run --rcfile=.coveragerc -m pytest tests/test_unit_app.py && coverage html && coverage xml && coverage report > ./coverage.txt - "cat ./coverage.txt | grep -o 'TOTAL[^%]*%'" artifacts: when: always @@ -419,7 +491,7 @@ test-search-service-init: junit: ./dbrepo-search-service/coverage.xml coverage: '/TOTAL.*?([0-9]{1,3})%/' -test-lib: +test-python-lib: image: docker.io/python:${PYTHON_VERSION}-alpine${ALPINE_VERSION} stage: test only: @@ -428,9 +500,9 @@ test-lib: variables: PIPENV_PIPFILE: "./lib/python/Pipfile" needs: - - build-lib + - build-python-lib dependencies: - - build-lib + - build-python-lib script: - "pip install pipenv" - "pipenv install gunicorn && pipenv install --dev --system --deploy" @@ -490,7 +562,7 @@ release-images: - test-analyse-service - test-auth-service-init - test-data-service - - test-lib + - test-python-lib - test-metadata-service - test-search-service - test-search-service-init @@ -504,29 +576,32 @@ release-images: - "docker logout ${CI_REGISTRY2_URL}" - "echo ${CI_REGISTRY2_PASSWORD} | docker login --username ${CI_REGISTRY2_USER} --password-stdin ${CI_REGISTRY2_URL}" script: - - docker build -q --network=host -t dbrepo-metadata-service:build --target build dbrepo-metadata-service - - docker build -q --network=host -t dbrepo-data-service:build --target build dbrepo-data-service + - docker build --network=host -t dbrepo-core:build --target build ./lib/java/dbrepo-core + - docker build --network=host -t dbrepo-data-service:build --target build dbrepo-data-service + - docker build --network=host -t dbrepo-metadata-service:build --target build dbrepo-metadata-service - docker compose build -q --parallel - docker tag dbrepo-analyse-service:latest "${CI_REGISTRY2_URL}/analyse-service:${APP_VERSION}${BUILD_VERSION}" + - docker tag dbrepo-auth-service-init:latest "${CI_REGISTRY2_URL}/auth-service-init:${APP_VERSION}${BUILD_VERSION}" - docker tag dbrepo-dashboard-service:latest "${CI_REGISTRY2_URL}/dashboard-service:${APP_VERSION}${BUILD_VERSION}" - - docker tag dbrepo-ui:latest "${CI_REGISTRY2_URL}/ui:${APP_VERSION}${BUILD_VERSION}" + - docker tag dbrepo-dashboard-service-init:latest "${CI_REGISTRY2_URL}/dashboard-service-init:${APP_VERSION}${BUILD_VERSION}" - docker tag dbrepo-data-service:latest "${CI_REGISTRY2_URL}/data-service:${APP_VERSION}${BUILD_VERSION}" - - docker tag dbrepo-auth-service-init:latest "${CI_REGISTRY2_URL}/auth-service-init:${APP_VERSION}${BUILD_VERSION}" - docker tag dbrepo-metadata-service:latest "${CI_REGISTRY2_URL}/metadata-service:${APP_VERSION}${BUILD_VERSION}" - docker tag dbrepo-search-db:latest "${CI_REGISTRY2_URL}/search-db:${APP_VERSION}${BUILD_VERSION}" - docker tag dbrepo-search-service:latest "${CI_REGISTRY2_URL}/search-service:${APP_VERSION}${BUILD_VERSION}" - docker tag dbrepo-search-service-init:latest "${CI_REGISTRY2_URL}/search-service-init:${APP_VERSION}${BUILD_VERSION}" - docker tag dbrepo-storage-service-init:latest "${CI_REGISTRY2_URL}/storage-service-init:${APP_VERSION}${BUILD_VERSION}" + - docker tag dbrepo-ui:latest "${CI_REGISTRY2_URL}/ui:${APP_VERSION}${BUILD_VERSION}" - docker push "${CI_REGISTRY2_URL}/analyse-service:${APP_VERSION}${BUILD_VERSION}" + - docker push "${CI_REGISTRY2_URL}/auth-service-init:${APP_VERSION}${BUILD_VERSION}" - docker push "${CI_REGISTRY2_URL}/dashboard-service:${APP_VERSION}${BUILD_VERSION}" - - docker push "${CI_REGISTRY2_URL}/ui:${APP_VERSION}${BUILD_VERSION}" + - docker push "${CI_REGISTRY2_URL}/dashboard-service-init:${APP_VERSION}${BUILD_VERSION}" - docker push "${CI_REGISTRY2_URL}/data-service:${APP_VERSION}${BUILD_VERSION}" - - docker push "${CI_REGISTRY2_URL}/auth-service-init:${APP_VERSION}${BUILD_VERSION}" - docker push "${CI_REGISTRY2_URL}/search-db:${APP_VERSION}${BUILD_VERSION}" - docker push "${CI_REGISTRY2_URL}/metadata-service:${APP_VERSION}${BUILD_VERSION}" - docker push "${CI_REGISTRY2_URL}/search-service:${APP_VERSION}${BUILD_VERSION}" - docker push "${CI_REGISTRY2_URL}/search-service-init:${APP_VERSION}${BUILD_VERSION}" - docker push "${CI_REGISTRY2_URL}/storage-service-init:${APP_VERSION}${BUILD_VERSION}" + - docker push "${CI_REGISTRY2_URL}/ui:${APP_VERSION}${BUILD_VERSION}" release-helm: stage: release @@ -621,13 +696,21 @@ verify-dist: image: docker.io/alpine:${ALPINE_VERSION} stage: verify only: - refs: - - /^release-.*/ + - /^release-.*/ + - master before_script: - "apk add curl" script: - "curl -v --output /dev/null --fail https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/${APP_VERSION}/dist.tar.gz" +verify-images: + image: docker.io/docker:${DOCKER_VERSION}-dind + stage: verify + only: + - master + script: + - bash ./.gitlab/check-unsupported-images.sh + scan-sonarqube: image: sonarsource/sonar-scanner-cli:${SONARQUBE_VERSION} stage: scan @@ -635,10 +718,10 @@ scan-sonarqube: - master needs: - build-data-service - - build-metadata-service + - build-java-lib dependencies: - build-data-service - - build-metadata-service + - build-java-lib script: - 'sonar-scanner -Dsonar.token="${CI_SONAR_TOKEN}"' allow_failure: true diff --git a/.gitlab/check-supported-images.sh b/.gitlab/check-supported-images.sh new file mode 100755 index 0000000000000000000000000000000000000000..2f1f804e5dd5edc0d0b252ed6d1ecfed33863e69 --- /dev/null +++ b/.gitlab/check-supported-images.sh @@ -0,0 +1,30 @@ +#!/bin/bash +echo "Starting registry check ..." + +if [ -z $SUPPORTED_VERSIONS ]; then + echo "[ERROR] Missing environment variable SUPPORTED_VERSIONS" > /dev/stderr + exit 1 +elif [ -z $MAINTAINED_SERVICES ]; then + echo "[ERROR] Missing environment variable MAINTAINED_SERVICES" > /dev/stderr + exit 1 +elif [ -z $CI_REGISTRY2_URL ]; then + echo "[ERROR] Missing environment variable CI_REGISTRY2_URL" > /dev/stderr + exit 1 +fi + +VERSIONS=(${SUPPORTED_VERSIONS//,/ }) +SERVICES=(${MAINTAINED_SERVICES//,/ }) + +for SERVICE in "${SERVICES[@]}"; do + TAGS=$(regctl tag ls "${CI_REGISTRY2_URL}/${SERVICE}") + for VERSION in "${VERSIONS[@]}"; do + if [[ "$VERSION" == "$APP_VERSION" ]]; then + continue + fi + if [[ ! "${TAGS[*]}" =~ $VERSION ]]; then + >&2 echo "[ERROR] Failed to find image: ${CI_REGISTRY2_URL}/${SERVICE}:${VERSION}" + exit 1 + fi + done +done +echo "[INFO] Finished successfully." diff --git a/.gitlab/remove-unsupported-images.sh b/.gitlab/remove-unsupported-images.sh index ccfe3f7df828e6f4b6ec5279b894ea842a2efe9f..d3914e4a7f5dac2f54269db0e9e4d9a29d61b044 100755 --- a/.gitlab/remove-unsupported-images.sh +++ b/.gitlab/remove-unsupported-images.sh @@ -1,26 +1,28 @@ #!/bin/bash -declare -A services -services[0]=analyse-service -services[1]=auth-service-init -services[2]=dashboard-service -services[3]=data-service -services[4]=metadata-service -services[5]=search-db -services[6]=search-service -services[7]=search-service-init -services[8]=storage-service-init -services[9]=ui - echo "Starting registry housekeeping ..." -for key in "${!services[@]}"; do - echo "Checking ${CI_REGISTRY2_URL}/${services[$key]} tags ..." - TAGS=$(regctl tag ls ${CI_REGISTRY2_URL}/${services[$key]}) - for tag in $TAGS; do - res=$(echo "${SUPPORTED_VERSIONS}" | grep "$tag") - if [[ -z $res ]]; then - regctl tag rm ${CI_REGISTRY2_URL}/${services[$key]}:$tag - echo "Deleted unsupported tag ${CI_REGISTRY2_URL}/${services[$key]}:$tag" - fi +if [ -z $SUPPORTED_VERSIONS ]; then + echo "[ERROR] Missing environment variable SUPPORTED_VERSIONS" > /dev/stderr + exit 1 +elif [ -z $MAINTAINED_SERVICES ]; then + echo "[ERROR] Missing environment variable MAINTAINED_SERVICES" > /dev/stderr + exit 1 +elif [ -z $CI_REGISTRY2_URL ]; then + echo "[ERROR] Missing environment variable CI_REGISTRY2_URL" > /dev/stderr + exit 1 +fi + +VERSIONS=(${SUPPORTED_VERSIONS//,/ }) +SERVICES=(${MAINTAINED_SERVICES//,/ }) + +for SERVICE in "${SERVICES[@]}"; do + TAGS=$(regctl tag ls "${CI_REGISTRY2_URL}/${SERVICE}") + TAGS=(${TAGS//\n/ }) + for TAG in "${TAGS[@]}"; do + if [[ ! "${VERSIONS[*]}" =~ $TAG ]]; then + regctl tag rm ${CI_REGISTRY2_URL}/${SERVICE}:$TAG + echo "[INFO] Deleted unsupported tag ${CI_REGISTRY2_URL}/${SERVICE}:$TAG" + fi done done +echo "[INFO] Finished successfully." diff --git a/.scripts/check-service.sh b/.scripts/check-service.sh index 1af6d7eea1556ca90f30b0abbe10abe2b623d140..f5d144abaaac4ce6da02d1ffc2f5151f6329e14e 100755 --- a/.scripts/check-service.sh +++ b/.scripts/check-service.sh @@ -7,6 +7,7 @@ compare "services.$1.restart" compare "services.$1.container_name" compare "services.$1.hostname" compare "services.$1.environment" +compare "services.$1.depends_on" compare "services.$1.healthcheck" compare "services.$1.logging" diff --git a/Makefile b/Makefile index b32b8e6e15704dfb9621a506af1a9cf59e225c32..00c00d62087dbabd089c90f748232004ca2b0b5b 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ .PHONY: all -APP_VERSION ?= 1.7.3 -CHART_VERSION ?= 1.7.3 +APP_VERSION ?= 1.8.0 +CHART_VERSION ?= 1.8.0 REPOSITORY_URL ?= registry.datalab.tuwien.ac.at/dbrepo .PHONY: all diff --git a/dbrepo-analyse-service/.gitignore b/dbrepo-analyse-service/.gitignore index 4ae9f6930d70a7da1f7b06d28fc7dcecf7ce24c4..daf1899e30f293bd44dfbad3d66a04205d91d0a8 100644 --- a/dbrepo-analyse-service/.gitignore +++ b/dbrepo-analyse-service/.gitignore @@ -43,3 +43,4 @@ htmlcov/ .coverage .coverage.* *,cover +coverage.xml diff --git a/dbrepo-analyse-service/Dockerfile b/dbrepo-analyse-service/Dockerfile index 1432cd52c6b395ad4fb20c2802d61c1a48a724fa..a140efd513760a68af887a2474591bc2f6fb20d3 100644 --- a/dbrepo-analyse-service/Dockerfile +++ b/dbrepo-analyse-service/Dockerfile @@ -15,16 +15,15 @@ RUN pip install pipenv && \ pipenv install gunicorn && \ pipenv install --system --deploy -RUN adduser -D analyse-service --uid 1000 +RUN adduser -D dbrepo --uid 1001 WORKDIR /app -USER 1000 +USER 1001 -COPY --chown=1000 ./api ./api -COPY --chown=1000 ./as-yml ./as-yml -COPY --chown=1000 ./clients ./clients -COPY --chown=1000 ./*.py ./ +COPY --chown=1001 ./api ./api +COPY --chown=1001 ./as-yml ./as-yml +COPY --chown=1001 ./*.py ./ # non-root port EXPOSE 8080 diff --git a/dbrepo-analyse-service/Pipfile b/dbrepo-analyse-service/Pipfile index 0a8881e78e83a9a720a58c94ec91ed4967a73651..3e3dfe11e87a7fea0449ce17b832f975eb21fb1b 100644 --- a/dbrepo-analyse-service/Pipfile +++ b/dbrepo-analyse-service/Pipfile @@ -21,7 +21,7 @@ numpy = "*" pandas = "*" minio = "*" pydantic = "*" -dbrepo = {path = "./lib/dbrepo-1.7.3.tar.gz"} +dbrepo = {path = "./lib/dbrepo-1.8.0.tar.gz"} opensearch-py = "*" [dev-packages] diff --git a/dbrepo-analyse-service/Pipfile.lock b/dbrepo-analyse-service/Pipfile.lock index 7f5a9de58ad9d12ddcda7224402fe0bf134c3a5c..d9f5a1cdbc050c34b3c3927257ec61e037ddf07e 100644 --- a/dbrepo-analyse-service/Pipfile.lock +++ b/dbrepo-analyse-service/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "6af4b2ce324df97cc0877129f7986549d6e07a877998431609e062e2b63a40ca" + "sha256": "b7c8a1b53fbd95813c0accfa6e5351d63059e0ad816bff0a1cb82e5fb7beced2" }, "pipfile-spec": 6, "requires": { @@ -26,90 +26,90 @@ }, "aiohttp": { "hashes": [ - "sha256:04eb541ce1e03edc1e3be1917a0f45ac703e913c21a940111df73a2c2db11d73", - "sha256:05582cb2d156ac7506e68b5eac83179faedad74522ed88f88e5861b78740dc0e", - "sha256:0a29be28e60e5610d2437b5b2fed61d6f3dcde898b57fb048aa5079271e7f6f3", - "sha256:0b2501f1b981e70932b4a552fc9b3c942991c7ae429ea117e8fba57718cdeed0", - "sha256:0df3788187559c262922846087e36228b75987f3ae31dd0a1e5ee1034090d42f", - "sha256:12c5869e7ddf6b4b1f2109702b3cd7515667b437da90a5a4a50ba1354fe41881", - "sha256:14fc03508359334edc76d35b2821832f092c8f092e4b356e74e38419dfe7b6de", - "sha256:1a7169ded15505f55a87f8f0812c94c9412623c744227b9e51083a72a48b68a5", - "sha256:1c68e41c4d576cd6aa6c6d2eddfb32b2acfb07ebfbb4f9da991da26633a3db1a", - "sha256:20412c7cc3720e47a47e63c0005f78c0c2370020f9f4770d7fc0075f397a9fb0", - "sha256:22a8107896877212130c58f74e64b77f7007cb03cea8698be317272643602d45", - "sha256:28a3d083819741592685762d51d789e6155411277050d08066537c5edc4066e6", - "sha256:2b86efe23684b58a88e530c4ab5b20145f102916bbb2d82942cafec7bd36a647", - "sha256:2d0b46abee5b5737cb479cc9139b29f010a37b1875ee56d142aefc10686a390b", - "sha256:321238a42ed463848f06e291c4bbfb3d15ba5a79221a82c502da3e23d7525d06", - "sha256:3a8a0d127c10b8d89e69bbd3430da0f73946d839e65fec00ae48ca7916a31948", - "sha256:3a8b0321e40a833e381d127be993b7349d1564b756910b28b5f6588a159afef3", - "sha256:3b420d076a46f41ea48e5fcccb996f517af0d406267e31e6716f480a3d50d65c", - "sha256:3b512f1de1c688f88dbe1b8bb1283f7fbeb7a2b2b26e743bb2193cbadfa6f307", - "sha256:413fe39fd929329f697f41ad67936f379cba06fcd4c462b62e5b0f8061ee4a77", - "sha256:41cf0cefd9e7b5c646c2ef529c8335e7eafd326f444cc1cdb0c47b6bc836f9be", - "sha256:4848ae31ad44330b30f16c71e4f586cd5402a846b11264c412de99fa768f00f3", - "sha256:4b0a200e85da5c966277a402736a96457b882360aa15416bf104ca81e6f5807b", - "sha256:4e2e8ef37d4bc110917d038807ee3af82700a93ab2ba5687afae5271b8bc50ff", - "sha256:4edcbe34e6dba0136e4cabf7568f5a434d89cc9de5d5155371acda275353d228", - "sha256:51ba80d473eb780a329d73ac8afa44aa71dfb521693ccea1dea8b9b5c4df45ce", - "sha256:5409a59d5057f2386bb8b8f8bbcfb6e15505cedd8b2445db510563b5d7ea1186", - "sha256:572def4aad0a4775af66d5a2b5923c7de0820ecaeeb7987dcbccda2a735a993f", - "sha256:599b66582f7276ebefbaa38adf37585e636b6a7a73382eb412f7bc0fc55fb73d", - "sha256:59a05cdc636431f7ce843c7c2f04772437dd816a5289f16440b19441be6511f1", - "sha256:602d4db80daf4497de93cb1ce00b8fc79969c0a7cf5b67bec96fa939268d806a", - "sha256:65c75b14ee74e8eeff2886321e76188cbe938d18c85cff349d948430179ad02c", - "sha256:69bb252bfdca385ccabfd55f4cd740d421dd8c8ad438ded9637d81c228d0da49", - "sha256:6d3986112e34eaa36e280dc8286b9dd4cc1a5bcf328a7f147453e188f6fe148f", - "sha256:6dd9766da617855f7e85f27d2bf9a565ace04ba7c387323cd3e651ac4329db91", - "sha256:70ab0f61c1a73d3e0342cedd9a7321425c27a7067bebeeacd509f96695b875fc", - "sha256:749f1eb10e51dbbcdba9df2ef457ec060554842eea4d23874a3e26495f9e87b1", - "sha256:781c8bd423dcc4641298c8c5a2a125c8b1c31e11f828e8d35c1d3a722af4c15a", - "sha256:7e7abe865504f41b10777ac162c727af14e9f4db9262e3ed8254179053f63e6d", - "sha256:7f2dadece8b85596ac3ab1ec04b00694bdd62abc31e5618f524648d18d9dd7fa", - "sha256:86135c32d06927339c8c5e64f96e4eee8825d928374b9b71a3c42379d7437058", - "sha256:8778620396e554b758b59773ab29c03b55047841d8894c5e335f12bfc45ebd28", - "sha256:87f0e003fb4dd5810c7fbf47a1239eaa34cd929ef160e0a54c570883125c4831", - "sha256:8aa5c68e1e68fff7cd3142288101deb4316b51f03d50c92de6ea5ce646e6c71f", - "sha256:8d14e274828561db91e4178f0057a915f3af1757b94c2ca283cb34cbb6e00b50", - "sha256:8d1dd75aa4d855c7debaf1ef830ff2dfcc33f893c7db0af2423ee761ebffd22b", - "sha256:92007c89a8cb7be35befa2732b0b32bf3a394c1b22ef2dff0ef12537d98a7bda", - "sha256:92868f6512714efd4a6d6cb2bfc4903b997b36b97baea85f744229f18d12755e", - "sha256:948abc8952aff63de7b2c83bfe3f211c727da3a33c3a5866a0e2cf1ee1aa950f", - "sha256:95d7787f2bcbf7cb46823036a8d64ccfbc2ffc7d52016b4044d901abceeba3db", - "sha256:997b57e38aa7dc6caab843c5e042ab557bc83a2f91b7bd302e3c3aebbb9042a1", - "sha256:99b8bbfc8111826aa8363442c0fc1f5751456b008737ff053570f06a151650b3", - "sha256:9e73fa341d8b308bb799cf0ab6f55fc0461d27a9fa3e4582755a3d81a6af8c09", - "sha256:a0d2c04a623ab83963576548ce098baf711a18e2c32c542b62322a0b4584b990", - "sha256:a40087b82f83bd671cbeb5f582c233d196e9653220404a798798bfc0ee189fff", - "sha256:ad1f2fb9fe9b585ea4b436d6e998e71b50d2b087b694ab277b30e060c434e5db", - "sha256:b05774864c87210c531b48dfeb2f7659407c2dda8643104fb4ae5e2c311d12d9", - "sha256:b41693b7388324b80f9acfabd479bd1c84f0bc7e8f17bab4ecd9675e9ff9c734", - "sha256:b42dbd097abb44b3f1156b4bf978ec5853840802d6eee2784857be11ee82c6a0", - "sha256:b4e7c7ec4146a94a307ca4f112802a8e26d969018fabed526efc340d21d3e7d0", - "sha256:b59d096b5537ec7c85954cb97d821aae35cfccce3357a2cafe85660cc6295628", - "sha256:b9c60d1de973ca94af02053d9b5111c4fbf97158e139b14f1be68337be267be6", - "sha256:bccd2cb7aa5a3bfada72681bdb91637094d81639e116eac368f8b3874620a654", - "sha256:c32593ead1a8c6aabd58f9d7ee706e48beac796bb0cb71d6b60f2c1056f0a65f", - "sha256:c7571f99525c76a6280f5fe8e194eeb8cb4da55586c3c61c59c33a33f10cfce7", - "sha256:c8b2df9feac55043759aa89f722a967d977d80f8b5865a4153fc41c93b957efc", - "sha256:ca9f835cdfedcb3f5947304e85b8ca3ace31eef6346d8027a97f4de5fb687534", - "sha256:cc9253069158d57e27d47a8453d8a2c5a370dc461374111b5184cf2f147a3cc3", - "sha256:ced66c5c6ad5bcaf9be54560398654779ec1c3695f1a9cf0ae5e3606694a000a", - "sha256:d173c0ac508a2175f7c9a115a50db5fd3e35190d96fdd1a17f9cb10a6ab09aa1", - "sha256:d6edc538c7480fa0a3b2bdd705f8010062d74700198da55d16498e1b49549b9c", - "sha256:daf20d9c3b12ae0fdf15ed92235e190f8284945563c4b8ad95b2d7a31f331cd3", - "sha256:dc311634f6f28661a76cbc1c28ecf3b3a70a8edd67b69288ab7ca91058eb5a33", - "sha256:e2bc827c01f75803de77b134afdbf74fa74b62970eafdf190f3244931d7a5c0d", - "sha256:e365034c5cf6cf74f57420b57682ea79e19eb29033399dd3f40de4d0171998fa", - "sha256:e906da0f2bcbf9b26cc2b144929e88cb3bf943dd1942b4e5af066056875c7618", - "sha256:e9faafa74dbb906b2b6f3eb9942352e9e9db8d583ffed4be618a89bd71a4e914", - "sha256:ec6cd1954ca2bbf0970f531a628da1b1338f594bf5da7e361e19ba163ecc4f3b", - "sha256:f296d637a50bb15fb6a229fbb0eb053080e703b53dbfe55b1e4bb1c5ed25d325", - "sha256:f30fc72daf85486cdcdfc3f5e0aea9255493ef499e31582b34abadbfaafb0965", - "sha256:fe846f0a98aa9913c2852b630cd39b4098f296e0907dd05f6c7b30d911afa4c3" + "sha256:004511d3413737700835e949433536a2fe95a7d0297edd911a1e9705c5b5ea43", + "sha256:0902e887b0e1d50424112f200eb9ae3dfed6c0d0a19fc60f633ae5a57c809656", + "sha256:09b00dd520d88eac9d1768439a59ab3d145065c91a8fab97f900d1b5f802895e", + "sha256:0a2f451849e6b39e5c226803dcacfa9c7133e9825dcefd2f4e837a2ec5a3bb98", + "sha256:0a950c2eb8ff17361abd8c85987fd6076d9f47d040ebffce67dce4993285e973", + "sha256:0ad1fb47da60ae1ddfb316f0ff16d1f3b8e844d1a1e154641928ea0583d486ed", + "sha256:13ceac2c5cdcc3f64b9015710221ddf81c900c5febc505dbd8f810e770011540", + "sha256:14461157d8426bcb40bd94deb0450a6fa16f05129f7da546090cebf8f3123b0f", + "sha256:16f8a2c9538c14a557b4d309ed4d0a7c60f0253e8ed7b6c9a2859a7582f8b1b8", + "sha256:17ae4664031aadfbcb34fd40ffd90976671fa0c0286e6c4113989f78bebab37a", + "sha256:1ce63ae04719513dd2651202352a2beb9f67f55cb8490c40f056cea3c5c355ce", + "sha256:23a15727fbfccab973343b6d1b7181bfb0b4aa7ae280f36fd2f90f5476805682", + "sha256:2540ddc83cc724b13d1838026f6a5ad178510953302a49e6d647f6e1de82bc34", + "sha256:37dcee4906454ae377be5937ab2a66a9a88377b11dd7c072df7a7c142b63c37c", + "sha256:38bea84ee4fe24ebcc8edeb7b54bf20f06fd53ce4d2cc8b74344c5b9620597fd", + "sha256:3ab3367bb7f61ad18793fea2ef71f2d181c528c87948638366bf1de26e239183", + "sha256:3ad1d59fd7114e6a08c4814983bb498f391c699f3c78712770077518cae63ff7", + "sha256:3b4e6db8dc4879015b9955778cfb9881897339c8fab7b3676f8433f849425913", + "sha256:3e061b09f6fa42997cf627307f220315e313ece74907d35776ec4373ed718b86", + "sha256:42864e70a248f5f6a49fdaf417d9bc62d6e4d8ee9695b24c5916cb4bb666c802", + "sha256:493910ceb2764f792db4dc6e8e4b375dae1b08f72e18e8f10f18b34ca17d0979", + "sha256:4d0c970c0d602b1017e2067ff3b7dac41c98fef4f7472ec2ea26fd8a4e8c2149", + "sha256:54eb3aead72a5c19fad07219acd882c1643a1027fbcdefac9b502c267242f955", + "sha256:56a3443aca82abda0e07be2e1ecb76a050714faf2be84256dae291182ba59049", + "sha256:576f5ca28d1b3276026f7df3ec841ae460e0fc3aac2a47cbf72eabcfc0f102e1", + "sha256:58ede86453a6cf2d6ce40ef0ca15481677a66950e73b0a788917916f7e35a0bb", + "sha256:61c721764e41af907c9d16b6daa05a458f066015abd35923051be8705108ed17", + "sha256:634d96869be6c4dc232fc503e03e40c42d32cfaa51712aee181e922e61d74814", + "sha256:696ef00e8a1f0cec5e30640e64eca75d8e777933d1438f4facc9c0cdf288a810", + "sha256:69a2cbd61788d26f8f1e626e188044834f37f6ae3f937bd9f08b65fc9d7e514e", + "sha256:6a792ce34b999fbe04a7a71a90c74f10c57ae4c51f65461a411faa70e154154e", + "sha256:6ac13b71761e49d5f9e4d05d33683bbafef753e876e8e5a7ef26e937dd766713", + "sha256:6fdec0213244c39973674ca2a7f5435bf74369e7d4e104d6c7473c81c9bcc8c4", + "sha256:72b1b03fb4655c1960403c131740755ec19c5898c82abd3961c364c2afd59fe7", + "sha256:745f1ed5e2c687baefc3c5e7b4304e91bf3e2f32834d07baaee243e349624b24", + "sha256:776c8e959a01e5e8321f1dec77964cb6101020a69d5a94cd3d34db6d555e01f7", + "sha256:780df0d837276276226a1ff803f8d0fa5f8996c479aeef52eb040179f3156cbd", + "sha256:78e6e23b954644737e385befa0deb20233e2dfddf95dd11e9db752bdd2a294d3", + "sha256:7951decace76a9271a1ef181b04aa77d3cc309a02a51d73826039003210bdc86", + "sha256:7ba92a2d9ace559a0a14b03d87f47e021e4fa7681dc6970ebbc7b447c7d4b7cd", + "sha256:7f6428fee52d2bcf96a8aa7b62095b190ee341ab0e6b1bcf50c615d7966fd45b", + "sha256:87944bd16b7fe6160607f6a17808abd25f17f61ae1e26c47a491b970fb66d8cb", + "sha256:87a6e922b2b2401e0b0cf6b976b97f11ec7f136bfed445e16384fbf6fd5e8602", + "sha256:8cb0688a8d81c63d716e867d59a9ccc389e97ac7037ebef904c2b89334407180", + "sha256:8df6612df74409080575dca38a5237282865408016e65636a76a2eb9348c2567", + "sha256:911a6e91d08bb2c72938bc17f0a2d97864c531536b7832abee6429d5296e5b27", + "sha256:92b7ee222e2b903e0a4b329a9943d432b3767f2d5029dbe4ca59fb75223bbe2e", + "sha256:938f756c2b9374bbcc262a37eea521d8a0e6458162f2a9c26329cc87fdf06534", + "sha256:9756d9b9d4547e091f99d554fbba0d2a920aab98caa82a8fb3d3d9bee3c9ae85", + "sha256:98b88a2bf26965f2015a771381624dd4b0839034b70d406dc74fd8be4cc053e3", + "sha256:9b751a6306f330801665ae69270a8a3993654a85569b3469662efaad6cf5cc50", + "sha256:a2a450bcce4931b295fc0848f384834c3f9b00edfc2150baafb4488c27953de6", + "sha256:a3814760a1a700f3cfd2f977249f1032301d0a12c92aba74605cfa6ce9f78489", + "sha256:a5abcbba9f4b463a45c8ca8b7720891200658f6f46894f79517e6cd11f3405ca", + "sha256:a6db7458ab89c7d80bc1f4e930cc9df6edee2200127cfa6f6e080cf619eddfbd", + "sha256:ad497f38a0d6c329cb621774788583ee12321863cd4bd9feee1effd60f2ad133", + "sha256:ad9509ffb2396483ceacb1eee9134724443ee45b92141105a4645857244aecc8", + "sha256:bbcba75fe879ad6fd2e0d6a8d937f34a571f116a0e4db37df8079e738ea95c71", + "sha256:c10d85e81d0b9ef87970ecbdbfaeec14a361a7fa947118817fcea8e45335fa46", + "sha256:c15b2271c44da77ee9d822552201180779e5e942f3a71fb74e026bf6172ff287", + "sha256:ca37057625693d097543bd88076ceebeb248291df9d6ca8481349efc0b05dcd0", + "sha256:cc3a145479a76ad0ed646434d09216d33d08eef0d8c9a11f5ae5cdc37caa3540", + "sha256:ccf10f16ab498d20e28bc2b5c1306e9c1512f2840f7b6a67000a517a4b37d5ee", + "sha256:cd464ba806e27ee24a91362ba3621bfc39dbbb8b79f2e1340201615197370f7c", + "sha256:d007aa39a52d62373bd23428ba4a2546eed0e7643d7bf2e41ddcefd54519842c", + "sha256:d0666afbe984f6933fe72cd1f1c3560d8c55880a0bdd728ad774006eb4241ecd", + "sha256:d07502cc14ecd64f52b2a74ebbc106893d9a9717120057ea9ea1fd6568a747e7", + "sha256:d489d9778522fbd0f8d6a5c6e48e3514f11be81cb0a5954bdda06f7e1594b321", + "sha256:df7db76400bf46ec6a0a73192b14c8295bdb9812053f4fe53f4e789f3ea66bbb", + "sha256:e3538bc9fe1b902bef51372462e3d7c96fce2b566642512138a480b7adc9d508", + "sha256:e87fd812899aa78252866ae03a048e77bd11b80fb4878ce27c23cade239b42b2", + "sha256:ecdb8173e6c7aa09eee342ac62e193e6904923bd232e76b4157ac0bfa670609f", + "sha256:f244b8e541f414664889e2c87cac11a07b918cb4b540c36f7ada7bfa76571ea2", + "sha256:f4065145bf69de124accdd17ea5f4dc770da0a6a6e440c53f6e0a8c27b3e635c", + "sha256:f420bfe862fb357a6d76f2065447ef6f484bc489292ac91e29bc65d2d7a2c84d", + "sha256:f6ddd90d9fb4b501c97a4458f1c1720e42432c26cb76d28177c5b5ad4e332601", + "sha256:fa73e8c2656a3653ae6c307b3f4e878a21f87859a9afab228280ddccd7369d71", + "sha256:fadbb8f1d4140825069db3fedbbb843290fd5f5bc0a5dbd7eaf81d91bf1b003b", + "sha256:fb3d0cc5cdb926090748ea60172fa8a213cec728bd6c54eae18b96040fcd6227", + "sha256:fb46bb0f24813e6cede6cc07b1961d4b04f331f7112a23b5e21f567da4ee50aa", + "sha256:fd36c119c5d6551bce374fcb5c19269638f8d09862445f85a5a48596fd59f4bb" ], "markers": "python_version >= '3.9'", - "version": "==3.11.14" + "version": "==3.11.16" }, "aiosignal": { "hashes": [ @@ -180,20 +180,20 @@ }, "boto3": { "hashes": [ - "sha256:295648f887464ab74c5c301a44982df76f9ba39ebfc16be5b8f071ad1a81fe95", - "sha256:90fa5a91d7d7456219f0b7c4a93b38335dc5cf4613d885da4d4c1d099e04c6b7" + "sha256:77ff13723ad5b836a565c382610c3994e14ce643144dc9c604bfe1efb3213739", + "sha256:78fb57556c2337e087d2eda419ee371b52843a2420861114413791113efeabe2" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.37.13" + "version": "==1.37.26" }, "botocore": { "hashes": [ - "sha256:60dfb831c54eb466db9b91891a6c8a0c223626caa049969d5d42858ad1e7f8c7", - "sha256:aa417bac0f4d79533080e6e17c0509e149353aec83cfe7879597a7942f7f08d0" + "sha256:7f6dc999e7a34c0917623aac67c9ea2389b741bb7babee1a88cf2cd04006ea7a", + "sha256:d499a617903cbcaae18380320125fa3a95cb625b613d746e6edc69c6f01f1326" ], "markers": "python_version >= '3.8'", - "version": "==1.37.13" + "version": "==1.37.26" }, "certifi": { "hashes": [ @@ -425,9 +425,9 @@ }, "dbrepo": { "hashes": [ - "sha256:ad01d6dc5d99f3c0c9caf3fb11b51502bec5390c72ff28b6b725e2755f5a2f7c" + "sha256:55de6a4934010e14a574032b5a5179bf3dac9895ef74e5cd4a221a625a75674b" ], - "path": "./lib/dbrepo-1.7.3.tar.gz" + "path": "./lib/dbrepo-1.8.0.tar.gz" }, "events": { "hashes": [ @@ -852,109 +852,109 @@ }, "mistune": { "hashes": [ - "sha256:4b47731332315cdca99e0ded46fc0004001c1299ff773dfb48fbe1fd226de319", - "sha256:733bf018ba007e8b5f2d3a9eb624034f6ee26c4ea769a98ec533ee111d504dff" + "sha256:1a32314113cff28aa6432e99e522677c8587fd83e3d51c29b82a52409c842bd9", + "sha256:a7035c21782b2becb6be62f8f25d3df81ccb4d6fa477a6525b15af06539f02a0" ], "markers": "python_version >= '3.8'", - "version": "==3.1.2" + "version": "==3.1.3" }, "multidict": { "hashes": [ - "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f", - "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056", - "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761", - "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3", - "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b", - "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6", - "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748", - "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966", - "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f", - "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1", - "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6", - "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada", - "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305", - "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2", - "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d", - "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a", - "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef", - "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c", - "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb", - "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60", - "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6", - "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4", - "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478", - "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81", - "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7", - "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56", - "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3", - "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6", - "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30", - "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb", - "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", - "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0", - "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925", - "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c", - "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6", - "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e", - "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95", - "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2", - "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133", - "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2", - "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa", - "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3", - "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3", - "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436", - "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657", - "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581", - "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492", - "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43", - "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2", - "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2", - "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926", - "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057", - "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc", - "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80", - "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255", - "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1", - "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972", - "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53", - "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1", - "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423", - "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a", - "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160", - "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c", - "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd", - "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa", - "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5", - "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b", - "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa", - "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef", - "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44", - "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4", - "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156", - "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753", - "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28", - "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d", - "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a", - "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304", - "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008", - "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429", - "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72", - "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399", - "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3", - "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392", - "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167", - "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c", - "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774", - "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351", - "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76", - "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875", - "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd", - "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28", - "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db" + "sha256:0085b0afb2446e57050140240a8595846ed64d1cbd26cef936bfab3192c673b8", + "sha256:042028348dc5a1f2be6c666437042a98a5d24cee50380f4c0902215e5ec41844", + "sha256:05fefbc3cddc4e36da209a5e49f1094bbece9a581faa7f3589201fd95df40e5d", + "sha256:063be88bd684782a0715641de853e1e58a2f25b76388538bd62d974777ce9bc2", + "sha256:07bfa8bc649783e703263f783f73e27fef8cd37baaad4389816cf6a133141331", + "sha256:08549895e6a799bd551cf276f6e59820aa084f0f90665c0f03dd3a50db5d3c48", + "sha256:095a2eabe8c43041d3e6c2cb8287a257b5f1801c2d6ebd1dd877424f1e89cf29", + "sha256:0b183a959fb88ad1be201de2c4bdf52fa8e46e6c185d76201286a97b6f5ee65c", + "sha256:0c383d28857f66f5aebe3e91d6cf498da73af75fbd51cedbe1adfb85e90c0460", + "sha256:0d57a01a2a9fa00234aace434d8c131f0ac6e0ac6ef131eda5962d7e79edfb5b", + "sha256:0dc25a3293c50744796e87048de5e68996104d86d940bb24bc3ec31df281b191", + "sha256:0e5a644e50ef9fb87878d4d57907f03a12410d2aa3b93b3acdf90a741df52c49", + "sha256:0f249badb360b0b4d694307ad40f811f83df4da8cef7b68e429e4eea939e49dd", + "sha256:0f74f2fc51555f4b037ef278efc29a870d327053aba5cb7d86ae572426c7cccc", + "sha256:125dd82b40f8c06d08d87b3510beaccb88afac94e9ed4a6f6c71362dc7dbb04b", + "sha256:13551d0e2d7201f0959725a6a769b6f7b9019a168ed96006479c9ac33fe4096b", + "sha256:14ed9ed1bfedd72a877807c71113deac292bf485159a29025dfdc524c326f3e1", + "sha256:163f4604e76639f728d127293d24c3e208b445b463168af3d031b92b0998bb90", + "sha256:19e2819b0b468174de25c0ceed766606a07cedeab132383f1e83b9a4e96ccb4f", + "sha256:1e2a2193d3aa5cbf5758f6d5680a52aa848e0cf611da324f71e5e48a9695cc86", + "sha256:1f3c099d3899b14e1ce52262eb82a5f5cb92157bb5106bf627b618c090a0eadc", + "sha256:214207dcc7a6221d9942f23797fe89144128a71c03632bf713d918db99bd36de", + "sha256:2325105e16d434749e1be8022f942876a936f9bece4ec41ae244e3d7fae42aaf", + "sha256:2529ddbdaa424b2c6c2eb668ea684dd6b75b839d0ad4b21aad60c168269478d7", + "sha256:256d431fe4583c5f1e0f2e9c4d9c22f3a04ae96009b8cfa096da3a8723db0a16", + "sha256:25bb96338512e2f46f615a2bb7c6012fe92a4a5ebd353e5020836a7e33120349", + "sha256:2e87f1926e91855ae61769ba3e3f7315120788c099677e0842e697b0bfb659f2", + "sha256:2fc6af8e39f7496047c7876314f4317736eac82bf85b54c7c76cf1a6f8e35d98", + "sha256:3157126b028c074951839233647bd0e30df77ef1fedd801b48bdcad242a60f4e", + "sha256:32c9b4878f48be3e75808ea7e499d6223b1eea6d54c487a66bc10a1871e3dc6a", + "sha256:32ed748ff9ac682eae7859790d3044b50e3076c7d80e17a44239683769ff485e", + "sha256:3501621d5e86f1a88521ea65d5cad0a0834c77b26f193747615b7c911e5422d2", + "sha256:437c33561edb6eb504b5a30203daf81d4a9b727e167e78b0854d9a4e18e8950b", + "sha256:48d39b1824b8d6ea7de878ef6226efbe0773f9c64333e1125e0efcfdd18a24c7", + "sha256:4ac3fcf9a2d369bd075b2c2965544036a27ccd277fc3c04f708338cc57533081", + "sha256:4ccfd74957ef53fa7380aaa1c961f523d582cd5e85a620880ffabd407f8202c0", + "sha256:52b05e21ff05729fbea9bc20b3a791c3c11da61649ff64cce8257c82a020466d", + "sha256:5389445f0173c197f4a3613713b5fb3f3879df1ded2a1a2e4bc4b5b9c5441b7e", + "sha256:5c5e7d2e300d5cb3b2693b6d60d3e8c8e7dd4ebe27cd17c9cb57020cac0acb80", + "sha256:5d26547423e5e71dcc562c4acdc134b900640a39abd9066d7326a7cc2324c530", + "sha256:5dd7106d064d05896ce28c97da3f46caa442fe5a43bc26dfb258e90853b39b44", + "sha256:5f8cb1329f42fadfb40d6211e5ff568d71ab49be36e759345f91c69d1033d633", + "sha256:61d5541f27533f803a941d3a3f8a3d10ed48c12cf918f557efcbf3cd04ef265c", + "sha256:639556758c36093b35e2e368ca485dada6afc2bd6a1b1207d85ea6dfc3deab27", + "sha256:641cf2e3447c9ecff2f7aa6e9eee9eaa286ea65d57b014543a4911ff2799d08a", + "sha256:6aed763b6a1b28c46c055692836879328f0b334a6d61572ee4113a5d0c859872", + "sha256:6e2a2d6749e1ff2c9c76a72c6530d5baa601205b14e441e6d98011000f47a7ac", + "sha256:7243c5a6523c5cfeca76e063efa5f6a656d1d74c8b1fc64b2cd1e84e507f7e2a", + "sha256:76b34c12b013d813e6cb325e6bd4f9c984db27758b16085926bbe7ceeaace626", + "sha256:781b5dd1db18c9e9eacc419027b0acb5073bdec9de1675c0be25ceb10e2ad133", + "sha256:7c611345bbe7cb44aabb877cb94b63e86f2d0db03e382667dbd037866d44b4f8", + "sha256:83b78c680d4b15d33042d330c2fa31813ca3974197bddb3836a5c635a5fd013f", + "sha256:84e87a7d75fa36839a3a432286d719975362d230c70ebfa0948549cc38bd5b46", + "sha256:89b3857652183b8206a891168af47bac10b970d275bba1f6ee46565a758c078d", + "sha256:8cd1a0644ccaf27e9d2f6d9c9474faabee21f0578fe85225cc5af9a61e1653df", + "sha256:8de4d42dffd5ced9117af2ce66ba8722402541a3aa98ffdf78dde92badb68932", + "sha256:94a7bb972178a8bfc4055db80c51efd24baefaced5e51c59b0d598a004e8305d", + "sha256:98aa8325c7f47183b45588af9c434533196e241be0a4e4ae2190b06d17675c02", + "sha256:9e658d1373c424457ddf6d55ec1db93c280b8579276bebd1f72f113072df8a5d", + "sha256:9f49585f4abadd2283034fc605961f40c638635bc60f5162276fec075f2e37a4", + "sha256:9f6cad071960ba1914fa231677d21b1b4a3acdcce463cee41ea30bc82e6040cf", + "sha256:a0cc398350ef31167e03f3ca7c19313d4e40a662adcb98a88755e4e861170bdd", + "sha256:a1133414b771619aa3c3000701c11b2e4624a7f492f12f256aedde97c28331a2", + "sha256:a33273a541f1e1a8219b2a4ed2de355848ecc0254264915b9290c8d2de1c74e1", + "sha256:a3c0ff89fe40a152e77b191b83282c9664357dce3004032d42e68c514ceff27e", + "sha256:a49994481b99cd7dedde07f2e7e93b1d86c01c0fca1c32aded18f10695ae17eb", + "sha256:abf5b17bc0cf626a8a497d89ac691308dbd825d2ac372aa990b1ca114e470151", + "sha256:ac380cacdd3b183338ba63a144a34e9044520a6fb30c58aa14077157a033c13e", + "sha256:ad81012b24b88aad4c70b2cbc2dad84018783221b7f923e926f4690ff8569da3", + "sha256:b2c00ad31fbc2cbac85d7d0fcf90853b2ca2e69d825a2d3f3edb842ef1544a2c", + "sha256:b4c153863dd6569f6511845922c53e39c8d61f6e81f228ad5443e690fca403de", + "sha256:b4f3d66dd0354b79761481fc15bdafaba0b9d9076f1f42cc9ce10d7fcbda205a", + "sha256:b99aac6bb2c37db336fa03a39b40ed4ef2818bf2dfb9441458165ebe88b793af", + "sha256:b9f6392d98c0bd70676ae41474e2eecf4c7150cb419237a41f8f96043fcb81d1", + "sha256:c537da54ce4ff7c15e78ab1292e5799d0d43a2108e006578a57f531866f64025", + "sha256:ca23db5fb195b5ef4fd1f77ce26cadefdf13dba71dab14dadd29b34d457d7c44", + "sha256:cc826b9a8176e686b67aa60fd6c6a7047b0461cae5591ea1dc73d28f72332a8a", + "sha256:cca83a629f77402cfadd58352e394d79a61c8015f1694b83ab72237ec3941f88", + "sha256:cf8d370b2fea27fb300825ec3984334f7dd54a581bde6456799ba3776915a656", + "sha256:d1175b0e0d6037fab207f05774a176d71210ebd40b1c51f480a04b65ec5c786d", + "sha256:d1996ee1330e245cd3aeda0887b4409e3930524c27642b046e4fae88ffa66c5e", + "sha256:d5a36953389f35f0a4e88dc796048829a2f467c9197265504593f0e420571547", + "sha256:da51d8928ad8b4244926fe862ba1795f0b6e68ed8c42cd2f822d435db9c2a8f4", + "sha256:e16e7297f29a544f49340012d6fc08cf14de0ab361c9eb7529f6a57a30cbfda1", + "sha256:e25b11a0417475f093d0f0809a149aff3943c2c56da50fdf2c3c88d57fe3dfbd", + "sha256:e4371591e621579cb6da8401e4ea405b33ff25a755874a3567c4075ca63d56e2", + "sha256:e653d36b1bf48fa78c7fcebb5fa679342e025121ace8c87ab05c1cefd33b34fc", + "sha256:e7d91a230c7f8af86c904a5a992b8c064b66330544693fd6759c3d6162382ecf", + "sha256:e851e6363d0dbe515d8de81fd544a2c956fdec6f8a049739562286727d4a00c3", + "sha256:ef7d48207926edbf8b16b336f779c557dd8f5a33035a85db9c4b0febb0706817", + "sha256:f7716f7e7138252d88607228ce40be22660d6608d20fd365d596e7ca0738e019", + "sha256:facaf11f21f3a4c51b62931feb13310e6fe3475f85e20d9c9fdce0d2ea561b87" ], - "markers": "python_version >= '3.8'", - "version": "==6.1.0" + "markers": "python_version >= '3.9'", + "version": "==6.2.0" }, "numpy": { "hashes": [ @@ -1110,107 +1110,107 @@ }, "propcache": { "hashes": [ - "sha256:02df07041e0820cacc8f739510078f2aadcfd3fc57eaeeb16d5ded85c872c89e", - "sha256:03acd9ff19021bd0567582ac88f821b66883e158274183b9e5586f678984f8fe", - "sha256:03c091bb752349402f23ee43bb2bff6bd80ccab7c9df6b88ad4322258d6960fc", - "sha256:07700939b2cbd67bfb3b76a12e1412405d71019df00ca5697ce75e5ef789d829", - "sha256:0c3e893c4464ebd751b44ae76c12c5f5c1e4f6cbd6fbf67e3783cd93ad221863", - "sha256:119e244ab40f70a98c91906d4c1f4c5f2e68bd0b14e7ab0a06922038fae8a20f", - "sha256:11ae6a8a01b8a4dc79093b5d3ca2c8a4436f5ee251a9840d7790dccbd96cb649", - "sha256:15010f29fbed80e711db272909a074dc79858c6d28e2915704cfc487a8ac89c6", - "sha256:19d36bb351ad5554ff20f2ae75f88ce205b0748c38b146c75628577020351e3c", - "sha256:1c8f7d896a16da9455f882870a507567d4f58c53504dc2d4b1e1d386dfe4588a", - "sha256:2383a17385d9800b6eb5855c2f05ee550f803878f344f58b6e194de08b96352c", - "sha256:24c04f8fbf60094c531667b8207acbae54146661657a1b1be6d3ca7773b7a545", - "sha256:2578541776769b500bada3f8a4eeaf944530516b6e90c089aa368266ed70c49e", - "sha256:26a67e5c04e3119594d8cfae517f4b9330c395df07ea65eab16f3d559b7068fe", - "sha256:2b975528998de037dfbc10144b8aed9b8dd5a99ec547f14d1cb7c5665a43f075", - "sha256:2d15bc27163cd4df433e75f546b9ac31c1ba7b0b128bfb1b90df19082466ff57", - "sha256:2d913d36bdaf368637b4f88d554fb9cb9d53d6920b9c5563846555938d5450bf", - "sha256:3302c5287e504d23bb0e64d2a921d1eb4a03fb93a0a0aa3b53de059f5a5d737d", - "sha256:36ca5e9a21822cc1746023e88f5c0af6fce3af3b85d4520efb1ce4221bed75cc", - "sha256:3b812b3cb6caacd072276ac0492d249f210006c57726b6484a1e1805b3cfeea0", - "sha256:3c6ec957025bf32b15cbc6b67afe233c65b30005e4c55fe5768e4bb518d712f1", - "sha256:41de3da5458edd5678b0f6ff66691507f9885f5fe6a0fb99a5d10d10c0fd2d64", - "sha256:42924dc0c9d73e49908e35bbdec87adedd651ea24c53c29cac103ede0ea1d340", - "sha256:4544699674faf66fb6b4473a1518ae4999c1b614f0b8297b1cef96bac25381db", - "sha256:46ed02532cb66612d42ae5c3929b5e98ae330ea0f3900bc66ec5f4862069519b", - "sha256:49ea05212a529c2caffe411e25a59308b07d6e10bf2505d77da72891f9a05641", - "sha256:4fa0e7c9c3cf7c276d4f6ab9af8adddc127d04e0fcabede315904d2ff76db626", - "sha256:507c5357a8d8b4593b97fb669c50598f4e6cccbbf77e22fa9598aba78292b4d7", - "sha256:549722908de62aa0b47a78b90531c022fa6e139f9166be634f667ff45632cc92", - "sha256:58e6d2a5a7cb3e5f166fd58e71e9a4ff504be9dc61b88167e75f835da5764d07", - "sha256:5a16167118677d94bb48bfcd91e420088854eb0737b76ec374b91498fb77a70e", - "sha256:5d62c4f6706bff5d8a52fd51fec6069bef69e7202ed481486c0bc3874912c787", - "sha256:5fa159dcee5dba00c1def3231c249cf261185189205073bde13797e57dd7540a", - "sha256:6032231d4a5abd67c7f71168fd64a47b6b451fbcb91c8397c2f7610e67683810", - "sha256:63f26258a163c34542c24808f03d734b338da66ba91f410a703e505c8485791d", - "sha256:65a37714b8ad9aba5780325228598a5b16c47ba0f8aeb3dc0514701e4413d7c0", - "sha256:67054e47c01b7b349b94ed0840ccae075449503cf1fdd0a1fdd98ab5ddc2667b", - "sha256:67dda3c7325691c2081510e92c561f465ba61b975f481735aefdfc845d2cd043", - "sha256:6985a593417cdbc94c7f9c3403747335e450c1599da1647a5af76539672464d3", - "sha256:6a1948df1bb1d56b5e7b0553c0fa04fd0e320997ae99689488201f19fa90d2e7", - "sha256:6b5b7fd6ee7b54e01759f2044f936dcf7dea6e7585f35490f7ca0420fe723c0d", - "sha256:6c929916cbdb540d3407c66f19f73387f43e7c12fa318a66f64ac99da601bcdf", - "sha256:6f4d7a7c0aff92e8354cceca6fe223973ddf08401047920df0fcb24be2bd5138", - "sha256:728af36011bb5d344c4fe4af79cfe186729efb649d2f8b395d1572fb088a996c", - "sha256:742840d1d0438eb7ea4280f3347598f507a199a35a08294afdcc560c3739989d", - "sha256:75e872573220d1ee2305b35c9813626e620768248425f58798413e9c39741f46", - "sha256:794c3dd744fad478b6232289c866c25406ecdfc47e294618bdf1697e69bd64a6", - "sha256:7c0fdbdf6983526e269e5a8d53b7ae3622dd6998468821d660d0daf72779aefa", - "sha256:7c5f5290799a3f6539cc5e6f474c3e5c5fbeba74a5e1e5be75587746a940d51e", - "sha256:7c6e7e4f9167fddc438cd653d826f2222222564daed4116a02a184b464d3ef05", - "sha256:7cedd25e5f678f7738da38037435b340694ab34d424938041aa630d8bac42663", - "sha256:7e2e068a83552ddf7a39a99488bcba05ac13454fb205c847674da0352602082f", - "sha256:8319293e85feadbbfe2150a5659dbc2ebc4afdeaf7d98936fb9a2f2ba0d4c35c", - "sha256:8526b0941ec5a40220fc4dfde76aed58808e2b309c03e9fa8e2260083ef7157f", - "sha256:8884ba1a0fe7210b775106b25850f5e5a9dc3c840d1ae9924ee6ea2eb3acbfe7", - "sha256:8cb625bcb5add899cb8ba7bf716ec1d3e8f7cdea9b0713fa99eadf73b6d4986f", - "sha256:8d663fd71491dde7dfdfc899d13a067a94198e90695b4321084c6e450743b8c7", - "sha256:8ee1983728964d6070ab443399c476de93d5d741f71e8f6e7880a065f878e0b9", - "sha256:997e7b8f173a391987df40f3b52c423e5850be6f6df0dcfb5376365440b56667", - "sha256:9be90eebc9842a93ef8335291f57b3b7488ac24f70df96a6034a13cb58e6ff86", - "sha256:9ddd49258610499aab83b4f5b61b32e11fce873586282a0e972e5ab3bcadee51", - "sha256:9ecde3671e62eeb99e977f5221abcf40c208f69b5eb986b061ccec317c82ebd0", - "sha256:9ff4e9ecb6e4b363430edf2c6e50173a63e0820e549918adef70515f87ced19a", - "sha256:a254537b9b696ede293bfdbc0a65200e8e4507bc9f37831e2a0318a9b333c85c", - "sha256:a2b9bf8c79b660d0ca1ad95e587818c30ccdb11f787657458d6f26a1ea18c568", - "sha256:a61a68d630e812b67b5bf097ab84e2cd79b48c792857dc10ba8a223f5b06a2af", - "sha256:a7080b0159ce05f179cfac592cda1a82898ca9cd097dacf8ea20ae33474fbb25", - "sha256:a8fd93de4e1d278046345f49e2238cdb298589325849b2645d4a94c53faeffc5", - "sha256:a94ffc66738da99232ddffcf7910e0f69e2bbe3a0802e54426dbf0714e1c2ffe", - "sha256:aa806bbc13eac1ab6291ed21ecd2dd426063ca5417dd507e6be58de20e58dfcf", - "sha256:b0c1a133d42c6fc1f5fbcf5c91331657a1ff822e87989bf4a6e2e39b818d0ee9", - "sha256:b58229a844931bca61b3a20efd2be2a2acb4ad1622fc026504309a6883686fbf", - "sha256:bb2f144c6d98bb5cbc94adeb0447cfd4c0f991341baa68eee3f3b0c9c0e83767", - "sha256:be90c94570840939fecedf99fa72839aed70b0ced449b415c85e01ae67422c90", - "sha256:bf0d9a171908f32d54f651648c7290397b8792f4303821c42a74e7805bfb813c", - "sha256:bf15fc0b45914d9d1b706f7c9c4f66f2b7b053e9517e40123e137e8ca8958b3d", - "sha256:bf4298f366ca7e1ad1d21bbb58300a6985015909964077afd37559084590c929", - "sha256:c441c841e82c5ba7a85ad25986014be8d7849c3cfbdb6004541873505929a74e", - "sha256:cacea77ef7a2195f04f9279297684955e3d1ae4241092ff0cfcef532bb7a1c32", - "sha256:cd54895e4ae7d32f1e3dd91261df46ee7483a735017dc6f987904f194aa5fd14", - "sha256:d1323cd04d6e92150bcc79d0174ce347ed4b349d748b9358fd2e497b121e03c8", - "sha256:d383bf5e045d7f9d239b38e6acadd7b7fdf6c0087259a84ae3475d18e9a2ae8b", - "sha256:d3e7420211f5a65a54675fd860ea04173cde60a7cc20ccfbafcccd155225f8bc", - "sha256:d8074c5dd61c8a3e915fa8fc04754fa55cfa5978200d2daa1e2d4294c1f136aa", - "sha256:df03cd88f95b1b99052b52b1bb92173229d7a674df0ab06d2b25765ee8404bce", - "sha256:e45377d5d6fefe1677da2a2c07b024a6dac782088e37c0b1efea4cfe2b1be19b", - "sha256:e53d19c2bf7d0d1e6998a7e693c7e87300dd971808e6618964621ccd0e01fe4e", - "sha256:e560fd75aaf3e5693b91bcaddd8b314f4d57e99aef8a6c6dc692f935cc1e6bbf", - "sha256:ec5060592d83454e8063e487696ac3783cc48c9a329498bafae0d972bc7816c9", - "sha256:ecc2920630283e0783c22e2ac94427f8cca29a04cfdf331467d4f661f4072dac", - "sha256:ed7161bccab7696a473fe7ddb619c1d75963732b37da4618ba12e60899fefe4f", - "sha256:ee0bd3a7b2e184e88d25c9baa6a9dc609ba25b76daae942edfb14499ac7ec374", - "sha256:ee25f1ac091def37c4b59d192bbe3a206298feeb89132a470325bf76ad122a1e", - "sha256:efa44f64c37cc30c9f05932c740a8b40ce359f51882c70883cc95feac842da4d", - "sha256:f47d52fd9b2ac418c4890aad2f6d21a6b96183c98021f0a48497a904199f006e", - "sha256:f857034dc68d5ceb30fb60afb6ff2103087aea10a01b613985610e007053a121", - "sha256:fb91d20fa2d3b13deea98a690534697742029f4fb83673a3501ae6e3746508b5", - "sha256:fddb8870bdb83456a489ab67c6b3040a8d5a55069aa6f72f9d872235fbc52f54" + "sha256:050b571b2e96ec942898f8eb46ea4bfbb19bd5502424747e83badc2d4a99a44e", + "sha256:05543250deac8e61084234d5fc54f8ebd254e8f2b39a16b1dce48904f45b744b", + "sha256:069e7212890b0bcf9b2be0a03afb0c2d5161d91e1bf51569a64f629acc7defbf", + "sha256:09400e98545c998d57d10035ff623266927cb784d13dd2b31fd33b8a5316b85b", + "sha256:0c3c3a203c375b08fd06a20da3cf7aac293b834b6f4f4db71190e8422750cca5", + "sha256:0c86e7ceea56376216eba345aa1fc6a8a6b27ac236181f840d1d7e6a1ea9ba5c", + "sha256:0fbe94666e62ebe36cd652f5fc012abfbc2342de99b523f8267a678e4dfdee3c", + "sha256:17d1c688a443355234f3c031349da69444be052613483f3e4158eef751abcd8a", + "sha256:19a06db789a4bd896ee91ebc50d059e23b3639c25d58eb35be3ca1cbe967c3bf", + "sha256:1c5c7ab7f2bb3f573d1cb921993006ba2d39e8621019dffb1c5bc94cdbae81e8", + "sha256:1eb34d90aac9bfbced9a58b266f8946cb5935869ff01b164573a7634d39fbcb5", + "sha256:1f6cc0ad7b4560e5637eb2c994e97b4fa41ba8226069c9277eb5ea7101845b42", + "sha256:27c6ac6aa9fc7bc662f594ef380707494cb42c22786a558d95fcdedb9aa5d035", + "sha256:2d219b0dbabe75e15e581fc1ae796109b07c8ba7d25b9ae8d650da582bed01b0", + "sha256:2fce1df66915909ff6c824bbb5eb403d2d15f98f1518e583074671a30fe0c21e", + "sha256:319fa8765bfd6a265e5fa661547556da381e53274bc05094fc9ea50da51bfd46", + "sha256:359e81a949a7619802eb601d66d37072b79b79c2505e6d3fd8b945538411400d", + "sha256:3a02a28095b5e63128bcae98eb59025924f121f048a62393db682f049bf4ac24", + "sha256:3e19ea4ea0bf46179f8a3652ac1426e6dcbaf577ce4b4f65be581e237340420d", + "sha256:3e584b6d388aeb0001d6d5c2bd86b26304adde6d9bb9bfa9c4889805021b96de", + "sha256:40d980c33765359098837527e18eddefc9a24cea5b45e078a7f3bb5b032c6ecf", + "sha256:4114c4ada8f3181af20808bedb250da6bae56660e4b8dfd9cd95d4549c0962f7", + "sha256:43593c6772aa12abc3af7784bff4a41ffa921608dd38b77cf1dfd7f5c4e71371", + "sha256:47ef24aa6511e388e9894ec16f0fbf3313a53ee68402bc428744a367ec55b833", + "sha256:4cf9e93a81979f1424f1a3d155213dc928f1069d697e4353edb8a5eba67c6259", + "sha256:4d0dfdd9a2ebc77b869a0b04423591ea8823f791293b527dc1bb896c1d6f1136", + "sha256:563f9d8c03ad645597b8d010ef4e9eab359faeb11a0a2ac9f7b4bc8c28ebef25", + "sha256:58aa11f4ca8b60113d4b8e32d37e7e78bd8af4d1a5b5cb4979ed856a45e62005", + "sha256:5a0a9898fdb99bf11786265468571e628ba60af80dc3f6eb89a3545540c6b0ef", + "sha256:5aed8d8308215089c0734a2af4f2e95eeb360660184ad3912686c181e500b2e7", + "sha256:5b9145c35cc87313b5fd480144f8078716007656093d23059e8993d3a8fa730f", + "sha256:5cb5918253912e088edbf023788de539219718d3b10aef334476b62d2b53de53", + "sha256:5cdb0f3e1eb6dfc9965d19734d8f9c481b294b5274337a8cb5cb01b462dcb7e0", + "sha256:5ced33d827625d0a589e831126ccb4f5c29dfdf6766cac441d23995a65825dcb", + "sha256:603f1fe4144420374f1a69b907494c3acbc867a581c2d49d4175b0de7cc64566", + "sha256:61014615c1274df8da5991a1e5da85a3ccb00c2d4701ac6f3383afd3ca47ab0a", + "sha256:64a956dff37080b352c1c40b2966b09defb014347043e740d420ca1eb7c9b908", + "sha256:668ddddc9f3075af019f784456267eb504cb77c2c4bd46cc8402d723b4d200bf", + "sha256:6d8e309ff9a0503ef70dc9a0ebd3e69cf7b3894c9ae2ae81fc10943c37762458", + "sha256:6f173bbfe976105aaa890b712d1759de339d8a7cef2fc0a1714cc1a1e1c47f64", + "sha256:71ebe3fe42656a2328ab08933d420df5f3ab121772eef78f2dc63624157f0ed9", + "sha256:730178f476ef03d3d4d255f0c9fa186cb1d13fd33ffe89d39f2cda4da90ceb71", + "sha256:7d2d5a0028d920738372630870e7d9644ce437142197f8c827194fca404bf03b", + "sha256:7f30241577d2fef2602113b70ef7231bf4c69a97e04693bde08ddab913ba0ce5", + "sha256:813fbb8b6aea2fc9659815e585e548fe706d6f663fa73dff59a1677d4595a037", + "sha256:82de5da8c8893056603ac2d6a89eb8b4df49abf1a7c19d536984c8dd63f481d5", + "sha256:83be47aa4e35b87c106fc0c84c0fc069d3f9b9b06d3c494cd404ec6747544894", + "sha256:8638f99dca15b9dff328fb6273e09f03d1c50d9b6512f3b65a4154588a7595fe", + "sha256:87380fb1f3089d2a0b8b00f006ed12bd41bd858fabfa7330c954c70f50ed8757", + "sha256:88c423efef9d7a59dae0614eaed718449c09a5ac79a5f224a8b9664d603f04a3", + "sha256:89498dd49c2f9a026ee057965cdf8192e5ae070ce7d7a7bd4b66a8e257d0c976", + "sha256:8a17583515a04358b034e241f952f1715243482fc2c2945fd99a1b03a0bd77d6", + "sha256:916cd229b0150129d645ec51614d38129ee74c03293a9f3f17537be0029a9641", + "sha256:9532ea0b26a401264b1365146c440a6d78269ed41f83f23818d4b79497aeabe7", + "sha256:967a8eec513dbe08330f10137eacb427b2ca52118769e82ebcfcab0fba92a649", + "sha256:975af16f406ce48f1333ec5e912fe11064605d5c5b3f6746969077cc3adeb120", + "sha256:9979643ffc69b799d50d3a7b72b5164a2e97e117009d7af6dfdd2ab906cb72cd", + "sha256:9a8ecf38de50a7f518c21568c80f985e776397b902f1ce0b01f799aba1608b40", + "sha256:9cec3239c85ed15bfaded997773fdad9fb5662b0a7cbc854a43f291eb183179e", + "sha256:9e64e948ab41411958670f1093c0a57acfdc3bee5cf5b935671bbd5313bcf229", + "sha256:9f64d91b751df77931336b5ff7bafbe8845c5770b06630e27acd5dbb71e1931c", + "sha256:a0ab8cf8cdd2194f8ff979a43ab43049b1df0b37aa64ab7eca04ac14429baeb7", + "sha256:a110205022d077da24e60b3df8bcee73971be9575dec5573dd17ae5d81751111", + "sha256:a34aa3a1abc50740be6ac0ab9d594e274f59960d3ad253cd318af76b996dd654", + "sha256:a444192f20f5ce8a5e52761a031b90f5ea6288b1eef42ad4c7e64fef33540b8f", + "sha256:a461959ead5b38e2581998700b26346b78cd98540b5524796c175722f18b0294", + "sha256:a75801768bbe65499495660b777e018cbe90c7980f07f8aa57d6be79ea6f71da", + "sha256:aa8efd8c5adc5a2c9d3b952815ff8f7710cefdcaf5f2c36d26aff51aeca2f12f", + "sha256:aca63103895c7d960a5b9b044a83f544b233c95e0dcff114389d64d762017af7", + "sha256:b0313e8b923b3814d1c4a524c93dfecea5f39fa95601f6a9b1ac96cd66f89ea0", + "sha256:b23c11c2c9e6d4e7300c92e022046ad09b91fd00e36e83c44483df4afa990073", + "sha256:b303b194c2e6f171cfddf8b8ba30baefccf03d36a4d9cab7fd0bb68ba476a3d7", + "sha256:b655032b202028a582d27aeedc2e813299f82cb232f969f87a4fde491a233f11", + "sha256:bd39c92e4c8f6cbf5f08257d6360123af72af9f4da75a690bef50da77362d25f", + "sha256:bef100c88d8692864651b5f98e871fb090bd65c8a41a1cb0ff2322db39c96c27", + "sha256:c2fe5c910f6007e716a06d269608d307b4f36e7babee5f36533722660e8c4a70", + "sha256:c66d8ccbc902ad548312b96ed8d5d266d0d2c6d006fd0f66323e9d8f2dd49be7", + "sha256:cd6a55f65241c551eb53f8cf4d2f4af33512c39da5d9777694e9d9c60872f519", + "sha256:d249609e547c04d190e820d0d4c8ca03ed4582bcf8e4e160a6969ddfb57b62e5", + "sha256:d4e89cde74154c7b5957f87a355bb9c8ec929c167b59c83d90654ea36aeb6180", + "sha256:dc1915ec523b3b494933b5424980831b636fe483d7d543f7afb7b3bf00f0c10f", + "sha256:e1c4d24b804b3a87e9350f79e2371a705a188d292fd310e663483af6ee6718ee", + "sha256:e474fc718e73ba5ec5180358aa07f6aded0ff5f2abe700e3115c37d75c947e18", + "sha256:e4fe2a6d5ce975c117a6bb1e8ccda772d1e7029c1cca1acd209f91d30fa72815", + "sha256:e7fb9a84c9abbf2b2683fa3e7b0d7da4d8ecf139a1c635732a8bda29c5214b0e", + "sha256:e861ad82892408487be144906a368ddbe2dc6297074ade2d892341b35c59844a", + "sha256:ec314cde7314d2dd0510c6787326bbffcbdc317ecee6b7401ce218b3099075a7", + "sha256:ed5f6d2edbf349bd8d630e81f474d33d6ae5d07760c44d33cd808e2f5c8f4ae6", + "sha256:ef2e4e91fb3945769e14ce82ed53007195e616a63aa43b40fb7ebaaf907c8d4c", + "sha256:f011f104db880f4e2166bcdcf7f58250f7a465bc6b068dc84c824a3d4a5c94dc", + "sha256:f1528ec4374617a7a753f90f20e2f551121bb558fcb35926f99e3c42367164b8", + "sha256:f27785888d2fdd918bc36de8b8739f2d6c791399552333721b58193f68ea3e98", + "sha256:f35c7070eeec2cdaac6fd3fe245226ed2a6292d3ee8c938e5bb645b434c5f256", + "sha256:f3bbecd2f34d0e6d3c543fdb3b15d6b60dd69970c2b4c822379e5ec8f6f621d5", + "sha256:f6f1324db48f001c2ca26a25fa25af60711e09b9aaf4b28488602776f4f9a744", + "sha256:f78eb8422acc93d7b69964012ad7048764bb45a54ba7a39bb9e146c72ea29723", + "sha256:fb6e0faf8cb6b4beea5d6ed7b5a578254c6d7df54c36ccd3d8b3eb00d6770277", + "sha256:feccd282de1f6322f56f6845bf1207a537227812f0a9bf5571df52bb418d79d5" ], "markers": "python_version >= '3.9'", - "version": "==0.3.0" + "version": "==0.3.1" }, "pycparser": { "hashes": [ @@ -1257,118 +1257,117 @@ }, "pydantic": { "hashes": [ - "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584", - "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236" + "sha256:442557d2910e75c991c39f4b4ab18963d57b9b55122c8b2a9cd176d8c29ce968", + "sha256:5b6c415eee9f8123a14d859be0c84363fec6b1feb6b688d6435801230b56e0b8" ], "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==2.10.6" + "markers": "python_version >= '3.9'", + "version": "==2.11.1" }, "pydantic-core": { "hashes": [ - "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278", - "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50", - "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9", - "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f", - "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", - "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", - "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54", - "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630", - "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9", - "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236", - "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", - "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", - "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", - "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", - "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", - "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", - "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", - "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd", - "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", - "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", - "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7", - "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", - "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e", - "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa", - "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", - "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962", - "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", - "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f", - "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", - "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5", - "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", - "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf", - "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a", - "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c", - "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76", - "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362", - "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4", - "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", - "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320", - "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118", - "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96", - "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", - "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046", - "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3", - "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", - "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af", - "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", - "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67", - "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a", - "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", - "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35", - "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", - "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151", - "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b", - "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", - "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133", - "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", - "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145", - "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", - "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", - "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", - "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", - "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", - "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", - "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5", - "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", - "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", - "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8", - "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", - "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da", - "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", - "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc", - "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993", - "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656", - "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4", - "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", - "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb", - "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d", - "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", - "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e", - "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", - "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc", - "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a", - "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9", - "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506", - "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b", - "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1", - "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", - "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", - "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", - "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31", - "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c", - "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", - "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", - "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308", - "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2", - "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228", - "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b", - "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", - "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad" + "sha256:024d136ae44d233e6322027bbf356712b3940bee816e6c948ce4b90f18471b3d", + "sha256:0310524c833d91403c960b8a3cf9f46c282eadd6afd276c8c5edc617bd705dc9", + "sha256:07b4ced28fccae3f00626eaa0c4001aa9ec140a29501770a88dbbb0966019a86", + "sha256:085d8985b1c1e48ef271e98a658f562f29d89bda98bf120502283efbc87313eb", + "sha256:0a98257451164666afafc7cbf5fb00d613e33f7e7ebb322fbcd99345695a9a61", + "sha256:0bcf0bab28995d483f6c8d7db25e0d05c3efa5cebfd7f56474359e7137f39856", + "sha256:138d31e3f90087f42aa6286fb640f3c7a8eb7bdae829418265e7e7474bd2574b", + "sha256:14229c1504287533dbf6b1fc56f752ce2b4e9694022ae7509631ce346158de11", + "sha256:1583539533160186ac546b49f5cde9ffc928062c96920f58bd95de32ffd7bffd", + "sha256:175ab598fb457a9aee63206a1993874badf3ed9a456e0654273e56f00747bbd6", + "sha256:1a69b7596c6603afd049ce7f3835bcf57dd3892fc7279f0ddf987bebed8caa5a", + "sha256:1a73be93ecef45786d7d95b0c5e9b294faf35629d03d5b145b09b81258c7cd6d", + "sha256:1b1262b912435a501fa04cd213720609e2cefa723a07c92017d18693e69bf00b", + "sha256:1b2ea72dea0825949a045fa4071f6d5b3d7620d2a208335207793cf29c5a182d", + "sha256:20d4275f3c4659d92048c70797e5fdc396c6e4446caf517ba5cad2db60cd39d3", + "sha256:23c3e77bf8a7317612e5c26a3b084c7edeb9552d645742a54a5867635b4f2453", + "sha256:26a4ea04195638dcd8c53dadb545d70badba51735b1594810e9768c2c0b4a5da", + "sha256:26bc7367c0961dec292244ef2549afa396e72e28cc24706210bd44d947582c59", + "sha256:2a0147c0bef783fd9abc9f016d66edb6cac466dc54a17ec5f5ada08ff65caf5d", + "sha256:2c0afd34f928383e3fd25740f2050dbac9d077e7ba5adbaa2227f4d4f3c8da5c", + "sha256:30369e54d6d0113d2aa5aee7a90d17f225c13d87902ace8fcd7bbf99b19124db", + "sha256:31860fbda80d8f6828e84b4a4d129fd9c4535996b8249cfb8c720dc2a1a00bb8", + "sha256:34e7fb3abe375b5c4e64fab75733d605dda0f59827752debc99c17cb2d5f3276", + "sha256:40eb8af662ba409c3cbf4a8150ad32ae73514cd7cb1f1a2113af39763dd616b3", + "sha256:41d698dcbe12b60661f0632b543dbb119e6ba088103b364ff65e951610cb7ce0", + "sha256:4726f1f3f42d6a25678c67da3f0b10f148f5655813c5aca54b0d1742ba821b8f", + "sha256:4927564be53239a87770a5f86bdc272b8d1fbb87ab7783ad70255b4ab01aa25b", + "sha256:4b6d77c75a57f041c5ee915ff0b0bb58eabb78728b69ed967bc5b780e8f701b8", + "sha256:4d9149e7528af8bbd76cc055967e6e04617dcb2a2afdaa3dea899406c5521faa", + "sha256:4deac83a8cc1d09e40683be0bc6d1fa4cde8df0a9bf0cda5693f9b0569ac01b6", + "sha256:4f1ab031feb8676f6bd7c85abec86e2935850bf19b84432c64e3e239bffeb1ec", + "sha256:502ed542e0d958bd12e7c3e9a015bce57deaf50eaa8c2e1c439b512cb9db1e3a", + "sha256:5461934e895968655225dfa8b3be79e7e927e95d4bd6c2d40edd2fa7052e71b6", + "sha256:58c1151827eef98b83d49b6ca6065575876a02d2211f259fb1a6b7757bd24dd8", + "sha256:5bdd36b362f419c78d09630cbaebc64913f66f62bda6d42d5fbb08da8cc4f181", + "sha256:5bf637300ff35d4f59c006fff201c510b2b5e745b07125458a5389af3c0dff8c", + "sha256:5bf68bb859799e9cec3d9dd8323c40c00a254aabb56fe08f907e437005932f2b", + "sha256:5d8dc9f63a26f7259b57f46a7aab5af86b2ad6fbe48487500bb1f4b27e051e4c", + "sha256:5f36afd0d56a6c42cf4e8465b6441cf546ed69d3a4ec92724cc9c8c61bd6ecf4", + "sha256:5f72914cfd1d0176e58ddc05c7a47674ef4222c8253bf70322923e73e14a4ac3", + "sha256:6291797cad239285275558e0a27872da735b05c75d5237bbade8736f80e4c225", + "sha256:62c151ce3d59ed56ebd7ce9ce5986a409a85db697d25fc232f8e81f195aa39a1", + "sha256:635702b2fed997e0ac256b2cfbdb4dd0bf7c56b5d8fba8ef03489c03b3eb40e2", + "sha256:64672fa888595a959cfeff957a654e947e65bbe1d7d82f550417cbd6898a1d6b", + "sha256:68504959253303d3ae9406b634997a2123a0b0c1da86459abbd0ffc921695eac", + "sha256:69297418ad644d521ea3e1aa2e14a2a422726167e9ad22b89e8f1130d68e1e9a", + "sha256:6c32a40712e3662bebe524abe8abb757f2fa2000028d64cc5a1006016c06af43", + "sha256:715c62af74c236bf386825c0fdfa08d092ab0f191eb5b4580d11c3189af9d330", + "sha256:71dffba8fe9ddff628c68f3abd845e91b028361d43c5f8e7b3f8b91d7d85413e", + "sha256:7419241e17c7fbe5074ba79143d5523270e04f86f1b3a0dff8df490f84c8273a", + "sha256:759871f00e26ad3709efc773ac37b4d571de065f9dfb1778012908bcc36b3a73", + "sha256:7a25493320203005d2a4dac76d1b7d953cb49bce6d459d9ae38e30dd9f29bc9c", + "sha256:7b79af799630af263eca9ec87db519426d8c9b3be35016eddad1832bac812d87", + "sha256:7c9c84749f5787781c1c45bb99f433402e484e515b40675a5d121ea14711cf61", + "sha256:7da333f21cd9df51d5731513a6d39319892947604924ddf2e24a4612975fb936", + "sha256:82a4eba92b7ca8af1b7d5ef5f3d9647eee94d1f74d21ca7c21e3a2b92e008358", + "sha256:89670d7a0045acb52be0566df5bc8b114ac967c662c06cf5e0c606e4aadc964b", + "sha256:8a1d581e8cdbb857b0e0e81df98603376c1a5c34dc5e54039dcc00f043df81e7", + "sha256:8ec86b5baa36f0a0bfb37db86c7d52652f8e8aa076ab745ef7725784183c3fdd", + "sha256:91301a0980a1d4530d4ba7e6a739ca1a6b31341252cb709948e0aca0860ce0ae", + "sha256:918f2013d7eadea1d88d1a35fd4a1e16aaf90343eb446f91cb091ce7f9b431a2", + "sha256:9cb2390355ba084c1ad49485d18449b4242da344dea3e0fe10babd1f0db7dcfc", + "sha256:9ee65f0cc652261744fd07f2c6e6901c914aa6c5ff4dcfaf1136bc394d0dd26b", + "sha256:a608a75846804271cf9c83e40bbb4dab2ac614d33c6fd5b0c6187f53f5c593ef", + "sha256:a66d931ea2c1464b738ace44b7334ab32a2fd50be023d863935eb00f42be1778", + "sha256:a7a7f2a3f628d2f7ef11cb6188bcf0b9e1558151d511b974dfea10a49afe192b", + "sha256:abaeec1be6ed535a5d7ffc2e6c390083c425832b20efd621562fbb5bff6dc518", + "sha256:abfa44cf2f7f7d7a199be6c6ec141c9024063205545aa09304349781b9a125e6", + "sha256:ade5dbcf8d9ef8f4b28e682d0b29f3008df9842bb5ac48ac2c17bc55771cc976", + "sha256:ae62032ef513fe6281ef0009e30838a01057b832dc265da32c10469622613885", + "sha256:aec79acc183865bad120b0190afac467c20b15289050648b876b07777e67ea48", + "sha256:b716294e721d8060908dbebe32639b01bfe61b15f9f57bcc18ca9a0e00d9520b", + "sha256:b9ec80eb5a5f45a2211793f1c4aeddff0c3761d1c70d684965c1807e923a588b", + "sha256:ba95691cf25f63df53c1d342413b41bd7762d9acb425df8858d7efa616c0870e", + "sha256:bccc06fa0372151f37f6b69834181aa9eb57cf8665ed36405fb45fbf6cac3bae", + "sha256:c860773a0f205926172c6644c394e02c25421dc9a456deff16f64c0e299487d3", + "sha256:ca1103d70306489e3d006b0f79db8ca5dd3c977f6f13b2c59ff745249431a606", + "sha256:ce72d46eb201ca43994303025bd54d8a35a3fc2a3495fac653d6eb7205ce04f4", + "sha256:d20cbb9d3e95114325780f3cfe990f3ecae24de7a2d75f978783878cce2ad585", + "sha256:dcfebee69cd5e1c0b76a17e17e347c84b00acebb8dd8edb22d4a03e88e82a207", + "sha256:e1c69aa459f5609dec2fa0652d495353accf3eda5bdb18782bc5a2ae45c9273a", + "sha256:e2762c568596332fdab56b07060c8ab8362c56cf2a339ee54e491cd503612c50", + "sha256:e37f10f6d4bc67c58fbd727108ae1d8b92b397355e68519f1e4a7babb1473442", + "sha256:e790954b5093dff1e3a9a2523fddc4e79722d6f07993b4cd5547825c3cbf97b5", + "sha256:e81a295adccf73477220e15ff79235ca9dcbcee4be459eb9d4ce9a2763b8386c", + "sha256:e925819a98318d17251776bd3d6aa9f3ff77b965762155bdad15d1a9265c4cfd", + "sha256:ea30239c148b6ef41364c6f51d103c2988965b643d62e10b233b5efdca8c0099", + "sha256:eabf946a4739b5237f4f56d77fa6668263bc466d06a8036c055587c130a46f7b", + "sha256:ecb158fb9b9091b515213bed3061eb7deb1d3b4e02327c27a0ea714ff46b0760", + "sha256:ecc6d02d69b54a2eb83ebcc6f29df04957f734bcf309d346b4f83354d8376862", + "sha256:eddb18a00bbb855325db27b4c2a89a4ba491cd6a0bd6d852b225172a1f54b36c", + "sha256:f00e8b59e1fc8f09d05594aa7d2b726f1b277ca6155fc84c0396db1b373c4555", + "sha256:f1fb026c575e16f673c61c7b86144517705865173f3d0907040ac30c4f9f5915", + "sha256:f200b2f20856b5a6c3a35f0d4e344019f805e363416e609e9b47c552d35fd5ea", + "sha256:f225f3a3995dbbc26affc191d0443c6c4aa71b83358fd4c2b7d63e2f6f0336f9", + "sha256:f22dab23cdbce2005f26a8f0c71698457861f97fc6318c75814a50c75e87d025", + "sha256:f3eb479354c62067afa62f53bb387827bee2f75c9c79ef25eef6ab84d4b1ae3b", + "sha256:fc53e05c16697ff0c1c7c2b98e45e131d4bfb78068fffff92a82d169cbb4c7b7", + "sha256:ff48a55be9da6930254565ff5238d71d5e9cd8c5487a191cb85df3bdb8c77365" ], - "markers": "python_version >= '3.8'", - "version": "==2.27.2" + "markers": "python_version >= '3.9'", + "version": "==2.33.0" }, "pyjwt": { "hashes": [ @@ -1388,10 +1387,10 @@ }, "pytz": { "hashes": [ - "sha256:89dd22dca55b46eac6eda23b2d72721bf1bdfef212645d81513ef5d03038de57", - "sha256:c2db42be2a2518b28e65f9207c4d05e6ff547d1efa4086469ef855e4ab70178e" + "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", + "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00" ], - "version": "==2025.1" + "version": "==2025.2" }, "pyyaml": { "hashes": [ @@ -1471,112 +1470,123 @@ }, "rpds-py": { "hashes": [ - "sha256:09cd7dbcb673eb60518231e02874df66ec1296c01a4fcd733875755c02014b19", - "sha256:0f3288930b947cbebe767f84cf618d2cbe0b13be476e749da0e6a009f986248c", - "sha256:0fced9fd4a07a1ded1bac7e961ddd9753dd5d8b755ba8e05acba54a21f5f1522", - "sha256:112b8774b0b4ee22368fec42749b94366bd9b536f8f74c3d4175d4395f5cbd31", - "sha256:11dd60b2ffddba85715d8a66bb39b95ddbe389ad2cfcf42c833f1bcde0878eaf", - "sha256:178f8a60fc24511c0eb756af741c476b87b610dba83270fce1e5a430204566a4", - "sha256:1b08027489ba8fedde72ddd233a5ea411b85a6ed78175f40285bd401bde7466d", - "sha256:1bf5be5ba34e19be579ae873da515a2836a2166d8d7ee43be6ff909eda42b72b", - "sha256:1ed7de3c86721b4e83ac440751329ec6a1102229aa18163f84c75b06b525ad7e", - "sha256:1eedaaccc9bb66581d4ae7c50e15856e335e57ef2734dbc5fd8ba3e2a4ab3cb6", - "sha256:243241c95174b5fb7204c04595852fe3943cc41f47aa14c3828bc18cd9d3b2d6", - "sha256:26bb3e8de93443d55e2e748e9fd87deb5f8075ca7bc0502cfc8be8687d69a2ec", - "sha256:271fa2184cf28bdded86bb6217c8e08d3a169fe0bbe9be5e8d96e8476b707122", - "sha256:28358c54fffadf0ae893f6c1050e8f8853e45df22483b7fff2f6ab6152f5d8bf", - "sha256:285019078537949cecd0190f3690a0b0125ff743d6a53dfeb7a4e6787af154f5", - "sha256:2893d778d4671ee627bac4037a075168b2673c57186fb1a57e993465dbd79a93", - "sha256:2a54027554ce9b129fc3d633c92fa33b30de9f08bc61b32c053dc9b537266fed", - "sha256:2c6ae11e6e93728d86aafc51ced98b1658a0080a7dd9417d24bfb955bb09c3c2", - "sha256:2cfa07c346a7ad07019c33fb9a63cf3acb1f5363c33bc73014e20d9fe8b01cdd", - "sha256:35d5631ce0af26318dba0ae0ac941c534453e42f569011585cb323b7774502a5", - "sha256:3614d280bf7aab0d3721b5ce0e73434acb90a2c993121b6e81a1c15c665298ac", - "sha256:3902df19540e9af4cc0c3ae75974c65d2c156b9257e91f5101a51f99136d834c", - "sha256:3aaf141d39f45322e44fc2c742e4b8b4098ead5317e5f884770c8df0c332da70", - "sha256:3d8abf7896a91fb97e7977d1aadfcc2c80415d6dc2f1d0fca5b8d0df247248f3", - "sha256:3e77febf227a1dc3220159355dba68faa13f8dca9335d97504abf428469fb18b", - "sha256:3e9212f52074fc9d72cf242a84063787ab8e21e0950d4d6709886fb62bcb91d5", - "sha256:3ee9d6f0b38efb22ad94c3b68ffebe4c47865cdf4b17f6806d6c674e1feb4246", - "sha256:4233df01a250b3984465faed12ad472f035b7cd5240ea3f7c76b7a7016084495", - "sha256:4263320ed887ed843f85beba67f8b2d1483b5947f2dc73a8b068924558bfeace", - "sha256:4ab923167cfd945abb9b51a407407cf19f5bee35001221f2911dc85ffd35ff4f", - "sha256:4caafd1a22e5eaa3732acb7672a497123354bef79a9d7ceed43387d25025e935", - "sha256:50fb62f8d8364978478b12d5f03bf028c6bc2af04082479299139dc26edf4c64", - "sha256:55ff4151cfd4bc635e51cfb1c59ac9f7196b256b12e3a57deb9e5742e65941ad", - "sha256:5b98b6c953e5c2bda51ab4d5b4f172617d462eebc7f4bfdc7c7e6b423f6da957", - "sha256:5c9ff044eb07c8468594d12602291c635da292308c8c619244e30698e7fc455a", - "sha256:5e9c206a1abc27e0588cf8b7c8246e51f1a16a103734f7750830a1ccb63f557a", - "sha256:5fb89edee2fa237584e532fbf78f0ddd1e49a47c7c8cfa153ab4849dc72a35e6", - "sha256:633462ef7e61d839171bf206551d5ab42b30b71cac8f10a64a662536e057fdef", - "sha256:66f8d2a17e5838dd6fb9be6baaba8e75ae2f5fa6b6b755d597184bfcd3cb0eba", - "sha256:6959bb9928c5c999aba4a3f5a6799d571ddc2c59ff49917ecf55be2bbb4e3722", - "sha256:698a79d295626ee292d1730bc2ef6e70a3ab135b1d79ada8fde3ed0047b65a10", - "sha256:721f9c4011b443b6e84505fc00cc7aadc9d1743f1c988e4c89353e19c4a968ee", - "sha256:72e680c1518733b73c994361e4b06441b92e973ef7d9449feec72e8ee4f713da", - "sha256:75307599f0d25bf6937248e5ac4e3bde5ea72ae6618623b86146ccc7845ed00b", - "sha256:754fba3084b70162a6b91efceee8a3f06b19e43dac3f71841662053c0584209a", - "sha256:759462b2d0aa5a04be5b3e37fb8183615f47014ae6b116e17036b131985cb731", - "sha256:7938c7b0599a05246d704b3f5e01be91a93b411d0d6cc62275f025293b8a11ce", - "sha256:7b77e07233925bd33fc0022b8537774423e4c6680b6436316c5075e79b6384f4", - "sha256:7e5413d2e2d86025e73f05510ad23dad5950ab8417b7fc6beaad99be8077138b", - "sha256:7f3240dcfa14d198dba24b8b9cb3b108c06b68d45b7babd9eefc1038fdf7e707", - "sha256:7f9682a8f71acdf59fd554b82b1c12f517118ee72c0f3944eda461606dfe7eb9", - "sha256:8d67beb6002441faef8251c45e24994de32c4c8686f7356a1f601ad7c466f7c3", - "sha256:9441af1d25aed96901f97ad83d5c3e35e6cd21a25ca5e4916c82d7dd0490a4fa", - "sha256:98b257ae1e83f81fb947a363a274c4eb66640212516becaff7bef09a5dceacaa", - "sha256:9e9f3a3ac919406bc0414bbbd76c6af99253c507150191ea79fab42fdb35982a", - "sha256:a1c66e71ecfd2a4acf0e4bd75e7a3605afa8f9b28a3b497e4ba962719df2be57", - "sha256:a1e17d8dc8e57d8e0fd21f8f0f0a5211b3fa258b2e444c2053471ef93fe25a00", - "sha256:a20cb698c4a59c534c6701b1c24a968ff2768b18ea2991f886bd8985ce17a89f", - "sha256:a970bfaf130c29a679b1d0a6e0f867483cea455ab1535fb427566a475078f27f", - "sha256:a98f510d86f689fcb486dc59e6e363af04151e5260ad1bdddb5625c10f1e95f8", - "sha256:a9d3b728f5a5873d84cba997b9d617c6090ca5721caaa691f3b1a78c60adc057", - "sha256:ad76f44f70aac3a54ceb1813ca630c53415da3a24fd93c570b2dfb4856591017", - "sha256:ae28144c1daa61366205d32abd8c90372790ff79fc60c1a8ad7fd3c8553a600e", - "sha256:b03a8d50b137ee758e4c73638b10747b7c39988eb8e6cd11abb7084266455165", - "sha256:b5a96fcac2f18e5a0a23a75cd27ce2656c66c11c127b0318e508aab436b77428", - "sha256:b5ef909a37e9738d146519657a1aab4584018746a18f71c692f2f22168ece40c", - "sha256:b79f5ced71efd70414a9a80bbbfaa7160da307723166f09b69773153bf17c590", - "sha256:b91cceb5add79ee563bd1f70b30896bd63bc5f78a11c1f00a1e931729ca4f1f4", - "sha256:b92f5654157de1379c509b15acec9d12ecf6e3bc1996571b6cb82a4302060447", - "sha256:c04ca91dda8a61584165825907f5c967ca09e9c65fe8966ee753a3f2b019fe1e", - "sha256:c1f8afa346ccd59e4e5630d5abb67aba6a9812fddf764fd7eb11f382a345f8cc", - "sha256:c5334a71f7dc1160382d45997e29f2637c02f8a26af41073189d79b95d3321f1", - "sha256:c617d7453a80e29d9973b926983b1e700a9377dbe021faa36041c78537d7b08c", - "sha256:c632419c3870507ca20a37c8f8f5352317aca097639e524ad129f58c125c61c6", - "sha256:c6760211eee3a76316cf328f5a8bd695b47b1626d21c8a27fb3b2473a884d597", - "sha256:c698d123ce5d8f2d0cd17f73336615f6a2e3bdcedac07a1291bb4d8e7d82a05a", - "sha256:c76b32eb2ab650a29e423525e84eb197c45504b1c1e6e17b6cc91fcfeb1a4b1d", - "sha256:c8f7e90b948dc9dcfff8003f1ea3af08b29c062f681c05fd798e36daa3f7e3e8", - "sha256:c9e799dac1ffbe7b10c1fd42fe4cd51371a549c6e108249bde9cd1200e8f59b4", - "sha256:cafa48f2133d4daa028473ede7d81cd1b9f9e6925e9e4003ebdf77010ee02f35", - "sha256:ce473a2351c018b06dd8d30d5da8ab5a0831056cc53b2006e2a8028172c37ce5", - "sha256:d31ed4987d72aabdf521eddfb6a72988703c091cfc0064330b9e5f8d6a042ff5", - "sha256:d550d7e9e7d8676b183b37d65b5cd8de13676a738973d330b59dc8312df9c5dc", - "sha256:d6adb81564af0cd428910f83fa7da46ce9ad47c56c0b22b50872bc4515d91966", - "sha256:d6f6512a90bd5cd9030a6237f5346f046c6f0e40af98657568fa45695d4de59d", - "sha256:d7031d493c4465dbc8d40bd6cafefef4bd472b17db0ab94c53e7909ee781b9ef", - "sha256:d9f75a06ecc68f159d5d7603b734e1ff6daa9497a929150f794013aa9f6e3f12", - "sha256:db7707dde9143a67b8812c7e66aeb2d843fe33cc8e374170f4d2c50bd8f2472d", - "sha256:e0397dd0b3955c61ef9b22838144aa4bef6f0796ba5cc8edfc64d468b93798b4", - "sha256:e0df046f2266e8586cf09d00588302a32923eb6386ced0ca5c9deade6af9a149", - "sha256:e14f86b871ea74c3fddc9a40e947d6a5d09def5adc2076ee61fb910a9014fb35", - "sha256:e5963ea87f88bddf7edd59644a35a0feecf75f8985430124c253612d4f7d27ae", - "sha256:e768267cbe051dd8d1c5305ba690bb153204a09bf2e3de3ae530de955f5b5580", - "sha256:e9cb79ecedfc156c0692257ac7ed415243b6c35dd969baa461a6888fc79f2f07", - "sha256:ed6f011bedca8585787e5082cce081bac3d30f54520097b2411351b3574e1219", - "sha256:f3429fb8e15b20961efca8c8b21432623d85db2228cc73fe22756c6637aa39e7", - "sha256:f35eff113ad430b5272bbfc18ba111c66ff525828f24898b4e146eb479a2cdda", - "sha256:f3a6cb95074777f1ecda2ca4fa7717caa9ee6e534f42b7575a8f0d4cb0c24013", - "sha256:f7356a6da0562190558c4fcc14f0281db191cdf4cb96e7604c06acfcee96df15", - "sha256:f88626e3f5e57432e6191cd0c5d6d6b319b635e70b40be2ffba713053e5147dd", - "sha256:fad784a31869747df4ac968a351e070c06ca377549e4ace94775aaa3ab33ee06", - "sha256:fc869af5cba24d45fb0399b0cfdbcefcf6910bf4dee5d74036a57cf5264b3ff4", - "sha256:fee513135b5a58f3bb6d89e48326cd5aa308e4bcdf2f7d59f67c861ada482bf8" + "sha256:0047638c3aa0dbcd0ab99ed1e549bbf0e142c9ecc173b6492868432d8989a046", + "sha256:006f4342fe729a368c6df36578d7a348c7c716be1da0a1a0f86e3021f8e98724", + "sha256:041f00419e1da7a03c46042453598479f45be3d787eb837af382bfc169c0db33", + "sha256:04ecf5c1ff4d589987b4d9882872f80ba13da7d42427234fce8f22efb43133bc", + "sha256:04f2b712a2206e13800a8136b07aaedc23af3facab84918e7aa89e4be0260032", + "sha256:0aeb3329c1721c43c58cae274d7d2ca85c1690d89485d9c63a006cb79a85771a", + "sha256:0e374c0ce0ca82e5b67cd61fb964077d40ec177dd2c4eda67dba130de09085c7", + "sha256:0f00c16e089282ad68a3820fd0c831c35d3194b7cdc31d6e469511d9bffc535c", + "sha256:174e46569968ddbbeb8a806d9922f17cd2b524aa753b468f35b97ff9c19cb718", + "sha256:1b221c2457d92a1fb3c97bee9095c874144d196f47c038462ae6e4a14436f7bc", + "sha256:208b3a70a98cf3710e97cabdc308a51cd4f28aa6e7bb11de3d56cd8b74bab98d", + "sha256:20f2712bd1cc26a3cc16c5a1bfee9ed1abc33d4cdf1aabd297fe0eb724df4272", + "sha256:24795c099453e3721fda5d8ddd45f5dfcc8e5a547ce7b8e9da06fecc3832e26f", + "sha256:2a0f156e9509cee987283abd2296ec816225145a13ed0391df8f71bf1d789e2d", + "sha256:2b2356688e5d958c4d5cb964af865bea84db29971d3e563fb78e46e20fe1848b", + "sha256:2c13777ecdbbba2077670285dd1fe50828c8742f6a4119dbef6f83ea13ad10fb", + "sha256:2d3ee4615df36ab8eb16c2507b11e764dcc11fd350bbf4da16d09cda11fcedef", + "sha256:2d53747da70a4e4b17f559569d5f9506420966083a31c5fbd84e764461c4444b", + "sha256:32bab0a56eac685828e00cc2f5d1200c548f8bc11f2e44abf311d6b548ce2e45", + "sha256:34d90ad8c045df9a4259c47d2e16a3f21fdb396665c94520dbfe8766e62187a4", + "sha256:369d9c6d4c714e36d4a03957b4783217a3ccd1e222cdd67d464a3a479fc17796", + "sha256:3a55fc10fdcbf1a4bd3c018eea422c52cf08700cf99c28b5cb10fe97ab77a0d3", + "sha256:3d2d8e4508e15fc05b31285c4b00ddf2e0eb94259c2dc896771966a163122a0c", + "sha256:3fab5f4a2c64a8fb64fc13b3d139848817a64d467dd6ed60dcdd6b479e7febc9", + "sha256:43dba99f00f1d37b2a0265a259592d05fcc8e7c19d140fe51c6e6f16faabeb1f", + "sha256:44d51febb7a114293ffd56c6cf4736cb31cd68c0fddd6aa303ed09ea5a48e029", + "sha256:493fe54318bed7d124ce272fc36adbf59d46729659b2c792e87c3b95649cdee9", + "sha256:4b28e5122829181de1898c2c97f81c0b3246d49f585f22743a1246420bb8d399", + "sha256:4cd031e63bc5f05bdcda120646a0d32f6d729486d0067f09d79c8db5368f4586", + "sha256:528927e63a70b4d5f3f5ccc1fa988a35456eb5d15f804d276709c33fc2f19bda", + "sha256:564c96b6076a98215af52f55efa90d8419cc2ef45d99e314fddefe816bc24f91", + "sha256:5db385bacd0c43f24be92b60c857cf760b7f10d8234f4bd4be67b5b20a7c0b6b", + "sha256:5ef877fa3bbfb40b388a5ae1cb00636a624690dcb9a29a65267054c9ea86d88a", + "sha256:5f6e3cec44ba05ee5cbdebe92d052f69b63ae792e7d05f1020ac5e964394080c", + "sha256:5fc13b44de6419d1e7a7e592a4885b323fbc2f46e1f22151e3a8ed3b8b920405", + "sha256:60748789e028d2a46fc1c70750454f83c6bdd0d05db50f5ae83e2db500b34da5", + "sha256:60d9b630c8025b9458a9d114e3af579a2c54bd32df601c4581bd054e85258143", + "sha256:619ca56a5468f933d940e1bf431c6f4e13bef8e688698b067ae68eb4f9b30e3a", + "sha256:630d3d8ea77eabd6cbcd2ea712e1c5cecb5b558d39547ac988351195db433f6c", + "sha256:63981feca3f110ed132fd217bf7768ee8ed738a55549883628ee3da75bb9cb78", + "sha256:66420986c9afff67ef0c5d1e4cdc2d0e5262f53ad11e4f90e5e22448df485bf0", + "sha256:675269d407a257b8c00a6b58205b72eec8231656506c56fd429d924ca00bb350", + "sha256:6a4a535013aeeef13c5532f802708cecae8d66c282babb5cd916379b72110cf7", + "sha256:6a727fd083009bc83eb83d6950f0c32b3c94c8b80a9b667c87f4bd1274ca30ba", + "sha256:6e1daf5bf6c2be39654beae83ee6b9a12347cb5aced9a29eecf12a2d25fff664", + "sha256:6eea559077d29486c68218178ea946263b87f1c41ae7f996b1f30a983c476a5a", + "sha256:75a810b7664c17f24bf2ffd7f92416c00ec84b49bb68e6a0d93e542406336b56", + "sha256:772cc1b2cd963e7e17e6cc55fe0371fb9c704d63e44cacec7b9b7f523b78919e", + "sha256:78884d155fd15d9f64f5d6124b486f3d3f7fd7cd71a78e9670a0f6f6ca06fb2d", + "sha256:79e8d804c2ccd618417e96720ad5cd076a86fa3f8cb310ea386a3e6229bae7d1", + "sha256:7e80d375134ddb04231a53800503752093dbb65dad8dabacce2c84cccc78e964", + "sha256:8097b3422d020ff1c44effc40ae58e67d93e60d540a65649d2cdaf9466030791", + "sha256:8205ee14463248d3349131bb8099efe15cd3ce83b8ef3ace63c7e976998e7124", + "sha256:8212ff58ac6dfde49946bea57474a386cca3f7706fc72c25b772b9ca4af6b79e", + "sha256:823e74ab6fbaa028ec89615ff6acb409e90ff45580c45920d4dfdddb069f2120", + "sha256:84e0566f15cf4d769dade9b366b7b87c959be472c92dffb70462dd0844d7cbad", + "sha256:896c41007931217a343eff197c34513c154267636c8056fb409eafd494c3dcdc", + "sha256:8aa362811ccdc1f8dadcc916c6d47e554169ab79559319ae9fae7d7752d0d60c", + "sha256:8b3b397eefecec8e8e39fa65c630ef70a24b09141a6f9fc17b3c3a50bed6b50e", + "sha256:8ebc7e65ca4b111d928b669713865f021b7773350eeac4a31d3e70144297baba", + "sha256:9168764133fd919f8dcca2ead66de0105f4ef5659cbb4fa044f7014bed9a1797", + "sha256:921ae54f9ecba3b6325df425cf72c074cd469dea843fb5743a26ca7fb2ccb149", + "sha256:92558d37d872e808944c3c96d0423b8604879a3d1c86fdad508d7ed91ea547d5", + "sha256:951cc481c0c395c4a08639a469d53b7d4afa252529a085418b82a6b43c45c240", + "sha256:998c01b8e71cf051c28f5d6f1187abbdf5cf45fc0efce5da6c06447cba997034", + "sha256:9abc80fe8c1f87218db116016de575a7998ab1629078c90840e8d11ab423ee25", + "sha256:9be4f99bee42ac107870c61dfdb294d912bf81c3c6d45538aad7aecab468b6b7", + "sha256:9c39438c55983d48f4bb3487734d040e22dad200dab22c41e331cee145e7a50d", + "sha256:9d7e8ce990ae17dda686f7e82fd41a055c668e13ddcf058e7fb5e9da20b57793", + "sha256:9ea7f4174d2e4194289cb0c4e172d83e79a6404297ff95f2875cf9ac9bced8ba", + "sha256:a18fc371e900a21d7392517c6f60fe859e802547309e94313cd8181ad9db004d", + "sha256:a36b452abbf29f68527cf52e181fced56685731c86b52e852053e38d8b60bc8d", + "sha256:a5b66d1b201cc71bc3081bc2f1fc36b0c1f268b773e03bbc39066651b9e18391", + "sha256:a824d2c7a703ba6daaca848f9c3d5cb93af0505be505de70e7e66829affd676e", + "sha256:a88c0d17d039333a41d9bf4616bd062f0bd7aa0edeb6cafe00a2fc2a804e944f", + "sha256:aa6800adc8204ce898c8a424303969b7aa6a5e4ad2789c13f8648739830323b7", + "sha256:aad911555286884be1e427ef0dc0ba3929e6821cbeca2194b13dc415a462c7fd", + "sha256:afc6e35f344490faa8276b5f2f7cbf71f88bc2cda4328e00553bd451728c571f", + "sha256:b9a4df06c35465ef4d81799999bba810c68d29972bf1c31db61bfdb81dd9d5bb", + "sha256:bb2954155bb8f63bb19d56d80e5e5320b61d71084617ed89efedb861a684baea", + "sha256:bbc4362e06f950c62cad3d4abf1191021b2ffaf0b31ac230fbf0526453eee75e", + "sha256:c0145295ca415668420ad142ee42189f78d27af806fcf1f32a18e51d47dd2052", + "sha256:c30ff468163a48535ee7e9bf21bd14c7a81147c0e58a36c1078289a8ca7af0bd", + "sha256:c347a20d79cedc0a7bd51c4d4b7dbc613ca4e65a756b5c3e57ec84bd43505b47", + "sha256:c43583ea8517ed2e780a345dd9960896afc1327e8cf3ac8239c167530397440d", + "sha256:c61a2cb0085c8783906b2f8b1f16a7e65777823c7f4d0a6aaffe26dc0d358dd9", + "sha256:c9ca89938dff18828a328af41ffdf3902405a19f4131c88e22e776a8e228c5a8", + "sha256:cc31e13ce212e14a539d430428cd365e74f8b2d534f8bc22dd4c9c55b277b875", + "sha256:cdabcd3beb2a6dca7027007473d8ef1c3b053347c76f685f5f060a00327b8b65", + "sha256:cf86f72d705fc2ef776bb7dd9e5fbba79d7e1f3e258bf9377f8204ad0fc1c51e", + "sha256:d09dc82af2d3c17e7dd17120b202a79b578d79f2b5424bda209d9966efeed114", + "sha256:d3aa13bdf38630da298f2e0d77aca967b200b8cc1473ea05248f6c5e9c9bdb44", + "sha256:d69d003296df4840bd445a5d15fa5b6ff6ac40496f956a221c4d1f6f7b4bc4d9", + "sha256:d6e109a454412ab82979c5b1b3aee0604eca4bbf9a02693bb9df027af2bfa91a", + "sha256:d8551e733626afec514b5d15befabea0dd70a343a9f23322860c4f16a9430205", + "sha256:d8754d872a5dfc3c5bf9c0e059e8107451364a30d9fd50f1f1a85c4fb9481164", + "sha256:d8f9a6e7fd5434817526815f09ea27f2746c4a51ee11bb3439065f5fc754db58", + "sha256:dbcbb6db5582ea33ce46a5d20a5793134b5365110d84df4e30b9d37c6fd40ad3", + "sha256:e0f3ef95795efcd3b2ec3fe0a5bcfb5dadf5e3996ea2117427e524d4fbf309c6", + "sha256:e13ae74a8a3a0c2f22f450f773e35f893484fcfacb00bb4344a7e0f4f48e1f97", + "sha256:e274f62cbd274359eff63e5c7e7274c913e8e09620f6a57aae66744b3df046d6", + "sha256:e838bf2bb0b91ee67bf2b889a1a841e5ecac06dd7a2b1ef4e6151e2ce155c7ae", + "sha256:e8acd55bd5b071156bae57b555f5d33697998752673b9de554dd82f5b5352727", + "sha256:e8e5ab32cf9eb3647450bc74eb201b27c185d3857276162c101c0f8c6374e098", + "sha256:ebcb786b9ff30b994d5969213a8430cbb984cdd7ea9fd6df06663194bd3c450c", + "sha256:ebea2821cdb5f9fef44933617be76185b80150632736f3d76e54829ab4a3b4d1", + "sha256:ed0ef550042a8dbcd657dfb284a8ee00f0ba269d3f2286b0493b15a5694f9fe8", + "sha256:eda5c1e2a715a4cbbca2d6d304988460942551e4e5e3b7457b50943cd741626d", + "sha256:f5c0ed12926dec1dfe7d645333ea59cf93f4d07750986a586f511c0bc61fe103", + "sha256:f6016bd950be4dcd047b7475fdf55fb1e1f59fc7403f387be0e8123e4a576d30", + "sha256:f9e0057a509e096e47c87f753136c9b10d7a91842d8042c2ee6866899a717c0d", + "sha256:fc1c892b1ec1f8cbd5da8de287577b455e388d9c328ad592eabbdcb6fc93bee5", + "sha256:fc2c1e1b00f88317d9de6b2c2b39b012ebbfe35fe5e7bef980fd2a91f6100a07", + "sha256:fd822f019ccccd75c832deb7aa040bb02d70a92eb15a2f16c7987b7ad4ee8d83" ], "markers": "python_version >= '3.9'", - "version": "==0.23.1" + "version": "==0.24.0" }, "s3transfer": { "hashes": [ @@ -1588,11 +1598,11 @@ }, "setuptools": { "hashes": [ - "sha256:199466a166ff664970d0ee145839f5582cb9bca7a0a3a2e795b6a9cb2308e9c6", - "sha256:43b4ee60e10b0d0ee98ad11918e114c70701bc6051662a9a675a0496c1a158f4" + "sha256:18fd474d4a82a5f83dac888df697af65afa82dec7323d09c3e37d1f14288da54", + "sha256:3e386e96793c8702ae83d17b853fb93d3e09ef82ec62722e61da5cd22376dcd8" ], "markers": "python_version >= '3.9'", - "version": "==76.0.0" + "version": "==78.1.0" }, "six": { "hashes": [ @@ -1620,19 +1630,27 @@ }, "typing-extensions": { "hashes": [ - "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", - "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" + "sha256:0a4ac55a5820789d87e297727d229866c9650f6521b64206413c4fbada24d95b", + "sha256:c8dd92cc0d6425a97c18fbb9d1954e5ff92c1ca881a309c45f06ebc0b79058e5" ], "markers": "python_version >= '3.8'", - "version": "==4.12.2" + "version": "==4.13.0" + }, + "typing-inspection": { + "hashes": [ + "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f", + "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122" + ], + "markers": "python_version >= '3.9'", + "version": "==0.4.0" }, "tzdata": { "hashes": [ - "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694", - "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639" + "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", + "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9" ], "markers": "python_version >= '2'", - "version": "==2025.1" + "version": "==2025.2" }, "urllib3": { "hashes": [ @@ -2007,73 +2025,73 @@ }, "coverage": { "hashes": [ - "sha256:056d3017ed67e7ddf266e6f57378ece543755a4c9231e997789ab3bd11392c94", - "sha256:0ce8cf59e09d31a4915ff4c3b94c6514af4c84b22c4cc8ad7c3c546a86150a92", - "sha256:104bf640f408f4e115b85110047c7f27377e1a8b7ba86f7db4fa47aa49dc9a8e", - "sha256:1393e5aa9441dafb0162c36c8506c648b89aea9565b31f6bfa351e66c11bcd82", - "sha256:1586ad158523f4133499a4f322b230e2cfef9cc724820dbd58595a5a236186f4", - "sha256:180e3fc68ee4dc5af8b33b6ca4e3bb8aa1abe25eedcb958ba5cff7123071af68", - "sha256:1b336d06af14f8da5b1f391e8dec03634daf54dfcb4d1c4fb6d04c09d83cef90", - "sha256:1c8fbce80b2b8bf135d105aa8f5b36eae0c57d702a1cc3ebdea2a6f03f6cdde5", - "sha256:2d673e3add00048215c2cc507f1228a7523fd8bf34f279ac98334c9b07bd2656", - "sha256:316f29cc3392fa3912493ee4c83afa4a0e2db04ff69600711f8c03997c39baaa", - "sha256:33c1394d8407e2771547583b66a85d07ed441ff8fae5a4adb4237ad39ece60db", - "sha256:37cbc7b0d93dfd133e33c7ec01123fbb90401dce174c3b6661d8d36fb1e30608", - "sha256:39abcacd1ed54e2c33c54bdc488b310e8ef6705833f7148b6eb9a547199d375d", - "sha256:3ab7090f04b12dc6469882ce81244572779d3a4b67eea1c96fb9ecc8c607ef39", - "sha256:3b0e6e54591ae0d7427def8a4d40fca99df6b899d10354bab73cd5609807261c", - "sha256:416e2a8845eaff288f97eaf76ab40367deafb9073ffc47bf2a583f26b05e5265", - "sha256:4545485fef7a8a2d8f30e6f79ce719eb154aab7e44217eb444c1d38239af2072", - "sha256:4c124025430249118d018dcedc8b7426f39373527c845093132196f2a483b6dd", - "sha256:4fbb7a0c3c21908520149d7751cf5b74eb9b38b54d62997b1e9b3ac19a8ee2fe", - "sha256:52fc89602cde411a4196c8c6894afb384f2125f34c031774f82a4f2608c59d7d", - "sha256:55143aa13c49491f5606f05b49ed88663446dce3a4d3c5d77baa4e36a16d3573", - "sha256:57f3bd0d29bf2bd9325c0ff9cc532a175110c4bf8f412c05b2405fd35745266d", - "sha256:5b2f144444879363ea8834cd7b6869d79ac796cb8f864b0cfdde50296cd95816", - "sha256:5efdeff5f353ed3352c04e6b318ab05c6ce9249c25ed3c2090c6e9cadda1e3b2", - "sha256:60e6347d1ed882b1159ffea172cb8466ee46c665af4ca397edbf10ff53e9ffaf", - "sha256:693d921621a0c8043bfdc61f7d4df5ea6d22165fe8b807cac21eb80dd94e4bbd", - "sha256:708f0a1105ef2b11c79ed54ed31f17e6325ac936501fc373f24be3e6a578146a", - "sha256:70f0925c4e2bfc965369f417e7cc72538fd1ba91639cf1e4ef4b1a6b50439b3b", - "sha256:7789e700f33f2b133adae582c9f437523cd5db8de845774988a58c360fc88253", - "sha256:7b6c96d69928a3a6767fab8dc1ce8a02cf0156836ccb1e820c7f45a423570d98", - "sha256:7d2a65876274acf544703e943c010b60bd79404e3623a1e5d52b64a6e2728de5", - "sha256:7f18d47641282664276977c604b5a261e51fefc2980f5271d547d706b06a837f", - "sha256:89078312f06237417adda7c021c33f80f7a6d2db8572a5f6c330d89b080061ce", - "sha256:8c938c6ae59be67ac19a7204e079efc94b38222cd7d0269f96e45e18cddeaa59", - "sha256:8e336b56301774ace6be0017ff85c3566c556d938359b61b840796a0202f805c", - "sha256:a0a207c87a9f743c8072d059b4711f8d13c456eb42dac778a7d2e5d4f3c253a7", - "sha256:a2454b12a3f12cc4698f3508912e6225ec63682e2ca5a96f80a2b93cef9e63f3", - "sha256:a538a23119d1e2e2ce077e902d02ea3d8e0641786ef6e0faf11ce82324743944", - "sha256:aa4dff57fc21a575672176d5ab0ef15a927199e775c5e8a3d75162ab2b0c7705", - "sha256:ad0edaa97cb983d9f2ff48cadddc3e1fb09f24aa558abeb4dc9a0dbacd12cbb4", - "sha256:ae8006772c6b0fa53c33747913473e064985dac4d65f77fd2fdc6474e7cd54e4", - "sha256:b0fac2088ec4aaeb5468b814bd3ff5e5978364bfbce5e567c44c9e2854469f6c", - "sha256:b3e212a894d8ae07fde2ca8b43d666a6d49bbbddb10da0f6a74ca7bd31f20054", - "sha256:b54a1ee4c6f1905a436cbaa04b26626d27925a41cbc3a337e2d3ff7038187f07", - "sha256:b667b91f4f714b17af2a18e220015c941d1cf8b07c17f2160033dbe1e64149f0", - "sha256:b8c36093aca722db73633cf2359026ed7782a239eb1c6db2abcff876012dc4cf", - "sha256:bb356e7ae7c2da13f404bf8f75be90f743c6df8d4607022e759f5d7d89fe83f8", - "sha256:bce730d484038e97f27ea2dbe5d392ec5c2261f28c319a3bb266f6b213650135", - "sha256:c075d167a6ec99b798c1fdf6e391a1d5a2d054caffe9593ba0f97e3df2c04f0e", - "sha256:c4e09534037933bf6eb31d804e72c52ec23219b32c1730f9152feabbd7499463", - "sha256:c5f8a5364fc37b2f172c26a038bc7ec4885f429de4a05fc10fdcb53fb5834c5c", - "sha256:cb203c0afffaf1a8f5b9659a013f8f16a1b2cad3a80a8733ceedc968c0cf4c57", - "sha256:cc41374d2f27d81d6558f8a24e5c114580ffefc197fd43eabd7058182f743322", - "sha256:cd879d4646055a573775a1cec863d00c9ff8c55860f8b17f6d8eee9140c06166", - "sha256:d013c07061751ae81861cae6ec3a4fe04e84781b11fd4b6b4201590234b25c7b", - "sha256:d8c7524779003d59948c51b4fcbf1ca4e27c26a7d75984f63488f3625c328b9b", - "sha256:d9710521f07f526de30ccdead67e6b236fe996d214e1a7fba8b36e2ba2cd8261", - "sha256:e1ffde1d6bc2a92f9c9207d1ad808550873748ac2d4d923c815b866baa343b3f", - "sha256:e7f559c36d5cdc448ee13e7e56ed7b6b5d44a40a511d584d388a0f5d940977ba", - "sha256:f2a1e18a85bd066c7c556d85277a7adf4651f259b2579113844835ba1a74aafd", - "sha256:f32b165bf6dfea0846a9c9c38b7e1d68f313956d60a15cde5d1709fddcaf3bee", - "sha256:f5a2f71d6a91238e7628f23538c26aa464d390cbdedf12ee2a7a0fb92a24482a", - "sha256:f81fe93dc1b8e5673f33443c0786c14b77e36f1025973b85e07c70353e46882b" + "sha256:042e7841a26498fff7a37d6fda770d17519982f5b7d8bf5278d140b67b61095f", + "sha256:04bfec25a8ef1c5f41f5e7e5c842f6b615599ca8ba8391ec33a9290d9d2db3a3", + "sha256:0915742f4c82208ebf47a2b154a5334155ed9ef9fe6190674b8a46c2fb89cb05", + "sha256:18c5ae6d061ad5b3e7eef4363fb27a0576012a7447af48be6c75b88494c6cf25", + "sha256:2931f66991175369859b5fd58529cd4b73582461877ecfd859b6549869287ffe", + "sha256:2e4b6b87bb0c846a9315e3ab4be2d52fac905100565f4b92f02c445c8799e257", + "sha256:3043ba1c88b2139126fc72cb48574b90e2e0546d4c78b5299317f61b7f718b78", + "sha256:379fe315e206b14e21db5240f89dc0774bdd3e25c3c58c2c733c99eca96f1ada", + "sha256:42421e04069fb2cbcbca5a696c4050b84a43b05392679d4068acbe65449b5c64", + "sha256:4dfd9a93db9e78666d178d4f08a5408aa3f2474ad4d0e0378ed5f2ef71640cb6", + "sha256:52a523153c568d2c0ef8826f6cc23031dc86cffb8c6aeab92c4ff776e7951b28", + "sha256:554fec1199d93ab30adaa751db68acec2b41c5602ac944bb19187cb9a41a8067", + "sha256:581a40c7b94921fffd6457ffe532259813fc68eb2bdda60fa8cc343414ce3733", + "sha256:5a26c0c795c3e0b63ec7da6efded5f0bc856d7c0b24b2ac84b4d1d7bc578d676", + "sha256:5a570cd9bd20b85d1a0d7b009aaf6c110b52b5755c17be6962f8ccd65d1dbd23", + "sha256:5aaeb00761f985007b38cf463b1d160a14a22c34eb3f6a39d9ad6fc27cb73008", + "sha256:5ac46d0c2dd5820ce93943a501ac5f6548ea81594777ca585bf002aa8854cacd", + "sha256:5c8a5c139aae4c35cbd7cadca1df02ea8cf28a911534fc1b0456acb0b14234f3", + "sha256:6b8af63b9afa1031c0ef05b217faa598f3069148eeee6bb24b79da9012423b82", + "sha256:769773614e676f9d8e8a0980dd7740f09a6ea386d0f383db6821df07d0f08545", + "sha256:771eb7587a0563ca5bb6f622b9ed7f9d07bd08900f7589b4febff05f469bea00", + "sha256:77af0f6447a582fdc7de5e06fa3757a3ef87769fbb0fdbdeba78c23049140a47", + "sha256:7a3d62b3b03b4b6fd41a085f3574874cf946cb4604d2b4d3e8dca8cd570ca501", + "sha256:821f7bcbaa84318287115d54becb1915eece6918136c6f91045bb84e2f88739d", + "sha256:89b1f4af0d4afe495cd4787a68e00f30f1d15939f550e869de90a86efa7e0814", + "sha256:8a1d96e780bdb2d0cbb297325711701f7c0b6f89199a57f2049e90064c29f6bd", + "sha256:8a40fcf208e021eb14b0fac6bdb045c0e0cab53105f93ba0d03fd934c956143a", + "sha256:8f99eb72bf27cbb167b636eb1726f590c00e1ad375002230607a844d9e9a2318", + "sha256:90e7fbc6216ecaffa5a880cdc9c77b7418c1dcb166166b78dbc630d07f278cc3", + "sha256:94ec0be97723ae72d63d3aa41961a0b9a6f5a53ff599813c324548d18e3b9e8c", + "sha256:95aa6ae391a22bbbce1b77ddac846c98c5473de0372ba5c463480043a07bff42", + "sha256:96121edfa4c2dfdda409877ea8608dd01de816a4dc4a0523356067b305e4e17a", + "sha256:a1f406a8e0995d654b2ad87c62caf6befa767885301f3b8f6f73e6f3c31ec3a6", + "sha256:a321c61477ff8ee705b8a5fed370b5710c56b3a52d17b983d9215861e37b642a", + "sha256:a5761c70c017c1b0d21b0815a920ffb94a670c8d5d409d9b38857874c21f70d7", + "sha256:a9abbccd778d98e9c7e85038e35e91e67f5b520776781d9a1e2ee9d400869487", + "sha256:ad80e6b4a0c3cb6f10f29ae4c60e991f424e6b14219d46f1e7d442b938ee68a4", + "sha256:b44674870709017e4b4036e3d0d6c17f06a0e6d4436422e0ad29b882c40697d2", + "sha256:b571bf5341ba8c6bc02e0baeaf3b061ab993bf372d982ae509807e7f112554e9", + "sha256:b8194fb8e50d556d5849753de991d390c5a1edeeba50f68e3a9253fbd8bf8ccd", + "sha256:b87eb6fc9e1bb8f98892a2458781348fa37e6925f35bb6ceb9d4afd54ba36c73", + "sha256:bbb5cc845a0292e0c520656d19d7ce40e18d0e19b22cb3e0409135a575bf79fc", + "sha256:be945402e03de47ba1872cd5236395e0f4ad635526185a930735f66710e1bd3f", + "sha256:bf13d564d310c156d1c8e53877baf2993fb3073b2fc9f69790ca6a732eb4bfea", + "sha256:cf60dd2696b457b710dd40bf17ad269d5f5457b96442f7f85722bdb16fa6c899", + "sha256:d1ba00ae33be84066cfbe7361d4e04dec78445b2b88bdb734d0d1cbab916025a", + "sha256:d39fc4817fd67b3915256af5dda75fd4ee10621a3d484524487e33416c6f3543", + "sha256:d766a4f0e5aa1ba056ec3496243150698dc0481902e2b8559314368717be82b1", + "sha256:dbf364b4c5e7bae9250528167dfe40219b62e2d573c854d74be213e1e52069f7", + "sha256:dd19608788b50eed889e13a5d71d832edc34fc9dfce606f66e8f9f917eef910d", + "sha256:e013b07ba1c748dacc2a80e69a46286ff145935f260eb8c72df7185bf048f502", + "sha256:e5d2b9be5b0693cf21eb4ce0ec8d211efb43966f6657807f6859aab3814f946b", + "sha256:e5ff52d790c7e1628241ffbcaeb33e07d14b007b6eb00a19320c7b8a7024c040", + "sha256:e75a2ad7b647fd8046d58c3132d7eaf31b12d8a53c0e4b21fa9c4d23d6ee6d3c", + "sha256:e7ac22a0bb2c7c49f441f7a6d46c9c80d96e56f5a8bc6972529ed43c8b694e27", + "sha256:ed2144b8a78f9d94d9515963ed273d620e07846acd5d4b0a642d4849e8d91a0c", + "sha256:f017a61399f13aa6d1039f75cd467be388d157cd81f1a119b9d9a68ba6f2830d", + "sha256:f1d8a2a57b47142b10374902777e798784abf400a004b14f1b0b9eaf1e528ba4", + "sha256:f2d32f95922927186c6dbc8bc60df0d186b6edb828d299ab10898ef3f40052fe", + "sha256:f319bae0321bc838e205bf9e5bc28f0a3165f30c203b610f17ab5552cff90323", + "sha256:f3c38e4e5ccbdc9198aecc766cedbb134b2d89bf64533973678dfcf07effd883", + "sha256:f9983d01d7705b2d1f7a95e10bbe4091fabc03a46881a256c2787637b087003f", + "sha256:fa260de59dfb143af06dcf30c2be0b200bed2a73737a8a59248fcb9fa601ef0f" ], "index": "pypi", "markers": "python_version >= '3.9'", - "version": "==7.7.0" + "version": "==7.8.0" }, "docker": { "hashes": [ @@ -2099,11 +2117,11 @@ }, "iniconfig": { "hashes": [ - "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", - "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" + "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", + "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760" ], - "markers": "python_version >= '3.7'", - "version": "==2.0.0" + "markers": "python_version >= '3.8'", + "version": "==2.1.0" }, "minio": { "hashes": [ @@ -2250,11 +2268,11 @@ }, "typing-extensions": { "hashes": [ - "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", - "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" + "sha256:0a4ac55a5820789d87e297727d229866c9650f6521b64206413c4fbada24d95b", + "sha256:c8dd92cc0d6425a97c18fbb9d1954e5ff92c1ca881a309c45f06ebc0b79058e5" ], "markers": "python_version >= '3.8'", - "version": "==4.12.2" + "version": "==4.13.0" }, "urllib3": { "hashes": [ diff --git a/dbrepo-analyse-service/app.py b/dbrepo-analyse-service/app.py index 1a2a0580487eda0645bd664083140e5a26798e09..a0329d32e38815de37908f53dbfc21d3943fdaac 100644 --- a/dbrepo-analyse-service/app.py +++ b/dbrepo-analyse-service/app.py @@ -1,20 +1,17 @@ -import os import logging -from typing import Any, List - +import os from json import dumps +from typing import Any, List -import requests.exceptions +from botocore.exceptions import ClientError from dbrepo.api.dto import ApiError +from dbrepo.core.client.auth import User, AuthServiceClient from flasgger import LazyJSONEncoder, Swagger, swag_from from flask import Flask, Response, request from flask_cors import CORS from flask_httpauth import HTTPBasicAuth, MultiAuth, HTTPTokenAuth from prometheus_flask_exporter import PrometheusMetrics -from botocore.exceptions import ClientError - -from clients.keycloak_client import KeycloakClient, User from determine_dt import determine_datatypes from determine_pk import determine_pk @@ -100,15 +97,19 @@ template = { }, "type": "object" }, - "ErrorDto": { + "ApiError": { "properties": { "message": { "example": "Message", "type": "string" }, - "success": { - "example": False, - "type": "boolean" + "status": { + "example": "BAD_REQUEST", + "type": "string" + }, + "code": { + "example": "error.dashboard.create", + "type": "string" } }, "type": "object" @@ -149,10 +150,6 @@ template = { "type": "integer", "example": 4 }, - "dfid": { - "type": "integer", - "example": None - }, "enums": { "type": "array", "example": None, @@ -188,7 +185,7 @@ template = { "info": { "title": "Database Repository Analyse Service API", "description": "Service that analyses data structures", - "version": "1.5", + "version": "1.8.0", "contact": { "name": "Prof. Andreas Rauber", "email": "andreas.rauber@tuwien.ac.at" @@ -200,11 +197,11 @@ template = { }, "externalDocs": { "description": "Sourcecode Documentation", - "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.5/" + "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.8/" }, "servers": [ { - "url": "http://localhost:5000", + "url": "http://localhost", "description": "Generated server url" }, { @@ -219,7 +216,7 @@ app.config["JWT_ALGORITHM"] = "HS256" app.config["JWT_PUBKEY"] = '-----BEGIN PUBLIC KEY-----\n' + os.getenv("JWT_PUBKEY", "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB") + '\n-----END PUBLIC KEY-----' app.config["ANALYSE_NROWS"] = int(os.getenv('ANALYSE_NROWS', '10000')) -app.config["AUTH_SERVICE_ENDPOINT"] = os.getenv("AUTH_SERVICE_ENDPOINT", "http://localhost/api/auth") +app.config["AUTH_SERVICE_ENDPOINT"] = os.getenv("AUTH_SERVICE_ENDPOINT", "http://auth-service:8080") app.config["AUTH_SERVICE_CLIENT"] = os.getenv("AUTH_SERVICE_CLIENT", "dbrepo-client") app.config["AUTH_SERVICE_CLIENT_SECRET"] = os.getenv("AUTH_SERVICE_CLIENT_SECRET", "MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG") app.config["S3_ACCESS_KEY_ID"] = os.getenv('S3_ACCESS_KEY_ID', 'seaweedfsadmin') @@ -234,41 +231,28 @@ app.config["SYSTEM_PASSWORD"] = os.getenv('SYSTEM_PASSWORD', 'admin') app.json_encoder = LazyJSONEncoder +auth_client = AuthServiceClient(app.config["AUTH_SERVICE_ENDPOINT"], app.config["AUTH_SERVICE_CLIENT"], + app.config["AUTH_SERVICE_CLIENT_SECRET"], app.config["JWT_PUBKEY"]) + @token_auth.verify_token def verify_token(token: str): - if token is None or token == "": - return False - try: - client = KeycloakClient() - return client.verify_jwt(access_token=token) - except AssertionError: - return False + return auth_client.is_valid_token(token) @basic_auth.verify_password def verify_password(username: str, password: str) -> Any: - if username is None or username == "" or password is None or password == "": - return False - client = KeycloakClient() - try: - return client.verify_jwt(access_token=client.obtain_user_token(username=username, password=password)) - except AssertionError as error: - logging.error(error) - return False - except requests.exceptions.ConnectionError as error: - logging.error(f"Failed to connect to Authentication Service {error}") - return False + return auth_client.is_valid_password(username, password) @token_auth.get_user_roles def get_user_roles(user: User) -> List[str]: - return user.roles + return auth_client.get_user_roles(user) @basic_auth.get_user_roles def get_user_roles(user: User) -> List[str]: - return user.roles + return auth_client.get_user_roles(user) @app.route("/health", methods=["GET"], endpoint="analyse_health") @@ -300,7 +284,8 @@ def analyse_datatypes(): return ApiError(status='BAD_REQUEST', message=str(e), code='error.analyse.invalid').model_dump_json(), 400 except ClientError as e: logging.error(f"Failed to determine separator: {e}") - return ApiError(status='NOT_FOUND', message='Failed to find csv', code='error.analyse.missing').model_dump_json(), 404 + return ApiError(status='NOT_FOUND', message='Failed to find csv', + code='error.analyse.missing').model_dump_json(), 404 @app.route("/api/analyse/keys", methods=["GET"], endpoint="analyse_analyse_keys") diff --git a/dbrepo-analyse-service/clients/keycloak_client.py b/dbrepo-analyse-service/clients/keycloak_client.py deleted file mode 100644 index afa36a1112ce41b5686641f5691df3f44075cf2f..0000000000000000000000000000000000000000 --- a/dbrepo-analyse-service/clients/keycloak_client.py +++ /dev/null @@ -1,37 +0,0 @@ -import logging -from dataclasses import dataclass -import requests -from flask import current_app -from typing import List - -from jwt import jwk_from_pem, JWT - - -@dataclass(init=True, eq=True) -class User: - username: str - roles: List[str] - - -class KeycloakClient: - - def obtain_user_token(self, username: str, password: str) -> str: - response = requests.post( - f"{current_app.config['AUTH_SERVICE_ENDPOINT']}/realms/dbrepo/protocol/openid-connect/token", - data={ - "username": username, - "password": password, - "grant_type": "password", - "client_id": current_app.config["AUTH_SERVICE_CLIENT"], - "client_secret": current_app.config["AUTH_SERVICE_CLIENT_SECRET"] - }) - body = response.json() - if "access_token" not in body: - raise AssertionError("Failed to obtain user token(s)") - return response.json()["access_token"] - - def verify_jwt(self, access_token: str) -> User: - public_key = jwk_from_pem(str(current_app.config["JWT_PUBKEY"]).encode('utf-8')) - payload = JWT().decode(message=access_token, key=public_key, do_time_check=True) - logging.debug(f"JWT token client_id={payload.get('client_id')} and realm_access={payload.get('realm_access')}") - return User(username=payload.get('client_id'), roles=payload.get('realm_access')["roles"]) diff --git a/dbrepo-analyse-service/determine_dt.py b/dbrepo-analyse-service/determine_dt.py index 8df1b7363f97e92f934d3af27f6de9ecba611820..722131801e8dd32d19e08787919b057bbc25a97b 100644 --- a/dbrepo-analyse-service/determine_dt.py +++ b/dbrepo-analyse-service/determine_dt.py @@ -1,27 +1,24 @@ -# -*- coding: utf-8 -*- -""" -@author: Martin Weise -""" -import logging import io -import pandas +import logging -from numpy import dtype, max, min +import pandas +from dbrepo.core.client.storage import StorageServiceClient from flask import current_app -from pandas import DataFrame, NaT +from numpy import dtype, max, min +from pandas import DataFrame from pandas.errors import EmptyDataError, ParserError from api.dto import ColumnAnalysisDto, DataTypeDto, AnalysisDto -from clients.s3_client import S3Client def determine_datatypes(filename, enum=False, enum_tol=0.0001, separator=',') -> AnalysisDto: # Use option enum=True for searching Postgres ENUM Types in CSV file. Remark # Enum is not SQL standard, hence, it might not be supported by all db-engines. # However, it can be used in Postgres and MySQL. - s3_client = S3Client() - s3_client.file_exists(current_app.config['S3_BUCKET'], filename) - response = s3_client.get_file(current_app.config['S3_BUCKET'], filename) + storage_client = StorageServiceClient(current_app.config['S3_ENDPOINT'], current_app.config['S3_ACCESS_KEY_ID'], + current_app.config['S3_SECRET_ACCESS_KEY']) + storage_client.file_exists(current_app.config['S3_BUCKET'], filename) + response = storage_client.get_file(current_app.config['S3_BUCKET'], filename) stream = response['Body'] if response['ContentLength'] == 0: logging.warning(f'Failed to determine data types: file {filename} has empty body') @@ -44,8 +41,9 @@ def determine_datatypes(filename, enum=False, enum_tol=0.0001, separator=',') -> for encoding in ['utf-8', 'cp1252', 'latin1', 'iso-8859-1']: try: logging.debug(f"attempt parsing .csv using encoding {encoding}") - df = pandas.read_csv(fh, delimiter=separator, nrows=current_app.config['ANALYSE_NROWS'], - lineterminator=line_terminator, index_col=False, encoding=encoding) + df = pandas.read_csv(fh, delimiter=separator, lineterminator=line_terminator, index_col=False, + encoding=encoding) + df = df.sample(frac=1) logging.debug(f"parsing .csv using encoding {encoding} was successful") break except ParserError as error: @@ -98,7 +96,7 @@ def determine_datatypes(filename, enum=False, enum_tol=0.0001, separator=',') -> logging.debug(f"mapped column {name} from O to date") col.type = DataTypeDto.DATE continue - except ValueError: + except Exception: pass max_size = max(df[name].astype(str).map(len)) if max_size <= 1: diff --git a/dbrepo-analyse-service/determine_pk.py b/dbrepo-analyse-service/determine_pk.py index b0ad8cbf769bb87b814bd2d22261b349ce9bd303..772c356fdd33bd2e0f1dfdd89df663ead1762ff6 100644 --- a/dbrepo-analyse-service/determine_pk.py +++ b/dbrepo-analyse-service/determine_pk.py @@ -1,11 +1,13 @@ -import json import logging -import pandas +import math import random + import numpy -import math +import pandas +from dbrepo.core.client.storage import StorageServiceClient +from flask import current_app + from determine_dt import determine_datatypes -from clients.s3_client import S3Client def determine_pk(filename: str, separator: str = ','): @@ -14,10 +16,10 @@ def determine_pk(filename: str, separator: str = ','): # {k.lower(): v for k, v in dt['columns'].items() if v != 'Numeric'} colnames = dt.keys() colindex = list(range(0, len(colnames))) - - s3_client = S3Client() - s3_client.file_exists('dbrepo', filename) - response = s3_client.get_file('dbrepo', filename) + storage_client = StorageServiceClient(current_app.config['S3_ENDPOINT'], current_app.config['S3_ACCESS_KEY_ID'], + current_app.config['S3_SECRET_ACCESS_KEY']) + storage_client.file_exists('dbrepo', filename) + response = storage_client.get_file('dbrepo', filename) stream = response['Body'] if response['ContentLength'] == 0: raise OSError(f'Failed to determine primary key: file {filename} has empty body') diff --git a/dbrepo-analyse-service/lib/dbrepo-1.7.2.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.7.2.tar.gz deleted file mode 100644 index 12cef6f73928370726f75f4f3909aa6510049543..0000000000000000000000000000000000000000 Binary files a/dbrepo-analyse-service/lib/dbrepo-1.7.2.tar.gz and /dev/null differ diff --git a/dbrepo-analyse-service/lib/dbrepo-1.7.3-py3-none-any.whl b/dbrepo-analyse-service/lib/dbrepo-1.7.3-py3-none-any.whl deleted file mode 100644 index c1a74fe8c7e3f602651db9b6c30a5f7dcf17d97b..0000000000000000000000000000000000000000 Binary files a/dbrepo-analyse-service/lib/dbrepo-1.7.3-py3-none-any.whl and /dev/null differ diff --git a/dbrepo-analyse-service/lib/dbrepo-1.7.3.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.7.3.tar.gz deleted file mode 100644 index 7c13793a4936d21d621548c512ca88cfbf914716..0000000000000000000000000000000000000000 Binary files a/dbrepo-analyse-service/lib/dbrepo-1.7.3.tar.gz and /dev/null differ diff --git a/dbrepo-analyse-service/lib/dbrepo-1.8.0-py3-none-any.whl b/dbrepo-analyse-service/lib/dbrepo-1.8.0-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..a285fef8ff07eaeffb5a1dfbab34dd395c0330d9 Binary files /dev/null and b/dbrepo-analyse-service/lib/dbrepo-1.8.0-py3-none-any.whl differ diff --git a/dbrepo-analyse-service/lib/dbrepo-1.8.0.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.8.0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..4b3de54c835f7085ce9546cc519400bdbc9480b0 Binary files /dev/null and b/dbrepo-analyse-service/lib/dbrepo-1.8.0.tar.gz differ diff --git a/dbrepo-analyse-service/tests/conftest.py b/dbrepo-analyse-service/tests/conftest.py index 3418998a943a5891f34f0adea37987e8b46f1781..6c3745526bbd7b22faefd9c3c1a665891fe871f5 100644 --- a/dbrepo-analyse-service/tests/conftest.py +++ b/dbrepo-analyse-service/tests/conftest.py @@ -73,7 +73,7 @@ def opensearch_container(): with os_container: client = os_container.get_client() index_mapping_path = os.path.join( - "..", "dbrepo-search-db", "init", "indices", "database.json" + "..", "dbrepo-search-service", "init", "database.json" ) with open(index_mapping_path, "r") as file: mapping = json.load(file) diff --git a/dbrepo-analyse-service/tests/s3_config.json b/dbrepo-analyse-service/tests/s3_config.json deleted file mode 100644 index f270753cdc96278a039e483966ea864a16781cfe..0000000000000000000000000000000000000000 --- a/dbrepo-analyse-service/tests/s3_config.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "identities": [ - { - "name": "admin", - "credentials": [ - { - "accessKey": "seaweedfsadmin", - "secretKey": "seaweedfsadmin" - } - ], - "actions": [ - "Read", - "Write", - "List", - "Tagging", - "Admin" - ] - } - ] -} \ No newline at end of file diff --git a/dbrepo-analyse-service/tests/test_determine_dt.py b/dbrepo-analyse-service/tests/test_determine_dt.py index 824fbfcf479bea3b156a4de24a40878e8bf3523b..72cf915e52ba3429856a237f0dd827ce4207dd6c 100644 --- a/dbrepo-analyse-service/tests/test_determine_dt.py +++ b/dbrepo-analyse-service/tests/test_determine_dt.py @@ -1,8 +1,10 @@ import unittest -from api.dto import AnalysisDto -from clients.s3_client import S3Client from botocore.exceptions import ClientError +from dbrepo.core.client.storage import StorageServiceClient +from flask import current_app + +from api.dto import AnalysisDto from determine_dt import determine_datatypes @@ -47,9 +49,11 @@ class DetermineDatatypesTest(unittest.TestCase): }, }) - # mock - S3Client().upload_file("datetime.csv", './data/test_dt/', 'dbrepo') + with current_app.app_context(): + StorageServiceClient(current_app.config['S3_ENDPOINT'], current_app.config['S3_ACCESS_KEY_ID'], + current_app.config['S3_SECRET_ACCESS_KEY']).upload_file("datetime.csv", + './data/test_dt/', 'dbrepo') # test response = determine_datatypes(filename="datetime.csv", separator=",") @@ -95,7 +99,10 @@ class DetermineDatatypesTest(unittest.TestCase): }) # mock - S3Client().upload_file("datetime_tz.csv", './data/test_dt/', 'dbrepo') + with current_app.app_context(): + StorageServiceClient(current_app.config['S3_ENDPOINT'], current_app.config['S3_ACCESS_KEY_ID'], + current_app.config['S3_SECRET_ACCESS_KEY']).upload_file("datetime_tz.csv", + './data/test_dt/', 'dbrepo') # test response = determine_datatypes(filename="datetime_tz.csv", separator=",") @@ -141,7 +148,10 @@ class DetermineDatatypesTest(unittest.TestCase): }) # mock - S3Client().upload_file("datetime_t.csv", './data/test_dt/', 'dbrepo') + with current_app.app_context(): + StorageServiceClient(current_app.config['S3_ENDPOINT'], current_app.config['S3_ACCESS_KEY_ID'], + current_app.config['S3_SECRET_ACCESS_KEY']).upload_file("datetime_t.csv", + './data/test_dt/', 'dbrepo') # test response = determine_datatypes(filename="datetime_t.csv", separator=",") @@ -188,7 +198,10 @@ class DetermineDatatypesTest(unittest.TestCase): }) # mock - S3Client().upload_file("datatypes.csv", './data/test_dt/', 'dbrepo') + with current_app.app_context(): + StorageServiceClient(current_app.config['S3_ENDPOINT'], current_app.config['S3_ACCESS_KEY_ID'], + current_app.config['S3_SECRET_ACCESS_KEY']).upload_file("datatypes.csv", + './data/test_dt/', 'dbrepo') # test response = determine_datatypes(filename="datatypes.csv", separator=",") @@ -209,7 +222,10 @@ class DetermineDatatypesTest(unittest.TestCase): def test_determine_datatypes_fileEmpty_succeeds(self): # mock - S3Client().upload_file("empty.csv", './data/test_dt/', 'dbrepo') + with current_app.app_context(): + StorageServiceClient(current_app.config['S3_ENDPOINT'], current_app.config['S3_ACCESS_KEY_ID'], + current_app.config['S3_SECRET_ACCESS_KEY']).upload_file("empty.csv", './data/test_dt/', + 'dbrepo') # test response = determine_datatypes("empty.csv") @@ -219,7 +235,10 @@ class DetermineDatatypesTest(unittest.TestCase): def test_determine_datatypes_separatorSemicolon_succeeds(self): # mock - S3Client().upload_file("separator.csv", './data/test_dt/', 'dbrepo') + with current_app.app_context(): + StorageServiceClient(current_app.config['S3_ENDPOINT'], current_app.config['S3_ACCESS_KEY_ID'], + current_app.config['S3_SECRET_ACCESS_KEY']).upload_file("separator.csv", + './data/test_dt/', 'dbrepo') # test response = determine_datatypes(filename="separator.csv", separator=";") @@ -228,7 +247,10 @@ class DetermineDatatypesTest(unittest.TestCase): def test_determine_datatypes_separatorGuess_succeeds(self): # mock - S3Client().upload_file("separator.csv", './data/test_dt/', 'dbrepo') + with current_app.app_context(): + StorageServiceClient(current_app.config['S3_ENDPOINT'], current_app.config['S3_ACCESS_KEY_ID'], + current_app.config['S3_SECRET_ACCESS_KEY']).upload_file("separator.csv", + './data/test_dt/', 'dbrepo') # test response = determine_datatypes(filename="separator.csv") @@ -252,7 +274,10 @@ class DetermineDatatypesTest(unittest.TestCase): }) # mock - S3Client().upload_file("novel.csv", './data/test_dt/', 'dbrepo') + with current_app.app_context(): + StorageServiceClient(current_app.config['S3_ENDPOINT'], current_app.config['S3_ACCESS_KEY_ID'], + current_app.config['S3_SECRET_ACCESS_KEY']).upload_file("novel.csv", './data/test_dt/', + 'dbrepo') # test response = determine_datatypes(filename="novel.csv", separator=";") diff --git a/dbrepo-analyse-service/tests/test_determine_pk.py b/dbrepo-analyse-service/tests/test_determine_pk.py index 4e960d39c0b0bebd263c0453a94477fcae964319..b2e730edc61f0df7c3e127b6d96a378033b22f07 100644 --- a/dbrepo-analyse-service/tests/test_determine_pk.py +++ b/dbrepo-analyse-service/tests/test_determine_pk.py @@ -1,22 +1,29 @@ import unittest -from clients.s3_client import S3Client + +from dbrepo.core.client.storage import StorageServiceClient +from flask import current_app + from determine_pk import determine_pk class DeterminePrimaryKeyTest(unittest.TestCase): - # @Test def test_determine_pk_largeFileIdFirst_succeeds(self): # mock - S3Client().upload_file("largefile_idfirst.csv", './data/test_pk/', 'dbrepo') + with current_app.app_context(): + StorageServiceClient(current_app.config['S3_ENDPOINT'], current_app.config['S3_ACCESS_KEY_ID'], + current_app.config['S3_SECRET_ACCESS_KEY']).upload_file("largefile_idfirst.csv", + './data/test_pk/', 'dbrepo') # test response = determine_pk('largefile_idfirst.csv') self.assertEqual(1, int(response['id'])) - # @Test def test_determine_pk_largeFileIdInBetween_succeeds(self): # mock - S3Client().upload_file("largefile_idinbtw.csv", './data/test_pk/', 'dbrepo') + with current_app.app_context(): + StorageServiceClient(current_app.config['S3_ENDPOINT'], current_app.config['S3_ACCESS_KEY_ID'], + current_app.config['S3_SECRET_ACCESS_KEY']).upload_file("largefile_idinbtw.csv", + './data/test_pk/', 'dbrepo') # test response = determine_pk('largefile_idinbtw.csv') @@ -25,52 +32,65 @@ class DeterminePrimaryKeyTest(unittest.TestCase): # @Test def test_determine_pk_largeFileNoPrimaryKey_fails(self): # mock - S3Client().upload_file("largefile_no_pk.csv", './data/test_pk/', 'dbrepo') + with current_app.app_context(): + StorageServiceClient(current_app.config['S3_ENDPOINT'], current_app.config['S3_ACCESS_KEY_ID'], + current_app.config['S3_SECRET_ACCESS_KEY']).upload_file("largefile_no_pk.csv", + './data/test_pk/', 'dbrepo') # test response = determine_pk('largefile_no_pk.csv') self.assertEqual({}, response) - # @Test def test_determine_pk_largeFileNullInUnique_fails(self): # mock - S3Client().upload_file("largefile_nullinunique.csv", './data/test_pk/', 'dbrepo') + with current_app.app_context(): + StorageServiceClient(current_app.config['S3_ENDPOINT'], current_app.config['S3_ACCESS_KEY_ID'], + current_app.config['S3_SECRET_ACCESS_KEY']).upload_file("largefile_nullinunique.csv", + './data/test_pk/', 'dbrepo') # test response = determine_pk('largefile_nullinunique.csv') self.assertFalse('uniquestr' in response) - # @Test def test_determine_pk_smallFileIdFirst_fails(self): # mock - S3Client().upload_file("smallfile_idfirst.csv", './data/test_pk/', 'dbrepo') + with current_app.app_context(): + StorageServiceClient(current_app.config['S3_ENDPOINT'], current_app.config['S3_ACCESS_KEY_ID'], + current_app.config['S3_SECRET_ACCESS_KEY']).upload_file("smallfile_idfirst.csv", + './data/test_pk/', 'dbrepo') # test response = determine_pk('smallfile_idfirst.csv') self.assertEqual(1, int(response['id'])) - # @Test def test_determine_pk_smallFileIdIntBetween_fails(self): # mock - S3Client().upload_file("smallfile_idinbtw.csv", './data/test_pk/', 'dbrepo') + with current_app.app_context(): + StorageServiceClient(current_app.config['S3_ENDPOINT'], current_app.config['S3_ACCESS_KEY_ID'], + current_app.config['S3_SECRET_ACCESS_KEY']).upload_file("smallfile_idinbtw.csv", + './data/test_pk/', 'dbrepo') # test response = determine_pk('smallfile_idinbtw.csv') self.assertEqual(1, int(response['id'])) - # @Test def test_determine_pk_smallFileNoPrimaryKey_fails(self): # mock - S3Client().upload_file("smallfile_no_pk.csv", './data/test_pk/', 'dbrepo') + with current_app.app_context(): + StorageServiceClient(current_app.config['S3_ENDPOINT'], current_app.config['S3_ACCESS_KEY_ID'], + current_app.config['S3_SECRET_ACCESS_KEY']).upload_file("smallfile_no_pk.csv", + './data/test_pk/', 'dbrepo') # test response = determine_pk('smallfile_no_pk.csv') self.assertEqual({}, response) - # @Test def test_determine_pk_smallFileNullInUnique_fails(self): # mock - S3Client().upload_file("smallfile_nullinunique.csv", './data/test_pk/', 'dbrepo') + with current_app.app_context(): + StorageServiceClient(current_app.config['S3_ENDPOINT'], current_app.config['S3_ACCESS_KEY_ID'], + current_app.config['S3_SECRET_ACCESS_KEY']).upload_file("smallfile_nullinunique.csv", + './data/test_pk/', 'dbrepo') # test response = determine_pk('smallfile_nullinunique.csv') diff --git a/dbrepo-auth-service/init/.coveragerc b/dbrepo-auth-service/init/.coveragerc index a387be84259ecf1c8b1387a407e3cfc528960a30..75f7db52f9e99d919ec9c797589ae1d56a4fdf9c 100644 --- a/dbrepo-auth-service/init/.coveragerc +++ b/dbrepo-auth-service/init/.coveragerc @@ -2,8 +2,6 @@ omit = # omit tests ./tests/* - # omit ext lib - ./omlib/* [html] directory = htmlcov diff --git a/dbrepo-auth-service/init/app.py b/dbrepo-auth-service/init/app.py index 65252a5ccd615684c9533e3fddde0242c98f7e8a..55fa08cdaee443dd3c6ea0df7795373dc8188f74 100644 --- a/dbrepo-auth-service/init/app.py +++ b/dbrepo-auth-service/init/app.py @@ -5,22 +5,30 @@ from requests import post, get endpoint = os.getenv('AUTH_SERVICE_ENDPOINT', 'http://localhost:8080') system_username = os.getenv('SYSTEM_USERNAME', 'admin') +readonly_username = os.getenv('READONLY_USERNAME', 'user') -def fetch() -> (str, str): - print(f'Fetching user id of internal user with username: {system_username}') +def fetch_keycloak_master_access_token() -> str: + """ + Fetch admin access token from the master realm. + :return: The access token. + """ response = post(url=f'{endpoint}/realms/master/protocol/openid-connect/token', data=dict({ 'username': os.getenv('AUTH_SERVICE_ADMIN', 'admin'), 'password': os.getenv('AUTH_SERVICE_ADMIN_PASSWORD', 'admin'), 'grant_type': 'password', 'client_id': 'admin-cli' })) - if response.status_code != 200: raise IOError(f'Failed to obtain admin token: {response.status_code}') + return response.json()["access_token"] + + +def fetch(username) -> (str, str): + print(f'Fetching user id of internal user with username: {username}') - response = get(url=f'{endpoint}/admin/realms/dbrepo/users/?username={system_username}', headers=dict({ - 'Authorization': f'Bearer {response.json()["access_token"]}' + response = get(url=f'{endpoint}/admin/realms/dbrepo/users/?username={username}', headers=dict({ + 'Authorization': f'Bearer {fetch_keycloak_master_access_token()}' })) if response.status_code != 200 or len(response.json()) != 1: raise FileNotFoundError(f'Failed to obtain user') @@ -39,7 +47,7 @@ def fetch() -> (str, str): return (ldap_user_id, user_id) -def save(user_id: str, keycloak_id: str) -> None: +def save(user_id: str, keycloak_id: str, username: str) -> None: conn = mariadb.connect(user=os.getenv('METADATA_USERNAME', 'root'), password=os.getenv('METADATA_DB_PASSWORD', 'dbrepo'), host=os.getenv('METADATA_HOST', 'metadata-db'), @@ -48,12 +56,14 @@ def save(user_id: str, keycloak_id: str) -> None: cursor = conn.cursor() cursor.execute( "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)) + (user_id, keycloak_id, username)) conn.commit() conn.close() + print(f'Successfully inserted user: {username}') if __name__ == '__main__': - user_id, keycloak_id = fetch() - save(user_id, keycloak_id) - print(f'Successfully inserted user') + user_id, keycloak_id = fetch(system_username) + save(user_id, keycloak_id, system_username) + user_id, keycloak_id = fetch(readonly_username) + save(user_id, keycloak_id, readonly_username) diff --git a/dbrepo-auth-service/init/tests/test_unit_app.py b/dbrepo-auth-service/init/tests/test_unit_app.py index 4fb38ac2f45220d74f79ccbb12bc650f1cba4e3f..fc454cfa3ef1a358f1ce3a41c82e3f2c5d53a167 100644 --- a/dbrepo-auth-service/init/tests/test_unit_app.py +++ b/dbrepo-auth-service/init/tests/test_unit_app.py @@ -23,7 +23,7 @@ class AppUnitTest(unittest.TestCase): mock.post(f'{endpoint}/realms/master/protocol/openid-connect/token', json=self.token_res, status_code=400) # test try: - fetch() + fetch('admin') except IOError: pass @@ -33,7 +33,7 @@ class AppUnitTest(unittest.TestCase): mock.post(f'{endpoint}/realms/master/protocol/openid-connect/token', json=self.token_res, status_code=401) # test try: - fetch() + fetch('admin') except IOError: pass @@ -45,7 +45,7 @@ class AppUnitTest(unittest.TestCase): # test try: - fetch() + fetch('admin') except FileNotFoundError: pass @@ -57,7 +57,7 @@ class AppUnitTest(unittest.TestCase): # test try: - fetch() + fetch('admin') except FileNotFoundError: pass @@ -69,7 +69,7 @@ class AppUnitTest(unittest.TestCase): # test try: - fetch() + fetch('admin') except FileNotFoundError: pass @@ -83,7 +83,7 @@ class AppUnitTest(unittest.TestCase): # test try: - fetch() + fetch('admin') except ModuleNotFoundError: pass @@ -98,7 +98,7 @@ class AppUnitTest(unittest.TestCase): # test try: - fetch() + fetch('admin') except ImportError: pass @@ -115,7 +115,7 @@ class AppUnitTest(unittest.TestCase): # test try: - fetch() + fetch('admin') except EnvironmentError: pass @@ -131,6 +131,6 @@ class AppUnitTest(unittest.TestCase): }], status_code=200) # test - ldap_user_id, user_id = fetch() + ldap_user_id, user_id = fetch('admin') self.assertEqual("7a0b4b7f-77cd-4f28-a665-2da443024621", ldap_user_id) self.assertEqual("5b516520-67cb-4aa0-86a6-d12f8b8f1a20", user_id) diff --git a/dbrepo-auth-service/listeners/target/create-event-listener.jar b/dbrepo-auth-service/listeners/target/create-event-listener.jar index 9fb1271c4361841c3d4061e536d23bc16b590d0e..42cd10a361a5b4a644dabc8044ccc4a52f5870b9 100644 Binary files a/dbrepo-auth-service/listeners/target/create-event-listener.jar and b/dbrepo-auth-service/listeners/target/create-event-listener.jar differ diff --git a/dbrepo-dashboard-service/.coveragerc b/dbrepo-dashboard-service/.coveragerc new file mode 100644 index 0000000000000000000000000000000000000000..9fd61fc1664fc653df59d3f0be0aebf997c78060 --- /dev/null +++ b/dbrepo-dashboard-service/.coveragerc @@ -0,0 +1,7 @@ +[report] +omit = + # omit tests + ./tests/* + +[html] +directory = htmlcov \ No newline at end of file diff --git a/dbrepo-dashboard-service/.gitignore b/dbrepo-dashboard-service/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..cadb5f265763a13d8417c88cfd0d793b5b859a32 --- /dev/null +++ b/dbrepo-dashboard-service/.gitignore @@ -0,0 +1,135 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Generated +coverage.txt +report.xml +clients/ +api/ +dashboard.py +access.py +panel.py + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# SQLite db +*.db + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ diff --git a/dbrepo-dashboard-service/Dockerfile b/dbrepo-dashboard-service/Dockerfile index d5f64a82fb40c8823bbb7d0e5f8ac0a5426ce888..fcc698ed27662e6bea73cfd01e38d788b09ae4eb 100644 --- a/dbrepo-dashboard-service/Dockerfile +++ b/dbrepo-dashboard-service/Dockerfile @@ -1,8 +1,29 @@ -FROM docker.io/bitnami/grafana:11.5.1 AS runtime +FROM python:3.11-alpine3.21 LABEL org.opencontainers.image.authors="martin.weise@tuwien.ac.at" +RUN apk add --no-cache \ + curl \ + bash \ + jq + +COPY Pipfile Pipfile.lock ./ + +COPY ./lib ./lib + +RUN pip install pipenv && \ + pipenv install gunicorn && \ + pipenv install --system --deploy + +RUN adduser -D dbrepo --uid 1001 + WORKDIR /app -COPY --chown=grafana:grafana ./dashboards /app/dashboards -COPY --chown=grafana:grafana ./grafana.ini /etc/grafana/grafana.ini -COPY --chown=grafana:grafana ./ldap.toml /etc/grafana/ldap.toml +USER 1001 + +COPY --chown=1001 ./ds-yml ./ds-yml +COPY --chown=1001 ./app.py ./app.py + +# non-root port +EXPOSE 8080 + +ENTRYPOINT [ "gunicorn", "--log-level", "debug", "--workers", "4", "--bind", ":8080", "app:app" ] diff --git a/dbrepo-dashboard-service/Pipfile b/dbrepo-dashboard-service/Pipfile new file mode 100644 index 0000000000000000000000000000000000000000..6c446aaefa2b1aa5ea3603f567c4afe6980d29a0 --- /dev/null +++ b/dbrepo-dashboard-service/Pipfile @@ -0,0 +1,28 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +flasgger = "*" +flask = "~=2.0" +flask-cors = "~=4.0" +flask-jwt-extended = "~=4.5" +prometheus-flask-exporter = "*" +python-dotenv = "~=1.0" +jwt = "~=1.3" +pytest = "*" +dbrepo = {path = "./lib/dbrepo-1.8.0.tar.gz"} +gunicorn = "*" +pydantic = "*" +flask_httpauth = "*" +grafana-client = "*" + +[dev-packages] +coverage = "*" +pytest = "*" +testcontainers = "*" +requests-mock = "*" + +[requires] +python_version = "3.11" diff --git a/dbrepo-dashboard-service/Pipfile.lock b/dbrepo-dashboard-service/Pipfile.lock new file mode 100644 index 0000000000000000000000000000000000000000..ba1cf80caa50e4081124490c6546d976fbbb7b9b --- /dev/null +++ b/dbrepo-dashboard-service/Pipfile.lock @@ -0,0 +1,2224 @@ +{ + "_meta": { + "hash": { + "sha256": "911a375e6d52635530a1278e4186660b395093e16a092a223fd7050c6241bedc" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.11" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "aiohappyeyeballs": { + "hashes": [ + "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", + "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8" + ], + "markers": "python_version >= '3.9'", + "version": "==2.6.1" + }, + "aiohttp": { + "hashes": [ + "sha256:004511d3413737700835e949433536a2fe95a7d0297edd911a1e9705c5b5ea43", + "sha256:0902e887b0e1d50424112f200eb9ae3dfed6c0d0a19fc60f633ae5a57c809656", + "sha256:09b00dd520d88eac9d1768439a59ab3d145065c91a8fab97f900d1b5f802895e", + "sha256:0a2f451849e6b39e5c226803dcacfa9c7133e9825dcefd2f4e837a2ec5a3bb98", + "sha256:0a950c2eb8ff17361abd8c85987fd6076d9f47d040ebffce67dce4993285e973", + "sha256:0ad1fb47da60ae1ddfb316f0ff16d1f3b8e844d1a1e154641928ea0583d486ed", + "sha256:13ceac2c5cdcc3f64b9015710221ddf81c900c5febc505dbd8f810e770011540", + "sha256:14461157d8426bcb40bd94deb0450a6fa16f05129f7da546090cebf8f3123b0f", + "sha256:16f8a2c9538c14a557b4d309ed4d0a7c60f0253e8ed7b6c9a2859a7582f8b1b8", + "sha256:17ae4664031aadfbcb34fd40ffd90976671fa0c0286e6c4113989f78bebab37a", + "sha256:1ce63ae04719513dd2651202352a2beb9f67f55cb8490c40f056cea3c5c355ce", + "sha256:23a15727fbfccab973343b6d1b7181bfb0b4aa7ae280f36fd2f90f5476805682", + "sha256:2540ddc83cc724b13d1838026f6a5ad178510953302a49e6d647f6e1de82bc34", + "sha256:37dcee4906454ae377be5937ab2a66a9a88377b11dd7c072df7a7c142b63c37c", + "sha256:38bea84ee4fe24ebcc8edeb7b54bf20f06fd53ce4d2cc8b74344c5b9620597fd", + "sha256:3ab3367bb7f61ad18793fea2ef71f2d181c528c87948638366bf1de26e239183", + "sha256:3ad1d59fd7114e6a08c4814983bb498f391c699f3c78712770077518cae63ff7", + "sha256:3b4e6db8dc4879015b9955778cfb9881897339c8fab7b3676f8433f849425913", + "sha256:3e061b09f6fa42997cf627307f220315e313ece74907d35776ec4373ed718b86", + "sha256:42864e70a248f5f6a49fdaf417d9bc62d6e4d8ee9695b24c5916cb4bb666c802", + "sha256:493910ceb2764f792db4dc6e8e4b375dae1b08f72e18e8f10f18b34ca17d0979", + "sha256:4d0c970c0d602b1017e2067ff3b7dac41c98fef4f7472ec2ea26fd8a4e8c2149", + "sha256:54eb3aead72a5c19fad07219acd882c1643a1027fbcdefac9b502c267242f955", + "sha256:56a3443aca82abda0e07be2e1ecb76a050714faf2be84256dae291182ba59049", + "sha256:576f5ca28d1b3276026f7df3ec841ae460e0fc3aac2a47cbf72eabcfc0f102e1", + "sha256:58ede86453a6cf2d6ce40ef0ca15481677a66950e73b0a788917916f7e35a0bb", + "sha256:61c721764e41af907c9d16b6daa05a458f066015abd35923051be8705108ed17", + "sha256:634d96869be6c4dc232fc503e03e40c42d32cfaa51712aee181e922e61d74814", + "sha256:696ef00e8a1f0cec5e30640e64eca75d8e777933d1438f4facc9c0cdf288a810", + "sha256:69a2cbd61788d26f8f1e626e188044834f37f6ae3f937bd9f08b65fc9d7e514e", + "sha256:6a792ce34b999fbe04a7a71a90c74f10c57ae4c51f65461a411faa70e154154e", + "sha256:6ac13b71761e49d5f9e4d05d33683bbafef753e876e8e5a7ef26e937dd766713", + "sha256:6fdec0213244c39973674ca2a7f5435bf74369e7d4e104d6c7473c81c9bcc8c4", + "sha256:72b1b03fb4655c1960403c131740755ec19c5898c82abd3961c364c2afd59fe7", + "sha256:745f1ed5e2c687baefc3c5e7b4304e91bf3e2f32834d07baaee243e349624b24", + "sha256:776c8e959a01e5e8321f1dec77964cb6101020a69d5a94cd3d34db6d555e01f7", + "sha256:780df0d837276276226a1ff803f8d0fa5f8996c479aeef52eb040179f3156cbd", + "sha256:78e6e23b954644737e385befa0deb20233e2dfddf95dd11e9db752bdd2a294d3", + "sha256:7951decace76a9271a1ef181b04aa77d3cc309a02a51d73826039003210bdc86", + "sha256:7ba92a2d9ace559a0a14b03d87f47e021e4fa7681dc6970ebbc7b447c7d4b7cd", + "sha256:7f6428fee52d2bcf96a8aa7b62095b190ee341ab0e6b1bcf50c615d7966fd45b", + "sha256:87944bd16b7fe6160607f6a17808abd25f17f61ae1e26c47a491b970fb66d8cb", + "sha256:87a6e922b2b2401e0b0cf6b976b97f11ec7f136bfed445e16384fbf6fd5e8602", + "sha256:8cb0688a8d81c63d716e867d59a9ccc389e97ac7037ebef904c2b89334407180", + "sha256:8df6612df74409080575dca38a5237282865408016e65636a76a2eb9348c2567", + "sha256:911a6e91d08bb2c72938bc17f0a2d97864c531536b7832abee6429d5296e5b27", + "sha256:92b7ee222e2b903e0a4b329a9943d432b3767f2d5029dbe4ca59fb75223bbe2e", + "sha256:938f756c2b9374bbcc262a37eea521d8a0e6458162f2a9c26329cc87fdf06534", + "sha256:9756d9b9d4547e091f99d554fbba0d2a920aab98caa82a8fb3d3d9bee3c9ae85", + "sha256:98b88a2bf26965f2015a771381624dd4b0839034b70d406dc74fd8be4cc053e3", + "sha256:9b751a6306f330801665ae69270a8a3993654a85569b3469662efaad6cf5cc50", + "sha256:a2a450bcce4931b295fc0848f384834c3f9b00edfc2150baafb4488c27953de6", + "sha256:a3814760a1a700f3cfd2f977249f1032301d0a12c92aba74605cfa6ce9f78489", + "sha256:a5abcbba9f4b463a45c8ca8b7720891200658f6f46894f79517e6cd11f3405ca", + "sha256:a6db7458ab89c7d80bc1f4e930cc9df6edee2200127cfa6f6e080cf619eddfbd", + "sha256:ad497f38a0d6c329cb621774788583ee12321863cd4bd9feee1effd60f2ad133", + "sha256:ad9509ffb2396483ceacb1eee9134724443ee45b92141105a4645857244aecc8", + "sha256:bbcba75fe879ad6fd2e0d6a8d937f34a571f116a0e4db37df8079e738ea95c71", + "sha256:c10d85e81d0b9ef87970ecbdbfaeec14a361a7fa947118817fcea8e45335fa46", + "sha256:c15b2271c44da77ee9d822552201180779e5e942f3a71fb74e026bf6172ff287", + "sha256:ca37057625693d097543bd88076ceebeb248291df9d6ca8481349efc0b05dcd0", + "sha256:cc3a145479a76ad0ed646434d09216d33d08eef0d8c9a11f5ae5cdc37caa3540", + "sha256:ccf10f16ab498d20e28bc2b5c1306e9c1512f2840f7b6a67000a517a4b37d5ee", + "sha256:cd464ba806e27ee24a91362ba3621bfc39dbbb8b79f2e1340201615197370f7c", + "sha256:d007aa39a52d62373bd23428ba4a2546eed0e7643d7bf2e41ddcefd54519842c", + "sha256:d0666afbe984f6933fe72cd1f1c3560d8c55880a0bdd728ad774006eb4241ecd", + "sha256:d07502cc14ecd64f52b2a74ebbc106893d9a9717120057ea9ea1fd6568a747e7", + "sha256:d489d9778522fbd0f8d6a5c6e48e3514f11be81cb0a5954bdda06f7e1594b321", + "sha256:df7db76400bf46ec6a0a73192b14c8295bdb9812053f4fe53f4e789f3ea66bbb", + "sha256:e3538bc9fe1b902bef51372462e3d7c96fce2b566642512138a480b7adc9d508", + "sha256:e87fd812899aa78252866ae03a048e77bd11b80fb4878ce27c23cade239b42b2", + "sha256:ecdb8173e6c7aa09eee342ac62e193e6904923bd232e76b4157ac0bfa670609f", + "sha256:f244b8e541f414664889e2c87cac11a07b918cb4b540c36f7ada7bfa76571ea2", + "sha256:f4065145bf69de124accdd17ea5f4dc770da0a6a6e440c53f6e0a8c27b3e635c", + "sha256:f420bfe862fb357a6d76f2065447ef6f484bc489292ac91e29bc65d2d7a2c84d", + "sha256:f6ddd90d9fb4b501c97a4458f1c1720e42432c26cb76d28177c5b5ad4e332601", + "sha256:fa73e8c2656a3653ae6c307b3f4e878a21f87859a9afab228280ddccd7369d71", + "sha256:fadbb8f1d4140825069db3fedbbb843290fd5f5bc0a5dbd7eaf81d91bf1b003b", + "sha256:fb3d0cc5cdb926090748ea60172fa8a213cec728bd6c54eae18b96040fcd6227", + "sha256:fb46bb0f24813e6cede6cc07b1961d4b04f331f7112a23b5e21f567da4ee50aa", + "sha256:fd36c119c5d6551bce374fcb5c19269638f8d09862445f85a5a48596fd59f4bb" + ], + "markers": "python_version >= '3.9'", + "version": "==3.11.16" + }, + "aiosignal": { + "hashes": [ + "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", + "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54" + ], + "markers": "python_version >= '3.9'", + "version": "==1.3.2" + }, + "annotated-types": { + "hashes": [ + "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", + "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" + ], + "markers": "python_version >= '3.8'", + "version": "==0.7.0" + }, + "attrs": { + "hashes": [ + "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", + "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b" + ], + "markers": "python_version >= '3.8'", + "version": "==25.3.0" + }, + "blinker": { + "hashes": [ + "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", + "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc" + ], + "markers": "python_version >= '3.9'", + "version": "==1.9.0" + }, + "certifi": { + "hashes": [ + "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", + "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe" + ], + "markers": "python_version >= '3.6'", + "version": "==2025.1.31" + }, + "cffi": { + "hashes": [ + "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", + "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", + "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1", + "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", + "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", + "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", + "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", + "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", + "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", + "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", + "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc", + "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", + "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", + "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", + "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", + "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", + "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", + "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", + "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", + "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b", + "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", + "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", + "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c", + "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", + "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", + "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", + "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8", + "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1", + "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", + "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", + "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", + "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", + "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", + "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", + "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", + "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", + "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", + "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", + "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", + "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", + "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", + "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", + "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", + "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964", + "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", + "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", + "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", + "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", + "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", + "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", + "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", + "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", + "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", + "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", + "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", + "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", + "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", + "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9", + "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", + "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", + "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", + "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", + "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", + "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", + "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", + "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", + "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b" + ], + "markers": "python_version >= '3.8'", + "version": "==1.17.1" + }, + "charset-normalizer": { + "hashes": [ + "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537", + "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa", + "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a", + "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294", + "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b", + "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", + "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", + "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd", + "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4", + "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", + "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2", + "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", + "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd", + "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", + "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8", + "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1", + "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", + "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496", + "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d", + "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", + "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e", + "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a", + "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4", + "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca", + "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78", + "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408", + "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5", + "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", + "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", + "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a", + "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765", + "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6", + "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146", + "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6", + "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", + "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd", + "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c", + "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", + "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", + "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176", + "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770", + "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824", + "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f", + "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf", + "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487", + "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d", + "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd", + "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", + "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534", + "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f", + "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b", + "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", + "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd", + "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125", + "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9", + "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de", + "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", + "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d", + "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", + "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f", + "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", + "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7", + "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a", + "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", + "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8", + "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41", + "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", + "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f", + "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", + "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", + "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", + "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77", + "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76", + "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247", + "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", + "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb", + "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", + "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e", + "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6", + "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037", + "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", + "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e", + "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807", + "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", + "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c", + "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12", + "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3", + "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089", + "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", + "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e", + "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00", + "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616" + ], + "markers": "python_version >= '3.7'", + "version": "==3.4.1" + }, + "click": { + "hashes": [ + "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", + "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a" + ], + "markers": "python_version >= '3.7'", + "version": "==8.1.8" + }, + "cryptography": { + "hashes": [ + "sha256:04abd71114848aa25edb28e225ab5f268096f44cf0127f3d36975bdf1bdf3390", + "sha256:0529b1d5a0105dd3731fa65680b45ce49da4d8115ea76e9da77a875396727b41", + "sha256:1bc312dfb7a6e5d66082c87c34c8a62176e684b6fe3d90fcfe1568de675e6688", + "sha256:268e4e9b177c76d569e8a145a6939eca9a5fec658c932348598818acf31ae9a5", + "sha256:29ecec49f3ba3f3849362854b7253a9f59799e3763b0c9d0826259a88efa02f1", + "sha256:2bf7bf75f7df9715f810d1b038870309342bff3069c5bd8c6b96128cb158668d", + "sha256:3b721b8b4d948b218c88cb8c45a01793483821e709afe5f622861fc6182b20a7", + "sha256:3c00b6b757b32ce0f62c574b78b939afab9eecaf597c4d624caca4f9e71e7843", + "sha256:3dc62975e31617badc19a906481deacdeb80b4bb454394b4098e3f2525a488c5", + "sha256:4973da6ca3db4405c54cd0b26d328be54c7747e89e284fcff166132eb7bccc9c", + "sha256:4e389622b6927d8133f314949a9812972711a111d577a5d1f4bee5e58736b80a", + "sha256:51e4de3af4ec3899d6d178a8c005226491c27c4ba84101bfb59c901e10ca9f79", + "sha256:5f6f90b72d8ccadb9c6e311c775c8305381db88374c65fa1a68250aa8a9cb3a6", + "sha256:6210c05941994290f3f7f175a4a57dbbb2afd9273657614c506d5976db061181", + "sha256:6f101b1f780f7fc613d040ca4bdf835c6ef3b00e9bd7125a4255ec574c7916e4", + "sha256:7bdcd82189759aba3816d1f729ce42ffded1ac304c151d0a8e89b9996ab863d5", + "sha256:7ca25849404be2f8e4b3c59483d9d3c51298a22c1c61a0e84415104dacaf5562", + "sha256:81276f0ea79a208d961c433a947029e1a15948966658cf6710bbabb60fcc2639", + "sha256:8cadc6e3b5a1f144a039ea08a0bdb03a2a92e19c46be3285123d32029f40a922", + "sha256:8e0ddd63e6bf1161800592c71ac794d3fb8001f2caebe0966e77c5234fa9efc3", + "sha256:909c97ab43a9c0c0b0ada7a1281430e4e5ec0458e6d9244c0e821bbf152f061d", + "sha256:96e7a5e9d6e71f9f4fca8eebfd603f8e86c5225bb18eb621b2c1e50b290a9471", + "sha256:9a1e657c0f4ea2a23304ee3f964db058c9e9e635cc7019c4aa21c330755ef6fd", + "sha256:9eb9d22b0a5d8fd9925a7764a054dca914000607dff201a24c791ff5c799e1fa", + "sha256:af4ff3e388f2fa7bff9f7f2b31b87d5651c45731d3e8cfa0944be43dff5cfbdb", + "sha256:b042d2a275c8cee83a4b7ae30c45a15e6a4baa65a179a0ec2d78ebb90e4f6699", + "sha256:bc821e161ae88bfe8088d11bb39caf2916562e0a2dc7b6d56714a48b784ef0bb", + "sha256:c505d61b6176aaf982c5717ce04e87da5abc9a36a5b39ac03905c4aafe8de7aa", + "sha256:c63454aa261a0cf0c5b4718349629793e9e634993538db841165b3df74f37ec0", + "sha256:c7362add18b416b69d58c910caa217f980c5ef39b23a38a0880dfd87bdf8cd23", + "sha256:d03806036b4f89e3b13b6218fefea8d5312e450935b1a2d55f0524e2ed7c59d9", + "sha256:d1b3031093a366ac767b3feb8bcddb596671b3aaff82d4050f984da0c248b615", + "sha256:d1c3572526997b36f245a96a2b1713bf79ce99b271bbcf084beb6b9b075f29ea", + "sha256:efcfe97d1b3c79e486554efddeb8f6f53a4cdd4cf6086642784fa31fc384e1d7", + "sha256:f514ef4cd14bb6fb484b4a60203e912cfcb64f2ab139e88c2274511514bf7308" + ], + "markers": "python_version >= '3.7' and python_full_version not in '3.9.0, 3.9.1'", + "version": "==44.0.2" + }, + "dbrepo": { + "hashes": [ + "sha256:55de6a4934010e14a574032b5a5179bf3dac9895ef74e5cd4a221a625a75674b" + ], + "path": "./lib/dbrepo-1.8.0.tar.gz" + }, + "flasgger": { + "hashes": [ + "sha256:ca098e10bfbb12f047acc6299cc70a33851943a746e550d86e65e60d4df245fb" + ], + "index": "pypi", + "version": "==0.9.7.1" + }, + "flask": { + "hashes": [ + "sha256:09c347a92aa7ff4a8e7f3206795f30d826654baf38b873d0744cd571ca609efc", + "sha256:f69fcd559dc907ed196ab9df0e48471709175e696d6e698dd4dbe940f96ce66b" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==2.3.3" + }, + "flask-cors": { + "hashes": [ + "sha256:38364faf1a7a5d0a55bd1d2e2f83ee9e359039182f5e6a029557e1f56d92c09a", + "sha256:493b98e2d1e2f1a4720a7af25693ef2fe32fbafec09a2f72c59f3e475eda61d2" + ], + "index": "pypi", + "version": "==4.0.2" + }, + "flask-httpauth": { + "hashes": [ + "sha256:66568a05bc73942c65f1e2201ae746295816dc009edd84b482c44c758d75097a", + "sha256:a58fedd09989b9975448eef04806b096a3964a7feeebc0a78831ff55685b62b0" + ], + "index": "pypi", + "version": "==4.8.0" + }, + "flask-jwt-extended": { + "hashes": [ + "sha256:52f35bf0985354d7fb7b876e2eb0e0b141aaff865a22ff6cc33d9a18aa987978", + "sha256:8085d6757505b6f3291a2638c84d207e8f0ad0de662d1f46aa2f77e658a0c976" + ], + "index": "pypi", + "markers": "python_version >= '3.9' and python_version < '4'", + "version": "==4.7.1" + }, + "frozenlist": { + "hashes": [ + "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e", + "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf", + "sha256:04a5c6babd5e8fb7d3c871dc8b321166b80e41b637c31a995ed844a6139942b6", + "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a", + "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d", + "sha256:0f253985bb515ecd89629db13cb58d702035ecd8cfbca7d7a7e29a0e6d39af5f", + "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28", + "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b", + "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9", + "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2", + "sha256:15538c0cbf0e4fa11d1e3a71f823524b0c46299aed6e10ebb4c2089abd8c3bec", + "sha256:15b731db116ab3aedec558573c1a5eec78822b32292fe4f2f0345b7f697745c2", + "sha256:17dcc32fc7bda7ce5875435003220a457bcfa34ab7924a49a1c19f55b6ee185c", + "sha256:1893f948bf6681733aaccf36c5232c231e3b5166d607c5fa77773611df6dc336", + "sha256:189f03b53e64144f90990d29a27ec4f7997d91ed3d01b51fa39d2dbe77540fd4", + "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d", + "sha256:1b96af8c582b94d381a1c1f51ffaedeb77c821c690ea5f01da3d70a487dd0a9b", + "sha256:1e76bfbc72353269c44e0bc2cfe171900fbf7f722ad74c9a7b638052afe6a00c", + "sha256:2150cc6305a2c2ab33299453e2968611dacb970d2283a14955923062c8d00b10", + "sha256:226d72559fa19babe2ccd920273e767c96a49b9d3d38badd7c91a0fdeda8ea08", + "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942", + "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8", + "sha256:2b5e23253bb709ef57a8e95e6ae48daa9ac5f265637529e4ce6b003a37b2621f", + "sha256:2d0da8bbec082bf6bf18345b180958775363588678f64998c2b7609e34719b10", + "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5", + "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6", + "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21", + "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c", + "sha256:366d8f93e3edfe5a918c874702f78faac300209a4d5bf38352b2c1bdc07a766d", + "sha256:374ca2dabdccad8e2a76d40b1d037f5bd16824933bf7bcea3e59c891fd4a0923", + "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608", + "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de", + "sha256:498524025a5b8ba81695761d78c8dd7382ac0b052f34e66939c42df860b8ff17", + "sha256:50cf5e7ee9b98f22bdecbabf3800ae78ddcc26e4a435515fc72d97903e8488e0", + "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f", + "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641", + "sha256:5a3ba5f9a0dfed20337d3e966dc359784c9f96503674c2faf015f7fe8e96798c", + "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a", + "sha256:5c28f4b5dbef8a0d8aad0d4de24d1e9e981728628afaf4ea0792f5d0939372f0", + "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9", + "sha256:6321899477db90bdeb9299ac3627a6a53c7399c8cd58d25da094007402b039ab", + "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f", + "sha256:666534d15ba8f0fda3f53969117383d5dc021266b3c1a42c9ec4855e4b58b9d3", + "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a", + "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784", + "sha256:73f2e31ea8dd7df61a359b731716018c2be196e5bb3b74ddba107f694fbd7604", + "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d", + "sha256:76e4753701248476e6286f2ef492af900ea67d9706a0155335a40ea21bf3b2f5", + "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03", + "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e", + "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953", + "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee", + "sha256:7f3c8c1dacd037df16e85227bac13cca58c30da836c6f936ba1df0c05d046d8d", + "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817", + "sha256:828afae9f17e6de596825cf4228ff28fbdf6065974e5ac1410cecc22f699d2b3", + "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039", + "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f", + "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9", + "sha256:91d6c171862df0a6c61479d9724f22efb6109111017c87567cfeb7b5d1449fdf", + "sha256:9272fa73ca71266702c4c3e2d4a28553ea03418e591e377a03b8e3659d94fa76", + "sha256:92b5278ed9d50fe610185ecd23c55d8b307d75ca18e94c0e7de328089ac5dcba", + "sha256:97160e245ea33d8609cd2b8fd997c850b56db147a304a262abc2b3be021a9171", + "sha256:977701c081c0241d0955c9586ffdd9ce44f7a7795df39b9151cd9a6fd0ce4cfb", + "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439", + "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631", + "sha256:9bbcdfaf4af7ce002694a4e10a0159d5a8d20056a12b05b45cea944a4953f972", + "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d", + "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869", + "sha256:a72b7a6e3cd2725eff67cd64c8f13335ee18fc3c7befc05aed043d24c7b9ccb9", + "sha256:a9fe0f1c29ba24ba6ff6abf688cb0b7cf1efab6b6aa6adc55441773c252f7411", + "sha256:b97f7b575ab4a8af9b7bc1d2ef7f29d3afee2226bd03ca3875c16451ad5a7723", + "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2", + "sha256:c03eff4a41bd4e38415cbed054bbaff4a075b093e2394b6915dca34a40d1e38b", + "sha256:c16d2fa63e0800723139137d667e1056bee1a1cf7965153d2d104b62855e9b99", + "sha256:c1fac3e2ace2eb1052e9f7c7db480818371134410e1f5c55d65e8f3ac6d1407e", + "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840", + "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3", + "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb", + "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", + "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0", + "sha256:dd94994fc91a6177bfaafd7d9fd951bc8689b0a98168aa26b5f543868548d3ca", + "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45", + "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e", + "sha256:e66cc454f97053b79c2ab09c17fbe3c825ea6b4de20baf1be28919460dd7877f", + "sha256:e79225373c317ff1e35f210dd5f1344ff31066ba8067c307ab60254cd3a78ad5", + "sha256:f1577515d35ed5649d52ab4319db757bb881ce3b2b796d7283e6634d99ace307", + "sha256:f1e6540b7fa044eee0bb5111ada694cf3dc15f2b0347ca125ee9ca984d5e9e6e", + "sha256:f2ac49a9bedb996086057b75bf93538240538c6d9b38e57c82d51f75a73409d2", + "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778", + "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a", + "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30", + "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a" + ], + "markers": "python_version >= '3.8'", + "version": "==1.5.0" + }, + "grafana-client": { + "hashes": [ + "sha256:2477a47b923fd0637947e620b0b777c641af18a3025464fa4505783dbf05dfcc", + "sha256:8cb61bb2a87ec07bca10974df276b9a1a95bfdb63f3a696f065692ffc9b8c389" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==4.3.2" + }, + "gunicorn": { + "hashes": [ + "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d", + "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==23.0.0" + }, + "h11": { + "hashes": [ + "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", + "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761" + ], + "markers": "python_version >= '3.7'", + "version": "==0.14.0" + }, + "idna": { + "hashes": [ + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" + ], + "markers": "python_version >= '3.6'", + "version": "==3.10" + }, + "iniconfig": { + "hashes": [ + "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", + "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760" + ], + "markers": "python_version >= '3.8'", + "version": "==2.1.0" + }, + "itsdangerous": { + "hashes": [ + "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", + "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173" + ], + "markers": "python_version >= '3.8'", + "version": "==2.2.0" + }, + "jh2": { + "hashes": [ + "sha256:038091480cd1544e9389b0adbb1b1645a797689dcb68ceae7e45eec96ed24497", + "sha256:0c8e336df8ed1687590695f4469f480eeb4159bf13bb6193791c6530fe114b49", + "sha256:0c9bf2d5e4ef45c1686c6f76935e7ca263f5eae4de92bf5d1873a0e737e4eb7d", + "sha256:0faf6e96f74d27b8ca816b40217904891f91b664ed1c0388737949ceb50ac15d", + "sha256:10ea7f497e6226372e1d4fdbf42c8381f4887819a643ab930bff4072ad298d84", + "sha256:11650f7ed77ee1df30f25d6b3b74b2fa1c94124e074fd455abafea3cbc913d53", + "sha256:12ead3ee3e9c7caa00356b528a5cc7fe210fbe2060628af6e19ed76b8416572e", + "sha256:136b3c5b08883681fcb58f12393a5bbfa422d6e2d5ba887e263e776874276bc6", + "sha256:17d6e1691154ea9f726e43dcb717df48e56c66b5a01c90ad675c6494c36e5be1", + "sha256:19cb987915cc0d321746a12f2a693d087ffb721c37ac9a153cc088c57d4d90eb", + "sha256:1cdf15de698c4026e64fd914fead3180e52bf2a7bcbe44a3392404582dbf2d22", + "sha256:1e81e1c64e33506b8508ba5e3c7c139b2577e78b079c2c16a8e7a02a161f1080", + "sha256:2226c76e4ff2149c5d9f94bed22bf9c4f3411d38cc53d4a7ddfbe0899c8b558c", + "sha256:2837412fb7b684c6ce7392c8bc57440c6dbadaf1bde7a53144381f7df7083c1c", + "sha256:293f0f3da3c391e997e0d55fdb85540e98a8b0406622bb4ba57fb7617697f31e", + "sha256:2b9cc6c0239215a349d28c192fa4c4e7a7348eee7980531525c01bffe39eea80", + "sha256:2f3ad679f84ff236a0d7b71ddc4b3c09fe467abee2f1a86671f0cd417be5352b", + "sha256:358cad2f328c52c15756cf32b0ad17afb0d617e7cdfe93d59aa2616966d825b7", + "sha256:3663712305b509f79c002c8c0ca9994f716cadba576f5a59632dda1aec1ca8c6", + "sha256:41794820ccca039ca2ead6245f30b34601dd1456eee5b5dde620672bb989e79d", + "sha256:44b7e64aff542471c474c24f771eae5efd9152da02a12556f7cb7607020e1420", + "sha256:45770eb0990166026538d3c2fd7d92f17cfde13ca6567570c4baec3ce9162936", + "sha256:498060078a4d1b458e9381fefb027d85329397b50d65287712b3d48233e20836", + "sha256:4c2f18f337c2393f84e45e5011c8b02697b81638b1cec49da60a01b9ed067695", + "sha256:5162d6e475d2762035fb8ea25982bcbec6c58715e33bd0951499f743cd90b110", + "sha256:51e8c890bb59008c95b3a552cefd8bd9ce50a7466a6c920a78cf586e885d7449", + "sha256:56ad3839ac6ac5fd3d023cf59d4b04264b74bb4cb44c0780faf51d6b5ff38fbc", + "sha256:5821638ef0d7c973071810a6786f59b305172197f7e7e469a2ce169e7f4978e3", + "sha256:5ac1b2d379f4d40c13dcce537e69704452943cddbe991fd54a84fdb2da9026d5", + "sha256:5b465d4311b0429fe6fa85df8e2cfcb038c9fface95396dd14e838ecabaaadf2", + "sha256:5d8656b98057329bd03d968aac8d5198389cf51517511295cfc4cb827a507e39", + "sha256:5dcfb3e823ef4b91b70b92848570d1d8cfd584304bd2bd54272dc100c9494def", + "sha256:5e40d23ea43f683f3a7c032dde391104f609b05c21b6d284101120b51dbd50c1", + "sha256:63a01522bde161c713f7fa5ee5d850fee6386fc386073490ebcd438f14579cf2", + "sha256:6b2a3d7756035dde13571f4ad232629b78b7f35c2cd5fda7b464079fc697db3a", + "sha256:6b3be1a6bf6c965aea3b4e3a40df9d2c134c516d89c76cf2b6c81f67e6c5c6ed", + "sha256:6c7bea3357f2dc653756e6da55f66cd21c73d3875c8f3dc4e8d196a876252de0", + "sha256:6e6c8e229507cf29333a2f491cbaa7dff5b8a4a3e613af8090ccce9ce3e4f7a0", + "sha256:6fad27f2a63884ee45d491aebec4b1f38752cd6aaccc625038c21e7f43c02c49", + "sha256:71bfef52547c2b8b145897fa8d1b5142bc52313cfa38c0742e0ef755f0d09c60", + "sha256:72370d312323282b1bf74426e53fae861a310d7ae519b419da46673c38e7d147", + "sha256:76c7d36043a9c478b0c846fcec7da5cb095983722473e503e0122ccd170182b5", + "sha256:78d8a81ef51edb9a2f278a6fb278789b49e304b12bb21bccf2fe7e344f71a9fb", + "sha256:798a6b159ce32181a5e7ab7611c17d1080e74a5541fec47f961b728dab25a76f", + "sha256:7e370567f66a57e2c0e3ae2afcc6f126e1d6babd36831cfd0caad279b05c1c88", + "sha256:8004b845f606b95a8b17efa112aa10b327e46e95dcda604a257b4633d4ed45c8", + "sha256:80b20bf9ea4e709b3b9ae364ac298dfa872b084c186e5c1d60b0b79c79a7ee7e", + "sha256:87303f4bb1b493997f911a4f126123ccd2827d3a2e7dd2390cc6143fbc75805b", + "sha256:8d423f4631395b92dceda39f481a463498131ac02a58581124a44495491f715b", + "sha256:94ee262192db50fb9c069a0be7bb1a426fb1b43af26ce12bf4c6c30e13f46b56", + "sha256:960e4be2e7de340300ab4bcc2b45bed46be1d62330575b8265e6602dbcb9a14c", + "sha256:99397d5e1da6b345cec3e6125e2902b0e6864eb8eaa4be43a2013f059c502c93", + "sha256:9abbb8c1bad08817bad62ae1ea76c01bdbd0ee8c827d05f3ba038c9f6d6f14bb", + "sha256:9c0b8fadf80bc70d341032f92702bda1b0ed78c01e9c495f0df701938c99bcf5", + "sha256:9f977da9abae170eebdcf02bda33727c342fad5dcdbc08498bfdfb6cc6c65489", + "sha256:a6be712ca39d5e9c89b705bc9800be36739436fefb8d0b52b2d332f7d6d22a01", + "sha256:aa434418d6ee44b0ba3a5a407bc9e1543cf496328f43f149e9b58f74a63d5c21", + "sha256:ac4f778e32f7de0ba63346893a4af87c2280ffc1783f594a117be51d908a10da", + "sha256:ac85d65ee369c09b2904b55078ad589961e2e2e03c810963d35a26e6a3931425", + "sha256:ad5d78c664d39960435d4162db31117c8945ba74fb0c414e79ba85a8bdeafdec", + "sha256:ad91f57c3485d87a8edee558dafab0f08c716857d748731c0998dcefe9d3fd5f", + "sha256:afd255d42b340036883ca95bded553b29065b064e2fe5db64ad5988517db9694", + "sha256:b1c2c74f100a0c2110a8e30445554ae331860d32f145c60a2a1e1c27702022a2", + "sha256:b49a8c71378d40d43c6a56eaa536d7823baa43c27c93e082aeb60a9717be0c10", + "sha256:b5f52611323e8e35705e6750a760f32165b41c052d22da154ae343871e7cd50d", + "sha256:b6bf99ae529ac359263269710356d3ddb173c15d8f8dc8849ae794ab811e5cd0", + "sha256:ba361bf87c4701f11241be92c99ef5cf916865dd225955cccb2376bf76717b3c", + "sha256:bc351aa2158575e68943d8e1d5531719ad86bf6607776627ed5a1a60657664af", + "sha256:bd6eb7b1e12e4dd0b75cab1b023272f1333494add5ad61deedac738af1ffeede", + "sha256:bf8852595f5e2d2b072e24c29394b5aca7fba96ecc8656d56660535f9e9872c9", + "sha256:c1dd66541569a2bdbe92589cc96a89f470b20d168f2238fd463e1b59ee3e2d49", + "sha256:c36a7a004cba4e370d0675826eeefe4e42a256638b6b1432263ddb4af317bc02", + "sha256:c886cda61da4d39010be84802bed11bc75f03e8a6094cc18016957a2c80254d4", + "sha256:cc7aa83946f80c66a5d2dea7e165f15aa3eb21e7b74b24d8f850afc0d44bb00e", + "sha256:cea9c4bef70d1358bafec6019164abce362f4de15d79d1ecd64ae31c1749d77a", + "sha256:cfe1951e80869695857986be104a40a1e7fa8ec7de05f86bcbd7bd20854be764", + "sha256:d36cf6f139da3279644794fcfda18af425c8bb122ef9c2e7c762a937bbf7b0f4", + "sha256:d81308faaa9393b7e6ed20718d465c4c2b73c24d5e4826024961acf4b87b1524", + "sha256:db51ea1f9c5ac790848bc271fcdf4108ad1b77a77c6949a96320477962cf7ba5", + "sha256:dd05c18c920a15e00d7a52df37bffd3930fe2c004c690f9422b20e12077e6dbd", + "sha256:df05918a11e1db0198d00486e36673b4b4a89390e4458ff9479b4908dde357ac", + "sha256:e4c31dccf6be131709e545d0258eb5b75c5fac304857ad3976331c6740e8b9d6", + "sha256:e60954d673040430802b29fe5bba698e262182b5ba5f302ff4458e39f8101881", + "sha256:e60e2d2c88a0552e61c37172fe377f6a8abf479130a445314886de4a360ba940", + "sha256:e786f773ddc153846b2ebdb854011cfd1f7c874b8ee79cced3706801341c9f5d", + "sha256:e7cd91548fb95b69edd376f5204e27115ac7d093ec7d80066123a5bdb31c71d9", + "sha256:eaef2ea4f5602aefaaf3d6e8235f3b9ffde35aff15aac1c16cc802f6bbf0a3b5", + "sha256:ec8c5ea93a03775fbadd08462200cf34ce617ec75a032abfa44fd6d3a00e5424", + "sha256:eddeb8574bc9d9abb8491d4a46b60e553c2cea235b80373756acb06568101175", + "sha256:eeb300b0e4b428aab2f70d785cad4306529262af6de8c8c5fe6a4b41a674a434", + "sha256:f39d71ece8e97cf069e4154868eaac1256b133fe23e0459829432e4bb6406472", + "sha256:f4840ddad2b9d53710e92361391944da89e3576641a290066a1719520059247c", + "sha256:f70723a00bcbce0f9a216853139955be45da35741335eb3afead304e77662560", + "sha256:f829cf2ba5b553e6529d6238928c07096f1feb47f4ad536b7f06bca6cc77173f", + "sha256:f96386910467725895f7972939a6faabd6e96b1de0cc2c092e4bd2c40e956e25", + "sha256:fe259a9d6f555bc79aed9bb4b9a7fff73db443b4c483e4a81a428c8a2860428b" + ], + "markers": "python_version >= '3.7'", + "version": "==5.0.8" + }, + "jinja2": { + "hashes": [ + "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", + "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67" + ], + "markers": "python_version >= '3.7'", + "version": "==3.1.6" + }, + "jsonschema": { + "hashes": [ + "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", + "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566" + ], + "markers": "python_version >= '3.8'", + "version": "==4.23.0" + }, + "jsonschema-specifications": { + "hashes": [ + "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272", + "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf" + ], + "markers": "python_version >= '3.9'", + "version": "==2024.10.1" + }, + "jwt": { + "hashes": [ + "sha256:61c9170f92e736b530655e75374681d4fcca9cfa8763ab42be57353b2b203494" + ], + "index": "pypi", + "markers": "python_version >= '3.6'", + "version": "==1.3.1" + }, + "markupsafe": { + "hashes": [ + "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", + "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", + "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0", + "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", + "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", + "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13", + "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", + "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", + "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", + "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", + "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0", + "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", + "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", + "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", + "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", + "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff", + "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", + "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", + "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", + "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", + "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", + "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", + "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", + "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", + "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a", + "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", + "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", + "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", + "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", + "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144", + "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f", + "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", + "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", + "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", + "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", + "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", + "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", + "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", + "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", + "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", + "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", + "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", + "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", + "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", + "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", + "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", + "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", + "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", + "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29", + "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", + "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", + "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", + "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", + "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", + "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", + "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a", + "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178", + "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", + "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", + "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", + "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50" + ], + "markers": "python_version >= '3.9'", + "version": "==3.0.2" + }, + "mistune": { + "hashes": [ + "sha256:1a32314113cff28aa6432e99e522677c8587fd83e3d51c29b82a52409c842bd9", + "sha256:a7035c21782b2becb6be62f8f25d3df81ccb4d6fa477a6525b15af06539f02a0" + ], + "markers": "python_version >= '3.8'", + "version": "==3.1.3" + }, + "multidict": { + "hashes": [ + "sha256:0085b0afb2446e57050140240a8595846ed64d1cbd26cef936bfab3192c673b8", + "sha256:042028348dc5a1f2be6c666437042a98a5d24cee50380f4c0902215e5ec41844", + "sha256:05fefbc3cddc4e36da209a5e49f1094bbece9a581faa7f3589201fd95df40e5d", + "sha256:063be88bd684782a0715641de853e1e58a2f25b76388538bd62d974777ce9bc2", + "sha256:07bfa8bc649783e703263f783f73e27fef8cd37baaad4389816cf6a133141331", + "sha256:08549895e6a799bd551cf276f6e59820aa084f0f90665c0f03dd3a50db5d3c48", + "sha256:095a2eabe8c43041d3e6c2cb8287a257b5f1801c2d6ebd1dd877424f1e89cf29", + "sha256:0b183a959fb88ad1be201de2c4bdf52fa8e46e6c185d76201286a97b6f5ee65c", + "sha256:0c383d28857f66f5aebe3e91d6cf498da73af75fbd51cedbe1adfb85e90c0460", + "sha256:0d57a01a2a9fa00234aace434d8c131f0ac6e0ac6ef131eda5962d7e79edfb5b", + "sha256:0dc25a3293c50744796e87048de5e68996104d86d940bb24bc3ec31df281b191", + "sha256:0e5a644e50ef9fb87878d4d57907f03a12410d2aa3b93b3acdf90a741df52c49", + "sha256:0f249badb360b0b4d694307ad40f811f83df4da8cef7b68e429e4eea939e49dd", + "sha256:0f74f2fc51555f4b037ef278efc29a870d327053aba5cb7d86ae572426c7cccc", + "sha256:125dd82b40f8c06d08d87b3510beaccb88afac94e9ed4a6f6c71362dc7dbb04b", + "sha256:13551d0e2d7201f0959725a6a769b6f7b9019a168ed96006479c9ac33fe4096b", + "sha256:14ed9ed1bfedd72a877807c71113deac292bf485159a29025dfdc524c326f3e1", + "sha256:163f4604e76639f728d127293d24c3e208b445b463168af3d031b92b0998bb90", + "sha256:19e2819b0b468174de25c0ceed766606a07cedeab132383f1e83b9a4e96ccb4f", + "sha256:1e2a2193d3aa5cbf5758f6d5680a52aa848e0cf611da324f71e5e48a9695cc86", + "sha256:1f3c099d3899b14e1ce52262eb82a5f5cb92157bb5106bf627b618c090a0eadc", + "sha256:214207dcc7a6221d9942f23797fe89144128a71c03632bf713d918db99bd36de", + "sha256:2325105e16d434749e1be8022f942876a936f9bece4ec41ae244e3d7fae42aaf", + "sha256:2529ddbdaa424b2c6c2eb668ea684dd6b75b839d0ad4b21aad60c168269478d7", + "sha256:256d431fe4583c5f1e0f2e9c4d9c22f3a04ae96009b8cfa096da3a8723db0a16", + "sha256:25bb96338512e2f46f615a2bb7c6012fe92a4a5ebd353e5020836a7e33120349", + "sha256:2e87f1926e91855ae61769ba3e3f7315120788c099677e0842e697b0bfb659f2", + "sha256:2fc6af8e39f7496047c7876314f4317736eac82bf85b54c7c76cf1a6f8e35d98", + "sha256:3157126b028c074951839233647bd0e30df77ef1fedd801b48bdcad242a60f4e", + "sha256:32c9b4878f48be3e75808ea7e499d6223b1eea6d54c487a66bc10a1871e3dc6a", + "sha256:32ed748ff9ac682eae7859790d3044b50e3076c7d80e17a44239683769ff485e", + "sha256:3501621d5e86f1a88521ea65d5cad0a0834c77b26f193747615b7c911e5422d2", + "sha256:437c33561edb6eb504b5a30203daf81d4a9b727e167e78b0854d9a4e18e8950b", + "sha256:48d39b1824b8d6ea7de878ef6226efbe0773f9c64333e1125e0efcfdd18a24c7", + "sha256:4ac3fcf9a2d369bd075b2c2965544036a27ccd277fc3c04f708338cc57533081", + "sha256:4ccfd74957ef53fa7380aaa1c961f523d582cd5e85a620880ffabd407f8202c0", + "sha256:52b05e21ff05729fbea9bc20b3a791c3c11da61649ff64cce8257c82a020466d", + "sha256:5389445f0173c197f4a3613713b5fb3f3879df1ded2a1a2e4bc4b5b9c5441b7e", + "sha256:5c5e7d2e300d5cb3b2693b6d60d3e8c8e7dd4ebe27cd17c9cb57020cac0acb80", + "sha256:5d26547423e5e71dcc562c4acdc134b900640a39abd9066d7326a7cc2324c530", + "sha256:5dd7106d064d05896ce28c97da3f46caa442fe5a43bc26dfb258e90853b39b44", + "sha256:5f8cb1329f42fadfb40d6211e5ff568d71ab49be36e759345f91c69d1033d633", + "sha256:61d5541f27533f803a941d3a3f8a3d10ed48c12cf918f557efcbf3cd04ef265c", + "sha256:639556758c36093b35e2e368ca485dada6afc2bd6a1b1207d85ea6dfc3deab27", + "sha256:641cf2e3447c9ecff2f7aa6e9eee9eaa286ea65d57b014543a4911ff2799d08a", + "sha256:6aed763b6a1b28c46c055692836879328f0b334a6d61572ee4113a5d0c859872", + "sha256:6e2a2d6749e1ff2c9c76a72c6530d5baa601205b14e441e6d98011000f47a7ac", + "sha256:7243c5a6523c5cfeca76e063efa5f6a656d1d74c8b1fc64b2cd1e84e507f7e2a", + "sha256:76b34c12b013d813e6cb325e6bd4f9c984db27758b16085926bbe7ceeaace626", + "sha256:781b5dd1db18c9e9eacc419027b0acb5073bdec9de1675c0be25ceb10e2ad133", + "sha256:7c611345bbe7cb44aabb877cb94b63e86f2d0db03e382667dbd037866d44b4f8", + "sha256:83b78c680d4b15d33042d330c2fa31813ca3974197bddb3836a5c635a5fd013f", + "sha256:84e87a7d75fa36839a3a432286d719975362d230c70ebfa0948549cc38bd5b46", + "sha256:89b3857652183b8206a891168af47bac10b970d275bba1f6ee46565a758c078d", + "sha256:8cd1a0644ccaf27e9d2f6d9c9474faabee21f0578fe85225cc5af9a61e1653df", + "sha256:8de4d42dffd5ced9117af2ce66ba8722402541a3aa98ffdf78dde92badb68932", + "sha256:94a7bb972178a8bfc4055db80c51efd24baefaced5e51c59b0d598a004e8305d", + "sha256:98aa8325c7f47183b45588af9c434533196e241be0a4e4ae2190b06d17675c02", + "sha256:9e658d1373c424457ddf6d55ec1db93c280b8579276bebd1f72f113072df8a5d", + "sha256:9f49585f4abadd2283034fc605961f40c638635bc60f5162276fec075f2e37a4", + "sha256:9f6cad071960ba1914fa231677d21b1b4a3acdcce463cee41ea30bc82e6040cf", + "sha256:a0cc398350ef31167e03f3ca7c19313d4e40a662adcb98a88755e4e861170bdd", + "sha256:a1133414b771619aa3c3000701c11b2e4624a7f492f12f256aedde97c28331a2", + "sha256:a33273a541f1e1a8219b2a4ed2de355848ecc0254264915b9290c8d2de1c74e1", + "sha256:a3c0ff89fe40a152e77b191b83282c9664357dce3004032d42e68c514ceff27e", + "sha256:a49994481b99cd7dedde07f2e7e93b1d86c01c0fca1c32aded18f10695ae17eb", + "sha256:abf5b17bc0cf626a8a497d89ac691308dbd825d2ac372aa990b1ca114e470151", + "sha256:ac380cacdd3b183338ba63a144a34e9044520a6fb30c58aa14077157a033c13e", + "sha256:ad81012b24b88aad4c70b2cbc2dad84018783221b7f923e926f4690ff8569da3", + "sha256:b2c00ad31fbc2cbac85d7d0fcf90853b2ca2e69d825a2d3f3edb842ef1544a2c", + "sha256:b4c153863dd6569f6511845922c53e39c8d61f6e81f228ad5443e690fca403de", + "sha256:b4f3d66dd0354b79761481fc15bdafaba0b9d9076f1f42cc9ce10d7fcbda205a", + "sha256:b99aac6bb2c37db336fa03a39b40ed4ef2818bf2dfb9441458165ebe88b793af", + "sha256:b9f6392d98c0bd70676ae41474e2eecf4c7150cb419237a41f8f96043fcb81d1", + "sha256:c537da54ce4ff7c15e78ab1292e5799d0d43a2108e006578a57f531866f64025", + "sha256:ca23db5fb195b5ef4fd1f77ce26cadefdf13dba71dab14dadd29b34d457d7c44", + "sha256:cc826b9a8176e686b67aa60fd6c6a7047b0461cae5591ea1dc73d28f72332a8a", + "sha256:cca83a629f77402cfadd58352e394d79a61c8015f1694b83ab72237ec3941f88", + "sha256:cf8d370b2fea27fb300825ec3984334f7dd54a581bde6456799ba3776915a656", + "sha256:d1175b0e0d6037fab207f05774a176d71210ebd40b1c51f480a04b65ec5c786d", + "sha256:d1996ee1330e245cd3aeda0887b4409e3930524c27642b046e4fae88ffa66c5e", + "sha256:d5a36953389f35f0a4e88dc796048829a2f467c9197265504593f0e420571547", + "sha256:da51d8928ad8b4244926fe862ba1795f0b6e68ed8c42cd2f822d435db9c2a8f4", + "sha256:e16e7297f29a544f49340012d6fc08cf14de0ab361c9eb7529f6a57a30cbfda1", + "sha256:e25b11a0417475f093d0f0809a149aff3943c2c56da50fdf2c3c88d57fe3dfbd", + "sha256:e4371591e621579cb6da8401e4ea405b33ff25a755874a3567c4075ca63d56e2", + "sha256:e653d36b1bf48fa78c7fcebb5fa679342e025121ace8c87ab05c1cefd33b34fc", + "sha256:e7d91a230c7f8af86c904a5a992b8c064b66330544693fd6759c3d6162382ecf", + "sha256:e851e6363d0dbe515d8de81fd544a2c956fdec6f8a049739562286727d4a00c3", + "sha256:ef7d48207926edbf8b16b336f779c557dd8f5a33035a85db9c4b0febb0706817", + "sha256:f7716f7e7138252d88607228ce40be22660d6608d20fd365d596e7ca0738e019", + "sha256:facaf11f21f3a4c51b62931feb13310e6fe3475f85e20d9c9fdce0d2ea561b87" + ], + "markers": "python_version >= '3.9'", + "version": "==6.2.0" + }, + "niquests": { + "hashes": [ + "sha256:68e0a7e9f338466b3606945fffd11f75e3c90af7498aa9336ef03812323b7e36", + "sha256:86e484c2c60444aa96069c15f6295af6e25a8bad50781e1326df1b5c7ab48339" + ], + "markers": "python_version >= '3.7'", + "version": "==3.14.0" + }, + "numpy": { + "hashes": [ + "sha256:05c076d531e9998e7e694c36e8b349969c56eadd2cdcd07242958489d79a7286", + "sha256:0d54974f9cf14acf49c60f0f7f4084b6579d24d439453d5fc5805d46a165b542", + "sha256:11c43995255eb4127115956495f43e9343736edb7fcdb0d973defd9de14cd84f", + "sha256:188dcbca89834cc2e14eb2f106c96d6d46f200fe0200310fc29089657379c58d", + "sha256:1974afec0b479e50438fc3648974268f972e2d908ddb6d7fb634598cdb8260a0", + "sha256:1cf4e5c6a278d620dee9ddeb487dc6a860f9b199eadeecc567f777daace1e9e7", + "sha256:207a2b8441cc8b6a2a78c9ddc64d00d20c303d79fba08c577752f080c4007ee3", + "sha256:218f061d2faa73621fa23d6359442b0fc658d5b9a70801373625d958259eaca3", + "sha256:2aad3c17ed2ff455b8eaafe06bcdae0062a1db77cb99f4b9cbb5f4ecb13c5146", + "sha256:2fa8fa7697ad1646b5c93de1719965844e004fcad23c91228aca1cf0800044a1", + "sha256:31504f970f563d99f71a3512d0c01a645b692b12a63630d6aafa0939e52361e6", + "sha256:3387dd7232804b341165cedcb90694565a6015433ee076c6754775e85d86f1fc", + "sha256:4ba5054787e89c59c593a4169830ab362ac2bee8a969249dc56e5d7d20ff8df9", + "sha256:4f92084defa704deadd4e0a5ab1dc52d8ac9e8a8ef617f3fbb853e79b0ea3592", + "sha256:65ef3468b53269eb5fdb3a5c09508c032b793da03251d5f8722b1194f1790c00", + "sha256:6f527d8fdb0286fd2fd97a2a96c6be17ba4232da346931d967a0630050dfd298", + "sha256:7051ee569db5fbac144335e0f3b9c2337e0c8d5c9fee015f259a5bd70772b7e8", + "sha256:7716e4a9b7af82c06a2543c53ca476fa0b57e4d760481273e09da04b74ee6ee2", + "sha256:79bd5f0a02aa16808fcbc79a9a376a147cc1045f7dfe44c6e7d53fa8b8a79392", + "sha256:7a4e84a6283b36632e2a5b56e121961f6542ab886bc9e12f8f9818b3c266bfbb", + "sha256:8120575cb4882318c791f839a4fd66161a6fa46f3f0a5e613071aae35b5dd8f8", + "sha256:81413336ef121a6ba746892fad881a83351ee3e1e4011f52e97fba79233611fd", + "sha256:8146f3550d627252269ac42ae660281d673eb6f8b32f113538e0cc2a9aed42b9", + "sha256:879cf3a9a2b53a4672a168c21375166171bc3932b7e21f622201811c43cdd3b0", + "sha256:892c10d6a73e0f14935c31229e03325a7b3093fafd6ce0af704be7f894d95687", + "sha256:92bda934a791c01d6d9d8e038363c50918ef7c40601552a58ac84c9613a665bc", + "sha256:9ba03692a45d3eef66559efe1d1096c4b9b75c0986b5dff5530c378fb8331d4f", + "sha256:9eeea959168ea555e556b8188da5fa7831e21d91ce031e95ce23747b7609f8a4", + "sha256:a0258ad1f44f138b791327961caedffbf9612bfa504ab9597157806faa95194a", + "sha256:a761ba0fa886a7bb33c6c8f6f20213735cb19642c580a931c625ee377ee8bd39", + "sha256:a7b9084668aa0f64e64bd00d27ba5146ef1c3a8835f3bd912e7a9e01326804c4", + "sha256:a84eda42bd12edc36eb5b53bbcc9b406820d3353f1994b6cfe453a33ff101775", + "sha256:ab2939cd5bec30a7430cbdb2287b63151b77cf9624de0532d629c9a1c59b1d5c", + "sha256:ac0280f1ba4a4bfff363a99a6aceed4f8e123f8a9b234c89140f5e894e452ecd", + "sha256:adf8c1d66f432ce577d0197dceaac2ac00c0759f573f28516246351c58a85020", + "sha256:b4adfbbc64014976d2f91084915ca4e626fbf2057fb81af209c1a6d776d23e3d", + "sha256:bb649f8b207ab07caebba230d851b579a3c8711a851d29efe15008e31bb4de24", + "sha256:bce43e386c16898b91e162e5baaad90c4b06f9dcbe36282490032cec98dc8ae7", + "sha256:bd3ad3b0a40e713fc68f99ecfd07124195333f1e689387c180813f0e94309d6f", + "sha256:c3f7ac96b16955634e223b579a3e5798df59007ca43e8d451a0e6a50f6bfdfba", + "sha256:cf28633d64294969c019c6df4ff37f5698e8326db68cc2b66576a51fad634880", + "sha256:d0f35b19894a9e08639fd60a1ec1978cb7f5f7f1eace62f38dd36be8aecdef4d", + "sha256:db1f1c22173ac1c58db249ae48aa7ead29f534b9a948bc56828337aa84a32ed6", + "sha256:dbe512c511956b893d2dacd007d955a3f03d555ae05cfa3ff1c1ff6df8851854", + "sha256:df2f57871a96bbc1b69733cd4c51dc33bea66146b8c63cacbfed73eec0883017", + "sha256:e2f085ce2e813a50dfd0e01fbfc0c12bbe5d2063d99f8b29da30e544fb6483b8", + "sha256:e642d86b8f956098b564a45e6f6ce68a22c2c97a04f5acd3f221f57b8cb850ae", + "sha256:e9e0a277bb2eb5d8a7407e14688b85fd8ad628ee4e0c7930415687b6564207a4", + "sha256:ea2bb7e2ae9e37d96835b3576a4fa4b3a97592fbea8ef7c3587078b0068b8f09", + "sha256:ee4d528022f4c5ff67332469e10efe06a267e32f4067dc76bb7e2cddf3cd25ff", + "sha256:f05d4198c1bacc9124018109c5fba2f3201dbe7ab6e92ff100494f236209c960", + "sha256:f34dc300df798742b3d06515aa2a0aee20941c13579d7a2f2e10af01ae4901ee", + "sha256:f4162988a360a29af158aeb4a2f4f09ffed6a969c9776f8f3bdee9b06a8ab7e5", + "sha256:f486038e44caa08dbd97275a9a35a283a8f1d2f0ee60ac260a1790e76660833c", + "sha256:f7de08cbe5551911886d1ab60de58448c6df0f67d9feb7d1fb21e9875ef95e91" + ], + "markers": "python_version >= '3.10'", + "version": "==2.2.4" + }, + "packaging": { + "hashes": [ + "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", + "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" + ], + "markers": "python_version >= '3.8'", + "version": "==24.2" + }, + "pandas": { + "hashes": [ + "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a", + "sha256:15c0e1e02e93116177d29ff83e8b1619c93ddc9c49083f237d4312337a61165d", + "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5", + "sha256:1db71525a1538b30142094edb9adc10be3f3e176748cd7acc2240c2f2e5aa3a4", + "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0", + "sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32", + "sha256:31d0ced62d4ea3e231a9f228366919a5ea0b07440d9d4dac345376fd8e1477ea", + "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28", + "sha256:37e0aced3e8f539eccf2e099f65cdb9c8aa85109b0be6e93e2baff94264bdc6f", + "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348", + "sha256:38cf8125c40dae9d5acc10fa66af8ea6fdf760b2714ee482ca691fc66e6fcb18", + "sha256:3b71f27954685ee685317063bf13c7709a7ba74fc996b84fc6821c59b0f06468", + "sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5", + "sha256:4850ba03528b6dd51d6c5d273c46f183f39a9baf3f0143e566b89450965b105e", + "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", + "sha256:56534ce0746a58afaf7942ba4863e0ef81c9c50d3f0ae93e9497d6a41a057645", + "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", + "sha256:5dbca4c1acd72e8eeef4753eeca07de9b1db4f398669d5994086f788a5d7cc30", + "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3", + "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d", + "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb", + "sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3", + "sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039", + "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8", + "sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd", + "sha256:7eee9e7cea6adf3e3d24e304ac6b8300646e2a5d1cd3a3c2abed9101b0846761", + "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659", + "sha256:86976a1c5b25ae3f8ccae3a5306e443569ee3c3faf444dfd0f41cda24667ad57", + "sha256:8cd6d7cc958a3910f934ea8dbdf17b2364827bb4dafc38ce6eef6bb3d65ff09c", + "sha256:99df71520d25fade9db7c1076ac94eb994f4d2673ef2aa2e86ee039b6746d20c", + "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4", + "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a", + "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9", + "sha256:b8661b0238a69d7aafe156b7fa86c44b881387509653fdf857bebc5e4008ad42", + "sha256:ba96630bc17c875161df3818780af30e43be9b166ce51c9a18c1feae342906c2", + "sha256:bc6b93f9b966093cb0fd62ff1a7e4c09e6d546ad7c1de191767baffc57628f39", + "sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc", + "sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698", + "sha256:d9c45366def9a3dd85a6454c0e7908f2b3b8e9c138f5dc38fed7ce720d8453ed", + "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015", + "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24", + "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319" + ], + "markers": "python_version >= '3.9'", + "version": "==2.2.3" + }, + "pika": { + "hashes": [ + "sha256:0779a7c1fafd805672796085560d290213a465e4f6f76a6fb19e378d8041a14f", + "sha256:b2a327ddddf8570b4965b3576ac77091b850262d34ce8c1d8cb4e4146aa4145f" + ], + "markers": "python_version >= '3.7'", + "version": "==1.3.2" + }, + "pluggy": { + "hashes": [ + "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", + "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" + ], + "markers": "python_version >= '3.8'", + "version": "==1.5.0" + }, + "prometheus-client": { + "hashes": [ + "sha256:252505a722ac04b0456be05c05f75f45d760c2911ffc45f2a06bcaed9f3ae3fb", + "sha256:594b45c410d6f4f8888940fe80b5cc2521b305a1fafe1c58609ef715a001f301" + ], + "markers": "python_version >= '3.8'", + "version": "==0.21.1" + }, + "prometheus-flask-exporter": { + "hashes": [ + "sha256:41fc9bbd7d48cc958ed8384aacf60c3621d9e903768be61c4e7f0c63872eaf1a", + "sha256:94922a636d4c1d8b68e1ee605c30a23e9bbb0b21756df8222aa919634871784c" + ], + "index": "pypi", + "version": "==0.23.2" + }, + "propcache": { + "hashes": [ + "sha256:050b571b2e96ec942898f8eb46ea4bfbb19bd5502424747e83badc2d4a99a44e", + "sha256:05543250deac8e61084234d5fc54f8ebd254e8f2b39a16b1dce48904f45b744b", + "sha256:069e7212890b0bcf9b2be0a03afb0c2d5161d91e1bf51569a64f629acc7defbf", + "sha256:09400e98545c998d57d10035ff623266927cb784d13dd2b31fd33b8a5316b85b", + "sha256:0c3c3a203c375b08fd06a20da3cf7aac293b834b6f4f4db71190e8422750cca5", + "sha256:0c86e7ceea56376216eba345aa1fc6a8a6b27ac236181f840d1d7e6a1ea9ba5c", + "sha256:0fbe94666e62ebe36cd652f5fc012abfbc2342de99b523f8267a678e4dfdee3c", + "sha256:17d1c688a443355234f3c031349da69444be052613483f3e4158eef751abcd8a", + "sha256:19a06db789a4bd896ee91ebc50d059e23b3639c25d58eb35be3ca1cbe967c3bf", + "sha256:1c5c7ab7f2bb3f573d1cb921993006ba2d39e8621019dffb1c5bc94cdbae81e8", + "sha256:1eb34d90aac9bfbced9a58b266f8946cb5935869ff01b164573a7634d39fbcb5", + "sha256:1f6cc0ad7b4560e5637eb2c994e97b4fa41ba8226069c9277eb5ea7101845b42", + "sha256:27c6ac6aa9fc7bc662f594ef380707494cb42c22786a558d95fcdedb9aa5d035", + "sha256:2d219b0dbabe75e15e581fc1ae796109b07c8ba7d25b9ae8d650da582bed01b0", + "sha256:2fce1df66915909ff6c824bbb5eb403d2d15f98f1518e583074671a30fe0c21e", + "sha256:319fa8765bfd6a265e5fa661547556da381e53274bc05094fc9ea50da51bfd46", + "sha256:359e81a949a7619802eb601d66d37072b79b79c2505e6d3fd8b945538411400d", + "sha256:3a02a28095b5e63128bcae98eb59025924f121f048a62393db682f049bf4ac24", + "sha256:3e19ea4ea0bf46179f8a3652ac1426e6dcbaf577ce4b4f65be581e237340420d", + "sha256:3e584b6d388aeb0001d6d5c2bd86b26304adde6d9bb9bfa9c4889805021b96de", + "sha256:40d980c33765359098837527e18eddefc9a24cea5b45e078a7f3bb5b032c6ecf", + "sha256:4114c4ada8f3181af20808bedb250da6bae56660e4b8dfd9cd95d4549c0962f7", + "sha256:43593c6772aa12abc3af7784bff4a41ffa921608dd38b77cf1dfd7f5c4e71371", + "sha256:47ef24aa6511e388e9894ec16f0fbf3313a53ee68402bc428744a367ec55b833", + "sha256:4cf9e93a81979f1424f1a3d155213dc928f1069d697e4353edb8a5eba67c6259", + "sha256:4d0dfdd9a2ebc77b869a0b04423591ea8823f791293b527dc1bb896c1d6f1136", + "sha256:563f9d8c03ad645597b8d010ef4e9eab359faeb11a0a2ac9f7b4bc8c28ebef25", + "sha256:58aa11f4ca8b60113d4b8e32d37e7e78bd8af4d1a5b5cb4979ed856a45e62005", + "sha256:5a0a9898fdb99bf11786265468571e628ba60af80dc3f6eb89a3545540c6b0ef", + "sha256:5aed8d8308215089c0734a2af4f2e95eeb360660184ad3912686c181e500b2e7", + "sha256:5b9145c35cc87313b5fd480144f8078716007656093d23059e8993d3a8fa730f", + "sha256:5cb5918253912e088edbf023788de539219718d3b10aef334476b62d2b53de53", + "sha256:5cdb0f3e1eb6dfc9965d19734d8f9c481b294b5274337a8cb5cb01b462dcb7e0", + "sha256:5ced33d827625d0a589e831126ccb4f5c29dfdf6766cac441d23995a65825dcb", + "sha256:603f1fe4144420374f1a69b907494c3acbc867a581c2d49d4175b0de7cc64566", + "sha256:61014615c1274df8da5991a1e5da85a3ccb00c2d4701ac6f3383afd3ca47ab0a", + "sha256:64a956dff37080b352c1c40b2966b09defb014347043e740d420ca1eb7c9b908", + "sha256:668ddddc9f3075af019f784456267eb504cb77c2c4bd46cc8402d723b4d200bf", + "sha256:6d8e309ff9a0503ef70dc9a0ebd3e69cf7b3894c9ae2ae81fc10943c37762458", + "sha256:6f173bbfe976105aaa890b712d1759de339d8a7cef2fc0a1714cc1a1e1c47f64", + "sha256:71ebe3fe42656a2328ab08933d420df5f3ab121772eef78f2dc63624157f0ed9", + "sha256:730178f476ef03d3d4d255f0c9fa186cb1d13fd33ffe89d39f2cda4da90ceb71", + "sha256:7d2d5a0028d920738372630870e7d9644ce437142197f8c827194fca404bf03b", + "sha256:7f30241577d2fef2602113b70ef7231bf4c69a97e04693bde08ddab913ba0ce5", + "sha256:813fbb8b6aea2fc9659815e585e548fe706d6f663fa73dff59a1677d4595a037", + "sha256:82de5da8c8893056603ac2d6a89eb8b4df49abf1a7c19d536984c8dd63f481d5", + "sha256:83be47aa4e35b87c106fc0c84c0fc069d3f9b9b06d3c494cd404ec6747544894", + "sha256:8638f99dca15b9dff328fb6273e09f03d1c50d9b6512f3b65a4154588a7595fe", + "sha256:87380fb1f3089d2a0b8b00f006ed12bd41bd858fabfa7330c954c70f50ed8757", + "sha256:88c423efef9d7a59dae0614eaed718449c09a5ac79a5f224a8b9664d603f04a3", + "sha256:89498dd49c2f9a026ee057965cdf8192e5ae070ce7d7a7bd4b66a8e257d0c976", + "sha256:8a17583515a04358b034e241f952f1715243482fc2c2945fd99a1b03a0bd77d6", + "sha256:916cd229b0150129d645ec51614d38129ee74c03293a9f3f17537be0029a9641", + "sha256:9532ea0b26a401264b1365146c440a6d78269ed41f83f23818d4b79497aeabe7", + "sha256:967a8eec513dbe08330f10137eacb427b2ca52118769e82ebcfcab0fba92a649", + "sha256:975af16f406ce48f1333ec5e912fe11064605d5c5b3f6746969077cc3adeb120", + "sha256:9979643ffc69b799d50d3a7b72b5164a2e97e117009d7af6dfdd2ab906cb72cd", + "sha256:9a8ecf38de50a7f518c21568c80f985e776397b902f1ce0b01f799aba1608b40", + "sha256:9cec3239c85ed15bfaded997773fdad9fb5662b0a7cbc854a43f291eb183179e", + "sha256:9e64e948ab41411958670f1093c0a57acfdc3bee5cf5b935671bbd5313bcf229", + "sha256:9f64d91b751df77931336b5ff7bafbe8845c5770b06630e27acd5dbb71e1931c", + "sha256:a0ab8cf8cdd2194f8ff979a43ab43049b1df0b37aa64ab7eca04ac14429baeb7", + "sha256:a110205022d077da24e60b3df8bcee73971be9575dec5573dd17ae5d81751111", + "sha256:a34aa3a1abc50740be6ac0ab9d594e274f59960d3ad253cd318af76b996dd654", + "sha256:a444192f20f5ce8a5e52761a031b90f5ea6288b1eef42ad4c7e64fef33540b8f", + "sha256:a461959ead5b38e2581998700b26346b78cd98540b5524796c175722f18b0294", + "sha256:a75801768bbe65499495660b777e018cbe90c7980f07f8aa57d6be79ea6f71da", + "sha256:aa8efd8c5adc5a2c9d3b952815ff8f7710cefdcaf5f2c36d26aff51aeca2f12f", + "sha256:aca63103895c7d960a5b9b044a83f544b233c95e0dcff114389d64d762017af7", + "sha256:b0313e8b923b3814d1c4a524c93dfecea5f39fa95601f6a9b1ac96cd66f89ea0", + "sha256:b23c11c2c9e6d4e7300c92e022046ad09b91fd00e36e83c44483df4afa990073", + "sha256:b303b194c2e6f171cfddf8b8ba30baefccf03d36a4d9cab7fd0bb68ba476a3d7", + "sha256:b655032b202028a582d27aeedc2e813299f82cb232f969f87a4fde491a233f11", + "sha256:bd39c92e4c8f6cbf5f08257d6360123af72af9f4da75a690bef50da77362d25f", + "sha256:bef100c88d8692864651b5f98e871fb090bd65c8a41a1cb0ff2322db39c96c27", + "sha256:c2fe5c910f6007e716a06d269608d307b4f36e7babee5f36533722660e8c4a70", + "sha256:c66d8ccbc902ad548312b96ed8d5d266d0d2c6d006fd0f66323e9d8f2dd49be7", + "sha256:cd6a55f65241c551eb53f8cf4d2f4af33512c39da5d9777694e9d9c60872f519", + "sha256:d249609e547c04d190e820d0d4c8ca03ed4582bcf8e4e160a6969ddfb57b62e5", + "sha256:d4e89cde74154c7b5957f87a355bb9c8ec929c167b59c83d90654ea36aeb6180", + "sha256:dc1915ec523b3b494933b5424980831b636fe483d7d543f7afb7b3bf00f0c10f", + "sha256:e1c4d24b804b3a87e9350f79e2371a705a188d292fd310e663483af6ee6718ee", + "sha256:e474fc718e73ba5ec5180358aa07f6aded0ff5f2abe700e3115c37d75c947e18", + "sha256:e4fe2a6d5ce975c117a6bb1e8ccda772d1e7029c1cca1acd209f91d30fa72815", + "sha256:e7fb9a84c9abbf2b2683fa3e7b0d7da4d8ecf139a1c635732a8bda29c5214b0e", + "sha256:e861ad82892408487be144906a368ddbe2dc6297074ade2d892341b35c59844a", + "sha256:ec314cde7314d2dd0510c6787326bbffcbdc317ecee6b7401ce218b3099075a7", + "sha256:ed5f6d2edbf349bd8d630e81f474d33d6ae5d07760c44d33cd808e2f5c8f4ae6", + "sha256:ef2e4e91fb3945769e14ce82ed53007195e616a63aa43b40fb7ebaaf907c8d4c", + "sha256:f011f104db880f4e2166bcdcf7f58250f7a465bc6b068dc84c824a3d4a5c94dc", + "sha256:f1528ec4374617a7a753f90f20e2f551121bb558fcb35926f99e3c42367164b8", + "sha256:f27785888d2fdd918bc36de8b8739f2d6c791399552333721b58193f68ea3e98", + "sha256:f35c7070eeec2cdaac6fd3fe245226ed2a6292d3ee8c938e5bb645b434c5f256", + "sha256:f3bbecd2f34d0e6d3c543fdb3b15d6b60dd69970c2b4c822379e5ec8f6f621d5", + "sha256:f6f1324db48f001c2ca26a25fa25af60711e09b9aaf4b28488602776f4f9a744", + "sha256:f78eb8422acc93d7b69964012ad7048764bb45a54ba7a39bb9e146c72ea29723", + "sha256:fb6e0faf8cb6b4beea5d6ed7b5a578254c6d7df54c36ccd3d8b3eb00d6770277", + "sha256:feccd282de1f6322f56f6845bf1207a537227812f0a9bf5571df52bb418d79d5" + ], + "markers": "python_version >= '3.9'", + "version": "==0.3.1" + }, + "pycparser": { + "hashes": [ + "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", + "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc" + ], + "markers": "python_version >= '3.8'", + "version": "==2.22" + }, + "pydantic": { + "hashes": [ + "sha256:442557d2910e75c991c39f4b4ab18963d57b9b55122c8b2a9cd176d8c29ce968", + "sha256:5b6c415eee9f8123a14d859be0c84363fec6b1feb6b688d6435801230b56e0b8" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==2.11.1" + }, + "pydantic-core": { + "hashes": [ + "sha256:024d136ae44d233e6322027bbf356712b3940bee816e6c948ce4b90f18471b3d", + "sha256:0310524c833d91403c960b8a3cf9f46c282eadd6afd276c8c5edc617bd705dc9", + "sha256:07b4ced28fccae3f00626eaa0c4001aa9ec140a29501770a88dbbb0966019a86", + "sha256:085d8985b1c1e48ef271e98a658f562f29d89bda98bf120502283efbc87313eb", + "sha256:0a98257451164666afafc7cbf5fb00d613e33f7e7ebb322fbcd99345695a9a61", + "sha256:0bcf0bab28995d483f6c8d7db25e0d05c3efa5cebfd7f56474359e7137f39856", + "sha256:138d31e3f90087f42aa6286fb640f3c7a8eb7bdae829418265e7e7474bd2574b", + "sha256:14229c1504287533dbf6b1fc56f752ce2b4e9694022ae7509631ce346158de11", + "sha256:1583539533160186ac546b49f5cde9ffc928062c96920f58bd95de32ffd7bffd", + "sha256:175ab598fb457a9aee63206a1993874badf3ed9a456e0654273e56f00747bbd6", + "sha256:1a69b7596c6603afd049ce7f3835bcf57dd3892fc7279f0ddf987bebed8caa5a", + "sha256:1a73be93ecef45786d7d95b0c5e9b294faf35629d03d5b145b09b81258c7cd6d", + "sha256:1b1262b912435a501fa04cd213720609e2cefa723a07c92017d18693e69bf00b", + "sha256:1b2ea72dea0825949a045fa4071f6d5b3d7620d2a208335207793cf29c5a182d", + "sha256:20d4275f3c4659d92048c70797e5fdc396c6e4446caf517ba5cad2db60cd39d3", + "sha256:23c3e77bf8a7317612e5c26a3b084c7edeb9552d645742a54a5867635b4f2453", + "sha256:26a4ea04195638dcd8c53dadb545d70badba51735b1594810e9768c2c0b4a5da", + "sha256:26bc7367c0961dec292244ef2549afa396e72e28cc24706210bd44d947582c59", + "sha256:2a0147c0bef783fd9abc9f016d66edb6cac466dc54a17ec5f5ada08ff65caf5d", + "sha256:2c0afd34f928383e3fd25740f2050dbac9d077e7ba5adbaa2227f4d4f3c8da5c", + "sha256:30369e54d6d0113d2aa5aee7a90d17f225c13d87902ace8fcd7bbf99b19124db", + "sha256:31860fbda80d8f6828e84b4a4d129fd9c4535996b8249cfb8c720dc2a1a00bb8", + "sha256:34e7fb3abe375b5c4e64fab75733d605dda0f59827752debc99c17cb2d5f3276", + "sha256:40eb8af662ba409c3cbf4a8150ad32ae73514cd7cb1f1a2113af39763dd616b3", + "sha256:41d698dcbe12b60661f0632b543dbb119e6ba088103b364ff65e951610cb7ce0", + "sha256:4726f1f3f42d6a25678c67da3f0b10f148f5655813c5aca54b0d1742ba821b8f", + "sha256:4927564be53239a87770a5f86bdc272b8d1fbb87ab7783ad70255b4ab01aa25b", + "sha256:4b6d77c75a57f041c5ee915ff0b0bb58eabb78728b69ed967bc5b780e8f701b8", + "sha256:4d9149e7528af8bbd76cc055967e6e04617dcb2a2afdaa3dea899406c5521faa", + "sha256:4deac83a8cc1d09e40683be0bc6d1fa4cde8df0a9bf0cda5693f9b0569ac01b6", + "sha256:4f1ab031feb8676f6bd7c85abec86e2935850bf19b84432c64e3e239bffeb1ec", + "sha256:502ed542e0d958bd12e7c3e9a015bce57deaf50eaa8c2e1c439b512cb9db1e3a", + "sha256:5461934e895968655225dfa8b3be79e7e927e95d4bd6c2d40edd2fa7052e71b6", + "sha256:58c1151827eef98b83d49b6ca6065575876a02d2211f259fb1a6b7757bd24dd8", + "sha256:5bdd36b362f419c78d09630cbaebc64913f66f62bda6d42d5fbb08da8cc4f181", + "sha256:5bf637300ff35d4f59c006fff201c510b2b5e745b07125458a5389af3c0dff8c", + "sha256:5bf68bb859799e9cec3d9dd8323c40c00a254aabb56fe08f907e437005932f2b", + "sha256:5d8dc9f63a26f7259b57f46a7aab5af86b2ad6fbe48487500bb1f4b27e051e4c", + "sha256:5f36afd0d56a6c42cf4e8465b6441cf546ed69d3a4ec92724cc9c8c61bd6ecf4", + "sha256:5f72914cfd1d0176e58ddc05c7a47674ef4222c8253bf70322923e73e14a4ac3", + "sha256:6291797cad239285275558e0a27872da735b05c75d5237bbade8736f80e4c225", + "sha256:62c151ce3d59ed56ebd7ce9ce5986a409a85db697d25fc232f8e81f195aa39a1", + "sha256:635702b2fed997e0ac256b2cfbdb4dd0bf7c56b5d8fba8ef03489c03b3eb40e2", + "sha256:64672fa888595a959cfeff957a654e947e65bbe1d7d82f550417cbd6898a1d6b", + "sha256:68504959253303d3ae9406b634997a2123a0b0c1da86459abbd0ffc921695eac", + "sha256:69297418ad644d521ea3e1aa2e14a2a422726167e9ad22b89e8f1130d68e1e9a", + "sha256:6c32a40712e3662bebe524abe8abb757f2fa2000028d64cc5a1006016c06af43", + "sha256:715c62af74c236bf386825c0fdfa08d092ab0f191eb5b4580d11c3189af9d330", + "sha256:71dffba8fe9ddff628c68f3abd845e91b028361d43c5f8e7b3f8b91d7d85413e", + "sha256:7419241e17c7fbe5074ba79143d5523270e04f86f1b3a0dff8df490f84c8273a", + "sha256:759871f00e26ad3709efc773ac37b4d571de065f9dfb1778012908bcc36b3a73", + "sha256:7a25493320203005d2a4dac76d1b7d953cb49bce6d459d9ae38e30dd9f29bc9c", + "sha256:7b79af799630af263eca9ec87db519426d8c9b3be35016eddad1832bac812d87", + "sha256:7c9c84749f5787781c1c45bb99f433402e484e515b40675a5d121ea14711cf61", + "sha256:7da333f21cd9df51d5731513a6d39319892947604924ddf2e24a4612975fb936", + "sha256:82a4eba92b7ca8af1b7d5ef5f3d9647eee94d1f74d21ca7c21e3a2b92e008358", + "sha256:89670d7a0045acb52be0566df5bc8b114ac967c662c06cf5e0c606e4aadc964b", + "sha256:8a1d581e8cdbb857b0e0e81df98603376c1a5c34dc5e54039dcc00f043df81e7", + "sha256:8ec86b5baa36f0a0bfb37db86c7d52652f8e8aa076ab745ef7725784183c3fdd", + "sha256:91301a0980a1d4530d4ba7e6a739ca1a6b31341252cb709948e0aca0860ce0ae", + "sha256:918f2013d7eadea1d88d1a35fd4a1e16aaf90343eb446f91cb091ce7f9b431a2", + "sha256:9cb2390355ba084c1ad49485d18449b4242da344dea3e0fe10babd1f0db7dcfc", + "sha256:9ee65f0cc652261744fd07f2c6e6901c914aa6c5ff4dcfaf1136bc394d0dd26b", + "sha256:a608a75846804271cf9c83e40bbb4dab2ac614d33c6fd5b0c6187f53f5c593ef", + "sha256:a66d931ea2c1464b738ace44b7334ab32a2fd50be023d863935eb00f42be1778", + "sha256:a7a7f2a3f628d2f7ef11cb6188bcf0b9e1558151d511b974dfea10a49afe192b", + "sha256:abaeec1be6ed535a5d7ffc2e6c390083c425832b20efd621562fbb5bff6dc518", + "sha256:abfa44cf2f7f7d7a199be6c6ec141c9024063205545aa09304349781b9a125e6", + "sha256:ade5dbcf8d9ef8f4b28e682d0b29f3008df9842bb5ac48ac2c17bc55771cc976", + "sha256:ae62032ef513fe6281ef0009e30838a01057b832dc265da32c10469622613885", + "sha256:aec79acc183865bad120b0190afac467c20b15289050648b876b07777e67ea48", + "sha256:b716294e721d8060908dbebe32639b01bfe61b15f9f57bcc18ca9a0e00d9520b", + "sha256:b9ec80eb5a5f45a2211793f1c4aeddff0c3761d1c70d684965c1807e923a588b", + "sha256:ba95691cf25f63df53c1d342413b41bd7762d9acb425df8858d7efa616c0870e", + "sha256:bccc06fa0372151f37f6b69834181aa9eb57cf8665ed36405fb45fbf6cac3bae", + "sha256:c860773a0f205926172c6644c394e02c25421dc9a456deff16f64c0e299487d3", + "sha256:ca1103d70306489e3d006b0f79db8ca5dd3c977f6f13b2c59ff745249431a606", + "sha256:ce72d46eb201ca43994303025bd54d8a35a3fc2a3495fac653d6eb7205ce04f4", + "sha256:d20cbb9d3e95114325780f3cfe990f3ecae24de7a2d75f978783878cce2ad585", + "sha256:dcfebee69cd5e1c0b76a17e17e347c84b00acebb8dd8edb22d4a03e88e82a207", + "sha256:e1c69aa459f5609dec2fa0652d495353accf3eda5bdb18782bc5a2ae45c9273a", + "sha256:e2762c568596332fdab56b07060c8ab8362c56cf2a339ee54e491cd503612c50", + "sha256:e37f10f6d4bc67c58fbd727108ae1d8b92b397355e68519f1e4a7babb1473442", + "sha256:e790954b5093dff1e3a9a2523fddc4e79722d6f07993b4cd5547825c3cbf97b5", + "sha256:e81a295adccf73477220e15ff79235ca9dcbcee4be459eb9d4ce9a2763b8386c", + "sha256:e925819a98318d17251776bd3d6aa9f3ff77b965762155bdad15d1a9265c4cfd", + "sha256:ea30239c148b6ef41364c6f51d103c2988965b643d62e10b233b5efdca8c0099", + "sha256:eabf946a4739b5237f4f56d77fa6668263bc466d06a8036c055587c130a46f7b", + "sha256:ecb158fb9b9091b515213bed3061eb7deb1d3b4e02327c27a0ea714ff46b0760", + "sha256:ecc6d02d69b54a2eb83ebcc6f29df04957f734bcf309d346b4f83354d8376862", + "sha256:eddb18a00bbb855325db27b4c2a89a4ba491cd6a0bd6d852b225172a1f54b36c", + "sha256:f00e8b59e1fc8f09d05594aa7d2b726f1b277ca6155fc84c0396db1b373c4555", + "sha256:f1fb026c575e16f673c61c7b86144517705865173f3d0907040ac30c4f9f5915", + "sha256:f200b2f20856b5a6c3a35f0d4e344019f805e363416e609e9b47c552d35fd5ea", + "sha256:f225f3a3995dbbc26affc191d0443c6c4aa71b83358fd4c2b7d63e2f6f0336f9", + "sha256:f22dab23cdbce2005f26a8f0c71698457861f97fc6318c75814a50c75e87d025", + "sha256:f3eb479354c62067afa62f53bb387827bee2f75c9c79ef25eef6ab84d4b1ae3b", + "sha256:fc53e05c16697ff0c1c7c2b98e45e131d4bfb78068fffff92a82d169cbb4c7b7", + "sha256:ff48a55be9da6930254565ff5238d71d5e9cd8c5487a191cb85df3bdb8c77365" + ], + "markers": "python_version >= '3.9'", + "version": "==2.33.0" + }, + "pyjwt": { + "hashes": [ + "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", + "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb" + ], + "markers": "python_version >= '3.9'", + "version": "==2.10.1" + }, + "pytest": { + "hashes": [ + "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", + "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==8.3.5" + }, + "python-dateutil": { + "hashes": [ + "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", + "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==2.9.0.post0" + }, + "python-dotenv": { + "hashes": [ + "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5", + "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==1.1.0" + }, + "pytz": { + "hashes": [ + "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", + "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00" + ], + "version": "==2025.2" + }, + "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" + ], + "markers": "python_version >= '3.8'", + "version": "==6.0.2" + }, + "qh3": { + "hashes": [ + "sha256:0107f576a0524421e1b0f9e0437d2881a1835b1b6105eadd7ea0c1c9bf2da917", + "sha256:06159707895c606a321ccb5630347a2d2a44ee584f22945e5b22b0ad34f21ec8", + "sha256:06255835f99ea1af9e5d358056011686fcccbafaba893454027daa62ab6f701f", + "sha256:09b2305a954e61a9ed8b46a7a45f54e8d95ef870a47d5fd1836e14c7600d3b92", + "sha256:0a51dcffae03a89ddbab1884860569e0d1dbbf95deee47457c1fd29b4ac8d220", + "sha256:0a5d1cd881b7d43481ad60262cf3390a555e0e51751bc2af70ba4a612487e797", + "sha256:0e1c273660f9b8511c22d0b082137556e46d6a7eccf132bd82f95d29f90488b2", + "sha256:0e540cc7e7da65da30381bdb73a789a8635c6aaef98688d904eee3bc587654a5", + "sha256:10ed818f47dc522350a12641e8f2bea19ff824f8ce373c23a8e594b3481fd7a4", + "sha256:195b4ad58cf5a8da218e2368d34f47628c14581f3cc9863fc0406b32e137f3a6", + "sha256:1a80d07249c7ccbaa57bb9015b5ead0ead7ac1940cd5483548dfe56db99ce7a4", + "sha256:1cf0b18823801078d2294a0356abc2be34b4a224bea863a87029c1c97d6c34e0", + "sha256:1fac2ab4b8a2e50894b54a19416cd363defe0fb33f52754686ea58999f98dfc5", + "sha256:205cdaea9da8881b31b76eb6da5b88c9558ba96bc16a3ecf11333098ac7f3859", + "sha256:2294e78bcc40728a3a772df0f8ecf8b8756616d06dd001029016876aa4e5c9de", + "sha256:235236ab195d34e7cd18d186e46b7a4f8aceafe246bf36b42913f72627ded414", + "sha256:25eef1f2be50d79d23e01a567c719e46e4892518a5ccc96685fcb4746357320b", + "sha256:2ae147b756c3adf59699756feb9e07d4a69674f57b4e13d6c25f9d1dc3c8707c", + "sha256:2c9cdd7ea49c79b671e7de35dad61d2aa91920e2498d0c6dfa932d5e05070a5e", + "sha256:2dc9f269d7316b0a44e61ae7a11ffd8daa800b3f5ba773de2e9d8c4ee636a896", + "sha256:2f94d69edb0070ef4ec414deabfc2369aa2100b11bf4a4f2f393f2c28c4bc7ba", + "sha256:311da331e31c55afc3f4f4f2ba9d07a1d700ffb7db5aa4f58300b9f56f2523dc", + "sha256:3578844a9ff4c342a409d010f909782afc52a31680876f7fab65bf133aa3f4db", + "sha256:4032c2898b4c0ff7a25cf7d68c3b1f2abdcaf4f25cc8b6802a941a842f9a95b6", + "sha256:40abd150eddfa0884c139bd281e87ff920d4cd52d685fc4ef25ddcc77ff7a220", + "sha256:43e32602651d07f8a0860ba0a45d8c8fe9ccd537030e7632d1258f7b84881416", + "sha256:45a21d25fe17168f4db09fcaabee5dd171763ad1bd8753c257297837f5ba9197", + "sha256:45bfbb126e31ecf63ef74c249d38d07e149c0663b4a191cf9e2e3445a80758d5", + "sha256:4745667c9956bcfd74ff677edd4c73d6cb578b6b47c5fb3d246aaa223dd6a004", + "sha256:4936a5d8915866b4f08ab18018f41ed93a2593788ad0a80796aada2e23d402e5", + "sha256:4a45a9698b3bcae05f91356f50df8dab3c3fdef3187548b9c4a396a6eb6760b5", + "sha256:4b84c1ca283278e2e22a3b9e2ce8ea55c0a1797d6e86255640a1b6293fe18b2a", + "sha256:4dc88397ed7f3b46f542f87e19050a7f82267225009ce65651ac44cb55b204b1", + "sha256:4e10a872077373c71d7938fb1a7ae0561f2e79aad2b1b5323dbb6325a389041a", + "sha256:4f1b5dcb4d9da5b441e0b14216b816be7b5b5d080c2ccb957adf84266411ff6b", + "sha256:50d25182d598312197f500a65acebf5430391764e6ffcdb73d96e80c5dd06fc7", + "sha256:529c5b9e27fced27befce26e2699eca3110c576f6427dfbd26e30b7666b2d6d1", + "sha256:571da625b22e953731307539b44b2177f6ab13b6142d7698c0f28b9379ae1be6", + "sha256:5a9de89e2480b385a99613798d375e69a0a53d4575bd74b133307c8e83a84751", + "sha256:5bcc46cf89cb1036c2d029c01f360c82180329997a75728b20dc205f34114327", + "sha256:5dfa6238a6236f2bb3ecaac9befd23cee0bcbb9e497003fb3aef875e19325c61", + "sha256:6342b961b18037e3df8692e8914c576816a966bf29f913ee2728e7e838bde9bd", + "sha256:65e112c175a0b0328822dd0d19ead9ef1d7925359d154fb52e46b080945eef38", + "sha256:6f8a2b15c4dd58133e92f95d4312efd09b87ec15b881885629dff70e89f1e751", + "sha256:726f749444d1cc73c1bf221343dc6fdbde2541ffe30860d2d5ef6e310a1f5478", + "sha256:742f39cd807df31c21e035aec63f6f61e139a60545cffb16e8e87f61609d7cba", + "sha256:7840c18ec27aa08ecdd8ff23df348c124378c6f3edf9a0e02b16a5a4ce504c89", + "sha256:79d1de24d3c7345719af8333b64f19a8777dd50a059851bfcfa583c7109eddf2", + "sha256:7ba9303c5334d64b547483be92c4bbacd37964ff3abd0b1e8c82c63ec6f7b3ec", + "sha256:85587d9dfbd2f7f8622cf57f3c1a19cee441b5607a982cdf4c08ef38d45d5a36", + "sha256:8711b86e447e689d1b693419708b6ad64bf0c57091b94a3f65c6d4bd7cfb7d9a", + "sha256:877edc4db25309d86af07d992926394936f491cce84fce439961729552e942fe", + "sha256:8bb17669e362d3456bebd5c69abb0c26e8ab29c10894f123c715b0217aece479", + "sha256:8bb17a1e50e35a8d07cab784caea68b33f739391ccb5e3161afb9db0bde8faf4", + "sha256:8d4640a6bb3aa29797bdcf0c5bae4e86da5f2fbf84b67a7fad549fa34c19aa98", + "sha256:90697f3d9e4b3ddccfb31b40637bac6d44b39288cd57f78e51ff13e70916eccc", + "sha256:90f127f57c00b111ea3ffd95f4c12ad83efebd10310fd718d66771dd64e568f1", + "sha256:95f8f70bca1e880da7559ef38b7f1778a3b39b586fc829b8a7e989e912aa988f", + "sha256:9a60c102a01dfa8c5d737499c9a5d5e7c2b6642009c9b80b27f228ec50ce6fb0", + "sha256:9c7f1821ec749ea29bd9d079e4f13a552371731d0b664962a60cbb2f31d571b5", + "sha256:9f81ee66fadedbfd4d5c49e64151db3b6f353b041ddf5ab0b151340a4467e038", + "sha256:9f8e530e29e1afe9231b1100645aa5cc240b823c0e4162f70046270a3559400c", + "sha256:a0c647db3f156e8c94a63c1fa0fc4f2ce8b70f0eb12f2726e6c19493198b1e99", + "sha256:a0cda60607ab4ffc14fa8425ea7c9ae78ad60923c3c8be94d19c14f83198b1cf", + "sha256:a5bff397d49da302b5afbdf244dd7ca480a827f5de856d957df05dfd7e73b490", + "sha256:a94bd391b955b24948b2986845f9c6ad8abc709c2d57d0515daeacf16a2a3a4c", + "sha256:ad4572bd37c1a6a7a12ff47da4f3578a13e3c8ee85a1f02d2435dfdc6d9ed394", + "sha256:b13b7de1686f1b5da7526dc4f0de410a685f5cb654e984b09ddd8d14be6fffc0", + "sha256:b1724c43c5c0d08b68c3407467e07794b9adf153b6de8300d61883e8d95fa640", + "sha256:b27d29cb718df9ed006f8c75a89dd90534437761b2477dc7a4145bde0daa60fc", + "sha256:b3afa3a78b0f011ff5a09dea37d74fcea9269b318d2828f18b2fbf9dde625a71", + "sha256:bd6a61007e678284178bb00931af59f686a2a55797505e0886241050ec5c243c", + "sha256:befeca45fd7787c08a3286fb72caaccfa4c3962760981dfeb0992f5ba9be5cb2", + "sha256:c2d31b8233f406e00f180e221986f436765c3bb06839e72c898feca31fef1d4e", + "sha256:c3e2518ce442b70314892a594e21157deb13fbc436f77ad6555439cfd9912035", + "sha256:c8d5fbee607db24ef6c7b0bd08c21226d10782df4149b9d6f1f1516c7c85092b", + "sha256:cc2cc804998e852bdffcc87e8d008043ffa85efe6d3516d9784714d709f14774", + "sha256:cd8a681107c6118f60a0714671cec7b301533f25984a5c898e547a33a01af75c", + "sha256:d056831ebf3fa8116672ae970ad19a9f5f1427a2217cd0e01c1eaac5f8222668", + "sha256:d5ac3e8e3f66ff88819205dbc67e6f771cbb80529325ca9f3bc03fa00c5c83aa", + "sha256:dba15ca2da7859300ae79d2ea2eb8bb0eb827b93a2f104981783add16a97058a", + "sha256:de6cabb89248b60ea9bb9d7848de78dfb824abfdc15f52448a8efe821dd7d559", + "sha256:e02f6d1cc2005b847176dd8770fdfe90f04a34a3f094b79a8369bde0aa8f6a04", + "sha256:e514bd4b27c953c46485b2be0ecd2421aa196c5a0cd7d67f1ccec16a56b00507", + "sha256:e53464124379764f982a69f5ab34d0d5c527e8ac1e788db86a25f79045e5b18d", + "sha256:e9cf59660a543bef86de457c671c1d78ad2d88c53bb9eb3fce6ce0cb9729d490", + "sha256:edfc1bc732bc5e62fdaea268a541eb442d5e04927cb27dfd8e92ef07213658d2", + "sha256:ee8e7a66be70a18f5e0558f2f6a89e39c608f87b027234848f76a6699975dcf8", + "sha256:effb7072efef7dca10a98c24be0cc882a40edc78e293b41f5b6dc7f1952215ed", + "sha256:f04e4ee7e3c123ac7f21cee6f819cfa9b5a376e656257dfa7a4d133b3590bdd9", + "sha256:f0531c7abe963affebd3fb6cf9ea87eb8c63a0240535d81d0223945bd41be254", + "sha256:f5afd1c216315682a6bbf606618de0e3817ed8eeafc27ad7660ef2f581d4fd46", + "sha256:f93d3c74e00268ac6042c080653a34d0f0e8903697fd8dc480c1e3de81c90faf", + "sha256:fbc4e6452cc48c3e1398fe930349e2ec9ad76a2c00e729f3e797700c2f0646e6", + "sha256:fc73fc2889a01a43737c7a7c7fb9ee13aa56065b22abbed0e787cc58a3747808" + ], + "markers": "python_version >= '3.7'", + "version": "==1.4.2" + }, + "referencing": { + "hashes": [ + "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", + "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0" + ], + "markers": "python_version >= '3.9'", + "version": "==0.36.2" + }, + "requests": { + "hashes": [ + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" + ], + "markers": "python_version >= '3.8'", + "version": "==2.32.3" + }, + "rpds-py": { + "hashes": [ + "sha256:0047638c3aa0dbcd0ab99ed1e549bbf0e142c9ecc173b6492868432d8989a046", + "sha256:006f4342fe729a368c6df36578d7a348c7c716be1da0a1a0f86e3021f8e98724", + "sha256:041f00419e1da7a03c46042453598479f45be3d787eb837af382bfc169c0db33", + "sha256:04ecf5c1ff4d589987b4d9882872f80ba13da7d42427234fce8f22efb43133bc", + "sha256:04f2b712a2206e13800a8136b07aaedc23af3facab84918e7aa89e4be0260032", + "sha256:0aeb3329c1721c43c58cae274d7d2ca85c1690d89485d9c63a006cb79a85771a", + "sha256:0e374c0ce0ca82e5b67cd61fb964077d40ec177dd2c4eda67dba130de09085c7", + "sha256:0f00c16e089282ad68a3820fd0c831c35d3194b7cdc31d6e469511d9bffc535c", + "sha256:174e46569968ddbbeb8a806d9922f17cd2b524aa753b468f35b97ff9c19cb718", + "sha256:1b221c2457d92a1fb3c97bee9095c874144d196f47c038462ae6e4a14436f7bc", + "sha256:208b3a70a98cf3710e97cabdc308a51cd4f28aa6e7bb11de3d56cd8b74bab98d", + "sha256:20f2712bd1cc26a3cc16c5a1bfee9ed1abc33d4cdf1aabd297fe0eb724df4272", + "sha256:24795c099453e3721fda5d8ddd45f5dfcc8e5a547ce7b8e9da06fecc3832e26f", + "sha256:2a0f156e9509cee987283abd2296ec816225145a13ed0391df8f71bf1d789e2d", + "sha256:2b2356688e5d958c4d5cb964af865bea84db29971d3e563fb78e46e20fe1848b", + "sha256:2c13777ecdbbba2077670285dd1fe50828c8742f6a4119dbef6f83ea13ad10fb", + "sha256:2d3ee4615df36ab8eb16c2507b11e764dcc11fd350bbf4da16d09cda11fcedef", + "sha256:2d53747da70a4e4b17f559569d5f9506420966083a31c5fbd84e764461c4444b", + "sha256:32bab0a56eac685828e00cc2f5d1200c548f8bc11f2e44abf311d6b548ce2e45", + "sha256:34d90ad8c045df9a4259c47d2e16a3f21fdb396665c94520dbfe8766e62187a4", + "sha256:369d9c6d4c714e36d4a03957b4783217a3ccd1e222cdd67d464a3a479fc17796", + "sha256:3a55fc10fdcbf1a4bd3c018eea422c52cf08700cf99c28b5cb10fe97ab77a0d3", + "sha256:3d2d8e4508e15fc05b31285c4b00ddf2e0eb94259c2dc896771966a163122a0c", + "sha256:3fab5f4a2c64a8fb64fc13b3d139848817a64d467dd6ed60dcdd6b479e7febc9", + "sha256:43dba99f00f1d37b2a0265a259592d05fcc8e7c19d140fe51c6e6f16faabeb1f", + "sha256:44d51febb7a114293ffd56c6cf4736cb31cd68c0fddd6aa303ed09ea5a48e029", + "sha256:493fe54318bed7d124ce272fc36adbf59d46729659b2c792e87c3b95649cdee9", + "sha256:4b28e5122829181de1898c2c97f81c0b3246d49f585f22743a1246420bb8d399", + "sha256:4cd031e63bc5f05bdcda120646a0d32f6d729486d0067f09d79c8db5368f4586", + "sha256:528927e63a70b4d5f3f5ccc1fa988a35456eb5d15f804d276709c33fc2f19bda", + "sha256:564c96b6076a98215af52f55efa90d8419cc2ef45d99e314fddefe816bc24f91", + "sha256:5db385bacd0c43f24be92b60c857cf760b7f10d8234f4bd4be67b5b20a7c0b6b", + "sha256:5ef877fa3bbfb40b388a5ae1cb00636a624690dcb9a29a65267054c9ea86d88a", + "sha256:5f6e3cec44ba05ee5cbdebe92d052f69b63ae792e7d05f1020ac5e964394080c", + "sha256:5fc13b44de6419d1e7a7e592a4885b323fbc2f46e1f22151e3a8ed3b8b920405", + "sha256:60748789e028d2a46fc1c70750454f83c6bdd0d05db50f5ae83e2db500b34da5", + "sha256:60d9b630c8025b9458a9d114e3af579a2c54bd32df601c4581bd054e85258143", + "sha256:619ca56a5468f933d940e1bf431c6f4e13bef8e688698b067ae68eb4f9b30e3a", + "sha256:630d3d8ea77eabd6cbcd2ea712e1c5cecb5b558d39547ac988351195db433f6c", + "sha256:63981feca3f110ed132fd217bf7768ee8ed738a55549883628ee3da75bb9cb78", + "sha256:66420986c9afff67ef0c5d1e4cdc2d0e5262f53ad11e4f90e5e22448df485bf0", + "sha256:675269d407a257b8c00a6b58205b72eec8231656506c56fd429d924ca00bb350", + "sha256:6a4a535013aeeef13c5532f802708cecae8d66c282babb5cd916379b72110cf7", + "sha256:6a727fd083009bc83eb83d6950f0c32b3c94c8b80a9b667c87f4bd1274ca30ba", + "sha256:6e1daf5bf6c2be39654beae83ee6b9a12347cb5aced9a29eecf12a2d25fff664", + "sha256:6eea559077d29486c68218178ea946263b87f1c41ae7f996b1f30a983c476a5a", + "sha256:75a810b7664c17f24bf2ffd7f92416c00ec84b49bb68e6a0d93e542406336b56", + "sha256:772cc1b2cd963e7e17e6cc55fe0371fb9c704d63e44cacec7b9b7f523b78919e", + "sha256:78884d155fd15d9f64f5d6124b486f3d3f7fd7cd71a78e9670a0f6f6ca06fb2d", + "sha256:79e8d804c2ccd618417e96720ad5cd076a86fa3f8cb310ea386a3e6229bae7d1", + "sha256:7e80d375134ddb04231a53800503752093dbb65dad8dabacce2c84cccc78e964", + "sha256:8097b3422d020ff1c44effc40ae58e67d93e60d540a65649d2cdaf9466030791", + "sha256:8205ee14463248d3349131bb8099efe15cd3ce83b8ef3ace63c7e976998e7124", + "sha256:8212ff58ac6dfde49946bea57474a386cca3f7706fc72c25b772b9ca4af6b79e", + "sha256:823e74ab6fbaa028ec89615ff6acb409e90ff45580c45920d4dfdddb069f2120", + "sha256:84e0566f15cf4d769dade9b366b7b87c959be472c92dffb70462dd0844d7cbad", + "sha256:896c41007931217a343eff197c34513c154267636c8056fb409eafd494c3dcdc", + "sha256:8aa362811ccdc1f8dadcc916c6d47e554169ab79559319ae9fae7d7752d0d60c", + "sha256:8b3b397eefecec8e8e39fa65c630ef70a24b09141a6f9fc17b3c3a50bed6b50e", + "sha256:8ebc7e65ca4b111d928b669713865f021b7773350eeac4a31d3e70144297baba", + "sha256:9168764133fd919f8dcca2ead66de0105f4ef5659cbb4fa044f7014bed9a1797", + "sha256:921ae54f9ecba3b6325df425cf72c074cd469dea843fb5743a26ca7fb2ccb149", + "sha256:92558d37d872e808944c3c96d0423b8604879a3d1c86fdad508d7ed91ea547d5", + "sha256:951cc481c0c395c4a08639a469d53b7d4afa252529a085418b82a6b43c45c240", + "sha256:998c01b8e71cf051c28f5d6f1187abbdf5cf45fc0efce5da6c06447cba997034", + "sha256:9abc80fe8c1f87218db116016de575a7998ab1629078c90840e8d11ab423ee25", + "sha256:9be4f99bee42ac107870c61dfdb294d912bf81c3c6d45538aad7aecab468b6b7", + "sha256:9c39438c55983d48f4bb3487734d040e22dad200dab22c41e331cee145e7a50d", + "sha256:9d7e8ce990ae17dda686f7e82fd41a055c668e13ddcf058e7fb5e9da20b57793", + "sha256:9ea7f4174d2e4194289cb0c4e172d83e79a6404297ff95f2875cf9ac9bced8ba", + "sha256:a18fc371e900a21d7392517c6f60fe859e802547309e94313cd8181ad9db004d", + "sha256:a36b452abbf29f68527cf52e181fced56685731c86b52e852053e38d8b60bc8d", + "sha256:a5b66d1b201cc71bc3081bc2f1fc36b0c1f268b773e03bbc39066651b9e18391", + "sha256:a824d2c7a703ba6daaca848f9c3d5cb93af0505be505de70e7e66829affd676e", + "sha256:a88c0d17d039333a41d9bf4616bd062f0bd7aa0edeb6cafe00a2fc2a804e944f", + "sha256:aa6800adc8204ce898c8a424303969b7aa6a5e4ad2789c13f8648739830323b7", + "sha256:aad911555286884be1e427ef0dc0ba3929e6821cbeca2194b13dc415a462c7fd", + "sha256:afc6e35f344490faa8276b5f2f7cbf71f88bc2cda4328e00553bd451728c571f", + "sha256:b9a4df06c35465ef4d81799999bba810c68d29972bf1c31db61bfdb81dd9d5bb", + "sha256:bb2954155bb8f63bb19d56d80e5e5320b61d71084617ed89efedb861a684baea", + "sha256:bbc4362e06f950c62cad3d4abf1191021b2ffaf0b31ac230fbf0526453eee75e", + "sha256:c0145295ca415668420ad142ee42189f78d27af806fcf1f32a18e51d47dd2052", + "sha256:c30ff468163a48535ee7e9bf21bd14c7a81147c0e58a36c1078289a8ca7af0bd", + "sha256:c347a20d79cedc0a7bd51c4d4b7dbc613ca4e65a756b5c3e57ec84bd43505b47", + "sha256:c43583ea8517ed2e780a345dd9960896afc1327e8cf3ac8239c167530397440d", + "sha256:c61a2cb0085c8783906b2f8b1f16a7e65777823c7f4d0a6aaffe26dc0d358dd9", + "sha256:c9ca89938dff18828a328af41ffdf3902405a19f4131c88e22e776a8e228c5a8", + "sha256:cc31e13ce212e14a539d430428cd365e74f8b2d534f8bc22dd4c9c55b277b875", + "sha256:cdabcd3beb2a6dca7027007473d8ef1c3b053347c76f685f5f060a00327b8b65", + "sha256:cf86f72d705fc2ef776bb7dd9e5fbba79d7e1f3e258bf9377f8204ad0fc1c51e", + "sha256:d09dc82af2d3c17e7dd17120b202a79b578d79f2b5424bda209d9966efeed114", + "sha256:d3aa13bdf38630da298f2e0d77aca967b200b8cc1473ea05248f6c5e9c9bdb44", + "sha256:d69d003296df4840bd445a5d15fa5b6ff6ac40496f956a221c4d1f6f7b4bc4d9", + "sha256:d6e109a454412ab82979c5b1b3aee0604eca4bbf9a02693bb9df027af2bfa91a", + "sha256:d8551e733626afec514b5d15befabea0dd70a343a9f23322860c4f16a9430205", + "sha256:d8754d872a5dfc3c5bf9c0e059e8107451364a30d9fd50f1f1a85c4fb9481164", + "sha256:d8f9a6e7fd5434817526815f09ea27f2746c4a51ee11bb3439065f5fc754db58", + "sha256:dbcbb6db5582ea33ce46a5d20a5793134b5365110d84df4e30b9d37c6fd40ad3", + "sha256:e0f3ef95795efcd3b2ec3fe0a5bcfb5dadf5e3996ea2117427e524d4fbf309c6", + "sha256:e13ae74a8a3a0c2f22f450f773e35f893484fcfacb00bb4344a7e0f4f48e1f97", + "sha256:e274f62cbd274359eff63e5c7e7274c913e8e09620f6a57aae66744b3df046d6", + "sha256:e838bf2bb0b91ee67bf2b889a1a841e5ecac06dd7a2b1ef4e6151e2ce155c7ae", + "sha256:e8acd55bd5b071156bae57b555f5d33697998752673b9de554dd82f5b5352727", + "sha256:e8e5ab32cf9eb3647450bc74eb201b27c185d3857276162c101c0f8c6374e098", + "sha256:ebcb786b9ff30b994d5969213a8430cbb984cdd7ea9fd6df06663194bd3c450c", + "sha256:ebea2821cdb5f9fef44933617be76185b80150632736f3d76e54829ab4a3b4d1", + "sha256:ed0ef550042a8dbcd657dfb284a8ee00f0ba269d3f2286b0493b15a5694f9fe8", + "sha256:eda5c1e2a715a4cbbca2d6d304988460942551e4e5e3b7457b50943cd741626d", + "sha256:f5c0ed12926dec1dfe7d645333ea59cf93f4d07750986a586f511c0bc61fe103", + "sha256:f6016bd950be4dcd047b7475fdf55fb1e1f59fc7403f387be0e8123e4a576d30", + "sha256:f9e0057a509e096e47c87f753136c9b10d7a91842d8042c2ee6866899a717c0d", + "sha256:fc1c892b1ec1f8cbd5da8de287577b455e388d9c328ad592eabbdcb6fc93bee5", + "sha256:fc2c1e1b00f88317d9de6b2c2b39b012ebbfe35fe5e7bef980fd2a91f6100a07", + "sha256:fd822f019ccccd75c832deb7aa040bb02d70a92eb15a2f16c7987b7ad4ee8d83" + ], + "markers": "python_version >= '3.9'", + "version": "==0.24.0" + }, + "six": { + "hashes": [ + "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", + "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==1.17.0" + }, + "tinydb": { + "hashes": [ + "sha256:f7dfc39b8d7fda7a1ca62a8dbb449ffd340a117c1206b68c50b1a481fb95181d", + "sha256:f97030ee5cbc91eeadd1d7af07ab0e48ceb04aa63d4a983adbaca4cba16e86c3" + ], + "markers": "python_version >= '3.8' and python_version < '4.0'", + "version": "==4.8.2" + }, + "tuspy": { + "hashes": [ + "sha256:156734eac5c61a046cfecd70f14119f05be92cce198eb5a1a99a664482bedb89", + "sha256:7fc5ac8fb25de37c96c90213f83a1ffdede7f48a471cb5a15a2f57846828a79a" + ], + "markers": "python_full_version >= '3.5.3'", + "version": "==1.1.0" + }, + "typing-extensions": { + "hashes": [ + "sha256:0a4ac55a5820789d87e297727d229866c9650f6521b64206413c4fbada24d95b", + "sha256:c8dd92cc0d6425a97c18fbb9d1954e5ff92c1ca881a309c45f06ebc0b79058e5" + ], + "markers": "python_version >= '3.8'", + "version": "==4.13.0" + }, + "typing-inspection": { + "hashes": [ + "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f", + "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122" + ], + "markers": "python_version >= '3.9'", + "version": "==0.4.0" + }, + "tzdata": { + "hashes": [ + "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", + "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9" + ], + "markers": "python_version >= '2'", + "version": "==2025.2" + }, + "urllib3": { + "hashes": [ + "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", + "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d" + ], + "markers": "python_version >= '3.9'", + "version": "==2.3.0" + }, + "urllib3-future": { + "hashes": [ + "sha256:3adfa22c5718caee5ca69bc7f7461dc529f4396494d4d9b1db8af7c56cd3ac34", + "sha256:9cd79ce61da77b5d56681bc126f42955c2153e9c0da2f0a62bca8e0a05641f92" + ], + "markers": "python_version >= '3.7'", + "version": "==2.12.915" + }, + "verlib2": { + "hashes": [ + "sha256:2862f19528db400d130253a2b71c7c3616ee14e1d54bf6833bc0929d2cddd141", + "sha256:cf8e2be044b834a2670f2d4c20a93cfc674933c0070543a6f61d531439cca200" + ], + "markers": "python_version >= '3.6'", + "version": "==0.3.1" + }, + "wassima": { + "hashes": [ + "sha256:10508102696d5e2cf4df6942a8ae251c136a49dc32591e9c3f7dd007f5ea1c2f", + "sha256:1102836ba373912537eba891e7e5893532d4ee915ee2486e981b73f925f63c37", + "sha256:11887557464e0c3f9694fb16406bb56c1fb1566178cd04bfb5b4624fad183b31", + "sha256:12c855cc5b96a2ac32d405ab7de1563fc91be54108b4fb16b06d125d07ea892b", + "sha256:134e863b692c35afe8f5ccbe8082fa39963804e20439a4c7aa98510197034704", + "sha256:17f129f4d36591772d906bcc893b76b236363fda61b575067ddfa8250f84ad30", + "sha256:17f132ffbab294902f8740708f27fd995ea04182fe4b4fde20be563f8a010715", + "sha256:18bc78b2230c6f1f9ddbeb6ca38439fea4cc8f60836af4f3538ed259e60e5eb8", + "sha256:194c3fad38603618dec03307d10a4ece852516df56560e04fb2562506f79c175", + "sha256:1b18ec743ab98dcbfc221749026b23fc573891651342f20971e53bdbf56d28ae", + "sha256:1fa19a3652509edd18f693cd9c873d8f73c9d1624eae6c3bf93e561b18ae2766", + "sha256:24bdb1a2b90c215e11ed7ce82ed7eada339c7dca8e0366916e4e3215b3b9d8d3", + "sha256:27d518f0863788c826faf387326f3babb3ea95a0b908f5b3ad2bc1fcc3c5a37d", + "sha256:350b5854dfb3eeb95cd17723b0f3503de0c01454da5ae7d60f192be2009239eb", + "sha256:3b3a4c8ffa76147507f0c88c5cc8c76ef96ab93b81e49b288a3a0b94ebfb34af", + "sha256:3e00fa8ff1aef7d8aad2e1b957add6cba8549a42e415400bd72ff1b61dc9da9d", + "sha256:3f29045dd0a7c287f850f1dc3948632a2d2cf7dd7ec02271c5f248f058da5650", + "sha256:4a528244e4a0f9e01b8593b1c8a60ac1d80ce8b13fe079f44b38328e4be075e3", + "sha256:4c4f5ca102fd083aa2b05c65a1fd18175e3dc7a889525fd2964219ee3c51edef", + "sha256:52358d86195954816231d2aa8c2919b85075320b6d3ba5b96216985c3182bfa0", + "sha256:52f473233ec4d57322c6295e85b3912dc1fc400d6308a04bd427b863934aa74e", + "sha256:556cded582aef3089de889b5a6efcf6d87fabfec55d574fcc3a4ada21308d487", + "sha256:564eda7bf0420c8cbebe5e8efc15f1b27fdcb37ebc4c2f92b8461ca83381b223", + "sha256:57a0ab5aed596f129fd4ea7584336b11fbef25c07d1351e37a959901dea8728e", + "sha256:58f1fddd660da8c8f30f4b8460129e2f217c226cd1b54b1cabb6465881fd788a", + "sha256:597b0d8ba697f4319bc1f301ed31630ca783c9fe82d2a2434dd2f7f709c4e394", + "sha256:5b194f0de77a4ae7bcf217a3ccd10798e94ca430cec6307628098a61cd2ac230", + "sha256:5f5ee564f4b836ed1b70ddb187c817e8f6f1ffb521a636bb20676f07b523396b", + "sha256:601f96340e4c8071994a39a76d4278e8e1d087cf385781dba795c5334262d865", + "sha256:61bfa09f38c36f1b1e6e44e7af888bb8f9d739e86099082a3b45875651a425e2", + "sha256:67fd323b8ad0e057c06b153983d8c50f812aad979ac89b07ed6952c345f6da02", + "sha256:69cb51f629d118256da3d2373575190c7e30d3fa67c344dc655f6c8ab3e83f0d", + "sha256:6b1d7ceeede8d8eed48616d2d33ed23d2dff307d0b17c577eafdadafe86a0478", + "sha256:6b7d696155ddd7ab5739ac221e8854115d0d8171bbf805074d9484083de386aa", + "sha256:6d23e9483756b81850b82e8b7ed20fd23de22b50d6a678f765c660d4206b7ce9", + "sha256:7b0229fecc849234f2a2d11e948ac38a9bab02d201fa4d6ad43c143e18c1a66e", + "sha256:7c53050b670d702eed541503175bd5441fc4bdf3898714f8eac8c6ae9db548ac", + "sha256:7d65676f1fc138d1742f704bf490045571b9c2c48cab7d2c2076a52729c143e5", + "sha256:7db25328c40cd574e5a68ef6507c5af4d1fa2a44cb3c028ff9ca6b522f8faf32", + "sha256:83ce1b09e9eb2ae033c303b74ecc4f3186bbc0897db1d8cd9942153b0631b8e0", + "sha256:86c509900cbb90b7b75155c580b22af591b696fa059059bcdbd75bc74179df85", + "sha256:87f80d0075f0d396b73d41bb1626a2dd5607e0db4b74cb17e55d874fcd538971", + "sha256:8b719755d556649f2fbf226cf1ca8581ade114751df1facec96f94e75bffdb3c", + "sha256:8e739d4192758df6e5363791f527deb91c615d63020ee8965df4bcd1a217f9a5", + "sha256:923d3bf8770dfeb3d94bdfee1c5b5a081592de69766436a395e1e6203c19cf71", + "sha256:97772bb55cb47da3de49ca4b59309a9bd91ead730a7cfac1992932486fb41352", + "sha256:98bdfdf734144277132f34f770eeb6b0db2c4de87415f34b178adee766632f24", + "sha256:98f38b1b01e6f270b9279d76261d6f222b72ef06b025cbd4911b962bb6de4c98", + "sha256:99318b5ea78843e3c3e19cd56367216774674a99848f00a6f2dcf84e36039641", + "sha256:9c623ef06876d432dc8acc93ed3494d3453333d767b1b06bba1a016ea9d850c9", + "sha256:9d0f9720dfd0155432d23bcc3605fe5831cd0f586ede4f14ff6f3bebe8fb867a", + "sha256:9e79216760faac6395bee8ca4077a53a309312faba0f71982127ad8625861780", + "sha256:a470c908fd9baaecf41715ea3c30c57b530d598ae5e9de7e0bd532755e66bb1b", + "sha256:a634b9b79e059f45a56ff3ef6e7241662bc6f0e5a096ee6eed6770ea368e8278", + "sha256:acd8195a53d0e84ea95bdf15a2651c53b829a3ddead21b4a620b6a0c5e1ae2ff", + "sha256:addbd207df3718fc9d9de5b6c90a5e3fbe667830cf629186c9fdcafbb6578cb4", + "sha256:ae2aec9d55e108ae2d22fd0bda24450a6c13c116f9698b9e7ba2c6492c4fe715", + "sha256:af6b70ca9788964c5da5b59ca412b62db2ea7f2386a91c0117667bdd963e828c", + "sha256:afa7d60a9203db36a55b6f2868da90aaa829ab415a21fba7fa75678789aeb16f", + "sha256:b08c1931c44e3c034e645f3e3a7f4c47e8b0758fb8f09a52d1e880a307a1066f", + "sha256:b22e356914e606ff398c002b9925df4454c5deca9dbe55b3ba4a5c9b2365cf0f", + "sha256:b8c0f50397c51086df941b48057c82f85d9da000bf4fe6f4bc64c4f649b26a5b", + "sha256:bc068bcd79fe017866f536e0ad9424793220be34e3124476e17e6cb77a97e690", + "sha256:bc30f5a605a366acb7f301b3421508eaec3c1a515c960791bd776cb63d016302", + "sha256:c0d246b3f8a771578279eab9cfcb820dedefd3dd5dc0e34b37a337fe46271fc0", + "sha256:c0fee0a8593028bde17b57527b1ac21fea74f209b3522363e3ba0197ffaa6323", + "sha256:c139d5b103bb1f085d8918815d62ad946224a658ac1a7cc1b93dc44bd498ff9a", + "sha256:c25235cec12c0e38b4104268e312c9c2f3527ebc126d296cff69ea7aa13434dc", + "sha256:c7429d038dc383966c692e752010cbb4d5dab0e515f231aa01cd746aed9db359", + "sha256:c85cd2e64967c0dce2927ad7c62c090aae6d6b7f9e3a6b9fb91f58b890ea6adc", + "sha256:ca04984df012020dd846599b8555666c544982c2a91dc6135565e6708624eb71", + "sha256:cb7d43c07d58ba13736e70dc3e064496efeb1ed4475a28afb26b7a3b030b89df", + "sha256:d018e05cb61eed3050d45bd0c0ef9b75420899f6ae254e68e7f2ef26975098c9", + "sha256:d24d42881eb74729b34014e2e87f3a4d0419c43db309de2dff3f39118716865f", + "sha256:d6e17f218af856ca22c30d1a1ac58b19bccf768b8589eb8d6e45e1f1ff258404", + "sha256:d855d0be1759c5efc404c04977ee48a8b6260aef6441e72c10973924dbde5a73", + "sha256:dea0dcc0e50978ef73be8cb384694b71a6e64b46847ee7decad96dc85fbf650c", + "sha256:e1e9228049cf2442ac486a03a0d543c5dff3089a915a3e39ab809b22672e1d76", + "sha256:e26d052a248d5be2257d848d6078d932cc1fd4e8226639f550344d0a7a2b8813", + "sha256:ee6ccb8197936a308a4034c90a42b30b37c46b7cbda66101d439d6983f59b368", + "sha256:eea9c37b45e73cebb4670afd1779db138eeff0f84ffc0871d2fb90c04c8d3aa8", + "sha256:f195bf641276261e6bc5f79f52601850c9bdbff8af401483b4805dbff535ed30", + "sha256:f264827618400ebeab16708c8acf7870f693b03bfb4d7e95253eb9b35074db5c", + "sha256:f44ccd2eaa433ff1a10f70242dc33315fc192b81664696154127bdd66ad7d3b2", + "sha256:f7a6068d8857c403e105e62132a00e9d9d401bd0efbff7f8b5b5bc8ab768a2d8", + "sha256:f9886176fe4bf1ac008c02adb5bd103f1191799f1897777d203ee44f615325a5", + "sha256:fa1f38d5583d283b40f998e2f13471bfa952e0c423ff95ec2ec329f3e1898107", + "sha256:fa65494e7bd0e3ba33b3e5a5ab30c2b6e95d3d1762baaa56151a0861618dc261", + "sha256:fd7186e23963714bab3c9a2ab75d002078335110d2c9fc883c65cbce43717f26", + "sha256:fec32c22b521fcdeb9aa7dee4373b2d81ca2d3fc8edc532f3e189d6f4f6f1f81" + ], + "markers": "python_version >= '3.7'", + "version": "==1.2.2" + }, + "werkzeug": { + "hashes": [ + "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", + "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746" + ], + "markers": "python_version >= '3.9'", + "version": "==3.1.3" + }, + "yarl": { + "hashes": [ + "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba", + "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193", + "sha256:045b8482ce9483ada4f3f23b3774f4e1bf4f23a2d5c912ed5170f68efb053318", + "sha256:09c7907c8548bcd6ab860e5f513e727c53b4a714f459b084f6580b49fa1b9cee", + "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e", + "sha256:0b3c92fa08759dbf12b3a59579a4096ba9af8dd344d9a813fc7f5070d86bbab1", + "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a", + "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186", + "sha256:1d407181cfa6e70077df3377938c08012d18893f9f20e92f7d2f314a437c30b1", + "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50", + "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640", + "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb", + "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8", + "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc", + "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5", + "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58", + "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2", + "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393", + "sha256:4ac515b860c36becb81bb84b667466885096b5fc85596948548b667da3bf9f24", + "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b", + "sha256:54d6921f07555713b9300bee9c50fb46e57e2e639027089b1d795ecd9f7fa910", + "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c", + "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272", + "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed", + "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1", + "sha256:61e5e68cb65ac8f547f6b5ef933f510134a6bf31bb178be428994b0cb46c2a04", + "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d", + "sha256:6333c5a377c8e2f5fae35e7b8f145c617b02c939d04110c76f29ee3676b5f9a5", + "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d", + "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889", + "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae", + "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b", + "sha256:77a6e85b90a7641d2e07184df5557132a337f136250caafc9ccaa4a2a998ca2c", + "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576", + "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34", + "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477", + "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990", + "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2", + "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512", + "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069", + "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a", + "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6", + "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0", + "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8", + "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb", + "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa", + "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8", + "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e", + "sha256:a440a2a624683108a1b454705ecd7afc1c3438a08e890a1513d468671d90a04e", + "sha256:a4bb030cf46a434ec0225bddbebd4b89e6471814ca851abb8696170adb163985", + "sha256:a9ca04806f3be0ac6d558fffc2fdf8fcef767e0489d2684a21912cc4ed0cd1b8", + "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1", + "sha256:ac36703a585e0929b032fbaab0707b75dc12703766d0b53486eabd5139ebadd5", + "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690", + "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10", + "sha256:b4f6450109834af88cb4cc5ecddfc5380ebb9c228695afc11915a0bf82116789", + "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b", + "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca", + "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e", + "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5", + "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59", + "sha256:ba87babd629f8af77f557b61e49e7c7cac36f22f871156b91e10a6e9d4f829e9", + "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8", + "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db", + "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde", + "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7", + "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb", + "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3", + "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6", + "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285", + "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb", + "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8", + "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482", + "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd", + "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75", + "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760", + "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782", + "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53", + "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2", + "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1", + "sha256:fe57328fbc1bfd0bd0514470ac692630f3901c0ee39052ae47acd1d90a436719", + "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62" + ], + "markers": "python_version >= '3.9'", + "version": "==1.18.3" + } + }, + "develop": { + "certifi": { + "hashes": [ + "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", + "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe" + ], + "markers": "python_version >= '3.6'", + "version": "==2025.1.31" + }, + "charset-normalizer": { + "hashes": [ + "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537", + "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa", + "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a", + "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294", + "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b", + "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", + "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", + "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd", + "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4", + "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", + "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2", + "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", + "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd", + "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", + "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8", + "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1", + "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", + "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496", + "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d", + "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", + "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e", + "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a", + "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4", + "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca", + "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78", + "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408", + "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5", + "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", + "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", + "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a", + "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765", + "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6", + "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146", + "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6", + "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", + "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd", + "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c", + "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", + "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", + "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176", + "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770", + "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824", + "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f", + "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf", + "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487", + "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d", + "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd", + "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", + "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534", + "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f", + "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b", + "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", + "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd", + "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125", + "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9", + "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de", + "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", + "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d", + "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", + "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f", + "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", + "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7", + "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a", + "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", + "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8", + "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41", + "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", + "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f", + "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", + "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", + "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", + "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77", + "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76", + "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247", + "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", + "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb", + "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", + "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e", + "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6", + "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037", + "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", + "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e", + "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807", + "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", + "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c", + "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12", + "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3", + "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089", + "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", + "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e", + "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00", + "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616" + ], + "markers": "python_version >= '3.7'", + "version": "==3.4.1" + }, + "coverage": { + "hashes": [ + "sha256:042e7841a26498fff7a37d6fda770d17519982f5b7d8bf5278d140b67b61095f", + "sha256:04bfec25a8ef1c5f41f5e7e5c842f6b615599ca8ba8391ec33a9290d9d2db3a3", + "sha256:0915742f4c82208ebf47a2b154a5334155ed9ef9fe6190674b8a46c2fb89cb05", + "sha256:18c5ae6d061ad5b3e7eef4363fb27a0576012a7447af48be6c75b88494c6cf25", + "sha256:2931f66991175369859b5fd58529cd4b73582461877ecfd859b6549869287ffe", + "sha256:2e4b6b87bb0c846a9315e3ab4be2d52fac905100565f4b92f02c445c8799e257", + "sha256:3043ba1c88b2139126fc72cb48574b90e2e0546d4c78b5299317f61b7f718b78", + "sha256:379fe315e206b14e21db5240f89dc0774bdd3e25c3c58c2c733c99eca96f1ada", + "sha256:42421e04069fb2cbcbca5a696c4050b84a43b05392679d4068acbe65449b5c64", + "sha256:4dfd9a93db9e78666d178d4f08a5408aa3f2474ad4d0e0378ed5f2ef71640cb6", + "sha256:52a523153c568d2c0ef8826f6cc23031dc86cffb8c6aeab92c4ff776e7951b28", + "sha256:554fec1199d93ab30adaa751db68acec2b41c5602ac944bb19187cb9a41a8067", + "sha256:581a40c7b94921fffd6457ffe532259813fc68eb2bdda60fa8cc343414ce3733", + "sha256:5a26c0c795c3e0b63ec7da6efded5f0bc856d7c0b24b2ac84b4d1d7bc578d676", + "sha256:5a570cd9bd20b85d1a0d7b009aaf6c110b52b5755c17be6962f8ccd65d1dbd23", + "sha256:5aaeb00761f985007b38cf463b1d160a14a22c34eb3f6a39d9ad6fc27cb73008", + "sha256:5ac46d0c2dd5820ce93943a501ac5f6548ea81594777ca585bf002aa8854cacd", + "sha256:5c8a5c139aae4c35cbd7cadca1df02ea8cf28a911534fc1b0456acb0b14234f3", + "sha256:6b8af63b9afa1031c0ef05b217faa598f3069148eeee6bb24b79da9012423b82", + "sha256:769773614e676f9d8e8a0980dd7740f09a6ea386d0f383db6821df07d0f08545", + "sha256:771eb7587a0563ca5bb6f622b9ed7f9d07bd08900f7589b4febff05f469bea00", + "sha256:77af0f6447a582fdc7de5e06fa3757a3ef87769fbb0fdbdeba78c23049140a47", + "sha256:7a3d62b3b03b4b6fd41a085f3574874cf946cb4604d2b4d3e8dca8cd570ca501", + "sha256:821f7bcbaa84318287115d54becb1915eece6918136c6f91045bb84e2f88739d", + "sha256:89b1f4af0d4afe495cd4787a68e00f30f1d15939f550e869de90a86efa7e0814", + "sha256:8a1d96e780bdb2d0cbb297325711701f7c0b6f89199a57f2049e90064c29f6bd", + "sha256:8a40fcf208e021eb14b0fac6bdb045c0e0cab53105f93ba0d03fd934c956143a", + "sha256:8f99eb72bf27cbb167b636eb1726f590c00e1ad375002230607a844d9e9a2318", + "sha256:90e7fbc6216ecaffa5a880cdc9c77b7418c1dcb166166b78dbc630d07f278cc3", + "sha256:94ec0be97723ae72d63d3aa41961a0b9a6f5a53ff599813c324548d18e3b9e8c", + "sha256:95aa6ae391a22bbbce1b77ddac846c98c5473de0372ba5c463480043a07bff42", + "sha256:96121edfa4c2dfdda409877ea8608dd01de816a4dc4a0523356067b305e4e17a", + "sha256:a1f406a8e0995d654b2ad87c62caf6befa767885301f3b8f6f73e6f3c31ec3a6", + "sha256:a321c61477ff8ee705b8a5fed370b5710c56b3a52d17b983d9215861e37b642a", + "sha256:a5761c70c017c1b0d21b0815a920ffb94a670c8d5d409d9b38857874c21f70d7", + "sha256:a9abbccd778d98e9c7e85038e35e91e67f5b520776781d9a1e2ee9d400869487", + "sha256:ad80e6b4a0c3cb6f10f29ae4c60e991f424e6b14219d46f1e7d442b938ee68a4", + "sha256:b44674870709017e4b4036e3d0d6c17f06a0e6d4436422e0ad29b882c40697d2", + "sha256:b571bf5341ba8c6bc02e0baeaf3b061ab993bf372d982ae509807e7f112554e9", + "sha256:b8194fb8e50d556d5849753de991d390c5a1edeeba50f68e3a9253fbd8bf8ccd", + "sha256:b87eb6fc9e1bb8f98892a2458781348fa37e6925f35bb6ceb9d4afd54ba36c73", + "sha256:bbb5cc845a0292e0c520656d19d7ce40e18d0e19b22cb3e0409135a575bf79fc", + "sha256:be945402e03de47ba1872cd5236395e0f4ad635526185a930735f66710e1bd3f", + "sha256:bf13d564d310c156d1c8e53877baf2993fb3073b2fc9f69790ca6a732eb4bfea", + "sha256:cf60dd2696b457b710dd40bf17ad269d5f5457b96442f7f85722bdb16fa6c899", + "sha256:d1ba00ae33be84066cfbe7361d4e04dec78445b2b88bdb734d0d1cbab916025a", + "sha256:d39fc4817fd67b3915256af5dda75fd4ee10621a3d484524487e33416c6f3543", + "sha256:d766a4f0e5aa1ba056ec3496243150698dc0481902e2b8559314368717be82b1", + "sha256:dbf364b4c5e7bae9250528167dfe40219b62e2d573c854d74be213e1e52069f7", + "sha256:dd19608788b50eed889e13a5d71d832edc34fc9dfce606f66e8f9f917eef910d", + "sha256:e013b07ba1c748dacc2a80e69a46286ff145935f260eb8c72df7185bf048f502", + "sha256:e5d2b9be5b0693cf21eb4ce0ec8d211efb43966f6657807f6859aab3814f946b", + "sha256:e5ff52d790c7e1628241ffbcaeb33e07d14b007b6eb00a19320c7b8a7024c040", + "sha256:e75a2ad7b647fd8046d58c3132d7eaf31b12d8a53c0e4b21fa9c4d23d6ee6d3c", + "sha256:e7ac22a0bb2c7c49f441f7a6d46c9c80d96e56f5a8bc6972529ed43c8b694e27", + "sha256:ed2144b8a78f9d94d9515963ed273d620e07846acd5d4b0a642d4849e8d91a0c", + "sha256:f017a61399f13aa6d1039f75cd467be388d157cd81f1a119b9d9a68ba6f2830d", + "sha256:f1d8a2a57b47142b10374902777e798784abf400a004b14f1b0b9eaf1e528ba4", + "sha256:f2d32f95922927186c6dbc8bc60df0d186b6edb828d299ab10898ef3f40052fe", + "sha256:f319bae0321bc838e205bf9e5bc28f0a3165f30c203b610f17ab5552cff90323", + "sha256:f3c38e4e5ccbdc9198aecc766cedbb134b2d89bf64533973678dfcf07effd883", + "sha256:f9983d01d7705b2d1f7a95e10bbe4091fabc03a46881a256c2787637b087003f", + "sha256:fa260de59dfb143af06dcf30c2be0b200bed2a73737a8a59248fcb9fa601ef0f" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==7.8.0" + }, + "docker": { + "hashes": [ + "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c", + "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0" + ], + "markers": "python_version >= '3.8'", + "version": "==7.1.0" + }, + "idna": { + "hashes": [ + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" + ], + "markers": "python_version >= '3.6'", + "version": "==3.10" + }, + "iniconfig": { + "hashes": [ + "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", + "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760" + ], + "markers": "python_version >= '3.8'", + "version": "==2.1.0" + }, + "packaging": { + "hashes": [ + "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", + "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" + ], + "markers": "python_version >= '3.8'", + "version": "==24.2" + }, + "pluggy": { + "hashes": [ + "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", + "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" + ], + "markers": "python_version >= '3.8'", + "version": "==1.5.0" + }, + "pytest": { + "hashes": [ + "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", + "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==8.3.5" + }, + "python-dotenv": { + "hashes": [ + "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5", + "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==1.1.0" + }, + "requests": { + "hashes": [ + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" + ], + "markers": "python_version >= '3.8'", + "version": "==2.32.3" + }, + "requests-mock": { + "hashes": [ + "sha256:b1e37054004cdd5e56c84454cc7df12b25f90f382159087f4b6915aaeef39563", + "sha256:e9e12e333b525156e82a3c852f22016b9158220d2f47454de9cae8a77d371401" + ], + "index": "pypi", + "markers": "python_version >= '3.5'", + "version": "==1.12.1" + }, + "testcontainers": { + "hashes": [ + "sha256:03f85c3e505d8b4edeb192c72a961cebbcba0dd94344ae778b4a159cb6dcf8d3", + "sha256:31ed1a81238c7e131a2a29df6db8f23717d892b592fa5a1977fd0dcd0c23fc23" + ], + "index": "pypi", + "markers": "python_version >= '3.9' and python_version < '4.0'", + "version": "==4.10.0" + }, + "typing-extensions": { + "hashes": [ + "sha256:0a4ac55a5820789d87e297727d229866c9650f6521b64206413c4fbada24d95b", + "sha256:c8dd92cc0d6425a97c18fbb9d1954e5ff92c1ca881a309c45f06ebc0b79058e5" + ], + "markers": "python_version >= '3.8'", + "version": "==4.13.0" + }, + "urllib3": { + "hashes": [ + "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", + "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d" + ], + "markers": "python_version >= '3.9'", + "version": "==2.3.0" + }, + "wrapt": { + "hashes": [ + "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.2" + } + } +} diff --git a/dbrepo-dashboard-service/README.md b/dbrepo-dashboard-service/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a05a200d2d3dd938d3fd2667c9b1581874df484c --- /dev/null +++ b/dbrepo-dashboard-service/README.md @@ -0,0 +1,14 @@ +# Search Service + +## Actuator + +- Health: http://localhost:5000/api/search/health +- Prometheus: http://localhost:5000/metrics + +## Swagger UI Endpoints + +- Swagger UI: http://localhost:5000/swagger-ui/ + +## OpenAPI Endpoints + +- OpenAPI v3 as .json: http://localhost:5000/api-search.json \ No newline at end of file diff --git a/dbrepo-dashboard-service/access.py b/dbrepo-dashboard-service/access.py deleted file mode 100644 index b72b2dcfbf3afb35d00d882afaecafe4189ee4f1..0000000000000000000000000000000000000000 --- a/dbrepo-dashboard-service/access.py +++ /dev/null @@ -1,30 +0,0 @@ -import logging - -from grafana_client.client import GrafanaException - -from api.dto import Permission -from dbrepo.api.dto import Database -from clients import grafana_client - -statistics_row_title = '${table_id}' - - -def update_anonymous_read_access(uid: str, is_public: bool, is_schema_public: bool) -> None: - grafana = grafana_client.connect() - permissions = grafana.dashboard.get_permissions_by_uid(uid) - viewer_role = [permission for permission in permissions if - 'permissionName' in permission and permission['permissionName'] != 'View'] - permission = '' - if is_public or is_schema_public: - permission = 'View' - if len(viewer_role) == 0: - logging.warning(f'Failed to find permissionName=View') - return None - try: - response = grafana_client.generic_post(f'/api/access-control/dashboards/{uid}/builtInRoles/Viewer', - Permission(permission=permission).model_dump()) - if response.status_code != 200: - raise OSError(f'Failed to update anonymous read access: {response.content}') - except GrafanaException as e: - raise OSError(f'Failed to update anonymous read access: {e.message}') - logging.info(f"Updated anonymous read access for dashboard with uid: {uid}") diff --git a/dbrepo-dashboard-service/app.py b/dbrepo-dashboard-service/app.py new file mode 100644 index 0000000000000000000000000000000000000000..eb50fe66c78cabfd9ee7d74f5af82db9eb4c00f9 --- /dev/null +++ b/dbrepo-dashboard-service/app.py @@ -0,0 +1,237 @@ +import logging +import os +from http import HTTPStatus +from json import dumps +from typing import List, Any + +from dbrepo.api.dto import ApiError, Database, User +from dbrepo.core.api.exceptions import DashboardNotFound +from dbrepo.core.client.auth import AuthServiceClient +from dbrepo.core.client.dashboard import DashboardServiceClient +from flasgger import LazyJSONEncoder, Swagger, swag_from +from flask import Flask, request, Response +from flask_cors import CORS +from flask_httpauth import HTTPTokenAuth, HTTPBasicAuth, MultiAuth +from grafana_client.client import GrafanaClientError +from prometheus_flask_exporter import PrometheusMetrics +from pydantic import ValidationError + +logging.addLevelName(level=logging.NOTSET, levelName='TRACE') +logging.basicConfig(level=logging.DEBUG) + +from logging.config import dictConfig + +# 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': {'wsgi': { + 'class': 'logging.StreamHandler', + 'stream': 'ext://flask.logging.wsgi_errors_stream', + 'formatter': 'simple' # default + }}, + 'root': { + 'level': 'DEBUG', + 'handlers': ['wsgi'] + } +}) + +# create app object +app = Flask(__name__) + +cors = CORS(app, resources={r"/api/*": {"origins": "*"}}) + +metrics = PrometheusMetrics(app) +metrics.info("app_info", "Application info", version="0.0.1") +app.config["SWAGGER"] = {"openapi": "3.0.1", "title": "Swagger UI", "uiversion": 3} + +token_auth = HTTPTokenAuth(scheme='Bearer') +basic_auth = HTTPBasicAuth() +auth = MultiAuth(token_auth, basic_auth) + +swagger_config = { + "headers": [], + "specs": [ + { + "endpoint": "api-dashboard", + "route": "/api-dashboard.json", + "rule_filter": lambda rule: True, + "model_filter": lambda tag: True, # all in + } + ], + "static_url_path": "/flasgger_static", + "swagger_ui": True, + "specs_route": "/swagger-ui/", +} + +template = { + "openapi": "3.0.0", + "info": { + "title": "Database Repository Dashboard Service API", + "description": "Service that manages the dashboards", + "version": "1.8.0", + "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" + }, + }, + "externalDocs": { + "description": "Sourcecode Documentation", + "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.7/" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + }, + { + "url": "https://test.dbrepo.tuwien.ac.at", + "description": "Sandbox" + } + ], + "components": { + "schemas": { + "ApiError": { + "properties": { + "message": { + "example": "Message", + "type": "string" + }, + "status": { + "example": "BAD_REQUEST", + "type": "string" + }, + "code": { + "example": "error.dashboard.create", + "type": "string" + } + }, + "type": "object" + }, + }, + "securitySchemes": { + "bearerAuth": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT", + "in": "header" + }, + "basicAuth": { + "type": "http", + "scheme": "basic", + "in": "header" + } + }, + } +} + +swagger = Swagger(app, config=swagger_config, template=template) +app.config["AUTH_SERVICE_ENDPOINT"] = os.getenv("AUTH_SERVICE_ENDPOINT", "http://localhost:8080") +app.config["AUTH_SERVICE_CLIENT"] = os.getenv("AUTH_SERVICE_CLIENT", "dbrepo-client") +app.config["AUTH_SERVICE_CLIENT_SECRET"] = os.getenv("AUTH_SERVICE_CLIENT_SECRET", "MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG") +app.config["BASE_URL"] = os.getenv("BASE_URL", "http://localhost") +app.config["JSON_DATASOURCE_NAME"] = os.getenv('JSON_DATASOURCE_NAME', 'dbrepojson0') +app.config["JWT_ALGORITHM"] = "HS256" +app.config["JWT_PUBKEY"] = '-----BEGIN PUBLIC KEY-----\n' + os.getenv("JWT_PUBKEY", + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB") + '\n-----END PUBLIC KEY-----' +app.config["READONLY_USERNAME"] = os.getenv('READONLY_USERNAME', 'user') +app.config["READONLY_PASSWORD"] = os.getenv('READONLY_PASSWORD', 'user') + +app.json_encoder = LazyJSONEncoder + +headers = {'Content-Type': 'application/json'} + + +def dashboard_client(): + return DashboardServiceClient(os.getenv('DASHBOARD_UI_ENDPOINT', 'http://localhost:3000'), + os.getenv('SYSTEM_USERNAME', 'admin'), os.getenv('SYSTEM_PASSWORD', 'admin')) + + +def auth_client(): + return AuthServiceClient(app.config["AUTH_SERVICE_ENDPOINT"], app.config["AUTH_SERVICE_CLIENT"], + app.config["AUTH_SERVICE_CLIENT_SECRET"], app.config["JWT_PUBKEY"]) + + +@token_auth.verify_token +def verify_token(token: str) -> bool | User: + return auth_client().is_valid_token(token) + + +@basic_auth.verify_password +def verify_password(username: str, password: str) -> Any: + return auth_client().is_valid_password(username, password) + + +@token_auth.get_user_roles +def get_user_roles(user: User) -> List[str]: + return auth_client().get_user_roles(user) + + +@basic_auth.get_user_roles +def get_user_roles(user: User) -> List[str]: + return auth_client().get_user_roles(user) + + +@app.route("/health", methods=["GET"], endpoint="actuator_health") +def health(): + return dict({"status": "UP"}), 200 + + +@app.route("/api/dashboard", methods=["POST"], endpoint="create_dashboard") +@metrics.gauge(name='dbrepo_create_dashboard', description='Time needed to create dashboard') +@swag_from("ds-yml/create_dashboard.yml") +@auth.login_required(role=['system']) +def create_dashboard(): + for parameter in [param for param in ['is_public', 'is_schema_public', 'owner_username', 'database_name'] if + param not in request.json]: + return Response(ApiError(status='BAD_REQUEST', message=f'Missing required parameter: {parameter}', + code="error.dashboard.malformed").model_dump_json(), 400, headers) + + is_public = bool(request.json['is_public']) + is_schema_public = bool(request.json['is_schema_public']) + owner_username = request.json['owner_username'] + logging.debug( + f"endpoint create dashboard, is_public={is_public}, is_schema_public={is_schema_public}, owner_username={owner_username}") + try: + db = dashboard_client().create(request.json['database_name']) + dashboard_client().update_anonymous_read_access(db['uid'], is_public, is_schema_public) + return Response(dumps(db)), 201, headers + except GrafanaClientError as e: + dto = ApiError(status=HTTPStatus(e.status_code).phrase.upper(), + message=f"Failed to create dashboard: {e.response['message']}", code="error.dashboard.create") + if e.status_code == 409 or e.status_code == 412: + dto.code = "error.dashboard.exists" + return Response(dto.model_dump_json(), 409, headers) + return Response(dto.model_dump_json(), e.status_code, headers) + + +@app.route("/api/dashboard/<string:uid>", methods=["PUT"], endpoint="update_dashboard") +@metrics.gauge(name='dbrepo_update_dashboard', description='Time needed to update dashboard') +@swag_from("ds-yml/update_dashboard.yml") +@auth.login_required(role=['system']) +def update_dashboard(uid: str): + logging.debug(f'endpoint update dashboard, uid={uid}') + try: + database = Database.model_validate(request.json) + except ValidationError as e: + logging.error(f'Model malformed: {e}') + return Response(ApiError(status='BAD_REQUEST', message='Invalid database format', + code='error.database.malformed').model_dump_json(), 400, headers) + try: + dashboard_client().update(database) + except DashboardNotFound as e: + return Response(ApiError(status='NOT_FOUND', message=f"Failed to update dashboard: not found", + code="error.dashboard.missing").model_dump_json(), 404, headers) + dashboard_client().update_anonymous_read_access(uid, database.is_public, database.is_schema_public) + return Response(), 202, headers diff --git a/dbrepo-dashboard-service/clients/grafana_client.py b/dbrepo-dashboard-service/clients/grafana_client.py deleted file mode 100644 index 8f7d5aab0f3b28b702cf83cfd51e98bf1bc3c98e..0000000000000000000000000000000000000000 --- a/dbrepo-dashboard-service/clients/grafana_client.py +++ /dev/null @@ -1,27 +0,0 @@ -import logging -import os - -import requests -from requests import Response - -from grafana_client import GrafanaApi - -url = os.getenv('DASHBOARD_UI_ENDPOINT', 'http://localhost:3000') -username = os.getenv('SYSTEM_USERNAME', 'admin') -password = os.getenv('SYSTEM_PASSWORD', 'admin') - - -def connect() -> GrafanaApi: - return GrafanaApi.from_url(url=f'{url}', credential=(username, password)) - - -def generic_get(api_url: str) -> Response: - request_url = url + api_url - logging.debug(f'generic get url={request_url}, auth=({username}, <reacted>)') - return requests.get(request_url, auth=(username, password)) - - -def generic_post(api_url: str, payload: dict) -> Response: - request_url = url + api_url - logging.debug(f'generic post url={request_url}, payload={payload}, auth=({username}, <reacted>)') - return requests.post(request_url, json=payload, auth=(username, password)) diff --git a/dbrepo-dashboard-service/clients/keycloak_client.py b/dbrepo-dashboard-service/clients/keycloak_client.py deleted file mode 100644 index 7abb0a28a5122178e55e7902c9b634e9b61a558f..0000000000000000000000000000000000000000 --- a/dbrepo-dashboard-service/clients/keycloak_client.py +++ /dev/null @@ -1,35 +0,0 @@ -from dataclasses import dataclass -from typing import List - -import requests -from flask import current_app -from jwt import jwk_from_pem, JWT - - -@dataclass(init=True, eq=True) -class User: - username: str - roles: List[str] - - -class KeycloakClient: - - def obtain_user_token(self, username: str, password: str) -> str: - response = requests.post( - f"{current_app.config['AUTH_SERVICE_ENDPOINT']}/realms/dbrepo/protocol/openid-connect/token", - data={ - "username": username, - "password": password, - "grant_type": "password", - "client_id": current_app.config["AUTH_SERVICE_CLIENT"], - "client_secret": current_app.config["AUTH_SERVICE_CLIENT_SECRET"] - }) - body = response.json() - if "access_token" not in body: - raise AssertionError(f"Failed to obtain user token(s): {response.status_code}") - return response.json()["access_token"] - - def verify_jwt(self, access_token: str) -> User: - public_key = jwk_from_pem(str(current_app.config["JWT_PUBKEY"]).encode('utf-8')) - payload = JWT().decode(message=access_token, key=public_key, do_time_check=True) - return User(username=payload.get('client_id'), roles=payload.get('realm_access')["roles"]) diff --git a/dbrepo-dashboard-service/dashboard.py b/dbrepo-dashboard-service/dashboard.py deleted file mode 100644 index f8d4212be404b05d5d6daa78117868498d6885f9..0000000000000000000000000000000000000000 --- a/dbrepo-dashboard-service/dashboard.py +++ /dev/null @@ -1,344 +0,0 @@ -import logging -import os - -from dbrepo.api.dto import Database, View - -from clients import grafana_client - -statistics_row_title = '${view_id}' - -base_url = os.getenv('BASE_URL', 'http://localhost') -datasource_uid = os.getenv('JSON_DATASOURCE_NAME', 'dbrepojson0') - - -def map_link(title: str, url: str) -> dict: - return dict(targetBlank=True, - asDropdown=False, - includeVars=False, - keepTime=False, - tags=[], - type='link', - icon='info', - title=title, - url=url) - - -def map_statistics_row(dashboard: dict) -> dict | None: - filtered_panels = [panel for panel in dashboard['panels'] if - panel['type'] == 'row' and panel['title'] == statistics_row_title] - if len(filtered_panels) == 0: - logging.warning(f"Failed to find statistics row title {statistics_row_title} in: {filtered_panels}") - return None - return filtered_panels[0] - - -def map_links(database: Database) -> [dict]: - links = [] - if len(database.identifiers) > 0: - links.append(map_link('Database', f"{base_url}/pid/{database.identifiers[0].id}")) - else: - links.append(map_link('Database', f"{base_url}/database/{database.id}")) - return links - - -def map_templating(database: Database) -> dict: - options = [dict(selected=False, - text=view.name, - value=str(view.id)) for view in database.views] - selected = dict(selected=True, - text=[view.name for view in database.views], - value=[str(view.id) for view in database.views]) - datasource = dict(uid=datasource_uid, - type='yesoreyeram-infinity-datasource') - return dict(list=[dict(description='', - name='view_id', - hide=0, - includeAll=True, - multi=True, - datasource=datasource, - refresh=1, - regex='', - sort=0, - definition='dbrepo-json- (infinity) json', - query=dict(queryType='infinity', - query='', - infinityQuery=dict(format='table', - filters=[], - parser='backend', - refId='variable', - root_selector='', - source='url', - type='json', - url=f"/api/database/{database.id}/view", - columns=[dict(selector='id', - text='value', - type='string'), - dict( - selector='internal_name', - text='name', - type='string')], - url_options=dict(data='', - method='GET'))), - label='Datasource', - skipUrlSync=False, - type='query', - current=selected, - options=options)]) - - -def map_timeseries_panel(database: Database, view: View) -> dict: - datasource = dict(uid=datasource_uid, - type='yesoreyeram-infinity-datasource') - return dict( - title=view['name'], - type='timeseries', - datasource=datasource, - targets=[dict(datasource=datasource, - format='table', - global_query_id='', - hide=False, - refId='A', - root_selector='', - source='url', - type='json', - url=f"/api/database/{database['id']}/view/{view['id']}", - url_options=dict(data='', - method='GET'))], - gridPos=dict(h=8, - w=12, - x=0, - y=0), - options=dict(legend=dict(displayMode='list', - placement='bottom', - showLegend=True), - tooltip=dict(mode='single', - sort='none')), - fieldConfig=dict( - defaults=dict(color=dict(mode='palette-classic'), - custom=dict( - axisBorderShow=False, - axisCenteredZero=False, - axisColorMode='text', - axisLabel='', - axisPlacement='auto', - barAlignment=0, - drawStyle='line', - fillOpacity=0, - gradientMode='none', - hideFrom=dict(legend=False, - tooltip=False, - viz=False), - insertNulls=False, - lineInterpolation='linear', - lineWidth=1, - pointSize=5, - scaleDistribution=dict(type='linear'), - showPoints='auto', - spanNulls=False, - stacking=dict(group='A', - mode='none'), - thresholdsStyle=dict(mode='absolute'))))) - - -def map_statistics_panel(database_id: str, view: View) -> dict: - datasource = dict(uid=datasource_uid, - type='yesoreyeram-infinity-datasource') - return dict( - title=view.name, - type='table', - datasource=datasource, - targets=[dict(datasource=datasource, - columns=[], - filters=[], - format='table', - global_query_id='', - hide=False, - refId='A', - root_selector='', - source='url', - type='json', - url=f"/api/database/{database_id}/view/{view.id}/data", - url_options=dict(data='', - method='GET'))], - options=dict(cellHeight="sm", - showHeader=True, - footer=dict(countRows=False, - fields="", - reducer=["sum"], - show=False)), - gridPos=dict(h=8, - w=12, - x=12, - y=0), - transformations=dict(id="organize", - options=dict(excludeByName=dict(), - includeByName=dict(), - indexByName=dict( - HEADER_AVG=3, - HEADER_COL=0, - HEADER_STDDEV=4, - HEADER_MAX=2, - HEADER_MIN=1))), - fieldConfig=dict(defaults=dict(custom=dict(align="auto", - filterable="true", - cellOptions=dict(type="auto"), - inspect=False), - mappings=[], - thresholds=dict(mode="absolute", - steps=[dict(color="green", - value=None), - dict(color="red", - value=80) - ])), - overrides=[dict(matcher=dict(id="byName", - options="HEADER_COL"), - properties=[dict(id="custom.align", - value="center")]), - dict(matcher=dict(id="byName", - options="HEADER_MIN"), - properties=[dict(id="custom.width", - value=115)]), - dict(matcher=dict(id="byName", - options="HEADER_MAX"), - properties=[dict(id="custom.width", - value=115)]), - dict(matcher=dict(id="byName", - options="HEADER_AVG"), - properties=[dict(id="custom.width", - value=115)]), - dict(matcher=dict(id="byName", - options="HEADER_STDDEV"), - properties=[dict(id="custom.width", - value=115)]) - ])) - - -def map_overview_panel(database_id: str) -> dict: - datasource = dict(uid=datasource_uid, - type='yesoreyeram-infinity-datasource') - return dict(title='Preview', - type='table', - fieldConfig=dict( - defaults=dict( - color=dict(mode='palette-classic'), - custom=dict(axisBorderShow=False, - axisCenteredZero=False, - axisColorMode='text', - axisLabel='', - axisPlacement='auto', - barAlignment=0, - drawStyle='line', - fillOpacity=0, - gradientMode='none', - hideFrom=dict( - legend=False, - tooltip=False, - viz=False), - insertNulls=False, - lineInterpolation='linear', - lineWidth=1, - pointSize=5, - scaleDistribution=dict( - type='linear'), - showPoints='auto', - spanNulls=False, - stacking=dict(group='A', - mode='none'), - thresholdsStyle=dict( - mode='off'))), - overrides=[]), - options=dict(legend=dict(displayMode='list', - placement='bottom', - showLegend=True, - calcs=[]), - tooltip=dict(mode='single', - sort='none')), - targets=[dict(format='json', - columns=[], - datasource=datasource, - filters=[], - global_query_id='', - refId='A', - root_selector='', - source='url', - type='json', - url='/api/database/' + database_id + '/view/${view_id}/data', - url_options=dict(data='', - method='GET'))], - datasource=datasource, - gridPos=dict(h=4, - w=12, - x=0, - y=0)) - - -def map_row() -> dict: - datasource = dict(uid=datasource_uid, - type='yesoreyeram-infinity-datasource') - return dict(collapsed=False, - repeat='view_id', - repeatDirection='h', - title=statistics_row_title, - type='row', - panels=[], - targets=[dict(refId='A', - datasource=datasource)], - gridPos=dict(h=1, - w=24, - x=0, - y=0)) - - -def map_panels(dashboard: dict, database: Database) -> [dict]: - if map_statistics_row(dashboard) is None: - dashboard['panels'].append(map_row()) - dashboard['panels'].append(map_overview_panel(database.id)) - for view in database.views: - dashboard['panels'].append(map_statistics_panel(database.id, view)) - return dashboard['panels'] - - -def find(uid: str): - grafana = grafana_client.connect() - return grafana.dashboard.get_dashboard(uid) - - -def create(database_name: str, uid: str = '') -> dict: - grafana = grafana_client.connect() - dashboard = dict(uid=uid, - title=f'{database_name} Overview', - tags=['dbrepo'], - timezone='browser', - fiscalYearStartMonth=1, - panels=[]) - dashboard['panels'] = [] - payload = dict(folderUid='', - overwrite=False, - dashboard=dashboard) - dashboard = grafana.dashboard.update_dashboard(payload) - logging.info(f"Created dashboard with uid: {dashboard['uid']}") - return dashboard - - -def delete(uid: str) -> None: - grafana = grafana_client.connect() - grafana.dashboard.delete_dashboard(uid) - - -def update(database: Database) -> None: - grafana = grafana_client.connect() - dashboard = find(database.dashboard_uid)['dashboard'] - # update metadata - if len(database.identifiers) > 0 and len(database.identifiers[0].titles) > 0: - dashboard['title'] = database.identifiers[0].titles[0].title - if len(database.identifiers) > 0 and len(database.identifiers[0].descriptions) > 0: - dashboard['description'] = database.identifiers[0].descriptions[0].description - dashboard['links'] = map_links(database) - dashboard['templating'] = map_templating(database) - # update panels - dashboard['panels'] = map_panels(dashboard, database) - payload = dict(folderUid='', - overwrite=True, - dashboard=dashboard) - response = grafana.dashboard.update_dashboard(payload) - logging.info(f"Updated dashboard with uid: {response['uid']}") diff --git a/dbrepo-dashboard-service/ds-yml/create_dashboard.yml b/dbrepo-dashboard-service/ds-yml/create_dashboard.yml new file mode 100644 index 0000000000000000000000000000000000000000..8499d13ed5f5e2aa84fb609d0f6e7be35e08dce8 --- /dev/null +++ b/dbrepo-dashboard-service/ds-yml/create_dashboard.yml @@ -0,0 +1,55 @@ +tags: + - dashboard-endpoint +summary: "Create dashboard" +operationId: create_dashboard +description: "Creates a dashboard in the Dashboard UI. Requires role `system`." +consumes: + - "application/json" +produces: + - "application/json" +parameters: + - in: "body" + name: "body" + required: true + schema: + required: + - is_public + - is_schema_public + - database_name + - owner_username + type: object + properties: + is_public: + type: boolean + example: True + is_schema_public: + type: boolean + example: True + database_name: + type: string + example: "some_database" + owner_username: + type: string + example: "foobar" +responses: + 201: + description: Created dashboard successfully + content: + application/json: + schema: + type: object + 409: + description: "Dashboard exists with same name" + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + 500: + description: "Unexpected system error" + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' +security: + - bearerAuth: [ ] + - basicAuth: [ ] diff --git a/dbrepo-dashboard-service/ds-yml/update_dashboard.yml b/dbrepo-dashboard-service/ds-yml/update_dashboard.yml new file mode 100644 index 0000000000000000000000000000000000000000..0765ad9565ddf081f3109899d337873d0b055c10 --- /dev/null +++ b/dbrepo-dashboard-service/ds-yml/update_dashboard.yml @@ -0,0 +1,43 @@ +tags: + - dashboard-endpoint +summary: "Update dashboard" +operationId: update_dashboard +description: "Updates a dashboard in the Dashboard UI. Requires role `system`." +consumes: + - "application/json" +produces: + - "application/json" +parameters: + - name: uid + in: path + required: true + schema: + type: string + format: uuid + - name: "body" + in: "body" + required: true + schema: + type: object +responses: + 202: + description: Updated dashboard successfully + content: + application/json: + schema: + type: object + 404: + description: "Dashboard not found" + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + 500: + description: "Unexpected system error" + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' +security: + - bearerAuth: [ ] + - basicAuth: [ ] diff --git a/dbrepo-dashboard-service/init/.coveragerc b/dbrepo-dashboard-service/init/.coveragerc new file mode 100644 index 0000000000000000000000000000000000000000..9fd61fc1664fc653df59d3f0be0aebf997c78060 --- /dev/null +++ b/dbrepo-dashboard-service/init/.coveragerc @@ -0,0 +1,7 @@ +[report] +omit = + # omit tests + ./tests/* + +[html] +directory = htmlcov \ No newline at end of file diff --git a/dbrepo-dashboard-service/init/Dockerfile b/dbrepo-dashboard-service/init/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..a073362558e28bba4c2bbb521d41c7fafaa11798 --- /dev/null +++ b/dbrepo-dashboard-service/init/Dockerfile @@ -0,0 +1,25 @@ +FROM python:3.11-alpine3.21 +LABEL org.opencontainers.image.authors="martin.weise@tuwien.ac.at" + +RUN apk add --no-cache \ + curl \ + bash \ + jq + +COPY Pipfile Pipfile.lock ./ + +COPY ./lib ./lib + +RUN pip install pipenv && \ + pipenv install gunicorn && \ + pipenv install --system --deploy + +RUN adduser -D dbrepo --uid 1001 + +WORKDIR /app + +USER 1001 + +COPY --chown=1001 ./app.py ./app.py + +ENTRYPOINT [ "python", "./app.py" ] diff --git a/dbrepo-dashboard-service/init/Pipfile b/dbrepo-dashboard-service/init/Pipfile new file mode 100644 index 0000000000000000000000000000000000000000..e94396551e48ded57c3442e19b02f11977e5d58c --- /dev/null +++ b/dbrepo-dashboard-service/init/Pipfile @@ -0,0 +1,28 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +flasgger = "*" +flask = "~=2.0" +flask-cors = "~=4.0" +flask-jwt-extended = "~=4.5" +prometheus-flask-exporter = "*" +python-dotenv = "~=1.0" +pytest = "*" +dbrepo = {path = "./lib/dbrepo-1.8.0.tar.gz"} +gunicorn = "*" +pydantic = "*" +flask_httpauth = "*" +grafana-client = "*" + +[dev-packages] +coverage = "*" +pytest = "*" +testcontainers = "*" +requests-mock = "*" +grafana-client = "*" + +[requires] +python_version = "3.11" diff --git a/dbrepo-dashboard-service/init/Pipfile.lock b/dbrepo-dashboard-service/init/Pipfile.lock new file mode 100644 index 0000000000000000000000000000000000000000..0e70d6655ffd757511d816a27be36173ce48279b --- /dev/null +++ b/dbrepo-dashboard-service/init/Pipfile.lock @@ -0,0 +1,2434 @@ +{ + "_meta": { + "hash": { + "sha256": "63b2ba52d16213be5e67d8f325b8d28b7caac9f0c9aff04270dd46afc462b397" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.11" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "aiohappyeyeballs": { + "hashes": [ + "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", + "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8" + ], + "markers": "python_version >= '3.9'", + "version": "==2.6.1" + }, + "aiohttp": { + "hashes": [ + "sha256:004511d3413737700835e949433536a2fe95a7d0297edd911a1e9705c5b5ea43", + "sha256:0902e887b0e1d50424112f200eb9ae3dfed6c0d0a19fc60f633ae5a57c809656", + "sha256:09b00dd520d88eac9d1768439a59ab3d145065c91a8fab97f900d1b5f802895e", + "sha256:0a2f451849e6b39e5c226803dcacfa9c7133e9825dcefd2f4e837a2ec5a3bb98", + "sha256:0a950c2eb8ff17361abd8c85987fd6076d9f47d040ebffce67dce4993285e973", + "sha256:0ad1fb47da60ae1ddfb316f0ff16d1f3b8e844d1a1e154641928ea0583d486ed", + "sha256:13ceac2c5cdcc3f64b9015710221ddf81c900c5febc505dbd8f810e770011540", + "sha256:14461157d8426bcb40bd94deb0450a6fa16f05129f7da546090cebf8f3123b0f", + "sha256:16f8a2c9538c14a557b4d309ed4d0a7c60f0253e8ed7b6c9a2859a7582f8b1b8", + "sha256:17ae4664031aadfbcb34fd40ffd90976671fa0c0286e6c4113989f78bebab37a", + "sha256:1ce63ae04719513dd2651202352a2beb9f67f55cb8490c40f056cea3c5c355ce", + "sha256:23a15727fbfccab973343b6d1b7181bfb0b4aa7ae280f36fd2f90f5476805682", + "sha256:2540ddc83cc724b13d1838026f6a5ad178510953302a49e6d647f6e1de82bc34", + "sha256:37dcee4906454ae377be5937ab2a66a9a88377b11dd7c072df7a7c142b63c37c", + "sha256:38bea84ee4fe24ebcc8edeb7b54bf20f06fd53ce4d2cc8b74344c5b9620597fd", + "sha256:3ab3367bb7f61ad18793fea2ef71f2d181c528c87948638366bf1de26e239183", + "sha256:3ad1d59fd7114e6a08c4814983bb498f391c699f3c78712770077518cae63ff7", + "sha256:3b4e6db8dc4879015b9955778cfb9881897339c8fab7b3676f8433f849425913", + "sha256:3e061b09f6fa42997cf627307f220315e313ece74907d35776ec4373ed718b86", + "sha256:42864e70a248f5f6a49fdaf417d9bc62d6e4d8ee9695b24c5916cb4bb666c802", + "sha256:493910ceb2764f792db4dc6e8e4b375dae1b08f72e18e8f10f18b34ca17d0979", + "sha256:4d0c970c0d602b1017e2067ff3b7dac41c98fef4f7472ec2ea26fd8a4e8c2149", + "sha256:54eb3aead72a5c19fad07219acd882c1643a1027fbcdefac9b502c267242f955", + "sha256:56a3443aca82abda0e07be2e1ecb76a050714faf2be84256dae291182ba59049", + "sha256:576f5ca28d1b3276026f7df3ec841ae460e0fc3aac2a47cbf72eabcfc0f102e1", + "sha256:58ede86453a6cf2d6ce40ef0ca15481677a66950e73b0a788917916f7e35a0bb", + "sha256:61c721764e41af907c9d16b6daa05a458f066015abd35923051be8705108ed17", + "sha256:634d96869be6c4dc232fc503e03e40c42d32cfaa51712aee181e922e61d74814", + "sha256:696ef00e8a1f0cec5e30640e64eca75d8e777933d1438f4facc9c0cdf288a810", + "sha256:69a2cbd61788d26f8f1e626e188044834f37f6ae3f937bd9f08b65fc9d7e514e", + "sha256:6a792ce34b999fbe04a7a71a90c74f10c57ae4c51f65461a411faa70e154154e", + "sha256:6ac13b71761e49d5f9e4d05d33683bbafef753e876e8e5a7ef26e937dd766713", + "sha256:6fdec0213244c39973674ca2a7f5435bf74369e7d4e104d6c7473c81c9bcc8c4", + "sha256:72b1b03fb4655c1960403c131740755ec19c5898c82abd3961c364c2afd59fe7", + "sha256:745f1ed5e2c687baefc3c5e7b4304e91bf3e2f32834d07baaee243e349624b24", + "sha256:776c8e959a01e5e8321f1dec77964cb6101020a69d5a94cd3d34db6d555e01f7", + "sha256:780df0d837276276226a1ff803f8d0fa5f8996c479aeef52eb040179f3156cbd", + "sha256:78e6e23b954644737e385befa0deb20233e2dfddf95dd11e9db752bdd2a294d3", + "sha256:7951decace76a9271a1ef181b04aa77d3cc309a02a51d73826039003210bdc86", + "sha256:7ba92a2d9ace559a0a14b03d87f47e021e4fa7681dc6970ebbc7b447c7d4b7cd", + "sha256:7f6428fee52d2bcf96a8aa7b62095b190ee341ab0e6b1bcf50c615d7966fd45b", + "sha256:87944bd16b7fe6160607f6a17808abd25f17f61ae1e26c47a491b970fb66d8cb", + "sha256:87a6e922b2b2401e0b0cf6b976b97f11ec7f136bfed445e16384fbf6fd5e8602", + "sha256:8cb0688a8d81c63d716e867d59a9ccc389e97ac7037ebef904c2b89334407180", + "sha256:8df6612df74409080575dca38a5237282865408016e65636a76a2eb9348c2567", + "sha256:911a6e91d08bb2c72938bc17f0a2d97864c531536b7832abee6429d5296e5b27", + "sha256:92b7ee222e2b903e0a4b329a9943d432b3767f2d5029dbe4ca59fb75223bbe2e", + "sha256:938f756c2b9374bbcc262a37eea521d8a0e6458162f2a9c26329cc87fdf06534", + "sha256:9756d9b9d4547e091f99d554fbba0d2a920aab98caa82a8fb3d3d9bee3c9ae85", + "sha256:98b88a2bf26965f2015a771381624dd4b0839034b70d406dc74fd8be4cc053e3", + "sha256:9b751a6306f330801665ae69270a8a3993654a85569b3469662efaad6cf5cc50", + "sha256:a2a450bcce4931b295fc0848f384834c3f9b00edfc2150baafb4488c27953de6", + "sha256:a3814760a1a700f3cfd2f977249f1032301d0a12c92aba74605cfa6ce9f78489", + "sha256:a5abcbba9f4b463a45c8ca8b7720891200658f6f46894f79517e6cd11f3405ca", + "sha256:a6db7458ab89c7d80bc1f4e930cc9df6edee2200127cfa6f6e080cf619eddfbd", + "sha256:ad497f38a0d6c329cb621774788583ee12321863cd4bd9feee1effd60f2ad133", + "sha256:ad9509ffb2396483ceacb1eee9134724443ee45b92141105a4645857244aecc8", + "sha256:bbcba75fe879ad6fd2e0d6a8d937f34a571f116a0e4db37df8079e738ea95c71", + "sha256:c10d85e81d0b9ef87970ecbdbfaeec14a361a7fa947118817fcea8e45335fa46", + "sha256:c15b2271c44da77ee9d822552201180779e5e942f3a71fb74e026bf6172ff287", + "sha256:ca37057625693d097543bd88076ceebeb248291df9d6ca8481349efc0b05dcd0", + "sha256:cc3a145479a76ad0ed646434d09216d33d08eef0d8c9a11f5ae5cdc37caa3540", + "sha256:ccf10f16ab498d20e28bc2b5c1306e9c1512f2840f7b6a67000a517a4b37d5ee", + "sha256:cd464ba806e27ee24a91362ba3621bfc39dbbb8b79f2e1340201615197370f7c", + "sha256:d007aa39a52d62373bd23428ba4a2546eed0e7643d7bf2e41ddcefd54519842c", + "sha256:d0666afbe984f6933fe72cd1f1c3560d8c55880a0bdd728ad774006eb4241ecd", + "sha256:d07502cc14ecd64f52b2a74ebbc106893d9a9717120057ea9ea1fd6568a747e7", + "sha256:d489d9778522fbd0f8d6a5c6e48e3514f11be81cb0a5954bdda06f7e1594b321", + "sha256:df7db76400bf46ec6a0a73192b14c8295bdb9812053f4fe53f4e789f3ea66bbb", + "sha256:e3538bc9fe1b902bef51372462e3d7c96fce2b566642512138a480b7adc9d508", + "sha256:e87fd812899aa78252866ae03a048e77bd11b80fb4878ce27c23cade239b42b2", + "sha256:ecdb8173e6c7aa09eee342ac62e193e6904923bd232e76b4157ac0bfa670609f", + "sha256:f244b8e541f414664889e2c87cac11a07b918cb4b540c36f7ada7bfa76571ea2", + "sha256:f4065145bf69de124accdd17ea5f4dc770da0a6a6e440c53f6e0a8c27b3e635c", + "sha256:f420bfe862fb357a6d76f2065447ef6f484bc489292ac91e29bc65d2d7a2c84d", + "sha256:f6ddd90d9fb4b501c97a4458f1c1720e42432c26cb76d28177c5b5ad4e332601", + "sha256:fa73e8c2656a3653ae6c307b3f4e878a21f87859a9afab228280ddccd7369d71", + "sha256:fadbb8f1d4140825069db3fedbbb843290fd5f5bc0a5dbd7eaf81d91bf1b003b", + "sha256:fb3d0cc5cdb926090748ea60172fa8a213cec728bd6c54eae18b96040fcd6227", + "sha256:fb46bb0f24813e6cede6cc07b1961d4b04f331f7112a23b5e21f567da4ee50aa", + "sha256:fd36c119c5d6551bce374fcb5c19269638f8d09862445f85a5a48596fd59f4bb" + ], + "markers": "python_version >= '3.9'", + "version": "==3.11.16" + }, + "aiosignal": { + "hashes": [ + "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", + "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54" + ], + "markers": "python_version >= '3.9'", + "version": "==1.3.2" + }, + "annotated-types": { + "hashes": [ + "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", + "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" + ], + "markers": "python_version >= '3.8'", + "version": "==0.7.0" + }, + "attrs": { + "hashes": [ + "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", + "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b" + ], + "markers": "python_version >= '3.8'", + "version": "==25.3.0" + }, + "blinker": { + "hashes": [ + "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", + "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc" + ], + "markers": "python_version >= '3.9'", + "version": "==1.9.0" + }, + "certifi": { + "hashes": [ + "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", + "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe" + ], + "markers": "python_version >= '3.6'", + "version": "==2025.1.31" + }, + "charset-normalizer": { + "hashes": [ + "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537", + "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa", + "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a", + "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294", + "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b", + "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", + "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", + "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd", + "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4", + "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", + "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2", + "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", + "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd", + "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", + "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8", + "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1", + "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", + "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496", + "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d", + "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", + "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e", + "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a", + "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4", + "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca", + "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78", + "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408", + "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5", + "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", + "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", + "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a", + "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765", + "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6", + "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146", + "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6", + "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", + "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd", + "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c", + "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", + "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", + "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176", + "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770", + "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824", + "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f", + "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf", + "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487", + "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d", + "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd", + "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", + "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534", + "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f", + "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b", + "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", + "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd", + "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125", + "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9", + "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de", + "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", + "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d", + "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", + "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f", + "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", + "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7", + "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a", + "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", + "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8", + "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41", + "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", + "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f", + "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", + "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", + "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", + "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77", + "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76", + "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247", + "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", + "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb", + "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", + "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e", + "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6", + "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037", + "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", + "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e", + "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807", + "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", + "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c", + "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12", + "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3", + "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089", + "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", + "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e", + "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00", + "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616" + ], + "markers": "python_version >= '3.7'", + "version": "==3.4.1" + }, + "click": { + "hashes": [ + "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", + "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a" + ], + "markers": "python_version >= '3.7'", + "version": "==8.1.8" + }, + "dbrepo": { + "hashes": [ + "sha256:55de6a4934010e14a574032b5a5179bf3dac9895ef74e5cd4a221a625a75674b" + ], + "path": "./lib/dbrepo-1.8.0.tar.gz" + }, + "flasgger": { + "hashes": [ + "sha256:ca098e10bfbb12f047acc6299cc70a33851943a746e550d86e65e60d4df245fb" + ], + "index": "pypi", + "version": "==0.9.7.1" + }, + "flask": { + "hashes": [ + "sha256:09c347a92aa7ff4a8e7f3206795f30d826654baf38b873d0744cd571ca609efc", + "sha256:f69fcd559dc907ed196ab9df0e48471709175e696d6e698dd4dbe940f96ce66b" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==2.3.3" + }, + "flask-cors": { + "hashes": [ + "sha256:38364faf1a7a5d0a55bd1d2e2f83ee9e359039182f5e6a029557e1f56d92c09a", + "sha256:493b98e2d1e2f1a4720a7af25693ef2fe32fbafec09a2f72c59f3e475eda61d2" + ], + "index": "pypi", + "version": "==4.0.2" + }, + "flask-httpauth": { + "hashes": [ + "sha256:66568a05bc73942c65f1e2201ae746295816dc009edd84b482c44c758d75097a", + "sha256:a58fedd09989b9975448eef04806b096a3964a7feeebc0a78831ff55685b62b0" + ], + "index": "pypi", + "version": "==4.8.0" + }, + "flask-jwt-extended": { + "hashes": [ + "sha256:52f35bf0985354d7fb7b876e2eb0e0b141aaff865a22ff6cc33d9a18aa987978", + "sha256:8085d6757505b6f3291a2638c84d207e8f0ad0de662d1f46aa2f77e658a0c976" + ], + "index": "pypi", + "markers": "python_version >= '3.9' and python_version < '4'", + "version": "==4.7.1" + }, + "frozenlist": { + "hashes": [ + "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e", + "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf", + "sha256:04a5c6babd5e8fb7d3c871dc8b321166b80e41b637c31a995ed844a6139942b6", + "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a", + "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d", + "sha256:0f253985bb515ecd89629db13cb58d702035ecd8cfbca7d7a7e29a0e6d39af5f", + "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28", + "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b", + "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9", + "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2", + "sha256:15538c0cbf0e4fa11d1e3a71f823524b0c46299aed6e10ebb4c2089abd8c3bec", + "sha256:15b731db116ab3aedec558573c1a5eec78822b32292fe4f2f0345b7f697745c2", + "sha256:17dcc32fc7bda7ce5875435003220a457bcfa34ab7924a49a1c19f55b6ee185c", + "sha256:1893f948bf6681733aaccf36c5232c231e3b5166d607c5fa77773611df6dc336", + "sha256:189f03b53e64144f90990d29a27ec4f7997d91ed3d01b51fa39d2dbe77540fd4", + "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d", + "sha256:1b96af8c582b94d381a1c1f51ffaedeb77c821c690ea5f01da3d70a487dd0a9b", + "sha256:1e76bfbc72353269c44e0bc2cfe171900fbf7f722ad74c9a7b638052afe6a00c", + "sha256:2150cc6305a2c2ab33299453e2968611dacb970d2283a14955923062c8d00b10", + "sha256:226d72559fa19babe2ccd920273e767c96a49b9d3d38badd7c91a0fdeda8ea08", + "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942", + "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8", + "sha256:2b5e23253bb709ef57a8e95e6ae48daa9ac5f265637529e4ce6b003a37b2621f", + "sha256:2d0da8bbec082bf6bf18345b180958775363588678f64998c2b7609e34719b10", + "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5", + "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6", + "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21", + "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c", + "sha256:366d8f93e3edfe5a918c874702f78faac300209a4d5bf38352b2c1bdc07a766d", + "sha256:374ca2dabdccad8e2a76d40b1d037f5bd16824933bf7bcea3e59c891fd4a0923", + "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608", + "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de", + "sha256:498524025a5b8ba81695761d78c8dd7382ac0b052f34e66939c42df860b8ff17", + "sha256:50cf5e7ee9b98f22bdecbabf3800ae78ddcc26e4a435515fc72d97903e8488e0", + "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f", + "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641", + "sha256:5a3ba5f9a0dfed20337d3e966dc359784c9f96503674c2faf015f7fe8e96798c", + "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a", + "sha256:5c28f4b5dbef8a0d8aad0d4de24d1e9e981728628afaf4ea0792f5d0939372f0", + "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9", + "sha256:6321899477db90bdeb9299ac3627a6a53c7399c8cd58d25da094007402b039ab", + "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f", + "sha256:666534d15ba8f0fda3f53969117383d5dc021266b3c1a42c9ec4855e4b58b9d3", + "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a", + "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784", + "sha256:73f2e31ea8dd7df61a359b731716018c2be196e5bb3b74ddba107f694fbd7604", + "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d", + "sha256:76e4753701248476e6286f2ef492af900ea67d9706a0155335a40ea21bf3b2f5", + "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03", + "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e", + "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953", + "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee", + "sha256:7f3c8c1dacd037df16e85227bac13cca58c30da836c6f936ba1df0c05d046d8d", + "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817", + "sha256:828afae9f17e6de596825cf4228ff28fbdf6065974e5ac1410cecc22f699d2b3", + "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039", + "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f", + "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9", + "sha256:91d6c171862df0a6c61479d9724f22efb6109111017c87567cfeb7b5d1449fdf", + "sha256:9272fa73ca71266702c4c3e2d4a28553ea03418e591e377a03b8e3659d94fa76", + "sha256:92b5278ed9d50fe610185ecd23c55d8b307d75ca18e94c0e7de328089ac5dcba", + "sha256:97160e245ea33d8609cd2b8fd997c850b56db147a304a262abc2b3be021a9171", + "sha256:977701c081c0241d0955c9586ffdd9ce44f7a7795df39b9151cd9a6fd0ce4cfb", + "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439", + "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631", + "sha256:9bbcdfaf4af7ce002694a4e10a0159d5a8d20056a12b05b45cea944a4953f972", + "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d", + "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869", + "sha256:a72b7a6e3cd2725eff67cd64c8f13335ee18fc3c7befc05aed043d24c7b9ccb9", + "sha256:a9fe0f1c29ba24ba6ff6abf688cb0b7cf1efab6b6aa6adc55441773c252f7411", + "sha256:b97f7b575ab4a8af9b7bc1d2ef7f29d3afee2226bd03ca3875c16451ad5a7723", + "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2", + "sha256:c03eff4a41bd4e38415cbed054bbaff4a075b093e2394b6915dca34a40d1e38b", + "sha256:c16d2fa63e0800723139137d667e1056bee1a1cf7965153d2d104b62855e9b99", + "sha256:c1fac3e2ace2eb1052e9f7c7db480818371134410e1f5c55d65e8f3ac6d1407e", + "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840", + "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3", + "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb", + "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", + "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0", + "sha256:dd94994fc91a6177bfaafd7d9fd951bc8689b0a98168aa26b5f543868548d3ca", + "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45", + "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e", + "sha256:e66cc454f97053b79c2ab09c17fbe3c825ea6b4de20baf1be28919460dd7877f", + "sha256:e79225373c317ff1e35f210dd5f1344ff31066ba8067c307ab60254cd3a78ad5", + "sha256:f1577515d35ed5649d52ab4319db757bb881ce3b2b796d7283e6634d99ace307", + "sha256:f1e6540b7fa044eee0bb5111ada694cf3dc15f2b0347ca125ee9ca984d5e9e6e", + "sha256:f2ac49a9bedb996086057b75bf93538240538c6d9b38e57c82d51f75a73409d2", + "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778", + "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a", + "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30", + "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a" + ], + "markers": "python_version >= '3.8'", + "version": "==1.5.0" + }, + "grafana-client": { + "hashes": [ + "sha256:2477a47b923fd0637947e620b0b777c641af18a3025464fa4505783dbf05dfcc", + "sha256:8cb61bb2a87ec07bca10974df276b9a1a95bfdb63f3a696f065692ffc9b8c389" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==4.3.2" + }, + "gunicorn": { + "hashes": [ + "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d", + "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==23.0.0" + }, + "h11": { + "hashes": [ + "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", + "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761" + ], + "markers": "python_version >= '3.7'", + "version": "==0.14.0" + }, + "idna": { + "hashes": [ + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" + ], + "markers": "python_version >= '3.6'", + "version": "==3.10" + }, + "iniconfig": { + "hashes": [ + "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", + "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760" + ], + "markers": "python_version >= '3.8'", + "version": "==2.1.0" + }, + "itsdangerous": { + "hashes": [ + "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", + "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173" + ], + "markers": "python_version >= '3.8'", + "version": "==2.2.0" + }, + "jh2": { + "hashes": [ + "sha256:038091480cd1544e9389b0adbb1b1645a797689dcb68ceae7e45eec96ed24497", + "sha256:0c8e336df8ed1687590695f4469f480eeb4159bf13bb6193791c6530fe114b49", + "sha256:0c9bf2d5e4ef45c1686c6f76935e7ca263f5eae4de92bf5d1873a0e737e4eb7d", + "sha256:0faf6e96f74d27b8ca816b40217904891f91b664ed1c0388737949ceb50ac15d", + "sha256:10ea7f497e6226372e1d4fdbf42c8381f4887819a643ab930bff4072ad298d84", + "sha256:11650f7ed77ee1df30f25d6b3b74b2fa1c94124e074fd455abafea3cbc913d53", + "sha256:12ead3ee3e9c7caa00356b528a5cc7fe210fbe2060628af6e19ed76b8416572e", + "sha256:136b3c5b08883681fcb58f12393a5bbfa422d6e2d5ba887e263e776874276bc6", + "sha256:17d6e1691154ea9f726e43dcb717df48e56c66b5a01c90ad675c6494c36e5be1", + "sha256:19cb987915cc0d321746a12f2a693d087ffb721c37ac9a153cc088c57d4d90eb", + "sha256:1cdf15de698c4026e64fd914fead3180e52bf2a7bcbe44a3392404582dbf2d22", + "sha256:1e81e1c64e33506b8508ba5e3c7c139b2577e78b079c2c16a8e7a02a161f1080", + "sha256:2226c76e4ff2149c5d9f94bed22bf9c4f3411d38cc53d4a7ddfbe0899c8b558c", + "sha256:2837412fb7b684c6ce7392c8bc57440c6dbadaf1bde7a53144381f7df7083c1c", + "sha256:293f0f3da3c391e997e0d55fdb85540e98a8b0406622bb4ba57fb7617697f31e", + "sha256:2b9cc6c0239215a349d28c192fa4c4e7a7348eee7980531525c01bffe39eea80", + "sha256:2f3ad679f84ff236a0d7b71ddc4b3c09fe467abee2f1a86671f0cd417be5352b", + "sha256:358cad2f328c52c15756cf32b0ad17afb0d617e7cdfe93d59aa2616966d825b7", + "sha256:3663712305b509f79c002c8c0ca9994f716cadba576f5a59632dda1aec1ca8c6", + "sha256:41794820ccca039ca2ead6245f30b34601dd1456eee5b5dde620672bb989e79d", + "sha256:44b7e64aff542471c474c24f771eae5efd9152da02a12556f7cb7607020e1420", + "sha256:45770eb0990166026538d3c2fd7d92f17cfde13ca6567570c4baec3ce9162936", + "sha256:498060078a4d1b458e9381fefb027d85329397b50d65287712b3d48233e20836", + "sha256:4c2f18f337c2393f84e45e5011c8b02697b81638b1cec49da60a01b9ed067695", + "sha256:5162d6e475d2762035fb8ea25982bcbec6c58715e33bd0951499f743cd90b110", + "sha256:51e8c890bb59008c95b3a552cefd8bd9ce50a7466a6c920a78cf586e885d7449", + "sha256:56ad3839ac6ac5fd3d023cf59d4b04264b74bb4cb44c0780faf51d6b5ff38fbc", + "sha256:5821638ef0d7c973071810a6786f59b305172197f7e7e469a2ce169e7f4978e3", + "sha256:5ac1b2d379f4d40c13dcce537e69704452943cddbe991fd54a84fdb2da9026d5", + "sha256:5b465d4311b0429fe6fa85df8e2cfcb038c9fface95396dd14e838ecabaaadf2", + "sha256:5d8656b98057329bd03d968aac8d5198389cf51517511295cfc4cb827a507e39", + "sha256:5dcfb3e823ef4b91b70b92848570d1d8cfd584304bd2bd54272dc100c9494def", + "sha256:5e40d23ea43f683f3a7c032dde391104f609b05c21b6d284101120b51dbd50c1", + "sha256:63a01522bde161c713f7fa5ee5d850fee6386fc386073490ebcd438f14579cf2", + "sha256:6b2a3d7756035dde13571f4ad232629b78b7f35c2cd5fda7b464079fc697db3a", + "sha256:6b3be1a6bf6c965aea3b4e3a40df9d2c134c516d89c76cf2b6c81f67e6c5c6ed", + "sha256:6c7bea3357f2dc653756e6da55f66cd21c73d3875c8f3dc4e8d196a876252de0", + "sha256:6e6c8e229507cf29333a2f491cbaa7dff5b8a4a3e613af8090ccce9ce3e4f7a0", + "sha256:6fad27f2a63884ee45d491aebec4b1f38752cd6aaccc625038c21e7f43c02c49", + "sha256:71bfef52547c2b8b145897fa8d1b5142bc52313cfa38c0742e0ef755f0d09c60", + "sha256:72370d312323282b1bf74426e53fae861a310d7ae519b419da46673c38e7d147", + "sha256:76c7d36043a9c478b0c846fcec7da5cb095983722473e503e0122ccd170182b5", + "sha256:78d8a81ef51edb9a2f278a6fb278789b49e304b12bb21bccf2fe7e344f71a9fb", + "sha256:798a6b159ce32181a5e7ab7611c17d1080e74a5541fec47f961b728dab25a76f", + "sha256:7e370567f66a57e2c0e3ae2afcc6f126e1d6babd36831cfd0caad279b05c1c88", + "sha256:8004b845f606b95a8b17efa112aa10b327e46e95dcda604a257b4633d4ed45c8", + "sha256:80b20bf9ea4e709b3b9ae364ac298dfa872b084c186e5c1d60b0b79c79a7ee7e", + "sha256:87303f4bb1b493997f911a4f126123ccd2827d3a2e7dd2390cc6143fbc75805b", + "sha256:8d423f4631395b92dceda39f481a463498131ac02a58581124a44495491f715b", + "sha256:94ee262192db50fb9c069a0be7bb1a426fb1b43af26ce12bf4c6c30e13f46b56", + "sha256:960e4be2e7de340300ab4bcc2b45bed46be1d62330575b8265e6602dbcb9a14c", + "sha256:99397d5e1da6b345cec3e6125e2902b0e6864eb8eaa4be43a2013f059c502c93", + "sha256:9abbb8c1bad08817bad62ae1ea76c01bdbd0ee8c827d05f3ba038c9f6d6f14bb", + "sha256:9c0b8fadf80bc70d341032f92702bda1b0ed78c01e9c495f0df701938c99bcf5", + "sha256:9f977da9abae170eebdcf02bda33727c342fad5dcdbc08498bfdfb6cc6c65489", + "sha256:a6be712ca39d5e9c89b705bc9800be36739436fefb8d0b52b2d332f7d6d22a01", + "sha256:aa434418d6ee44b0ba3a5a407bc9e1543cf496328f43f149e9b58f74a63d5c21", + "sha256:ac4f778e32f7de0ba63346893a4af87c2280ffc1783f594a117be51d908a10da", + "sha256:ac85d65ee369c09b2904b55078ad589961e2e2e03c810963d35a26e6a3931425", + "sha256:ad5d78c664d39960435d4162db31117c8945ba74fb0c414e79ba85a8bdeafdec", + "sha256:ad91f57c3485d87a8edee558dafab0f08c716857d748731c0998dcefe9d3fd5f", + "sha256:afd255d42b340036883ca95bded553b29065b064e2fe5db64ad5988517db9694", + "sha256:b1c2c74f100a0c2110a8e30445554ae331860d32f145c60a2a1e1c27702022a2", + "sha256:b49a8c71378d40d43c6a56eaa536d7823baa43c27c93e082aeb60a9717be0c10", + "sha256:b5f52611323e8e35705e6750a760f32165b41c052d22da154ae343871e7cd50d", + "sha256:b6bf99ae529ac359263269710356d3ddb173c15d8f8dc8849ae794ab811e5cd0", + "sha256:ba361bf87c4701f11241be92c99ef5cf916865dd225955cccb2376bf76717b3c", + "sha256:bc351aa2158575e68943d8e1d5531719ad86bf6607776627ed5a1a60657664af", + "sha256:bd6eb7b1e12e4dd0b75cab1b023272f1333494add5ad61deedac738af1ffeede", + "sha256:bf8852595f5e2d2b072e24c29394b5aca7fba96ecc8656d56660535f9e9872c9", + "sha256:c1dd66541569a2bdbe92589cc96a89f470b20d168f2238fd463e1b59ee3e2d49", + "sha256:c36a7a004cba4e370d0675826eeefe4e42a256638b6b1432263ddb4af317bc02", + "sha256:c886cda61da4d39010be84802bed11bc75f03e8a6094cc18016957a2c80254d4", + "sha256:cc7aa83946f80c66a5d2dea7e165f15aa3eb21e7b74b24d8f850afc0d44bb00e", + "sha256:cea9c4bef70d1358bafec6019164abce362f4de15d79d1ecd64ae31c1749d77a", + "sha256:cfe1951e80869695857986be104a40a1e7fa8ec7de05f86bcbd7bd20854be764", + "sha256:d36cf6f139da3279644794fcfda18af425c8bb122ef9c2e7c762a937bbf7b0f4", + "sha256:d81308faaa9393b7e6ed20718d465c4c2b73c24d5e4826024961acf4b87b1524", + "sha256:db51ea1f9c5ac790848bc271fcdf4108ad1b77a77c6949a96320477962cf7ba5", + "sha256:dd05c18c920a15e00d7a52df37bffd3930fe2c004c690f9422b20e12077e6dbd", + "sha256:df05918a11e1db0198d00486e36673b4b4a89390e4458ff9479b4908dde357ac", + "sha256:e4c31dccf6be131709e545d0258eb5b75c5fac304857ad3976331c6740e8b9d6", + "sha256:e60954d673040430802b29fe5bba698e262182b5ba5f302ff4458e39f8101881", + "sha256:e60e2d2c88a0552e61c37172fe377f6a8abf479130a445314886de4a360ba940", + "sha256:e786f773ddc153846b2ebdb854011cfd1f7c874b8ee79cced3706801341c9f5d", + "sha256:e7cd91548fb95b69edd376f5204e27115ac7d093ec7d80066123a5bdb31c71d9", + "sha256:eaef2ea4f5602aefaaf3d6e8235f3b9ffde35aff15aac1c16cc802f6bbf0a3b5", + "sha256:ec8c5ea93a03775fbadd08462200cf34ce617ec75a032abfa44fd6d3a00e5424", + "sha256:eddeb8574bc9d9abb8491d4a46b60e553c2cea235b80373756acb06568101175", + "sha256:eeb300b0e4b428aab2f70d785cad4306529262af6de8c8c5fe6a4b41a674a434", + "sha256:f39d71ece8e97cf069e4154868eaac1256b133fe23e0459829432e4bb6406472", + "sha256:f4840ddad2b9d53710e92361391944da89e3576641a290066a1719520059247c", + "sha256:f70723a00bcbce0f9a216853139955be45da35741335eb3afead304e77662560", + "sha256:f829cf2ba5b553e6529d6238928c07096f1feb47f4ad536b7f06bca6cc77173f", + "sha256:f96386910467725895f7972939a6faabd6e96b1de0cc2c092e4bd2c40e956e25", + "sha256:fe259a9d6f555bc79aed9bb4b9a7fff73db443b4c483e4a81a428c8a2860428b" + ], + "markers": "python_version >= '3.7'", + "version": "==5.0.8" + }, + "jinja2": { + "hashes": [ + "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", + "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67" + ], + "markers": "python_version >= '3.7'", + "version": "==3.1.6" + }, + "jsonschema": { + "hashes": [ + "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", + "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566" + ], + "markers": "python_version >= '3.8'", + "version": "==4.23.0" + }, + "jsonschema-specifications": { + "hashes": [ + "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272", + "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf" + ], + "markers": "python_version >= '3.9'", + "version": "==2024.10.1" + }, + "markupsafe": { + "hashes": [ + "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", + "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", + "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0", + "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", + "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", + "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13", + "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", + "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", + "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", + "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", + "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0", + "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", + "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", + "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", + "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", + "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff", + "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", + "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", + "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", + "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", + "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", + "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", + "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", + "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", + "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a", + "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", + "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", + "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", + "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", + "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144", + "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f", + "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", + "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", + "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", + "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", + "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", + "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", + "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", + "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", + "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", + "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", + "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", + "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", + "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", + "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", + "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", + "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", + "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", + "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29", + "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", + "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", + "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", + "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", + "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", + "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", + "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a", + "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178", + "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", + "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", + "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", + "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50" + ], + "markers": "python_version >= '3.9'", + "version": "==3.0.2" + }, + "mistune": { + "hashes": [ + "sha256:1a32314113cff28aa6432e99e522677c8587fd83e3d51c29b82a52409c842bd9", + "sha256:a7035c21782b2becb6be62f8f25d3df81ccb4d6fa477a6525b15af06539f02a0" + ], + "markers": "python_version >= '3.8'", + "version": "==3.1.3" + }, + "multidict": { + "hashes": [ + "sha256:0085b0afb2446e57050140240a8595846ed64d1cbd26cef936bfab3192c673b8", + "sha256:042028348dc5a1f2be6c666437042a98a5d24cee50380f4c0902215e5ec41844", + "sha256:05fefbc3cddc4e36da209a5e49f1094bbece9a581faa7f3589201fd95df40e5d", + "sha256:063be88bd684782a0715641de853e1e58a2f25b76388538bd62d974777ce9bc2", + "sha256:07bfa8bc649783e703263f783f73e27fef8cd37baaad4389816cf6a133141331", + "sha256:08549895e6a799bd551cf276f6e59820aa084f0f90665c0f03dd3a50db5d3c48", + "sha256:095a2eabe8c43041d3e6c2cb8287a257b5f1801c2d6ebd1dd877424f1e89cf29", + "sha256:0b183a959fb88ad1be201de2c4bdf52fa8e46e6c185d76201286a97b6f5ee65c", + "sha256:0c383d28857f66f5aebe3e91d6cf498da73af75fbd51cedbe1adfb85e90c0460", + "sha256:0d57a01a2a9fa00234aace434d8c131f0ac6e0ac6ef131eda5962d7e79edfb5b", + "sha256:0dc25a3293c50744796e87048de5e68996104d86d940bb24bc3ec31df281b191", + "sha256:0e5a644e50ef9fb87878d4d57907f03a12410d2aa3b93b3acdf90a741df52c49", + "sha256:0f249badb360b0b4d694307ad40f811f83df4da8cef7b68e429e4eea939e49dd", + "sha256:0f74f2fc51555f4b037ef278efc29a870d327053aba5cb7d86ae572426c7cccc", + "sha256:125dd82b40f8c06d08d87b3510beaccb88afac94e9ed4a6f6c71362dc7dbb04b", + "sha256:13551d0e2d7201f0959725a6a769b6f7b9019a168ed96006479c9ac33fe4096b", + "sha256:14ed9ed1bfedd72a877807c71113deac292bf485159a29025dfdc524c326f3e1", + "sha256:163f4604e76639f728d127293d24c3e208b445b463168af3d031b92b0998bb90", + "sha256:19e2819b0b468174de25c0ceed766606a07cedeab132383f1e83b9a4e96ccb4f", + "sha256:1e2a2193d3aa5cbf5758f6d5680a52aa848e0cf611da324f71e5e48a9695cc86", + "sha256:1f3c099d3899b14e1ce52262eb82a5f5cb92157bb5106bf627b618c090a0eadc", + "sha256:214207dcc7a6221d9942f23797fe89144128a71c03632bf713d918db99bd36de", + "sha256:2325105e16d434749e1be8022f942876a936f9bece4ec41ae244e3d7fae42aaf", + "sha256:2529ddbdaa424b2c6c2eb668ea684dd6b75b839d0ad4b21aad60c168269478d7", + "sha256:256d431fe4583c5f1e0f2e9c4d9c22f3a04ae96009b8cfa096da3a8723db0a16", + "sha256:25bb96338512e2f46f615a2bb7c6012fe92a4a5ebd353e5020836a7e33120349", + "sha256:2e87f1926e91855ae61769ba3e3f7315120788c099677e0842e697b0bfb659f2", + "sha256:2fc6af8e39f7496047c7876314f4317736eac82bf85b54c7c76cf1a6f8e35d98", + "sha256:3157126b028c074951839233647bd0e30df77ef1fedd801b48bdcad242a60f4e", + "sha256:32c9b4878f48be3e75808ea7e499d6223b1eea6d54c487a66bc10a1871e3dc6a", + "sha256:32ed748ff9ac682eae7859790d3044b50e3076c7d80e17a44239683769ff485e", + "sha256:3501621d5e86f1a88521ea65d5cad0a0834c77b26f193747615b7c911e5422d2", + "sha256:437c33561edb6eb504b5a30203daf81d4a9b727e167e78b0854d9a4e18e8950b", + "sha256:48d39b1824b8d6ea7de878ef6226efbe0773f9c64333e1125e0efcfdd18a24c7", + "sha256:4ac3fcf9a2d369bd075b2c2965544036a27ccd277fc3c04f708338cc57533081", + "sha256:4ccfd74957ef53fa7380aaa1c961f523d582cd5e85a620880ffabd407f8202c0", + "sha256:52b05e21ff05729fbea9bc20b3a791c3c11da61649ff64cce8257c82a020466d", + "sha256:5389445f0173c197f4a3613713b5fb3f3879df1ded2a1a2e4bc4b5b9c5441b7e", + "sha256:5c5e7d2e300d5cb3b2693b6d60d3e8c8e7dd4ebe27cd17c9cb57020cac0acb80", + "sha256:5d26547423e5e71dcc562c4acdc134b900640a39abd9066d7326a7cc2324c530", + "sha256:5dd7106d064d05896ce28c97da3f46caa442fe5a43bc26dfb258e90853b39b44", + "sha256:5f8cb1329f42fadfb40d6211e5ff568d71ab49be36e759345f91c69d1033d633", + "sha256:61d5541f27533f803a941d3a3f8a3d10ed48c12cf918f557efcbf3cd04ef265c", + "sha256:639556758c36093b35e2e368ca485dada6afc2bd6a1b1207d85ea6dfc3deab27", + "sha256:641cf2e3447c9ecff2f7aa6e9eee9eaa286ea65d57b014543a4911ff2799d08a", + "sha256:6aed763b6a1b28c46c055692836879328f0b334a6d61572ee4113a5d0c859872", + "sha256:6e2a2d6749e1ff2c9c76a72c6530d5baa601205b14e441e6d98011000f47a7ac", + "sha256:7243c5a6523c5cfeca76e063efa5f6a656d1d74c8b1fc64b2cd1e84e507f7e2a", + "sha256:76b34c12b013d813e6cb325e6bd4f9c984db27758b16085926bbe7ceeaace626", + "sha256:781b5dd1db18c9e9eacc419027b0acb5073bdec9de1675c0be25ceb10e2ad133", + "sha256:7c611345bbe7cb44aabb877cb94b63e86f2d0db03e382667dbd037866d44b4f8", + "sha256:83b78c680d4b15d33042d330c2fa31813ca3974197bddb3836a5c635a5fd013f", + "sha256:84e87a7d75fa36839a3a432286d719975362d230c70ebfa0948549cc38bd5b46", + "sha256:89b3857652183b8206a891168af47bac10b970d275bba1f6ee46565a758c078d", + "sha256:8cd1a0644ccaf27e9d2f6d9c9474faabee21f0578fe85225cc5af9a61e1653df", + "sha256:8de4d42dffd5ced9117af2ce66ba8722402541a3aa98ffdf78dde92badb68932", + "sha256:94a7bb972178a8bfc4055db80c51efd24baefaced5e51c59b0d598a004e8305d", + "sha256:98aa8325c7f47183b45588af9c434533196e241be0a4e4ae2190b06d17675c02", + "sha256:9e658d1373c424457ddf6d55ec1db93c280b8579276bebd1f72f113072df8a5d", + "sha256:9f49585f4abadd2283034fc605961f40c638635bc60f5162276fec075f2e37a4", + "sha256:9f6cad071960ba1914fa231677d21b1b4a3acdcce463cee41ea30bc82e6040cf", + "sha256:a0cc398350ef31167e03f3ca7c19313d4e40a662adcb98a88755e4e861170bdd", + "sha256:a1133414b771619aa3c3000701c11b2e4624a7f492f12f256aedde97c28331a2", + "sha256:a33273a541f1e1a8219b2a4ed2de355848ecc0254264915b9290c8d2de1c74e1", + "sha256:a3c0ff89fe40a152e77b191b83282c9664357dce3004032d42e68c514ceff27e", + "sha256:a49994481b99cd7dedde07f2e7e93b1d86c01c0fca1c32aded18f10695ae17eb", + "sha256:abf5b17bc0cf626a8a497d89ac691308dbd825d2ac372aa990b1ca114e470151", + "sha256:ac380cacdd3b183338ba63a144a34e9044520a6fb30c58aa14077157a033c13e", + "sha256:ad81012b24b88aad4c70b2cbc2dad84018783221b7f923e926f4690ff8569da3", + "sha256:b2c00ad31fbc2cbac85d7d0fcf90853b2ca2e69d825a2d3f3edb842ef1544a2c", + "sha256:b4c153863dd6569f6511845922c53e39c8d61f6e81f228ad5443e690fca403de", + "sha256:b4f3d66dd0354b79761481fc15bdafaba0b9d9076f1f42cc9ce10d7fcbda205a", + "sha256:b99aac6bb2c37db336fa03a39b40ed4ef2818bf2dfb9441458165ebe88b793af", + "sha256:b9f6392d98c0bd70676ae41474e2eecf4c7150cb419237a41f8f96043fcb81d1", + "sha256:c537da54ce4ff7c15e78ab1292e5799d0d43a2108e006578a57f531866f64025", + "sha256:ca23db5fb195b5ef4fd1f77ce26cadefdf13dba71dab14dadd29b34d457d7c44", + "sha256:cc826b9a8176e686b67aa60fd6c6a7047b0461cae5591ea1dc73d28f72332a8a", + "sha256:cca83a629f77402cfadd58352e394d79a61c8015f1694b83ab72237ec3941f88", + "sha256:cf8d370b2fea27fb300825ec3984334f7dd54a581bde6456799ba3776915a656", + "sha256:d1175b0e0d6037fab207f05774a176d71210ebd40b1c51f480a04b65ec5c786d", + "sha256:d1996ee1330e245cd3aeda0887b4409e3930524c27642b046e4fae88ffa66c5e", + "sha256:d5a36953389f35f0a4e88dc796048829a2f467c9197265504593f0e420571547", + "sha256:da51d8928ad8b4244926fe862ba1795f0b6e68ed8c42cd2f822d435db9c2a8f4", + "sha256:e16e7297f29a544f49340012d6fc08cf14de0ab361c9eb7529f6a57a30cbfda1", + "sha256:e25b11a0417475f093d0f0809a149aff3943c2c56da50fdf2c3c88d57fe3dfbd", + "sha256:e4371591e621579cb6da8401e4ea405b33ff25a755874a3567c4075ca63d56e2", + "sha256:e653d36b1bf48fa78c7fcebb5fa679342e025121ace8c87ab05c1cefd33b34fc", + "sha256:e7d91a230c7f8af86c904a5a992b8c064b66330544693fd6759c3d6162382ecf", + "sha256:e851e6363d0dbe515d8de81fd544a2c956fdec6f8a049739562286727d4a00c3", + "sha256:ef7d48207926edbf8b16b336f779c557dd8f5a33035a85db9c4b0febb0706817", + "sha256:f7716f7e7138252d88607228ce40be22660d6608d20fd365d596e7ca0738e019", + "sha256:facaf11f21f3a4c51b62931feb13310e6fe3475f85e20d9c9fdce0d2ea561b87" + ], + "markers": "python_version >= '3.9'", + "version": "==6.2.0" + }, + "niquests": { + "hashes": [ + "sha256:68e0a7e9f338466b3606945fffd11f75e3c90af7498aa9336ef03812323b7e36", + "sha256:86e484c2c60444aa96069c15f6295af6e25a8bad50781e1326df1b5c7ab48339" + ], + "markers": "python_version >= '3.7'", + "version": "==3.14.0" + }, + "numpy": { + "hashes": [ + "sha256:05c076d531e9998e7e694c36e8b349969c56eadd2cdcd07242958489d79a7286", + "sha256:0d54974f9cf14acf49c60f0f7f4084b6579d24d439453d5fc5805d46a165b542", + "sha256:11c43995255eb4127115956495f43e9343736edb7fcdb0d973defd9de14cd84f", + "sha256:188dcbca89834cc2e14eb2f106c96d6d46f200fe0200310fc29089657379c58d", + "sha256:1974afec0b479e50438fc3648974268f972e2d908ddb6d7fb634598cdb8260a0", + "sha256:1cf4e5c6a278d620dee9ddeb487dc6a860f9b199eadeecc567f777daace1e9e7", + "sha256:207a2b8441cc8b6a2a78c9ddc64d00d20c303d79fba08c577752f080c4007ee3", + "sha256:218f061d2faa73621fa23d6359442b0fc658d5b9a70801373625d958259eaca3", + "sha256:2aad3c17ed2ff455b8eaafe06bcdae0062a1db77cb99f4b9cbb5f4ecb13c5146", + "sha256:2fa8fa7697ad1646b5c93de1719965844e004fcad23c91228aca1cf0800044a1", + "sha256:31504f970f563d99f71a3512d0c01a645b692b12a63630d6aafa0939e52361e6", + "sha256:3387dd7232804b341165cedcb90694565a6015433ee076c6754775e85d86f1fc", + "sha256:4ba5054787e89c59c593a4169830ab362ac2bee8a969249dc56e5d7d20ff8df9", + "sha256:4f92084defa704deadd4e0a5ab1dc52d8ac9e8a8ef617f3fbb853e79b0ea3592", + "sha256:65ef3468b53269eb5fdb3a5c09508c032b793da03251d5f8722b1194f1790c00", + "sha256:6f527d8fdb0286fd2fd97a2a96c6be17ba4232da346931d967a0630050dfd298", + "sha256:7051ee569db5fbac144335e0f3b9c2337e0c8d5c9fee015f259a5bd70772b7e8", + "sha256:7716e4a9b7af82c06a2543c53ca476fa0b57e4d760481273e09da04b74ee6ee2", + "sha256:79bd5f0a02aa16808fcbc79a9a376a147cc1045f7dfe44c6e7d53fa8b8a79392", + "sha256:7a4e84a6283b36632e2a5b56e121961f6542ab886bc9e12f8f9818b3c266bfbb", + "sha256:8120575cb4882318c791f839a4fd66161a6fa46f3f0a5e613071aae35b5dd8f8", + "sha256:81413336ef121a6ba746892fad881a83351ee3e1e4011f52e97fba79233611fd", + "sha256:8146f3550d627252269ac42ae660281d673eb6f8b32f113538e0cc2a9aed42b9", + "sha256:879cf3a9a2b53a4672a168c21375166171bc3932b7e21f622201811c43cdd3b0", + "sha256:892c10d6a73e0f14935c31229e03325a7b3093fafd6ce0af704be7f894d95687", + "sha256:92bda934a791c01d6d9d8e038363c50918ef7c40601552a58ac84c9613a665bc", + "sha256:9ba03692a45d3eef66559efe1d1096c4b9b75c0986b5dff5530c378fb8331d4f", + "sha256:9eeea959168ea555e556b8188da5fa7831e21d91ce031e95ce23747b7609f8a4", + "sha256:a0258ad1f44f138b791327961caedffbf9612bfa504ab9597157806faa95194a", + "sha256:a761ba0fa886a7bb33c6c8f6f20213735cb19642c580a931c625ee377ee8bd39", + "sha256:a7b9084668aa0f64e64bd00d27ba5146ef1c3a8835f3bd912e7a9e01326804c4", + "sha256:a84eda42bd12edc36eb5b53bbcc9b406820d3353f1994b6cfe453a33ff101775", + "sha256:ab2939cd5bec30a7430cbdb2287b63151b77cf9624de0532d629c9a1c59b1d5c", + "sha256:ac0280f1ba4a4bfff363a99a6aceed4f8e123f8a9b234c89140f5e894e452ecd", + "sha256:adf8c1d66f432ce577d0197dceaac2ac00c0759f573f28516246351c58a85020", + "sha256:b4adfbbc64014976d2f91084915ca4e626fbf2057fb81af209c1a6d776d23e3d", + "sha256:bb649f8b207ab07caebba230d851b579a3c8711a851d29efe15008e31bb4de24", + "sha256:bce43e386c16898b91e162e5baaad90c4b06f9dcbe36282490032cec98dc8ae7", + "sha256:bd3ad3b0a40e713fc68f99ecfd07124195333f1e689387c180813f0e94309d6f", + "sha256:c3f7ac96b16955634e223b579a3e5798df59007ca43e8d451a0e6a50f6bfdfba", + "sha256:cf28633d64294969c019c6df4ff37f5698e8326db68cc2b66576a51fad634880", + "sha256:d0f35b19894a9e08639fd60a1ec1978cb7f5f7f1eace62f38dd36be8aecdef4d", + "sha256:db1f1c22173ac1c58db249ae48aa7ead29f534b9a948bc56828337aa84a32ed6", + "sha256:dbe512c511956b893d2dacd007d955a3f03d555ae05cfa3ff1c1ff6df8851854", + "sha256:df2f57871a96bbc1b69733cd4c51dc33bea66146b8c63cacbfed73eec0883017", + "sha256:e2f085ce2e813a50dfd0e01fbfc0c12bbe5d2063d99f8b29da30e544fb6483b8", + "sha256:e642d86b8f956098b564a45e6f6ce68a22c2c97a04f5acd3f221f57b8cb850ae", + "sha256:e9e0a277bb2eb5d8a7407e14688b85fd8ad628ee4e0c7930415687b6564207a4", + "sha256:ea2bb7e2ae9e37d96835b3576a4fa4b3a97592fbea8ef7c3587078b0068b8f09", + "sha256:ee4d528022f4c5ff67332469e10efe06a267e32f4067dc76bb7e2cddf3cd25ff", + "sha256:f05d4198c1bacc9124018109c5fba2f3201dbe7ab6e92ff100494f236209c960", + "sha256:f34dc300df798742b3d06515aa2a0aee20941c13579d7a2f2e10af01ae4901ee", + "sha256:f4162988a360a29af158aeb4a2f4f09ffed6a969c9776f8f3bdee9b06a8ab7e5", + "sha256:f486038e44caa08dbd97275a9a35a283a8f1d2f0ee60ac260a1790e76660833c", + "sha256:f7de08cbe5551911886d1ab60de58448c6df0f67d9feb7d1fb21e9875ef95e91" + ], + "markers": "python_version >= '3.10'", + "version": "==2.2.4" + }, + "packaging": { + "hashes": [ + "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", + "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" + ], + "markers": "python_version >= '3.8'", + "version": "==24.2" + }, + "pandas": { + "hashes": [ + "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a", + "sha256:15c0e1e02e93116177d29ff83e8b1619c93ddc9c49083f237d4312337a61165d", + "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5", + "sha256:1db71525a1538b30142094edb9adc10be3f3e176748cd7acc2240c2f2e5aa3a4", + "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0", + "sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32", + "sha256:31d0ced62d4ea3e231a9f228366919a5ea0b07440d9d4dac345376fd8e1477ea", + "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28", + "sha256:37e0aced3e8f539eccf2e099f65cdb9c8aa85109b0be6e93e2baff94264bdc6f", + "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348", + "sha256:38cf8125c40dae9d5acc10fa66af8ea6fdf760b2714ee482ca691fc66e6fcb18", + "sha256:3b71f27954685ee685317063bf13c7709a7ba74fc996b84fc6821c59b0f06468", + "sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5", + "sha256:4850ba03528b6dd51d6c5d273c46f183f39a9baf3f0143e566b89450965b105e", + "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", + "sha256:56534ce0746a58afaf7942ba4863e0ef81c9c50d3f0ae93e9497d6a41a057645", + "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", + "sha256:5dbca4c1acd72e8eeef4753eeca07de9b1db4f398669d5994086f788a5d7cc30", + "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3", + "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d", + "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb", + "sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3", + "sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039", + "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8", + "sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd", + "sha256:7eee9e7cea6adf3e3d24e304ac6b8300646e2a5d1cd3a3c2abed9101b0846761", + "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659", + "sha256:86976a1c5b25ae3f8ccae3a5306e443569ee3c3faf444dfd0f41cda24667ad57", + "sha256:8cd6d7cc958a3910f934ea8dbdf17b2364827bb4dafc38ce6eef6bb3d65ff09c", + "sha256:99df71520d25fade9db7c1076ac94eb994f4d2673ef2aa2e86ee039b6746d20c", + "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4", + "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a", + "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9", + "sha256:b8661b0238a69d7aafe156b7fa86c44b881387509653fdf857bebc5e4008ad42", + "sha256:ba96630bc17c875161df3818780af30e43be9b166ce51c9a18c1feae342906c2", + "sha256:bc6b93f9b966093cb0fd62ff1a7e4c09e6d546ad7c1de191767baffc57628f39", + "sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc", + "sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698", + "sha256:d9c45366def9a3dd85a6454c0e7908f2b3b8e9c138f5dc38fed7ce720d8453ed", + "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015", + "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24", + "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319" + ], + "markers": "python_version >= '3.9'", + "version": "==2.2.3" + }, + "pika": { + "hashes": [ + "sha256:0779a7c1fafd805672796085560d290213a465e4f6f76a6fb19e378d8041a14f", + "sha256:b2a327ddddf8570b4965b3576ac77091b850262d34ce8c1d8cb4e4146aa4145f" + ], + "markers": "python_version >= '3.7'", + "version": "==1.3.2" + }, + "pluggy": { + "hashes": [ + "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", + "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" + ], + "markers": "python_version >= '3.8'", + "version": "==1.5.0" + }, + "prometheus-client": { + "hashes": [ + "sha256:252505a722ac04b0456be05c05f75f45d760c2911ffc45f2a06bcaed9f3ae3fb", + "sha256:594b45c410d6f4f8888940fe80b5cc2521b305a1fafe1c58609ef715a001f301" + ], + "markers": "python_version >= '3.8'", + "version": "==0.21.1" + }, + "prometheus-flask-exporter": { + "hashes": [ + "sha256:41fc9bbd7d48cc958ed8384aacf60c3621d9e903768be61c4e7f0c63872eaf1a", + "sha256:94922a636d4c1d8b68e1ee605c30a23e9bbb0b21756df8222aa919634871784c" + ], + "index": "pypi", + "version": "==0.23.2" + }, + "propcache": { + "hashes": [ + "sha256:050b571b2e96ec942898f8eb46ea4bfbb19bd5502424747e83badc2d4a99a44e", + "sha256:05543250deac8e61084234d5fc54f8ebd254e8f2b39a16b1dce48904f45b744b", + "sha256:069e7212890b0bcf9b2be0a03afb0c2d5161d91e1bf51569a64f629acc7defbf", + "sha256:09400e98545c998d57d10035ff623266927cb784d13dd2b31fd33b8a5316b85b", + "sha256:0c3c3a203c375b08fd06a20da3cf7aac293b834b6f4f4db71190e8422750cca5", + "sha256:0c86e7ceea56376216eba345aa1fc6a8a6b27ac236181f840d1d7e6a1ea9ba5c", + "sha256:0fbe94666e62ebe36cd652f5fc012abfbc2342de99b523f8267a678e4dfdee3c", + "sha256:17d1c688a443355234f3c031349da69444be052613483f3e4158eef751abcd8a", + "sha256:19a06db789a4bd896ee91ebc50d059e23b3639c25d58eb35be3ca1cbe967c3bf", + "sha256:1c5c7ab7f2bb3f573d1cb921993006ba2d39e8621019dffb1c5bc94cdbae81e8", + "sha256:1eb34d90aac9bfbced9a58b266f8946cb5935869ff01b164573a7634d39fbcb5", + "sha256:1f6cc0ad7b4560e5637eb2c994e97b4fa41ba8226069c9277eb5ea7101845b42", + "sha256:27c6ac6aa9fc7bc662f594ef380707494cb42c22786a558d95fcdedb9aa5d035", + "sha256:2d219b0dbabe75e15e581fc1ae796109b07c8ba7d25b9ae8d650da582bed01b0", + "sha256:2fce1df66915909ff6c824bbb5eb403d2d15f98f1518e583074671a30fe0c21e", + "sha256:319fa8765bfd6a265e5fa661547556da381e53274bc05094fc9ea50da51bfd46", + "sha256:359e81a949a7619802eb601d66d37072b79b79c2505e6d3fd8b945538411400d", + "sha256:3a02a28095b5e63128bcae98eb59025924f121f048a62393db682f049bf4ac24", + "sha256:3e19ea4ea0bf46179f8a3652ac1426e6dcbaf577ce4b4f65be581e237340420d", + "sha256:3e584b6d388aeb0001d6d5c2bd86b26304adde6d9bb9bfa9c4889805021b96de", + "sha256:40d980c33765359098837527e18eddefc9a24cea5b45e078a7f3bb5b032c6ecf", + "sha256:4114c4ada8f3181af20808bedb250da6bae56660e4b8dfd9cd95d4549c0962f7", + "sha256:43593c6772aa12abc3af7784bff4a41ffa921608dd38b77cf1dfd7f5c4e71371", + "sha256:47ef24aa6511e388e9894ec16f0fbf3313a53ee68402bc428744a367ec55b833", + "sha256:4cf9e93a81979f1424f1a3d155213dc928f1069d697e4353edb8a5eba67c6259", + "sha256:4d0dfdd9a2ebc77b869a0b04423591ea8823f791293b527dc1bb896c1d6f1136", + "sha256:563f9d8c03ad645597b8d010ef4e9eab359faeb11a0a2ac9f7b4bc8c28ebef25", + "sha256:58aa11f4ca8b60113d4b8e32d37e7e78bd8af4d1a5b5cb4979ed856a45e62005", + "sha256:5a0a9898fdb99bf11786265468571e628ba60af80dc3f6eb89a3545540c6b0ef", + "sha256:5aed8d8308215089c0734a2af4f2e95eeb360660184ad3912686c181e500b2e7", + "sha256:5b9145c35cc87313b5fd480144f8078716007656093d23059e8993d3a8fa730f", + "sha256:5cb5918253912e088edbf023788de539219718d3b10aef334476b62d2b53de53", + "sha256:5cdb0f3e1eb6dfc9965d19734d8f9c481b294b5274337a8cb5cb01b462dcb7e0", + "sha256:5ced33d827625d0a589e831126ccb4f5c29dfdf6766cac441d23995a65825dcb", + "sha256:603f1fe4144420374f1a69b907494c3acbc867a581c2d49d4175b0de7cc64566", + "sha256:61014615c1274df8da5991a1e5da85a3ccb00c2d4701ac6f3383afd3ca47ab0a", + "sha256:64a956dff37080b352c1c40b2966b09defb014347043e740d420ca1eb7c9b908", + "sha256:668ddddc9f3075af019f784456267eb504cb77c2c4bd46cc8402d723b4d200bf", + "sha256:6d8e309ff9a0503ef70dc9a0ebd3e69cf7b3894c9ae2ae81fc10943c37762458", + "sha256:6f173bbfe976105aaa890b712d1759de339d8a7cef2fc0a1714cc1a1e1c47f64", + "sha256:71ebe3fe42656a2328ab08933d420df5f3ab121772eef78f2dc63624157f0ed9", + "sha256:730178f476ef03d3d4d255f0c9fa186cb1d13fd33ffe89d39f2cda4da90ceb71", + "sha256:7d2d5a0028d920738372630870e7d9644ce437142197f8c827194fca404bf03b", + "sha256:7f30241577d2fef2602113b70ef7231bf4c69a97e04693bde08ddab913ba0ce5", + "sha256:813fbb8b6aea2fc9659815e585e548fe706d6f663fa73dff59a1677d4595a037", + "sha256:82de5da8c8893056603ac2d6a89eb8b4df49abf1a7c19d536984c8dd63f481d5", + "sha256:83be47aa4e35b87c106fc0c84c0fc069d3f9b9b06d3c494cd404ec6747544894", + "sha256:8638f99dca15b9dff328fb6273e09f03d1c50d9b6512f3b65a4154588a7595fe", + "sha256:87380fb1f3089d2a0b8b00f006ed12bd41bd858fabfa7330c954c70f50ed8757", + "sha256:88c423efef9d7a59dae0614eaed718449c09a5ac79a5f224a8b9664d603f04a3", + "sha256:89498dd49c2f9a026ee057965cdf8192e5ae070ce7d7a7bd4b66a8e257d0c976", + "sha256:8a17583515a04358b034e241f952f1715243482fc2c2945fd99a1b03a0bd77d6", + "sha256:916cd229b0150129d645ec51614d38129ee74c03293a9f3f17537be0029a9641", + "sha256:9532ea0b26a401264b1365146c440a6d78269ed41f83f23818d4b79497aeabe7", + "sha256:967a8eec513dbe08330f10137eacb427b2ca52118769e82ebcfcab0fba92a649", + "sha256:975af16f406ce48f1333ec5e912fe11064605d5c5b3f6746969077cc3adeb120", + "sha256:9979643ffc69b799d50d3a7b72b5164a2e97e117009d7af6dfdd2ab906cb72cd", + "sha256:9a8ecf38de50a7f518c21568c80f985e776397b902f1ce0b01f799aba1608b40", + "sha256:9cec3239c85ed15bfaded997773fdad9fb5662b0a7cbc854a43f291eb183179e", + "sha256:9e64e948ab41411958670f1093c0a57acfdc3bee5cf5b935671bbd5313bcf229", + "sha256:9f64d91b751df77931336b5ff7bafbe8845c5770b06630e27acd5dbb71e1931c", + "sha256:a0ab8cf8cdd2194f8ff979a43ab43049b1df0b37aa64ab7eca04ac14429baeb7", + "sha256:a110205022d077da24e60b3df8bcee73971be9575dec5573dd17ae5d81751111", + "sha256:a34aa3a1abc50740be6ac0ab9d594e274f59960d3ad253cd318af76b996dd654", + "sha256:a444192f20f5ce8a5e52761a031b90f5ea6288b1eef42ad4c7e64fef33540b8f", + "sha256:a461959ead5b38e2581998700b26346b78cd98540b5524796c175722f18b0294", + "sha256:a75801768bbe65499495660b777e018cbe90c7980f07f8aa57d6be79ea6f71da", + "sha256:aa8efd8c5adc5a2c9d3b952815ff8f7710cefdcaf5f2c36d26aff51aeca2f12f", + "sha256:aca63103895c7d960a5b9b044a83f544b233c95e0dcff114389d64d762017af7", + "sha256:b0313e8b923b3814d1c4a524c93dfecea5f39fa95601f6a9b1ac96cd66f89ea0", + "sha256:b23c11c2c9e6d4e7300c92e022046ad09b91fd00e36e83c44483df4afa990073", + "sha256:b303b194c2e6f171cfddf8b8ba30baefccf03d36a4d9cab7fd0bb68ba476a3d7", + "sha256:b655032b202028a582d27aeedc2e813299f82cb232f969f87a4fde491a233f11", + "sha256:bd39c92e4c8f6cbf5f08257d6360123af72af9f4da75a690bef50da77362d25f", + "sha256:bef100c88d8692864651b5f98e871fb090bd65c8a41a1cb0ff2322db39c96c27", + "sha256:c2fe5c910f6007e716a06d269608d307b4f36e7babee5f36533722660e8c4a70", + "sha256:c66d8ccbc902ad548312b96ed8d5d266d0d2c6d006fd0f66323e9d8f2dd49be7", + "sha256:cd6a55f65241c551eb53f8cf4d2f4af33512c39da5d9777694e9d9c60872f519", + "sha256:d249609e547c04d190e820d0d4c8ca03ed4582bcf8e4e160a6969ddfb57b62e5", + "sha256:d4e89cde74154c7b5957f87a355bb9c8ec929c167b59c83d90654ea36aeb6180", + "sha256:dc1915ec523b3b494933b5424980831b636fe483d7d543f7afb7b3bf00f0c10f", + "sha256:e1c4d24b804b3a87e9350f79e2371a705a188d292fd310e663483af6ee6718ee", + "sha256:e474fc718e73ba5ec5180358aa07f6aded0ff5f2abe700e3115c37d75c947e18", + "sha256:e4fe2a6d5ce975c117a6bb1e8ccda772d1e7029c1cca1acd209f91d30fa72815", + "sha256:e7fb9a84c9abbf2b2683fa3e7b0d7da4d8ecf139a1c635732a8bda29c5214b0e", + "sha256:e861ad82892408487be144906a368ddbe2dc6297074ade2d892341b35c59844a", + "sha256:ec314cde7314d2dd0510c6787326bbffcbdc317ecee6b7401ce218b3099075a7", + "sha256:ed5f6d2edbf349bd8d630e81f474d33d6ae5d07760c44d33cd808e2f5c8f4ae6", + "sha256:ef2e4e91fb3945769e14ce82ed53007195e616a63aa43b40fb7ebaaf907c8d4c", + "sha256:f011f104db880f4e2166bcdcf7f58250f7a465bc6b068dc84c824a3d4a5c94dc", + "sha256:f1528ec4374617a7a753f90f20e2f551121bb558fcb35926f99e3c42367164b8", + "sha256:f27785888d2fdd918bc36de8b8739f2d6c791399552333721b58193f68ea3e98", + "sha256:f35c7070eeec2cdaac6fd3fe245226ed2a6292d3ee8c938e5bb645b434c5f256", + "sha256:f3bbecd2f34d0e6d3c543fdb3b15d6b60dd69970c2b4c822379e5ec8f6f621d5", + "sha256:f6f1324db48f001c2ca26a25fa25af60711e09b9aaf4b28488602776f4f9a744", + "sha256:f78eb8422acc93d7b69964012ad7048764bb45a54ba7a39bb9e146c72ea29723", + "sha256:fb6e0faf8cb6b4beea5d6ed7b5a578254c6d7df54c36ccd3d8b3eb00d6770277", + "sha256:feccd282de1f6322f56f6845bf1207a537227812f0a9bf5571df52bb418d79d5" + ], + "markers": "python_version >= '3.9'", + "version": "==0.3.1" + }, + "pydantic": { + "hashes": [ + "sha256:442557d2910e75c991c39f4b4ab18963d57b9b55122c8b2a9cd176d8c29ce968", + "sha256:5b6c415eee9f8123a14d859be0c84363fec6b1feb6b688d6435801230b56e0b8" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==2.11.1" + }, + "pydantic-core": { + "hashes": [ + "sha256:024d136ae44d233e6322027bbf356712b3940bee816e6c948ce4b90f18471b3d", + "sha256:0310524c833d91403c960b8a3cf9f46c282eadd6afd276c8c5edc617bd705dc9", + "sha256:07b4ced28fccae3f00626eaa0c4001aa9ec140a29501770a88dbbb0966019a86", + "sha256:085d8985b1c1e48ef271e98a658f562f29d89bda98bf120502283efbc87313eb", + "sha256:0a98257451164666afafc7cbf5fb00d613e33f7e7ebb322fbcd99345695a9a61", + "sha256:0bcf0bab28995d483f6c8d7db25e0d05c3efa5cebfd7f56474359e7137f39856", + "sha256:138d31e3f90087f42aa6286fb640f3c7a8eb7bdae829418265e7e7474bd2574b", + "sha256:14229c1504287533dbf6b1fc56f752ce2b4e9694022ae7509631ce346158de11", + "sha256:1583539533160186ac546b49f5cde9ffc928062c96920f58bd95de32ffd7bffd", + "sha256:175ab598fb457a9aee63206a1993874badf3ed9a456e0654273e56f00747bbd6", + "sha256:1a69b7596c6603afd049ce7f3835bcf57dd3892fc7279f0ddf987bebed8caa5a", + "sha256:1a73be93ecef45786d7d95b0c5e9b294faf35629d03d5b145b09b81258c7cd6d", + "sha256:1b1262b912435a501fa04cd213720609e2cefa723a07c92017d18693e69bf00b", + "sha256:1b2ea72dea0825949a045fa4071f6d5b3d7620d2a208335207793cf29c5a182d", + "sha256:20d4275f3c4659d92048c70797e5fdc396c6e4446caf517ba5cad2db60cd39d3", + "sha256:23c3e77bf8a7317612e5c26a3b084c7edeb9552d645742a54a5867635b4f2453", + "sha256:26a4ea04195638dcd8c53dadb545d70badba51735b1594810e9768c2c0b4a5da", + "sha256:26bc7367c0961dec292244ef2549afa396e72e28cc24706210bd44d947582c59", + "sha256:2a0147c0bef783fd9abc9f016d66edb6cac466dc54a17ec5f5ada08ff65caf5d", + "sha256:2c0afd34f928383e3fd25740f2050dbac9d077e7ba5adbaa2227f4d4f3c8da5c", + "sha256:30369e54d6d0113d2aa5aee7a90d17f225c13d87902ace8fcd7bbf99b19124db", + "sha256:31860fbda80d8f6828e84b4a4d129fd9c4535996b8249cfb8c720dc2a1a00bb8", + "sha256:34e7fb3abe375b5c4e64fab75733d605dda0f59827752debc99c17cb2d5f3276", + "sha256:40eb8af662ba409c3cbf4a8150ad32ae73514cd7cb1f1a2113af39763dd616b3", + "sha256:41d698dcbe12b60661f0632b543dbb119e6ba088103b364ff65e951610cb7ce0", + "sha256:4726f1f3f42d6a25678c67da3f0b10f148f5655813c5aca54b0d1742ba821b8f", + "sha256:4927564be53239a87770a5f86bdc272b8d1fbb87ab7783ad70255b4ab01aa25b", + "sha256:4b6d77c75a57f041c5ee915ff0b0bb58eabb78728b69ed967bc5b780e8f701b8", + "sha256:4d9149e7528af8bbd76cc055967e6e04617dcb2a2afdaa3dea899406c5521faa", + "sha256:4deac83a8cc1d09e40683be0bc6d1fa4cde8df0a9bf0cda5693f9b0569ac01b6", + "sha256:4f1ab031feb8676f6bd7c85abec86e2935850bf19b84432c64e3e239bffeb1ec", + "sha256:502ed542e0d958bd12e7c3e9a015bce57deaf50eaa8c2e1c439b512cb9db1e3a", + "sha256:5461934e895968655225dfa8b3be79e7e927e95d4bd6c2d40edd2fa7052e71b6", + "sha256:58c1151827eef98b83d49b6ca6065575876a02d2211f259fb1a6b7757bd24dd8", + "sha256:5bdd36b362f419c78d09630cbaebc64913f66f62bda6d42d5fbb08da8cc4f181", + "sha256:5bf637300ff35d4f59c006fff201c510b2b5e745b07125458a5389af3c0dff8c", + "sha256:5bf68bb859799e9cec3d9dd8323c40c00a254aabb56fe08f907e437005932f2b", + "sha256:5d8dc9f63a26f7259b57f46a7aab5af86b2ad6fbe48487500bb1f4b27e051e4c", + "sha256:5f36afd0d56a6c42cf4e8465b6441cf546ed69d3a4ec92724cc9c8c61bd6ecf4", + "sha256:5f72914cfd1d0176e58ddc05c7a47674ef4222c8253bf70322923e73e14a4ac3", + "sha256:6291797cad239285275558e0a27872da735b05c75d5237bbade8736f80e4c225", + "sha256:62c151ce3d59ed56ebd7ce9ce5986a409a85db697d25fc232f8e81f195aa39a1", + "sha256:635702b2fed997e0ac256b2cfbdb4dd0bf7c56b5d8fba8ef03489c03b3eb40e2", + "sha256:64672fa888595a959cfeff957a654e947e65bbe1d7d82f550417cbd6898a1d6b", + "sha256:68504959253303d3ae9406b634997a2123a0b0c1da86459abbd0ffc921695eac", + "sha256:69297418ad644d521ea3e1aa2e14a2a422726167e9ad22b89e8f1130d68e1e9a", + "sha256:6c32a40712e3662bebe524abe8abb757f2fa2000028d64cc5a1006016c06af43", + "sha256:715c62af74c236bf386825c0fdfa08d092ab0f191eb5b4580d11c3189af9d330", + "sha256:71dffba8fe9ddff628c68f3abd845e91b028361d43c5f8e7b3f8b91d7d85413e", + "sha256:7419241e17c7fbe5074ba79143d5523270e04f86f1b3a0dff8df490f84c8273a", + "sha256:759871f00e26ad3709efc773ac37b4d571de065f9dfb1778012908bcc36b3a73", + "sha256:7a25493320203005d2a4dac76d1b7d953cb49bce6d459d9ae38e30dd9f29bc9c", + "sha256:7b79af799630af263eca9ec87db519426d8c9b3be35016eddad1832bac812d87", + "sha256:7c9c84749f5787781c1c45bb99f433402e484e515b40675a5d121ea14711cf61", + "sha256:7da333f21cd9df51d5731513a6d39319892947604924ddf2e24a4612975fb936", + "sha256:82a4eba92b7ca8af1b7d5ef5f3d9647eee94d1f74d21ca7c21e3a2b92e008358", + "sha256:89670d7a0045acb52be0566df5bc8b114ac967c662c06cf5e0c606e4aadc964b", + "sha256:8a1d581e8cdbb857b0e0e81df98603376c1a5c34dc5e54039dcc00f043df81e7", + "sha256:8ec86b5baa36f0a0bfb37db86c7d52652f8e8aa076ab745ef7725784183c3fdd", + "sha256:91301a0980a1d4530d4ba7e6a739ca1a6b31341252cb709948e0aca0860ce0ae", + "sha256:918f2013d7eadea1d88d1a35fd4a1e16aaf90343eb446f91cb091ce7f9b431a2", + "sha256:9cb2390355ba084c1ad49485d18449b4242da344dea3e0fe10babd1f0db7dcfc", + "sha256:9ee65f0cc652261744fd07f2c6e6901c914aa6c5ff4dcfaf1136bc394d0dd26b", + "sha256:a608a75846804271cf9c83e40bbb4dab2ac614d33c6fd5b0c6187f53f5c593ef", + "sha256:a66d931ea2c1464b738ace44b7334ab32a2fd50be023d863935eb00f42be1778", + "sha256:a7a7f2a3f628d2f7ef11cb6188bcf0b9e1558151d511b974dfea10a49afe192b", + "sha256:abaeec1be6ed535a5d7ffc2e6c390083c425832b20efd621562fbb5bff6dc518", + "sha256:abfa44cf2f7f7d7a199be6c6ec141c9024063205545aa09304349781b9a125e6", + "sha256:ade5dbcf8d9ef8f4b28e682d0b29f3008df9842bb5ac48ac2c17bc55771cc976", + "sha256:ae62032ef513fe6281ef0009e30838a01057b832dc265da32c10469622613885", + "sha256:aec79acc183865bad120b0190afac467c20b15289050648b876b07777e67ea48", + "sha256:b716294e721d8060908dbebe32639b01bfe61b15f9f57bcc18ca9a0e00d9520b", + "sha256:b9ec80eb5a5f45a2211793f1c4aeddff0c3761d1c70d684965c1807e923a588b", + "sha256:ba95691cf25f63df53c1d342413b41bd7762d9acb425df8858d7efa616c0870e", + "sha256:bccc06fa0372151f37f6b69834181aa9eb57cf8665ed36405fb45fbf6cac3bae", + "sha256:c860773a0f205926172c6644c394e02c25421dc9a456deff16f64c0e299487d3", + "sha256:ca1103d70306489e3d006b0f79db8ca5dd3c977f6f13b2c59ff745249431a606", + "sha256:ce72d46eb201ca43994303025bd54d8a35a3fc2a3495fac653d6eb7205ce04f4", + "sha256:d20cbb9d3e95114325780f3cfe990f3ecae24de7a2d75f978783878cce2ad585", + "sha256:dcfebee69cd5e1c0b76a17e17e347c84b00acebb8dd8edb22d4a03e88e82a207", + "sha256:e1c69aa459f5609dec2fa0652d495353accf3eda5bdb18782bc5a2ae45c9273a", + "sha256:e2762c568596332fdab56b07060c8ab8362c56cf2a339ee54e491cd503612c50", + "sha256:e37f10f6d4bc67c58fbd727108ae1d8b92b397355e68519f1e4a7babb1473442", + "sha256:e790954b5093dff1e3a9a2523fddc4e79722d6f07993b4cd5547825c3cbf97b5", + "sha256:e81a295adccf73477220e15ff79235ca9dcbcee4be459eb9d4ce9a2763b8386c", + "sha256:e925819a98318d17251776bd3d6aa9f3ff77b965762155bdad15d1a9265c4cfd", + "sha256:ea30239c148b6ef41364c6f51d103c2988965b643d62e10b233b5efdca8c0099", + "sha256:eabf946a4739b5237f4f56d77fa6668263bc466d06a8036c055587c130a46f7b", + "sha256:ecb158fb9b9091b515213bed3061eb7deb1d3b4e02327c27a0ea714ff46b0760", + "sha256:ecc6d02d69b54a2eb83ebcc6f29df04957f734bcf309d346b4f83354d8376862", + "sha256:eddb18a00bbb855325db27b4c2a89a4ba491cd6a0bd6d852b225172a1f54b36c", + "sha256:f00e8b59e1fc8f09d05594aa7d2b726f1b277ca6155fc84c0396db1b373c4555", + "sha256:f1fb026c575e16f673c61c7b86144517705865173f3d0907040ac30c4f9f5915", + "sha256:f200b2f20856b5a6c3a35f0d4e344019f805e363416e609e9b47c552d35fd5ea", + "sha256:f225f3a3995dbbc26affc191d0443c6c4aa71b83358fd4c2b7d63e2f6f0336f9", + "sha256:f22dab23cdbce2005f26a8f0c71698457861f97fc6318c75814a50c75e87d025", + "sha256:f3eb479354c62067afa62f53bb387827bee2f75c9c79ef25eef6ab84d4b1ae3b", + "sha256:fc53e05c16697ff0c1c7c2b98e45e131d4bfb78068fffff92a82d169cbb4c7b7", + "sha256:ff48a55be9da6930254565ff5238d71d5e9cd8c5487a191cb85df3bdb8c77365" + ], + "markers": "python_version >= '3.9'", + "version": "==2.33.0" + }, + "pyjwt": { + "hashes": [ + "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", + "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb" + ], + "markers": "python_version >= '3.9'", + "version": "==2.10.1" + }, + "pytest": { + "hashes": [ + "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", + "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==8.3.5" + }, + "python-dateutil": { + "hashes": [ + "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", + "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==2.9.0.post0" + }, + "python-dotenv": { + "hashes": [ + "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5", + "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==1.1.0" + }, + "pytz": { + "hashes": [ + "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", + "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00" + ], + "version": "==2025.2" + }, + "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" + ], + "markers": "python_version >= '3.8'", + "version": "==6.0.2" + }, + "qh3": { + "hashes": [ + "sha256:0107f576a0524421e1b0f9e0437d2881a1835b1b6105eadd7ea0c1c9bf2da917", + "sha256:06159707895c606a321ccb5630347a2d2a44ee584f22945e5b22b0ad34f21ec8", + "sha256:06255835f99ea1af9e5d358056011686fcccbafaba893454027daa62ab6f701f", + "sha256:09b2305a954e61a9ed8b46a7a45f54e8d95ef870a47d5fd1836e14c7600d3b92", + "sha256:0a51dcffae03a89ddbab1884860569e0d1dbbf95deee47457c1fd29b4ac8d220", + "sha256:0a5d1cd881b7d43481ad60262cf3390a555e0e51751bc2af70ba4a612487e797", + "sha256:0e1c273660f9b8511c22d0b082137556e46d6a7eccf132bd82f95d29f90488b2", + "sha256:0e540cc7e7da65da30381bdb73a789a8635c6aaef98688d904eee3bc587654a5", + "sha256:10ed818f47dc522350a12641e8f2bea19ff824f8ce373c23a8e594b3481fd7a4", + "sha256:195b4ad58cf5a8da218e2368d34f47628c14581f3cc9863fc0406b32e137f3a6", + "sha256:1a80d07249c7ccbaa57bb9015b5ead0ead7ac1940cd5483548dfe56db99ce7a4", + "sha256:1cf0b18823801078d2294a0356abc2be34b4a224bea863a87029c1c97d6c34e0", + "sha256:1fac2ab4b8a2e50894b54a19416cd363defe0fb33f52754686ea58999f98dfc5", + "sha256:205cdaea9da8881b31b76eb6da5b88c9558ba96bc16a3ecf11333098ac7f3859", + "sha256:2294e78bcc40728a3a772df0f8ecf8b8756616d06dd001029016876aa4e5c9de", + "sha256:235236ab195d34e7cd18d186e46b7a4f8aceafe246bf36b42913f72627ded414", + "sha256:25eef1f2be50d79d23e01a567c719e46e4892518a5ccc96685fcb4746357320b", + "sha256:2ae147b756c3adf59699756feb9e07d4a69674f57b4e13d6c25f9d1dc3c8707c", + "sha256:2c9cdd7ea49c79b671e7de35dad61d2aa91920e2498d0c6dfa932d5e05070a5e", + "sha256:2dc9f269d7316b0a44e61ae7a11ffd8daa800b3f5ba773de2e9d8c4ee636a896", + "sha256:2f94d69edb0070ef4ec414deabfc2369aa2100b11bf4a4f2f393f2c28c4bc7ba", + "sha256:311da331e31c55afc3f4f4f2ba9d07a1d700ffb7db5aa4f58300b9f56f2523dc", + "sha256:3578844a9ff4c342a409d010f909782afc52a31680876f7fab65bf133aa3f4db", + "sha256:4032c2898b4c0ff7a25cf7d68c3b1f2abdcaf4f25cc8b6802a941a842f9a95b6", + "sha256:40abd150eddfa0884c139bd281e87ff920d4cd52d685fc4ef25ddcc77ff7a220", + "sha256:43e32602651d07f8a0860ba0a45d8c8fe9ccd537030e7632d1258f7b84881416", + "sha256:45a21d25fe17168f4db09fcaabee5dd171763ad1bd8753c257297837f5ba9197", + "sha256:45bfbb126e31ecf63ef74c249d38d07e149c0663b4a191cf9e2e3445a80758d5", + "sha256:4745667c9956bcfd74ff677edd4c73d6cb578b6b47c5fb3d246aaa223dd6a004", + "sha256:4936a5d8915866b4f08ab18018f41ed93a2593788ad0a80796aada2e23d402e5", + "sha256:4a45a9698b3bcae05f91356f50df8dab3c3fdef3187548b9c4a396a6eb6760b5", + "sha256:4b84c1ca283278e2e22a3b9e2ce8ea55c0a1797d6e86255640a1b6293fe18b2a", + "sha256:4dc88397ed7f3b46f542f87e19050a7f82267225009ce65651ac44cb55b204b1", + "sha256:4e10a872077373c71d7938fb1a7ae0561f2e79aad2b1b5323dbb6325a389041a", + "sha256:4f1b5dcb4d9da5b441e0b14216b816be7b5b5d080c2ccb957adf84266411ff6b", + "sha256:50d25182d598312197f500a65acebf5430391764e6ffcdb73d96e80c5dd06fc7", + "sha256:529c5b9e27fced27befce26e2699eca3110c576f6427dfbd26e30b7666b2d6d1", + "sha256:571da625b22e953731307539b44b2177f6ab13b6142d7698c0f28b9379ae1be6", + "sha256:5a9de89e2480b385a99613798d375e69a0a53d4575bd74b133307c8e83a84751", + "sha256:5bcc46cf89cb1036c2d029c01f360c82180329997a75728b20dc205f34114327", + "sha256:5dfa6238a6236f2bb3ecaac9befd23cee0bcbb9e497003fb3aef875e19325c61", + "sha256:6342b961b18037e3df8692e8914c576816a966bf29f913ee2728e7e838bde9bd", + "sha256:65e112c175a0b0328822dd0d19ead9ef1d7925359d154fb52e46b080945eef38", + "sha256:6f8a2b15c4dd58133e92f95d4312efd09b87ec15b881885629dff70e89f1e751", + "sha256:726f749444d1cc73c1bf221343dc6fdbde2541ffe30860d2d5ef6e310a1f5478", + "sha256:742f39cd807df31c21e035aec63f6f61e139a60545cffb16e8e87f61609d7cba", + "sha256:7840c18ec27aa08ecdd8ff23df348c124378c6f3edf9a0e02b16a5a4ce504c89", + "sha256:79d1de24d3c7345719af8333b64f19a8777dd50a059851bfcfa583c7109eddf2", + "sha256:7ba9303c5334d64b547483be92c4bbacd37964ff3abd0b1e8c82c63ec6f7b3ec", + "sha256:85587d9dfbd2f7f8622cf57f3c1a19cee441b5607a982cdf4c08ef38d45d5a36", + "sha256:8711b86e447e689d1b693419708b6ad64bf0c57091b94a3f65c6d4bd7cfb7d9a", + "sha256:877edc4db25309d86af07d992926394936f491cce84fce439961729552e942fe", + "sha256:8bb17669e362d3456bebd5c69abb0c26e8ab29c10894f123c715b0217aece479", + "sha256:8bb17a1e50e35a8d07cab784caea68b33f739391ccb5e3161afb9db0bde8faf4", + "sha256:8d4640a6bb3aa29797bdcf0c5bae4e86da5f2fbf84b67a7fad549fa34c19aa98", + "sha256:90697f3d9e4b3ddccfb31b40637bac6d44b39288cd57f78e51ff13e70916eccc", + "sha256:90f127f57c00b111ea3ffd95f4c12ad83efebd10310fd718d66771dd64e568f1", + "sha256:95f8f70bca1e880da7559ef38b7f1778a3b39b586fc829b8a7e989e912aa988f", + "sha256:9a60c102a01dfa8c5d737499c9a5d5e7c2b6642009c9b80b27f228ec50ce6fb0", + "sha256:9c7f1821ec749ea29bd9d079e4f13a552371731d0b664962a60cbb2f31d571b5", + "sha256:9f81ee66fadedbfd4d5c49e64151db3b6f353b041ddf5ab0b151340a4467e038", + "sha256:9f8e530e29e1afe9231b1100645aa5cc240b823c0e4162f70046270a3559400c", + "sha256:a0c647db3f156e8c94a63c1fa0fc4f2ce8b70f0eb12f2726e6c19493198b1e99", + "sha256:a0cda60607ab4ffc14fa8425ea7c9ae78ad60923c3c8be94d19c14f83198b1cf", + "sha256:a5bff397d49da302b5afbdf244dd7ca480a827f5de856d957df05dfd7e73b490", + "sha256:a94bd391b955b24948b2986845f9c6ad8abc709c2d57d0515daeacf16a2a3a4c", + "sha256:ad4572bd37c1a6a7a12ff47da4f3578a13e3c8ee85a1f02d2435dfdc6d9ed394", + "sha256:b13b7de1686f1b5da7526dc4f0de410a685f5cb654e984b09ddd8d14be6fffc0", + "sha256:b1724c43c5c0d08b68c3407467e07794b9adf153b6de8300d61883e8d95fa640", + "sha256:b27d29cb718df9ed006f8c75a89dd90534437761b2477dc7a4145bde0daa60fc", + "sha256:b3afa3a78b0f011ff5a09dea37d74fcea9269b318d2828f18b2fbf9dde625a71", + "sha256:bd6a61007e678284178bb00931af59f686a2a55797505e0886241050ec5c243c", + "sha256:befeca45fd7787c08a3286fb72caaccfa4c3962760981dfeb0992f5ba9be5cb2", + "sha256:c2d31b8233f406e00f180e221986f436765c3bb06839e72c898feca31fef1d4e", + "sha256:c3e2518ce442b70314892a594e21157deb13fbc436f77ad6555439cfd9912035", + "sha256:c8d5fbee607db24ef6c7b0bd08c21226d10782df4149b9d6f1f1516c7c85092b", + "sha256:cc2cc804998e852bdffcc87e8d008043ffa85efe6d3516d9784714d709f14774", + "sha256:cd8a681107c6118f60a0714671cec7b301533f25984a5c898e547a33a01af75c", + "sha256:d056831ebf3fa8116672ae970ad19a9f5f1427a2217cd0e01c1eaac5f8222668", + "sha256:d5ac3e8e3f66ff88819205dbc67e6f771cbb80529325ca9f3bc03fa00c5c83aa", + "sha256:dba15ca2da7859300ae79d2ea2eb8bb0eb827b93a2f104981783add16a97058a", + "sha256:de6cabb89248b60ea9bb9d7848de78dfb824abfdc15f52448a8efe821dd7d559", + "sha256:e02f6d1cc2005b847176dd8770fdfe90f04a34a3f094b79a8369bde0aa8f6a04", + "sha256:e514bd4b27c953c46485b2be0ecd2421aa196c5a0cd7d67f1ccec16a56b00507", + "sha256:e53464124379764f982a69f5ab34d0d5c527e8ac1e788db86a25f79045e5b18d", + "sha256:e9cf59660a543bef86de457c671c1d78ad2d88c53bb9eb3fce6ce0cb9729d490", + "sha256:edfc1bc732bc5e62fdaea268a541eb442d5e04927cb27dfd8e92ef07213658d2", + "sha256:ee8e7a66be70a18f5e0558f2f6a89e39c608f87b027234848f76a6699975dcf8", + "sha256:effb7072efef7dca10a98c24be0cc882a40edc78e293b41f5b6dc7f1952215ed", + "sha256:f04e4ee7e3c123ac7f21cee6f819cfa9b5a376e656257dfa7a4d133b3590bdd9", + "sha256:f0531c7abe963affebd3fb6cf9ea87eb8c63a0240535d81d0223945bd41be254", + "sha256:f5afd1c216315682a6bbf606618de0e3817ed8eeafc27ad7660ef2f581d4fd46", + "sha256:f93d3c74e00268ac6042c080653a34d0f0e8903697fd8dc480c1e3de81c90faf", + "sha256:fbc4e6452cc48c3e1398fe930349e2ec9ad76a2c00e729f3e797700c2f0646e6", + "sha256:fc73fc2889a01a43737c7a7c7fb9ee13aa56065b22abbed0e787cc58a3747808" + ], + "markers": "python_version >= '3.7'", + "version": "==1.4.2" + }, + "referencing": { + "hashes": [ + "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", + "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0" + ], + "markers": "python_version >= '3.9'", + "version": "==0.36.2" + }, + "requests": { + "hashes": [ + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" + ], + "markers": "python_version >= '3.8'", + "version": "==2.32.3" + }, + "rpds-py": { + "hashes": [ + "sha256:0047638c3aa0dbcd0ab99ed1e549bbf0e142c9ecc173b6492868432d8989a046", + "sha256:006f4342fe729a368c6df36578d7a348c7c716be1da0a1a0f86e3021f8e98724", + "sha256:041f00419e1da7a03c46042453598479f45be3d787eb837af382bfc169c0db33", + "sha256:04ecf5c1ff4d589987b4d9882872f80ba13da7d42427234fce8f22efb43133bc", + "sha256:04f2b712a2206e13800a8136b07aaedc23af3facab84918e7aa89e4be0260032", + "sha256:0aeb3329c1721c43c58cae274d7d2ca85c1690d89485d9c63a006cb79a85771a", + "sha256:0e374c0ce0ca82e5b67cd61fb964077d40ec177dd2c4eda67dba130de09085c7", + "sha256:0f00c16e089282ad68a3820fd0c831c35d3194b7cdc31d6e469511d9bffc535c", + "sha256:174e46569968ddbbeb8a806d9922f17cd2b524aa753b468f35b97ff9c19cb718", + "sha256:1b221c2457d92a1fb3c97bee9095c874144d196f47c038462ae6e4a14436f7bc", + "sha256:208b3a70a98cf3710e97cabdc308a51cd4f28aa6e7bb11de3d56cd8b74bab98d", + "sha256:20f2712bd1cc26a3cc16c5a1bfee9ed1abc33d4cdf1aabd297fe0eb724df4272", + "sha256:24795c099453e3721fda5d8ddd45f5dfcc8e5a547ce7b8e9da06fecc3832e26f", + "sha256:2a0f156e9509cee987283abd2296ec816225145a13ed0391df8f71bf1d789e2d", + "sha256:2b2356688e5d958c4d5cb964af865bea84db29971d3e563fb78e46e20fe1848b", + "sha256:2c13777ecdbbba2077670285dd1fe50828c8742f6a4119dbef6f83ea13ad10fb", + "sha256:2d3ee4615df36ab8eb16c2507b11e764dcc11fd350bbf4da16d09cda11fcedef", + "sha256:2d53747da70a4e4b17f559569d5f9506420966083a31c5fbd84e764461c4444b", + "sha256:32bab0a56eac685828e00cc2f5d1200c548f8bc11f2e44abf311d6b548ce2e45", + "sha256:34d90ad8c045df9a4259c47d2e16a3f21fdb396665c94520dbfe8766e62187a4", + "sha256:369d9c6d4c714e36d4a03957b4783217a3ccd1e222cdd67d464a3a479fc17796", + "sha256:3a55fc10fdcbf1a4bd3c018eea422c52cf08700cf99c28b5cb10fe97ab77a0d3", + "sha256:3d2d8e4508e15fc05b31285c4b00ddf2e0eb94259c2dc896771966a163122a0c", + "sha256:3fab5f4a2c64a8fb64fc13b3d139848817a64d467dd6ed60dcdd6b479e7febc9", + "sha256:43dba99f00f1d37b2a0265a259592d05fcc8e7c19d140fe51c6e6f16faabeb1f", + "sha256:44d51febb7a114293ffd56c6cf4736cb31cd68c0fddd6aa303ed09ea5a48e029", + "sha256:493fe54318bed7d124ce272fc36adbf59d46729659b2c792e87c3b95649cdee9", + "sha256:4b28e5122829181de1898c2c97f81c0b3246d49f585f22743a1246420bb8d399", + "sha256:4cd031e63bc5f05bdcda120646a0d32f6d729486d0067f09d79c8db5368f4586", + "sha256:528927e63a70b4d5f3f5ccc1fa988a35456eb5d15f804d276709c33fc2f19bda", + "sha256:564c96b6076a98215af52f55efa90d8419cc2ef45d99e314fddefe816bc24f91", + "sha256:5db385bacd0c43f24be92b60c857cf760b7f10d8234f4bd4be67b5b20a7c0b6b", + "sha256:5ef877fa3bbfb40b388a5ae1cb00636a624690dcb9a29a65267054c9ea86d88a", + "sha256:5f6e3cec44ba05ee5cbdebe92d052f69b63ae792e7d05f1020ac5e964394080c", + "sha256:5fc13b44de6419d1e7a7e592a4885b323fbc2f46e1f22151e3a8ed3b8b920405", + "sha256:60748789e028d2a46fc1c70750454f83c6bdd0d05db50f5ae83e2db500b34da5", + "sha256:60d9b630c8025b9458a9d114e3af579a2c54bd32df601c4581bd054e85258143", + "sha256:619ca56a5468f933d940e1bf431c6f4e13bef8e688698b067ae68eb4f9b30e3a", + "sha256:630d3d8ea77eabd6cbcd2ea712e1c5cecb5b558d39547ac988351195db433f6c", + "sha256:63981feca3f110ed132fd217bf7768ee8ed738a55549883628ee3da75bb9cb78", + "sha256:66420986c9afff67ef0c5d1e4cdc2d0e5262f53ad11e4f90e5e22448df485bf0", + "sha256:675269d407a257b8c00a6b58205b72eec8231656506c56fd429d924ca00bb350", + "sha256:6a4a535013aeeef13c5532f802708cecae8d66c282babb5cd916379b72110cf7", + "sha256:6a727fd083009bc83eb83d6950f0c32b3c94c8b80a9b667c87f4bd1274ca30ba", + "sha256:6e1daf5bf6c2be39654beae83ee6b9a12347cb5aced9a29eecf12a2d25fff664", + "sha256:6eea559077d29486c68218178ea946263b87f1c41ae7f996b1f30a983c476a5a", + "sha256:75a810b7664c17f24bf2ffd7f92416c00ec84b49bb68e6a0d93e542406336b56", + "sha256:772cc1b2cd963e7e17e6cc55fe0371fb9c704d63e44cacec7b9b7f523b78919e", + "sha256:78884d155fd15d9f64f5d6124b486f3d3f7fd7cd71a78e9670a0f6f6ca06fb2d", + "sha256:79e8d804c2ccd618417e96720ad5cd076a86fa3f8cb310ea386a3e6229bae7d1", + "sha256:7e80d375134ddb04231a53800503752093dbb65dad8dabacce2c84cccc78e964", + "sha256:8097b3422d020ff1c44effc40ae58e67d93e60d540a65649d2cdaf9466030791", + "sha256:8205ee14463248d3349131bb8099efe15cd3ce83b8ef3ace63c7e976998e7124", + "sha256:8212ff58ac6dfde49946bea57474a386cca3f7706fc72c25b772b9ca4af6b79e", + "sha256:823e74ab6fbaa028ec89615ff6acb409e90ff45580c45920d4dfdddb069f2120", + "sha256:84e0566f15cf4d769dade9b366b7b87c959be472c92dffb70462dd0844d7cbad", + "sha256:896c41007931217a343eff197c34513c154267636c8056fb409eafd494c3dcdc", + "sha256:8aa362811ccdc1f8dadcc916c6d47e554169ab79559319ae9fae7d7752d0d60c", + "sha256:8b3b397eefecec8e8e39fa65c630ef70a24b09141a6f9fc17b3c3a50bed6b50e", + "sha256:8ebc7e65ca4b111d928b669713865f021b7773350eeac4a31d3e70144297baba", + "sha256:9168764133fd919f8dcca2ead66de0105f4ef5659cbb4fa044f7014bed9a1797", + "sha256:921ae54f9ecba3b6325df425cf72c074cd469dea843fb5743a26ca7fb2ccb149", + "sha256:92558d37d872e808944c3c96d0423b8604879a3d1c86fdad508d7ed91ea547d5", + "sha256:951cc481c0c395c4a08639a469d53b7d4afa252529a085418b82a6b43c45c240", + "sha256:998c01b8e71cf051c28f5d6f1187abbdf5cf45fc0efce5da6c06447cba997034", + "sha256:9abc80fe8c1f87218db116016de575a7998ab1629078c90840e8d11ab423ee25", + "sha256:9be4f99bee42ac107870c61dfdb294d912bf81c3c6d45538aad7aecab468b6b7", + "sha256:9c39438c55983d48f4bb3487734d040e22dad200dab22c41e331cee145e7a50d", + "sha256:9d7e8ce990ae17dda686f7e82fd41a055c668e13ddcf058e7fb5e9da20b57793", + "sha256:9ea7f4174d2e4194289cb0c4e172d83e79a6404297ff95f2875cf9ac9bced8ba", + "sha256:a18fc371e900a21d7392517c6f60fe859e802547309e94313cd8181ad9db004d", + "sha256:a36b452abbf29f68527cf52e181fced56685731c86b52e852053e38d8b60bc8d", + "sha256:a5b66d1b201cc71bc3081bc2f1fc36b0c1f268b773e03bbc39066651b9e18391", + "sha256:a824d2c7a703ba6daaca848f9c3d5cb93af0505be505de70e7e66829affd676e", + "sha256:a88c0d17d039333a41d9bf4616bd062f0bd7aa0edeb6cafe00a2fc2a804e944f", + "sha256:aa6800adc8204ce898c8a424303969b7aa6a5e4ad2789c13f8648739830323b7", + "sha256:aad911555286884be1e427ef0dc0ba3929e6821cbeca2194b13dc415a462c7fd", + "sha256:afc6e35f344490faa8276b5f2f7cbf71f88bc2cda4328e00553bd451728c571f", + "sha256:b9a4df06c35465ef4d81799999bba810c68d29972bf1c31db61bfdb81dd9d5bb", + "sha256:bb2954155bb8f63bb19d56d80e5e5320b61d71084617ed89efedb861a684baea", + "sha256:bbc4362e06f950c62cad3d4abf1191021b2ffaf0b31ac230fbf0526453eee75e", + "sha256:c0145295ca415668420ad142ee42189f78d27af806fcf1f32a18e51d47dd2052", + "sha256:c30ff468163a48535ee7e9bf21bd14c7a81147c0e58a36c1078289a8ca7af0bd", + "sha256:c347a20d79cedc0a7bd51c4d4b7dbc613ca4e65a756b5c3e57ec84bd43505b47", + "sha256:c43583ea8517ed2e780a345dd9960896afc1327e8cf3ac8239c167530397440d", + "sha256:c61a2cb0085c8783906b2f8b1f16a7e65777823c7f4d0a6aaffe26dc0d358dd9", + "sha256:c9ca89938dff18828a328af41ffdf3902405a19f4131c88e22e776a8e228c5a8", + "sha256:cc31e13ce212e14a539d430428cd365e74f8b2d534f8bc22dd4c9c55b277b875", + "sha256:cdabcd3beb2a6dca7027007473d8ef1c3b053347c76f685f5f060a00327b8b65", + "sha256:cf86f72d705fc2ef776bb7dd9e5fbba79d7e1f3e258bf9377f8204ad0fc1c51e", + "sha256:d09dc82af2d3c17e7dd17120b202a79b578d79f2b5424bda209d9966efeed114", + "sha256:d3aa13bdf38630da298f2e0d77aca967b200b8cc1473ea05248f6c5e9c9bdb44", + "sha256:d69d003296df4840bd445a5d15fa5b6ff6ac40496f956a221c4d1f6f7b4bc4d9", + "sha256:d6e109a454412ab82979c5b1b3aee0604eca4bbf9a02693bb9df027af2bfa91a", + "sha256:d8551e733626afec514b5d15befabea0dd70a343a9f23322860c4f16a9430205", + "sha256:d8754d872a5dfc3c5bf9c0e059e8107451364a30d9fd50f1f1a85c4fb9481164", + "sha256:d8f9a6e7fd5434817526815f09ea27f2746c4a51ee11bb3439065f5fc754db58", + "sha256:dbcbb6db5582ea33ce46a5d20a5793134b5365110d84df4e30b9d37c6fd40ad3", + "sha256:e0f3ef95795efcd3b2ec3fe0a5bcfb5dadf5e3996ea2117427e524d4fbf309c6", + "sha256:e13ae74a8a3a0c2f22f450f773e35f893484fcfacb00bb4344a7e0f4f48e1f97", + "sha256:e274f62cbd274359eff63e5c7e7274c913e8e09620f6a57aae66744b3df046d6", + "sha256:e838bf2bb0b91ee67bf2b889a1a841e5ecac06dd7a2b1ef4e6151e2ce155c7ae", + "sha256:e8acd55bd5b071156bae57b555f5d33697998752673b9de554dd82f5b5352727", + "sha256:e8e5ab32cf9eb3647450bc74eb201b27c185d3857276162c101c0f8c6374e098", + "sha256:ebcb786b9ff30b994d5969213a8430cbb984cdd7ea9fd6df06663194bd3c450c", + "sha256:ebea2821cdb5f9fef44933617be76185b80150632736f3d76e54829ab4a3b4d1", + "sha256:ed0ef550042a8dbcd657dfb284a8ee00f0ba269d3f2286b0493b15a5694f9fe8", + "sha256:eda5c1e2a715a4cbbca2d6d304988460942551e4e5e3b7457b50943cd741626d", + "sha256:f5c0ed12926dec1dfe7d645333ea59cf93f4d07750986a586f511c0bc61fe103", + "sha256:f6016bd950be4dcd047b7475fdf55fb1e1f59fc7403f387be0e8123e4a576d30", + "sha256:f9e0057a509e096e47c87f753136c9b10d7a91842d8042c2ee6866899a717c0d", + "sha256:fc1c892b1ec1f8cbd5da8de287577b455e388d9c328ad592eabbdcb6fc93bee5", + "sha256:fc2c1e1b00f88317d9de6b2c2b39b012ebbfe35fe5e7bef980fd2a91f6100a07", + "sha256:fd822f019ccccd75c832deb7aa040bb02d70a92eb15a2f16c7987b7ad4ee8d83" + ], + "markers": "python_version >= '3.9'", + "version": "==0.24.0" + }, + "six": { + "hashes": [ + "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", + "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==1.17.0" + }, + "tinydb": { + "hashes": [ + "sha256:f7dfc39b8d7fda7a1ca62a8dbb449ffd340a117c1206b68c50b1a481fb95181d", + "sha256:f97030ee5cbc91eeadd1d7af07ab0e48ceb04aa63d4a983adbaca4cba16e86c3" + ], + "markers": "python_version >= '3.8' and python_version < '4.0'", + "version": "==4.8.2" + }, + "tuspy": { + "hashes": [ + "sha256:156734eac5c61a046cfecd70f14119f05be92cce198eb5a1a99a664482bedb89", + "sha256:7fc5ac8fb25de37c96c90213f83a1ffdede7f48a471cb5a15a2f57846828a79a" + ], + "markers": "python_full_version >= '3.5.3'", + "version": "==1.1.0" + }, + "typing-extensions": { + "hashes": [ + "sha256:0a4ac55a5820789d87e297727d229866c9650f6521b64206413c4fbada24d95b", + "sha256:c8dd92cc0d6425a97c18fbb9d1954e5ff92c1ca881a309c45f06ebc0b79058e5" + ], + "markers": "python_version >= '3.8'", + "version": "==4.13.0" + }, + "typing-inspection": { + "hashes": [ + "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f", + "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122" + ], + "markers": "python_version >= '3.9'", + "version": "==0.4.0" + }, + "tzdata": { + "hashes": [ + "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", + "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9" + ], + "markers": "python_version >= '2'", + "version": "==2025.2" + }, + "urllib3": { + "hashes": [ + "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", + "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d" + ], + "markers": "python_version >= '3.9'", + "version": "==2.3.0" + }, + "urllib3-future": { + "hashes": [ + "sha256:3adfa22c5718caee5ca69bc7f7461dc529f4396494d4d9b1db8af7c56cd3ac34", + "sha256:9cd79ce61da77b5d56681bc126f42955c2153e9c0da2f0a62bca8e0a05641f92" + ], + "markers": "python_version >= '3.7'", + "version": "==2.12.915" + }, + "verlib2": { + "hashes": [ + "sha256:2862f19528db400d130253a2b71c7c3616ee14e1d54bf6833bc0929d2cddd141", + "sha256:cf8e2be044b834a2670f2d4c20a93cfc674933c0070543a6f61d531439cca200" + ], + "markers": "python_version >= '3.6'", + "version": "==0.3.1" + }, + "wassima": { + "hashes": [ + "sha256:10508102696d5e2cf4df6942a8ae251c136a49dc32591e9c3f7dd007f5ea1c2f", + "sha256:1102836ba373912537eba891e7e5893532d4ee915ee2486e981b73f925f63c37", + "sha256:11887557464e0c3f9694fb16406bb56c1fb1566178cd04bfb5b4624fad183b31", + "sha256:12c855cc5b96a2ac32d405ab7de1563fc91be54108b4fb16b06d125d07ea892b", + "sha256:134e863b692c35afe8f5ccbe8082fa39963804e20439a4c7aa98510197034704", + "sha256:17f129f4d36591772d906bcc893b76b236363fda61b575067ddfa8250f84ad30", + "sha256:17f132ffbab294902f8740708f27fd995ea04182fe4b4fde20be563f8a010715", + "sha256:18bc78b2230c6f1f9ddbeb6ca38439fea4cc8f60836af4f3538ed259e60e5eb8", + "sha256:194c3fad38603618dec03307d10a4ece852516df56560e04fb2562506f79c175", + "sha256:1b18ec743ab98dcbfc221749026b23fc573891651342f20971e53bdbf56d28ae", + "sha256:1fa19a3652509edd18f693cd9c873d8f73c9d1624eae6c3bf93e561b18ae2766", + "sha256:24bdb1a2b90c215e11ed7ce82ed7eada339c7dca8e0366916e4e3215b3b9d8d3", + "sha256:27d518f0863788c826faf387326f3babb3ea95a0b908f5b3ad2bc1fcc3c5a37d", + "sha256:350b5854dfb3eeb95cd17723b0f3503de0c01454da5ae7d60f192be2009239eb", + "sha256:3b3a4c8ffa76147507f0c88c5cc8c76ef96ab93b81e49b288a3a0b94ebfb34af", + "sha256:3e00fa8ff1aef7d8aad2e1b957add6cba8549a42e415400bd72ff1b61dc9da9d", + "sha256:3f29045dd0a7c287f850f1dc3948632a2d2cf7dd7ec02271c5f248f058da5650", + "sha256:4a528244e4a0f9e01b8593b1c8a60ac1d80ce8b13fe079f44b38328e4be075e3", + "sha256:4c4f5ca102fd083aa2b05c65a1fd18175e3dc7a889525fd2964219ee3c51edef", + "sha256:52358d86195954816231d2aa8c2919b85075320b6d3ba5b96216985c3182bfa0", + "sha256:52f473233ec4d57322c6295e85b3912dc1fc400d6308a04bd427b863934aa74e", + "sha256:556cded582aef3089de889b5a6efcf6d87fabfec55d574fcc3a4ada21308d487", + "sha256:564eda7bf0420c8cbebe5e8efc15f1b27fdcb37ebc4c2f92b8461ca83381b223", + "sha256:57a0ab5aed596f129fd4ea7584336b11fbef25c07d1351e37a959901dea8728e", + "sha256:58f1fddd660da8c8f30f4b8460129e2f217c226cd1b54b1cabb6465881fd788a", + "sha256:597b0d8ba697f4319bc1f301ed31630ca783c9fe82d2a2434dd2f7f709c4e394", + "sha256:5b194f0de77a4ae7bcf217a3ccd10798e94ca430cec6307628098a61cd2ac230", + "sha256:5f5ee564f4b836ed1b70ddb187c817e8f6f1ffb521a636bb20676f07b523396b", + "sha256:601f96340e4c8071994a39a76d4278e8e1d087cf385781dba795c5334262d865", + "sha256:61bfa09f38c36f1b1e6e44e7af888bb8f9d739e86099082a3b45875651a425e2", + "sha256:67fd323b8ad0e057c06b153983d8c50f812aad979ac89b07ed6952c345f6da02", + "sha256:69cb51f629d118256da3d2373575190c7e30d3fa67c344dc655f6c8ab3e83f0d", + "sha256:6b1d7ceeede8d8eed48616d2d33ed23d2dff307d0b17c577eafdadafe86a0478", + "sha256:6b7d696155ddd7ab5739ac221e8854115d0d8171bbf805074d9484083de386aa", + "sha256:6d23e9483756b81850b82e8b7ed20fd23de22b50d6a678f765c660d4206b7ce9", + "sha256:7b0229fecc849234f2a2d11e948ac38a9bab02d201fa4d6ad43c143e18c1a66e", + "sha256:7c53050b670d702eed541503175bd5441fc4bdf3898714f8eac8c6ae9db548ac", + "sha256:7d65676f1fc138d1742f704bf490045571b9c2c48cab7d2c2076a52729c143e5", + "sha256:7db25328c40cd574e5a68ef6507c5af4d1fa2a44cb3c028ff9ca6b522f8faf32", + "sha256:83ce1b09e9eb2ae033c303b74ecc4f3186bbc0897db1d8cd9942153b0631b8e0", + "sha256:86c509900cbb90b7b75155c580b22af591b696fa059059bcdbd75bc74179df85", + "sha256:87f80d0075f0d396b73d41bb1626a2dd5607e0db4b74cb17e55d874fcd538971", + "sha256:8b719755d556649f2fbf226cf1ca8581ade114751df1facec96f94e75bffdb3c", + "sha256:8e739d4192758df6e5363791f527deb91c615d63020ee8965df4bcd1a217f9a5", + "sha256:923d3bf8770dfeb3d94bdfee1c5b5a081592de69766436a395e1e6203c19cf71", + "sha256:97772bb55cb47da3de49ca4b59309a9bd91ead730a7cfac1992932486fb41352", + "sha256:98bdfdf734144277132f34f770eeb6b0db2c4de87415f34b178adee766632f24", + "sha256:98f38b1b01e6f270b9279d76261d6f222b72ef06b025cbd4911b962bb6de4c98", + "sha256:99318b5ea78843e3c3e19cd56367216774674a99848f00a6f2dcf84e36039641", + "sha256:9c623ef06876d432dc8acc93ed3494d3453333d767b1b06bba1a016ea9d850c9", + "sha256:9d0f9720dfd0155432d23bcc3605fe5831cd0f586ede4f14ff6f3bebe8fb867a", + "sha256:9e79216760faac6395bee8ca4077a53a309312faba0f71982127ad8625861780", + "sha256:a470c908fd9baaecf41715ea3c30c57b530d598ae5e9de7e0bd532755e66bb1b", + "sha256:a634b9b79e059f45a56ff3ef6e7241662bc6f0e5a096ee6eed6770ea368e8278", + "sha256:acd8195a53d0e84ea95bdf15a2651c53b829a3ddead21b4a620b6a0c5e1ae2ff", + "sha256:addbd207df3718fc9d9de5b6c90a5e3fbe667830cf629186c9fdcafbb6578cb4", + "sha256:ae2aec9d55e108ae2d22fd0bda24450a6c13c116f9698b9e7ba2c6492c4fe715", + "sha256:af6b70ca9788964c5da5b59ca412b62db2ea7f2386a91c0117667bdd963e828c", + "sha256:afa7d60a9203db36a55b6f2868da90aaa829ab415a21fba7fa75678789aeb16f", + "sha256:b08c1931c44e3c034e645f3e3a7f4c47e8b0758fb8f09a52d1e880a307a1066f", + "sha256:b22e356914e606ff398c002b9925df4454c5deca9dbe55b3ba4a5c9b2365cf0f", + "sha256:b8c0f50397c51086df941b48057c82f85d9da000bf4fe6f4bc64c4f649b26a5b", + "sha256:bc068bcd79fe017866f536e0ad9424793220be34e3124476e17e6cb77a97e690", + "sha256:bc30f5a605a366acb7f301b3421508eaec3c1a515c960791bd776cb63d016302", + "sha256:c0d246b3f8a771578279eab9cfcb820dedefd3dd5dc0e34b37a337fe46271fc0", + "sha256:c0fee0a8593028bde17b57527b1ac21fea74f209b3522363e3ba0197ffaa6323", + "sha256:c139d5b103bb1f085d8918815d62ad946224a658ac1a7cc1b93dc44bd498ff9a", + "sha256:c25235cec12c0e38b4104268e312c9c2f3527ebc126d296cff69ea7aa13434dc", + "sha256:c7429d038dc383966c692e752010cbb4d5dab0e515f231aa01cd746aed9db359", + "sha256:c85cd2e64967c0dce2927ad7c62c090aae6d6b7f9e3a6b9fb91f58b890ea6adc", + "sha256:ca04984df012020dd846599b8555666c544982c2a91dc6135565e6708624eb71", + "sha256:cb7d43c07d58ba13736e70dc3e064496efeb1ed4475a28afb26b7a3b030b89df", + "sha256:d018e05cb61eed3050d45bd0c0ef9b75420899f6ae254e68e7f2ef26975098c9", + "sha256:d24d42881eb74729b34014e2e87f3a4d0419c43db309de2dff3f39118716865f", + "sha256:d6e17f218af856ca22c30d1a1ac58b19bccf768b8589eb8d6e45e1f1ff258404", + "sha256:d855d0be1759c5efc404c04977ee48a8b6260aef6441e72c10973924dbde5a73", + "sha256:dea0dcc0e50978ef73be8cb384694b71a6e64b46847ee7decad96dc85fbf650c", + "sha256:e1e9228049cf2442ac486a03a0d543c5dff3089a915a3e39ab809b22672e1d76", + "sha256:e26d052a248d5be2257d848d6078d932cc1fd4e8226639f550344d0a7a2b8813", + "sha256:ee6ccb8197936a308a4034c90a42b30b37c46b7cbda66101d439d6983f59b368", + "sha256:eea9c37b45e73cebb4670afd1779db138eeff0f84ffc0871d2fb90c04c8d3aa8", + "sha256:f195bf641276261e6bc5f79f52601850c9bdbff8af401483b4805dbff535ed30", + "sha256:f264827618400ebeab16708c8acf7870f693b03bfb4d7e95253eb9b35074db5c", + "sha256:f44ccd2eaa433ff1a10f70242dc33315fc192b81664696154127bdd66ad7d3b2", + "sha256:f7a6068d8857c403e105e62132a00e9d9d401bd0efbff7f8b5b5bc8ab768a2d8", + "sha256:f9886176fe4bf1ac008c02adb5bd103f1191799f1897777d203ee44f615325a5", + "sha256:fa1f38d5583d283b40f998e2f13471bfa952e0c423ff95ec2ec329f3e1898107", + "sha256:fa65494e7bd0e3ba33b3e5a5ab30c2b6e95d3d1762baaa56151a0861618dc261", + "sha256:fd7186e23963714bab3c9a2ab75d002078335110d2c9fc883c65cbce43717f26", + "sha256:fec32c22b521fcdeb9aa7dee4373b2d81ca2d3fc8edc532f3e189d6f4f6f1f81" + ], + "markers": "python_version >= '3.7'", + "version": "==1.2.2" + }, + "werkzeug": { + "hashes": [ + "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", + "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746" + ], + "markers": "python_version >= '3.9'", + "version": "==3.1.3" + }, + "yarl": { + "hashes": [ + "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba", + "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193", + "sha256:045b8482ce9483ada4f3f23b3774f4e1bf4f23a2d5c912ed5170f68efb053318", + "sha256:09c7907c8548bcd6ab860e5f513e727c53b4a714f459b084f6580b49fa1b9cee", + "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e", + "sha256:0b3c92fa08759dbf12b3a59579a4096ba9af8dd344d9a813fc7f5070d86bbab1", + "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a", + "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186", + "sha256:1d407181cfa6e70077df3377938c08012d18893f9f20e92f7d2f314a437c30b1", + "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50", + "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640", + "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb", + "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8", + "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc", + "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5", + "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58", + "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2", + "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393", + "sha256:4ac515b860c36becb81bb84b667466885096b5fc85596948548b667da3bf9f24", + "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b", + "sha256:54d6921f07555713b9300bee9c50fb46e57e2e639027089b1d795ecd9f7fa910", + "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c", + "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272", + "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed", + "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1", + "sha256:61e5e68cb65ac8f547f6b5ef933f510134a6bf31bb178be428994b0cb46c2a04", + "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d", + "sha256:6333c5a377c8e2f5fae35e7b8f145c617b02c939d04110c76f29ee3676b5f9a5", + "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d", + "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889", + "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae", + "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b", + "sha256:77a6e85b90a7641d2e07184df5557132a337f136250caafc9ccaa4a2a998ca2c", + "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576", + "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34", + "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477", + "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990", + "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2", + "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512", + "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069", + "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a", + "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6", + "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0", + "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8", + "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb", + "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa", + "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8", + "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e", + "sha256:a440a2a624683108a1b454705ecd7afc1c3438a08e890a1513d468671d90a04e", + "sha256:a4bb030cf46a434ec0225bddbebd4b89e6471814ca851abb8696170adb163985", + "sha256:a9ca04806f3be0ac6d558fffc2fdf8fcef767e0489d2684a21912cc4ed0cd1b8", + "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1", + "sha256:ac36703a585e0929b032fbaab0707b75dc12703766d0b53486eabd5139ebadd5", + "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690", + "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10", + "sha256:b4f6450109834af88cb4cc5ecddfc5380ebb9c228695afc11915a0bf82116789", + "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b", + "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca", + "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e", + "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5", + "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59", + "sha256:ba87babd629f8af77f557b61e49e7c7cac36f22f871156b91e10a6e9d4f829e9", + "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8", + "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db", + "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde", + "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7", + "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb", + "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3", + "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6", + "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285", + "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb", + "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8", + "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482", + "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd", + "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75", + "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760", + "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782", + "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53", + "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2", + "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1", + "sha256:fe57328fbc1bfd0bd0514470ac692630f3901c0ee39052ae47acd1d90a436719", + "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62" + ], + "markers": "python_version >= '3.9'", + "version": "==1.18.3" + } + }, + "develop": { + "certifi": { + "hashes": [ + "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", + "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe" + ], + "markers": "python_version >= '3.6'", + "version": "==2025.1.31" + }, + "charset-normalizer": { + "hashes": [ + "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537", + "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa", + "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a", + "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294", + "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b", + "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", + "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", + "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd", + "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4", + "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", + "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2", + "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", + "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd", + "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", + "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8", + "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1", + "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", + "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496", + "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d", + "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", + "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e", + "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a", + "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4", + "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca", + "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78", + "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408", + "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5", + "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", + "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", + "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a", + "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765", + "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6", + "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146", + "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6", + "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", + "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd", + "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c", + "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", + "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", + "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176", + "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770", + "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824", + "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f", + "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf", + "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487", + "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d", + "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd", + "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", + "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534", + "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f", + "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b", + "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", + "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd", + "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125", + "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9", + "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de", + "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", + "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d", + "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", + "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f", + "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", + "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7", + "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a", + "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", + "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8", + "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41", + "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", + "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f", + "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", + "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", + "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", + "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77", + "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76", + "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247", + "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", + "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb", + "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", + "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e", + "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6", + "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037", + "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", + "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e", + "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807", + "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", + "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c", + "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12", + "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3", + "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089", + "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", + "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e", + "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00", + "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616" + ], + "markers": "python_version >= '3.7'", + "version": "==3.4.1" + }, + "coverage": { + "hashes": [ + "sha256:042e7841a26498fff7a37d6fda770d17519982f5b7d8bf5278d140b67b61095f", + "sha256:04bfec25a8ef1c5f41f5e7e5c842f6b615599ca8ba8391ec33a9290d9d2db3a3", + "sha256:0915742f4c82208ebf47a2b154a5334155ed9ef9fe6190674b8a46c2fb89cb05", + "sha256:18c5ae6d061ad5b3e7eef4363fb27a0576012a7447af48be6c75b88494c6cf25", + "sha256:2931f66991175369859b5fd58529cd4b73582461877ecfd859b6549869287ffe", + "sha256:2e4b6b87bb0c846a9315e3ab4be2d52fac905100565f4b92f02c445c8799e257", + "sha256:3043ba1c88b2139126fc72cb48574b90e2e0546d4c78b5299317f61b7f718b78", + "sha256:379fe315e206b14e21db5240f89dc0774bdd3e25c3c58c2c733c99eca96f1ada", + "sha256:42421e04069fb2cbcbca5a696c4050b84a43b05392679d4068acbe65449b5c64", + "sha256:4dfd9a93db9e78666d178d4f08a5408aa3f2474ad4d0e0378ed5f2ef71640cb6", + "sha256:52a523153c568d2c0ef8826f6cc23031dc86cffb8c6aeab92c4ff776e7951b28", + "sha256:554fec1199d93ab30adaa751db68acec2b41c5602ac944bb19187cb9a41a8067", + "sha256:581a40c7b94921fffd6457ffe532259813fc68eb2bdda60fa8cc343414ce3733", + "sha256:5a26c0c795c3e0b63ec7da6efded5f0bc856d7c0b24b2ac84b4d1d7bc578d676", + "sha256:5a570cd9bd20b85d1a0d7b009aaf6c110b52b5755c17be6962f8ccd65d1dbd23", + "sha256:5aaeb00761f985007b38cf463b1d160a14a22c34eb3f6a39d9ad6fc27cb73008", + "sha256:5ac46d0c2dd5820ce93943a501ac5f6548ea81594777ca585bf002aa8854cacd", + "sha256:5c8a5c139aae4c35cbd7cadca1df02ea8cf28a911534fc1b0456acb0b14234f3", + "sha256:6b8af63b9afa1031c0ef05b217faa598f3069148eeee6bb24b79da9012423b82", + "sha256:769773614e676f9d8e8a0980dd7740f09a6ea386d0f383db6821df07d0f08545", + "sha256:771eb7587a0563ca5bb6f622b9ed7f9d07bd08900f7589b4febff05f469bea00", + "sha256:77af0f6447a582fdc7de5e06fa3757a3ef87769fbb0fdbdeba78c23049140a47", + "sha256:7a3d62b3b03b4b6fd41a085f3574874cf946cb4604d2b4d3e8dca8cd570ca501", + "sha256:821f7bcbaa84318287115d54becb1915eece6918136c6f91045bb84e2f88739d", + "sha256:89b1f4af0d4afe495cd4787a68e00f30f1d15939f550e869de90a86efa7e0814", + "sha256:8a1d96e780bdb2d0cbb297325711701f7c0b6f89199a57f2049e90064c29f6bd", + "sha256:8a40fcf208e021eb14b0fac6bdb045c0e0cab53105f93ba0d03fd934c956143a", + "sha256:8f99eb72bf27cbb167b636eb1726f590c00e1ad375002230607a844d9e9a2318", + "sha256:90e7fbc6216ecaffa5a880cdc9c77b7418c1dcb166166b78dbc630d07f278cc3", + "sha256:94ec0be97723ae72d63d3aa41961a0b9a6f5a53ff599813c324548d18e3b9e8c", + "sha256:95aa6ae391a22bbbce1b77ddac846c98c5473de0372ba5c463480043a07bff42", + "sha256:96121edfa4c2dfdda409877ea8608dd01de816a4dc4a0523356067b305e4e17a", + "sha256:a1f406a8e0995d654b2ad87c62caf6befa767885301f3b8f6f73e6f3c31ec3a6", + "sha256:a321c61477ff8ee705b8a5fed370b5710c56b3a52d17b983d9215861e37b642a", + "sha256:a5761c70c017c1b0d21b0815a920ffb94a670c8d5d409d9b38857874c21f70d7", + "sha256:a9abbccd778d98e9c7e85038e35e91e67f5b520776781d9a1e2ee9d400869487", + "sha256:ad80e6b4a0c3cb6f10f29ae4c60e991f424e6b14219d46f1e7d442b938ee68a4", + "sha256:b44674870709017e4b4036e3d0d6c17f06a0e6d4436422e0ad29b882c40697d2", + "sha256:b571bf5341ba8c6bc02e0baeaf3b061ab993bf372d982ae509807e7f112554e9", + "sha256:b8194fb8e50d556d5849753de991d390c5a1edeeba50f68e3a9253fbd8bf8ccd", + "sha256:b87eb6fc9e1bb8f98892a2458781348fa37e6925f35bb6ceb9d4afd54ba36c73", + "sha256:bbb5cc845a0292e0c520656d19d7ce40e18d0e19b22cb3e0409135a575bf79fc", + "sha256:be945402e03de47ba1872cd5236395e0f4ad635526185a930735f66710e1bd3f", + "sha256:bf13d564d310c156d1c8e53877baf2993fb3073b2fc9f69790ca6a732eb4bfea", + "sha256:cf60dd2696b457b710dd40bf17ad269d5f5457b96442f7f85722bdb16fa6c899", + "sha256:d1ba00ae33be84066cfbe7361d4e04dec78445b2b88bdb734d0d1cbab916025a", + "sha256:d39fc4817fd67b3915256af5dda75fd4ee10621a3d484524487e33416c6f3543", + "sha256:d766a4f0e5aa1ba056ec3496243150698dc0481902e2b8559314368717be82b1", + "sha256:dbf364b4c5e7bae9250528167dfe40219b62e2d573c854d74be213e1e52069f7", + "sha256:dd19608788b50eed889e13a5d71d832edc34fc9dfce606f66e8f9f917eef910d", + "sha256:e013b07ba1c748dacc2a80e69a46286ff145935f260eb8c72df7185bf048f502", + "sha256:e5d2b9be5b0693cf21eb4ce0ec8d211efb43966f6657807f6859aab3814f946b", + "sha256:e5ff52d790c7e1628241ffbcaeb33e07d14b007b6eb00a19320c7b8a7024c040", + "sha256:e75a2ad7b647fd8046d58c3132d7eaf31b12d8a53c0e4b21fa9c4d23d6ee6d3c", + "sha256:e7ac22a0bb2c7c49f441f7a6d46c9c80d96e56f5a8bc6972529ed43c8b694e27", + "sha256:ed2144b8a78f9d94d9515963ed273d620e07846acd5d4b0a642d4849e8d91a0c", + "sha256:f017a61399f13aa6d1039f75cd467be388d157cd81f1a119b9d9a68ba6f2830d", + "sha256:f1d8a2a57b47142b10374902777e798784abf400a004b14f1b0b9eaf1e528ba4", + "sha256:f2d32f95922927186c6dbc8bc60df0d186b6edb828d299ab10898ef3f40052fe", + "sha256:f319bae0321bc838e205bf9e5bc28f0a3165f30c203b610f17ab5552cff90323", + "sha256:f3c38e4e5ccbdc9198aecc766cedbb134b2d89bf64533973678dfcf07effd883", + "sha256:f9983d01d7705b2d1f7a95e10bbe4091fabc03a46881a256c2787637b087003f", + "sha256:fa260de59dfb143af06dcf30c2be0b200bed2a73737a8a59248fcb9fa601ef0f" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==7.8.0" + }, + "docker": { + "hashes": [ + "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c", + "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0" + ], + "markers": "python_version >= '3.8'", + "version": "==7.1.0" + }, + "grafana-client": { + "hashes": [ + "sha256:2477a47b923fd0637947e620b0b777c641af18a3025464fa4505783dbf05dfcc", + "sha256:8cb61bb2a87ec07bca10974df276b9a1a95bfdb63f3a696f065692ffc9b8c389" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==4.3.2" + }, + "h11": { + "hashes": [ + "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", + "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761" + ], + "markers": "python_version >= '3.7'", + "version": "==0.14.0" + }, + "idna": { + "hashes": [ + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" + ], + "markers": "python_version >= '3.6'", + "version": "==3.10" + }, + "iniconfig": { + "hashes": [ + "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", + "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760" + ], + "markers": "python_version >= '3.8'", + "version": "==2.1.0" + }, + "jh2": { + "hashes": [ + "sha256:038091480cd1544e9389b0adbb1b1645a797689dcb68ceae7e45eec96ed24497", + "sha256:0c8e336df8ed1687590695f4469f480eeb4159bf13bb6193791c6530fe114b49", + "sha256:0c9bf2d5e4ef45c1686c6f76935e7ca263f5eae4de92bf5d1873a0e737e4eb7d", + "sha256:0faf6e96f74d27b8ca816b40217904891f91b664ed1c0388737949ceb50ac15d", + "sha256:10ea7f497e6226372e1d4fdbf42c8381f4887819a643ab930bff4072ad298d84", + "sha256:11650f7ed77ee1df30f25d6b3b74b2fa1c94124e074fd455abafea3cbc913d53", + "sha256:12ead3ee3e9c7caa00356b528a5cc7fe210fbe2060628af6e19ed76b8416572e", + "sha256:136b3c5b08883681fcb58f12393a5bbfa422d6e2d5ba887e263e776874276bc6", + "sha256:17d6e1691154ea9f726e43dcb717df48e56c66b5a01c90ad675c6494c36e5be1", + "sha256:19cb987915cc0d321746a12f2a693d087ffb721c37ac9a153cc088c57d4d90eb", + "sha256:1cdf15de698c4026e64fd914fead3180e52bf2a7bcbe44a3392404582dbf2d22", + "sha256:1e81e1c64e33506b8508ba5e3c7c139b2577e78b079c2c16a8e7a02a161f1080", + "sha256:2226c76e4ff2149c5d9f94bed22bf9c4f3411d38cc53d4a7ddfbe0899c8b558c", + "sha256:2837412fb7b684c6ce7392c8bc57440c6dbadaf1bde7a53144381f7df7083c1c", + "sha256:293f0f3da3c391e997e0d55fdb85540e98a8b0406622bb4ba57fb7617697f31e", + "sha256:2b9cc6c0239215a349d28c192fa4c4e7a7348eee7980531525c01bffe39eea80", + "sha256:2f3ad679f84ff236a0d7b71ddc4b3c09fe467abee2f1a86671f0cd417be5352b", + "sha256:358cad2f328c52c15756cf32b0ad17afb0d617e7cdfe93d59aa2616966d825b7", + "sha256:3663712305b509f79c002c8c0ca9994f716cadba576f5a59632dda1aec1ca8c6", + "sha256:41794820ccca039ca2ead6245f30b34601dd1456eee5b5dde620672bb989e79d", + "sha256:44b7e64aff542471c474c24f771eae5efd9152da02a12556f7cb7607020e1420", + "sha256:45770eb0990166026538d3c2fd7d92f17cfde13ca6567570c4baec3ce9162936", + "sha256:498060078a4d1b458e9381fefb027d85329397b50d65287712b3d48233e20836", + "sha256:4c2f18f337c2393f84e45e5011c8b02697b81638b1cec49da60a01b9ed067695", + "sha256:5162d6e475d2762035fb8ea25982bcbec6c58715e33bd0951499f743cd90b110", + "sha256:51e8c890bb59008c95b3a552cefd8bd9ce50a7466a6c920a78cf586e885d7449", + "sha256:56ad3839ac6ac5fd3d023cf59d4b04264b74bb4cb44c0780faf51d6b5ff38fbc", + "sha256:5821638ef0d7c973071810a6786f59b305172197f7e7e469a2ce169e7f4978e3", + "sha256:5ac1b2d379f4d40c13dcce537e69704452943cddbe991fd54a84fdb2da9026d5", + "sha256:5b465d4311b0429fe6fa85df8e2cfcb038c9fface95396dd14e838ecabaaadf2", + "sha256:5d8656b98057329bd03d968aac8d5198389cf51517511295cfc4cb827a507e39", + "sha256:5dcfb3e823ef4b91b70b92848570d1d8cfd584304bd2bd54272dc100c9494def", + "sha256:5e40d23ea43f683f3a7c032dde391104f609b05c21b6d284101120b51dbd50c1", + "sha256:63a01522bde161c713f7fa5ee5d850fee6386fc386073490ebcd438f14579cf2", + "sha256:6b2a3d7756035dde13571f4ad232629b78b7f35c2cd5fda7b464079fc697db3a", + "sha256:6b3be1a6bf6c965aea3b4e3a40df9d2c134c516d89c76cf2b6c81f67e6c5c6ed", + "sha256:6c7bea3357f2dc653756e6da55f66cd21c73d3875c8f3dc4e8d196a876252de0", + "sha256:6e6c8e229507cf29333a2f491cbaa7dff5b8a4a3e613af8090ccce9ce3e4f7a0", + "sha256:6fad27f2a63884ee45d491aebec4b1f38752cd6aaccc625038c21e7f43c02c49", + "sha256:71bfef52547c2b8b145897fa8d1b5142bc52313cfa38c0742e0ef755f0d09c60", + "sha256:72370d312323282b1bf74426e53fae861a310d7ae519b419da46673c38e7d147", + "sha256:76c7d36043a9c478b0c846fcec7da5cb095983722473e503e0122ccd170182b5", + "sha256:78d8a81ef51edb9a2f278a6fb278789b49e304b12bb21bccf2fe7e344f71a9fb", + "sha256:798a6b159ce32181a5e7ab7611c17d1080e74a5541fec47f961b728dab25a76f", + "sha256:7e370567f66a57e2c0e3ae2afcc6f126e1d6babd36831cfd0caad279b05c1c88", + "sha256:8004b845f606b95a8b17efa112aa10b327e46e95dcda604a257b4633d4ed45c8", + "sha256:80b20bf9ea4e709b3b9ae364ac298dfa872b084c186e5c1d60b0b79c79a7ee7e", + "sha256:87303f4bb1b493997f911a4f126123ccd2827d3a2e7dd2390cc6143fbc75805b", + "sha256:8d423f4631395b92dceda39f481a463498131ac02a58581124a44495491f715b", + "sha256:94ee262192db50fb9c069a0be7bb1a426fb1b43af26ce12bf4c6c30e13f46b56", + "sha256:960e4be2e7de340300ab4bcc2b45bed46be1d62330575b8265e6602dbcb9a14c", + "sha256:99397d5e1da6b345cec3e6125e2902b0e6864eb8eaa4be43a2013f059c502c93", + "sha256:9abbb8c1bad08817bad62ae1ea76c01bdbd0ee8c827d05f3ba038c9f6d6f14bb", + "sha256:9c0b8fadf80bc70d341032f92702bda1b0ed78c01e9c495f0df701938c99bcf5", + "sha256:9f977da9abae170eebdcf02bda33727c342fad5dcdbc08498bfdfb6cc6c65489", + "sha256:a6be712ca39d5e9c89b705bc9800be36739436fefb8d0b52b2d332f7d6d22a01", + "sha256:aa434418d6ee44b0ba3a5a407bc9e1543cf496328f43f149e9b58f74a63d5c21", + "sha256:ac4f778e32f7de0ba63346893a4af87c2280ffc1783f594a117be51d908a10da", + "sha256:ac85d65ee369c09b2904b55078ad589961e2e2e03c810963d35a26e6a3931425", + "sha256:ad5d78c664d39960435d4162db31117c8945ba74fb0c414e79ba85a8bdeafdec", + "sha256:ad91f57c3485d87a8edee558dafab0f08c716857d748731c0998dcefe9d3fd5f", + "sha256:afd255d42b340036883ca95bded553b29065b064e2fe5db64ad5988517db9694", + "sha256:b1c2c74f100a0c2110a8e30445554ae331860d32f145c60a2a1e1c27702022a2", + "sha256:b49a8c71378d40d43c6a56eaa536d7823baa43c27c93e082aeb60a9717be0c10", + "sha256:b5f52611323e8e35705e6750a760f32165b41c052d22da154ae343871e7cd50d", + "sha256:b6bf99ae529ac359263269710356d3ddb173c15d8f8dc8849ae794ab811e5cd0", + "sha256:ba361bf87c4701f11241be92c99ef5cf916865dd225955cccb2376bf76717b3c", + "sha256:bc351aa2158575e68943d8e1d5531719ad86bf6607776627ed5a1a60657664af", + "sha256:bd6eb7b1e12e4dd0b75cab1b023272f1333494add5ad61deedac738af1ffeede", + "sha256:bf8852595f5e2d2b072e24c29394b5aca7fba96ecc8656d56660535f9e9872c9", + "sha256:c1dd66541569a2bdbe92589cc96a89f470b20d168f2238fd463e1b59ee3e2d49", + "sha256:c36a7a004cba4e370d0675826eeefe4e42a256638b6b1432263ddb4af317bc02", + "sha256:c886cda61da4d39010be84802bed11bc75f03e8a6094cc18016957a2c80254d4", + "sha256:cc7aa83946f80c66a5d2dea7e165f15aa3eb21e7b74b24d8f850afc0d44bb00e", + "sha256:cea9c4bef70d1358bafec6019164abce362f4de15d79d1ecd64ae31c1749d77a", + "sha256:cfe1951e80869695857986be104a40a1e7fa8ec7de05f86bcbd7bd20854be764", + "sha256:d36cf6f139da3279644794fcfda18af425c8bb122ef9c2e7c762a937bbf7b0f4", + "sha256:d81308faaa9393b7e6ed20718d465c4c2b73c24d5e4826024961acf4b87b1524", + "sha256:db51ea1f9c5ac790848bc271fcdf4108ad1b77a77c6949a96320477962cf7ba5", + "sha256:dd05c18c920a15e00d7a52df37bffd3930fe2c004c690f9422b20e12077e6dbd", + "sha256:df05918a11e1db0198d00486e36673b4b4a89390e4458ff9479b4908dde357ac", + "sha256:e4c31dccf6be131709e545d0258eb5b75c5fac304857ad3976331c6740e8b9d6", + "sha256:e60954d673040430802b29fe5bba698e262182b5ba5f302ff4458e39f8101881", + "sha256:e60e2d2c88a0552e61c37172fe377f6a8abf479130a445314886de4a360ba940", + "sha256:e786f773ddc153846b2ebdb854011cfd1f7c874b8ee79cced3706801341c9f5d", + "sha256:e7cd91548fb95b69edd376f5204e27115ac7d093ec7d80066123a5bdb31c71d9", + "sha256:eaef2ea4f5602aefaaf3d6e8235f3b9ffde35aff15aac1c16cc802f6bbf0a3b5", + "sha256:ec8c5ea93a03775fbadd08462200cf34ce617ec75a032abfa44fd6d3a00e5424", + "sha256:eddeb8574bc9d9abb8491d4a46b60e553c2cea235b80373756acb06568101175", + "sha256:eeb300b0e4b428aab2f70d785cad4306529262af6de8c8c5fe6a4b41a674a434", + "sha256:f39d71ece8e97cf069e4154868eaac1256b133fe23e0459829432e4bb6406472", + "sha256:f4840ddad2b9d53710e92361391944da89e3576641a290066a1719520059247c", + "sha256:f70723a00bcbce0f9a216853139955be45da35741335eb3afead304e77662560", + "sha256:f829cf2ba5b553e6529d6238928c07096f1feb47f4ad536b7f06bca6cc77173f", + "sha256:f96386910467725895f7972939a6faabd6e96b1de0cc2c092e4bd2c40e956e25", + "sha256:fe259a9d6f555bc79aed9bb4b9a7fff73db443b4c483e4a81a428c8a2860428b" + ], + "markers": "python_version >= '3.7'", + "version": "==5.0.8" + }, + "niquests": { + "hashes": [ + "sha256:68e0a7e9f338466b3606945fffd11f75e3c90af7498aa9336ef03812323b7e36", + "sha256:86e484c2c60444aa96069c15f6295af6e25a8bad50781e1326df1b5c7ab48339" + ], + "markers": "python_version >= '3.7'", + "version": "==3.14.0" + }, + "packaging": { + "hashes": [ + "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", + "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" + ], + "markers": "python_version >= '3.8'", + "version": "==24.2" + }, + "pluggy": { + "hashes": [ + "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", + "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" + ], + "markers": "python_version >= '3.8'", + "version": "==1.5.0" + }, + "pytest": { + "hashes": [ + "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", + "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==8.3.5" + }, + "python-dotenv": { + "hashes": [ + "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5", + "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==1.1.0" + }, + "qh3": { + "hashes": [ + "sha256:0107f576a0524421e1b0f9e0437d2881a1835b1b6105eadd7ea0c1c9bf2da917", + "sha256:06159707895c606a321ccb5630347a2d2a44ee584f22945e5b22b0ad34f21ec8", + "sha256:06255835f99ea1af9e5d358056011686fcccbafaba893454027daa62ab6f701f", + "sha256:09b2305a954e61a9ed8b46a7a45f54e8d95ef870a47d5fd1836e14c7600d3b92", + "sha256:0a51dcffae03a89ddbab1884860569e0d1dbbf95deee47457c1fd29b4ac8d220", + "sha256:0a5d1cd881b7d43481ad60262cf3390a555e0e51751bc2af70ba4a612487e797", + "sha256:0e1c273660f9b8511c22d0b082137556e46d6a7eccf132bd82f95d29f90488b2", + "sha256:0e540cc7e7da65da30381bdb73a789a8635c6aaef98688d904eee3bc587654a5", + "sha256:10ed818f47dc522350a12641e8f2bea19ff824f8ce373c23a8e594b3481fd7a4", + "sha256:195b4ad58cf5a8da218e2368d34f47628c14581f3cc9863fc0406b32e137f3a6", + "sha256:1a80d07249c7ccbaa57bb9015b5ead0ead7ac1940cd5483548dfe56db99ce7a4", + "sha256:1cf0b18823801078d2294a0356abc2be34b4a224bea863a87029c1c97d6c34e0", + "sha256:1fac2ab4b8a2e50894b54a19416cd363defe0fb33f52754686ea58999f98dfc5", + "sha256:205cdaea9da8881b31b76eb6da5b88c9558ba96bc16a3ecf11333098ac7f3859", + "sha256:2294e78bcc40728a3a772df0f8ecf8b8756616d06dd001029016876aa4e5c9de", + "sha256:235236ab195d34e7cd18d186e46b7a4f8aceafe246bf36b42913f72627ded414", + "sha256:25eef1f2be50d79d23e01a567c719e46e4892518a5ccc96685fcb4746357320b", + "sha256:2ae147b756c3adf59699756feb9e07d4a69674f57b4e13d6c25f9d1dc3c8707c", + "sha256:2c9cdd7ea49c79b671e7de35dad61d2aa91920e2498d0c6dfa932d5e05070a5e", + "sha256:2dc9f269d7316b0a44e61ae7a11ffd8daa800b3f5ba773de2e9d8c4ee636a896", + "sha256:2f94d69edb0070ef4ec414deabfc2369aa2100b11bf4a4f2f393f2c28c4bc7ba", + "sha256:311da331e31c55afc3f4f4f2ba9d07a1d700ffb7db5aa4f58300b9f56f2523dc", + "sha256:3578844a9ff4c342a409d010f909782afc52a31680876f7fab65bf133aa3f4db", + "sha256:4032c2898b4c0ff7a25cf7d68c3b1f2abdcaf4f25cc8b6802a941a842f9a95b6", + "sha256:40abd150eddfa0884c139bd281e87ff920d4cd52d685fc4ef25ddcc77ff7a220", + "sha256:43e32602651d07f8a0860ba0a45d8c8fe9ccd537030e7632d1258f7b84881416", + "sha256:45a21d25fe17168f4db09fcaabee5dd171763ad1bd8753c257297837f5ba9197", + "sha256:45bfbb126e31ecf63ef74c249d38d07e149c0663b4a191cf9e2e3445a80758d5", + "sha256:4745667c9956bcfd74ff677edd4c73d6cb578b6b47c5fb3d246aaa223dd6a004", + "sha256:4936a5d8915866b4f08ab18018f41ed93a2593788ad0a80796aada2e23d402e5", + "sha256:4a45a9698b3bcae05f91356f50df8dab3c3fdef3187548b9c4a396a6eb6760b5", + "sha256:4b84c1ca283278e2e22a3b9e2ce8ea55c0a1797d6e86255640a1b6293fe18b2a", + "sha256:4dc88397ed7f3b46f542f87e19050a7f82267225009ce65651ac44cb55b204b1", + "sha256:4e10a872077373c71d7938fb1a7ae0561f2e79aad2b1b5323dbb6325a389041a", + "sha256:4f1b5dcb4d9da5b441e0b14216b816be7b5b5d080c2ccb957adf84266411ff6b", + "sha256:50d25182d598312197f500a65acebf5430391764e6ffcdb73d96e80c5dd06fc7", + "sha256:529c5b9e27fced27befce26e2699eca3110c576f6427dfbd26e30b7666b2d6d1", + "sha256:571da625b22e953731307539b44b2177f6ab13b6142d7698c0f28b9379ae1be6", + "sha256:5a9de89e2480b385a99613798d375e69a0a53d4575bd74b133307c8e83a84751", + "sha256:5bcc46cf89cb1036c2d029c01f360c82180329997a75728b20dc205f34114327", + "sha256:5dfa6238a6236f2bb3ecaac9befd23cee0bcbb9e497003fb3aef875e19325c61", + "sha256:6342b961b18037e3df8692e8914c576816a966bf29f913ee2728e7e838bde9bd", + "sha256:65e112c175a0b0328822dd0d19ead9ef1d7925359d154fb52e46b080945eef38", + "sha256:6f8a2b15c4dd58133e92f95d4312efd09b87ec15b881885629dff70e89f1e751", + "sha256:726f749444d1cc73c1bf221343dc6fdbde2541ffe30860d2d5ef6e310a1f5478", + "sha256:742f39cd807df31c21e035aec63f6f61e139a60545cffb16e8e87f61609d7cba", + "sha256:7840c18ec27aa08ecdd8ff23df348c124378c6f3edf9a0e02b16a5a4ce504c89", + "sha256:79d1de24d3c7345719af8333b64f19a8777dd50a059851bfcfa583c7109eddf2", + "sha256:7ba9303c5334d64b547483be92c4bbacd37964ff3abd0b1e8c82c63ec6f7b3ec", + "sha256:85587d9dfbd2f7f8622cf57f3c1a19cee441b5607a982cdf4c08ef38d45d5a36", + "sha256:8711b86e447e689d1b693419708b6ad64bf0c57091b94a3f65c6d4bd7cfb7d9a", + "sha256:877edc4db25309d86af07d992926394936f491cce84fce439961729552e942fe", + "sha256:8bb17669e362d3456bebd5c69abb0c26e8ab29c10894f123c715b0217aece479", + "sha256:8bb17a1e50e35a8d07cab784caea68b33f739391ccb5e3161afb9db0bde8faf4", + "sha256:8d4640a6bb3aa29797bdcf0c5bae4e86da5f2fbf84b67a7fad549fa34c19aa98", + "sha256:90697f3d9e4b3ddccfb31b40637bac6d44b39288cd57f78e51ff13e70916eccc", + "sha256:90f127f57c00b111ea3ffd95f4c12ad83efebd10310fd718d66771dd64e568f1", + "sha256:95f8f70bca1e880da7559ef38b7f1778a3b39b586fc829b8a7e989e912aa988f", + "sha256:9a60c102a01dfa8c5d737499c9a5d5e7c2b6642009c9b80b27f228ec50ce6fb0", + "sha256:9c7f1821ec749ea29bd9d079e4f13a552371731d0b664962a60cbb2f31d571b5", + "sha256:9f81ee66fadedbfd4d5c49e64151db3b6f353b041ddf5ab0b151340a4467e038", + "sha256:9f8e530e29e1afe9231b1100645aa5cc240b823c0e4162f70046270a3559400c", + "sha256:a0c647db3f156e8c94a63c1fa0fc4f2ce8b70f0eb12f2726e6c19493198b1e99", + "sha256:a0cda60607ab4ffc14fa8425ea7c9ae78ad60923c3c8be94d19c14f83198b1cf", + "sha256:a5bff397d49da302b5afbdf244dd7ca480a827f5de856d957df05dfd7e73b490", + "sha256:a94bd391b955b24948b2986845f9c6ad8abc709c2d57d0515daeacf16a2a3a4c", + "sha256:ad4572bd37c1a6a7a12ff47da4f3578a13e3c8ee85a1f02d2435dfdc6d9ed394", + "sha256:b13b7de1686f1b5da7526dc4f0de410a685f5cb654e984b09ddd8d14be6fffc0", + "sha256:b1724c43c5c0d08b68c3407467e07794b9adf153b6de8300d61883e8d95fa640", + "sha256:b27d29cb718df9ed006f8c75a89dd90534437761b2477dc7a4145bde0daa60fc", + "sha256:b3afa3a78b0f011ff5a09dea37d74fcea9269b318d2828f18b2fbf9dde625a71", + "sha256:bd6a61007e678284178bb00931af59f686a2a55797505e0886241050ec5c243c", + "sha256:befeca45fd7787c08a3286fb72caaccfa4c3962760981dfeb0992f5ba9be5cb2", + "sha256:c2d31b8233f406e00f180e221986f436765c3bb06839e72c898feca31fef1d4e", + "sha256:c3e2518ce442b70314892a594e21157deb13fbc436f77ad6555439cfd9912035", + "sha256:c8d5fbee607db24ef6c7b0bd08c21226d10782df4149b9d6f1f1516c7c85092b", + "sha256:cc2cc804998e852bdffcc87e8d008043ffa85efe6d3516d9784714d709f14774", + "sha256:cd8a681107c6118f60a0714671cec7b301533f25984a5c898e547a33a01af75c", + "sha256:d056831ebf3fa8116672ae970ad19a9f5f1427a2217cd0e01c1eaac5f8222668", + "sha256:d5ac3e8e3f66ff88819205dbc67e6f771cbb80529325ca9f3bc03fa00c5c83aa", + "sha256:dba15ca2da7859300ae79d2ea2eb8bb0eb827b93a2f104981783add16a97058a", + "sha256:de6cabb89248b60ea9bb9d7848de78dfb824abfdc15f52448a8efe821dd7d559", + "sha256:e02f6d1cc2005b847176dd8770fdfe90f04a34a3f094b79a8369bde0aa8f6a04", + "sha256:e514bd4b27c953c46485b2be0ecd2421aa196c5a0cd7d67f1ccec16a56b00507", + "sha256:e53464124379764f982a69f5ab34d0d5c527e8ac1e788db86a25f79045e5b18d", + "sha256:e9cf59660a543bef86de457c671c1d78ad2d88c53bb9eb3fce6ce0cb9729d490", + "sha256:edfc1bc732bc5e62fdaea268a541eb442d5e04927cb27dfd8e92ef07213658d2", + "sha256:ee8e7a66be70a18f5e0558f2f6a89e39c608f87b027234848f76a6699975dcf8", + "sha256:effb7072efef7dca10a98c24be0cc882a40edc78e293b41f5b6dc7f1952215ed", + "sha256:f04e4ee7e3c123ac7f21cee6f819cfa9b5a376e656257dfa7a4d133b3590bdd9", + "sha256:f0531c7abe963affebd3fb6cf9ea87eb8c63a0240535d81d0223945bd41be254", + "sha256:f5afd1c216315682a6bbf606618de0e3817ed8eeafc27ad7660ef2f581d4fd46", + "sha256:f93d3c74e00268ac6042c080653a34d0f0e8903697fd8dc480c1e3de81c90faf", + "sha256:fbc4e6452cc48c3e1398fe930349e2ec9ad76a2c00e729f3e797700c2f0646e6", + "sha256:fc73fc2889a01a43737c7a7c7fb9ee13aa56065b22abbed0e787cc58a3747808" + ], + "markers": "python_version >= '3.7'", + "version": "==1.4.2" + }, + "requests": { + "hashes": [ + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" + ], + "markers": "python_version >= '3.8'", + "version": "==2.32.3" + }, + "requests-mock": { + "hashes": [ + "sha256:b1e37054004cdd5e56c84454cc7df12b25f90f382159087f4b6915aaeef39563", + "sha256:e9e12e333b525156e82a3c852f22016b9158220d2f47454de9cae8a77d371401" + ], + "index": "pypi", + "markers": "python_version >= '3.5'", + "version": "==1.12.1" + }, + "testcontainers": { + "hashes": [ + "sha256:03f85c3e505d8b4edeb192c72a961cebbcba0dd94344ae778b4a159cb6dcf8d3", + "sha256:31ed1a81238c7e131a2a29df6db8f23717d892b592fa5a1977fd0dcd0c23fc23" + ], + "index": "pypi", + "markers": "python_version >= '3.9' and python_version < '4.0'", + "version": "==4.10.0" + }, + "typing-extensions": { + "hashes": [ + "sha256:0a4ac55a5820789d87e297727d229866c9650f6521b64206413c4fbada24d95b", + "sha256:c8dd92cc0d6425a97c18fbb9d1954e5ff92c1ca881a309c45f06ebc0b79058e5" + ], + "markers": "python_version >= '3.8'", + "version": "==4.13.0" + }, + "urllib3": { + "hashes": [ + "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", + "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d" + ], + "markers": "python_version >= '3.9'", + "version": "==2.3.0" + }, + "urllib3-future": { + "hashes": [ + "sha256:3adfa22c5718caee5ca69bc7f7461dc529f4396494d4d9b1db8af7c56cd3ac34", + "sha256:9cd79ce61da77b5d56681bc126f42955c2153e9c0da2f0a62bca8e0a05641f92" + ], + "markers": "python_version >= '3.7'", + "version": "==2.12.915" + }, + "verlib2": { + "hashes": [ + "sha256:2862f19528db400d130253a2b71c7c3616ee14e1d54bf6833bc0929d2cddd141", + "sha256:cf8e2be044b834a2670f2d4c20a93cfc674933c0070543a6f61d531439cca200" + ], + "markers": "python_version >= '3.6'", + "version": "==0.3.1" + }, + "wassima": { + "hashes": [ + "sha256:10508102696d5e2cf4df6942a8ae251c136a49dc32591e9c3f7dd007f5ea1c2f", + "sha256:1102836ba373912537eba891e7e5893532d4ee915ee2486e981b73f925f63c37", + "sha256:11887557464e0c3f9694fb16406bb56c1fb1566178cd04bfb5b4624fad183b31", + "sha256:12c855cc5b96a2ac32d405ab7de1563fc91be54108b4fb16b06d125d07ea892b", + "sha256:134e863b692c35afe8f5ccbe8082fa39963804e20439a4c7aa98510197034704", + "sha256:17f129f4d36591772d906bcc893b76b236363fda61b575067ddfa8250f84ad30", + "sha256:17f132ffbab294902f8740708f27fd995ea04182fe4b4fde20be563f8a010715", + "sha256:18bc78b2230c6f1f9ddbeb6ca38439fea4cc8f60836af4f3538ed259e60e5eb8", + "sha256:194c3fad38603618dec03307d10a4ece852516df56560e04fb2562506f79c175", + "sha256:1b18ec743ab98dcbfc221749026b23fc573891651342f20971e53bdbf56d28ae", + "sha256:1fa19a3652509edd18f693cd9c873d8f73c9d1624eae6c3bf93e561b18ae2766", + "sha256:24bdb1a2b90c215e11ed7ce82ed7eada339c7dca8e0366916e4e3215b3b9d8d3", + "sha256:27d518f0863788c826faf387326f3babb3ea95a0b908f5b3ad2bc1fcc3c5a37d", + "sha256:350b5854dfb3eeb95cd17723b0f3503de0c01454da5ae7d60f192be2009239eb", + "sha256:3b3a4c8ffa76147507f0c88c5cc8c76ef96ab93b81e49b288a3a0b94ebfb34af", + "sha256:3e00fa8ff1aef7d8aad2e1b957add6cba8549a42e415400bd72ff1b61dc9da9d", + "sha256:3f29045dd0a7c287f850f1dc3948632a2d2cf7dd7ec02271c5f248f058da5650", + "sha256:4a528244e4a0f9e01b8593b1c8a60ac1d80ce8b13fe079f44b38328e4be075e3", + "sha256:4c4f5ca102fd083aa2b05c65a1fd18175e3dc7a889525fd2964219ee3c51edef", + "sha256:52358d86195954816231d2aa8c2919b85075320b6d3ba5b96216985c3182bfa0", + "sha256:52f473233ec4d57322c6295e85b3912dc1fc400d6308a04bd427b863934aa74e", + "sha256:556cded582aef3089de889b5a6efcf6d87fabfec55d574fcc3a4ada21308d487", + "sha256:564eda7bf0420c8cbebe5e8efc15f1b27fdcb37ebc4c2f92b8461ca83381b223", + "sha256:57a0ab5aed596f129fd4ea7584336b11fbef25c07d1351e37a959901dea8728e", + "sha256:58f1fddd660da8c8f30f4b8460129e2f217c226cd1b54b1cabb6465881fd788a", + "sha256:597b0d8ba697f4319bc1f301ed31630ca783c9fe82d2a2434dd2f7f709c4e394", + "sha256:5b194f0de77a4ae7bcf217a3ccd10798e94ca430cec6307628098a61cd2ac230", + "sha256:5f5ee564f4b836ed1b70ddb187c817e8f6f1ffb521a636bb20676f07b523396b", + "sha256:601f96340e4c8071994a39a76d4278e8e1d087cf385781dba795c5334262d865", + "sha256:61bfa09f38c36f1b1e6e44e7af888bb8f9d739e86099082a3b45875651a425e2", + "sha256:67fd323b8ad0e057c06b153983d8c50f812aad979ac89b07ed6952c345f6da02", + "sha256:69cb51f629d118256da3d2373575190c7e30d3fa67c344dc655f6c8ab3e83f0d", + "sha256:6b1d7ceeede8d8eed48616d2d33ed23d2dff307d0b17c577eafdadafe86a0478", + "sha256:6b7d696155ddd7ab5739ac221e8854115d0d8171bbf805074d9484083de386aa", + "sha256:6d23e9483756b81850b82e8b7ed20fd23de22b50d6a678f765c660d4206b7ce9", + "sha256:7b0229fecc849234f2a2d11e948ac38a9bab02d201fa4d6ad43c143e18c1a66e", + "sha256:7c53050b670d702eed541503175bd5441fc4bdf3898714f8eac8c6ae9db548ac", + "sha256:7d65676f1fc138d1742f704bf490045571b9c2c48cab7d2c2076a52729c143e5", + "sha256:7db25328c40cd574e5a68ef6507c5af4d1fa2a44cb3c028ff9ca6b522f8faf32", + "sha256:83ce1b09e9eb2ae033c303b74ecc4f3186bbc0897db1d8cd9942153b0631b8e0", + "sha256:86c509900cbb90b7b75155c580b22af591b696fa059059bcdbd75bc74179df85", + "sha256:87f80d0075f0d396b73d41bb1626a2dd5607e0db4b74cb17e55d874fcd538971", + "sha256:8b719755d556649f2fbf226cf1ca8581ade114751df1facec96f94e75bffdb3c", + "sha256:8e739d4192758df6e5363791f527deb91c615d63020ee8965df4bcd1a217f9a5", + "sha256:923d3bf8770dfeb3d94bdfee1c5b5a081592de69766436a395e1e6203c19cf71", + "sha256:97772bb55cb47da3de49ca4b59309a9bd91ead730a7cfac1992932486fb41352", + "sha256:98bdfdf734144277132f34f770eeb6b0db2c4de87415f34b178adee766632f24", + "sha256:98f38b1b01e6f270b9279d76261d6f222b72ef06b025cbd4911b962bb6de4c98", + "sha256:99318b5ea78843e3c3e19cd56367216774674a99848f00a6f2dcf84e36039641", + "sha256:9c623ef06876d432dc8acc93ed3494d3453333d767b1b06bba1a016ea9d850c9", + "sha256:9d0f9720dfd0155432d23bcc3605fe5831cd0f586ede4f14ff6f3bebe8fb867a", + "sha256:9e79216760faac6395bee8ca4077a53a309312faba0f71982127ad8625861780", + "sha256:a470c908fd9baaecf41715ea3c30c57b530d598ae5e9de7e0bd532755e66bb1b", + "sha256:a634b9b79e059f45a56ff3ef6e7241662bc6f0e5a096ee6eed6770ea368e8278", + "sha256:acd8195a53d0e84ea95bdf15a2651c53b829a3ddead21b4a620b6a0c5e1ae2ff", + "sha256:addbd207df3718fc9d9de5b6c90a5e3fbe667830cf629186c9fdcafbb6578cb4", + "sha256:ae2aec9d55e108ae2d22fd0bda24450a6c13c116f9698b9e7ba2c6492c4fe715", + "sha256:af6b70ca9788964c5da5b59ca412b62db2ea7f2386a91c0117667bdd963e828c", + "sha256:afa7d60a9203db36a55b6f2868da90aaa829ab415a21fba7fa75678789aeb16f", + "sha256:b08c1931c44e3c034e645f3e3a7f4c47e8b0758fb8f09a52d1e880a307a1066f", + "sha256:b22e356914e606ff398c002b9925df4454c5deca9dbe55b3ba4a5c9b2365cf0f", + "sha256:b8c0f50397c51086df941b48057c82f85d9da000bf4fe6f4bc64c4f649b26a5b", + "sha256:bc068bcd79fe017866f536e0ad9424793220be34e3124476e17e6cb77a97e690", + "sha256:bc30f5a605a366acb7f301b3421508eaec3c1a515c960791bd776cb63d016302", + "sha256:c0d246b3f8a771578279eab9cfcb820dedefd3dd5dc0e34b37a337fe46271fc0", + "sha256:c0fee0a8593028bde17b57527b1ac21fea74f209b3522363e3ba0197ffaa6323", + "sha256:c139d5b103bb1f085d8918815d62ad946224a658ac1a7cc1b93dc44bd498ff9a", + "sha256:c25235cec12c0e38b4104268e312c9c2f3527ebc126d296cff69ea7aa13434dc", + "sha256:c7429d038dc383966c692e752010cbb4d5dab0e515f231aa01cd746aed9db359", + "sha256:c85cd2e64967c0dce2927ad7c62c090aae6d6b7f9e3a6b9fb91f58b890ea6adc", + "sha256:ca04984df012020dd846599b8555666c544982c2a91dc6135565e6708624eb71", + "sha256:cb7d43c07d58ba13736e70dc3e064496efeb1ed4475a28afb26b7a3b030b89df", + "sha256:d018e05cb61eed3050d45bd0c0ef9b75420899f6ae254e68e7f2ef26975098c9", + "sha256:d24d42881eb74729b34014e2e87f3a4d0419c43db309de2dff3f39118716865f", + "sha256:d6e17f218af856ca22c30d1a1ac58b19bccf768b8589eb8d6e45e1f1ff258404", + "sha256:d855d0be1759c5efc404c04977ee48a8b6260aef6441e72c10973924dbde5a73", + "sha256:dea0dcc0e50978ef73be8cb384694b71a6e64b46847ee7decad96dc85fbf650c", + "sha256:e1e9228049cf2442ac486a03a0d543c5dff3089a915a3e39ab809b22672e1d76", + "sha256:e26d052a248d5be2257d848d6078d932cc1fd4e8226639f550344d0a7a2b8813", + "sha256:ee6ccb8197936a308a4034c90a42b30b37c46b7cbda66101d439d6983f59b368", + "sha256:eea9c37b45e73cebb4670afd1779db138eeff0f84ffc0871d2fb90c04c8d3aa8", + "sha256:f195bf641276261e6bc5f79f52601850c9bdbff8af401483b4805dbff535ed30", + "sha256:f264827618400ebeab16708c8acf7870f693b03bfb4d7e95253eb9b35074db5c", + "sha256:f44ccd2eaa433ff1a10f70242dc33315fc192b81664696154127bdd66ad7d3b2", + "sha256:f7a6068d8857c403e105e62132a00e9d9d401bd0efbff7f8b5b5bc8ab768a2d8", + "sha256:f9886176fe4bf1ac008c02adb5bd103f1191799f1897777d203ee44f615325a5", + "sha256:fa1f38d5583d283b40f998e2f13471bfa952e0c423ff95ec2ec329f3e1898107", + "sha256:fa65494e7bd0e3ba33b3e5a5ab30c2b6e95d3d1762baaa56151a0861618dc261", + "sha256:fd7186e23963714bab3c9a2ab75d002078335110d2c9fc883c65cbce43717f26", + "sha256:fec32c22b521fcdeb9aa7dee4373b2d81ca2d3fc8edc532f3e189d6f4f6f1f81" + ], + "markers": "python_version >= '3.7'", + "version": "==1.2.2" + }, + "wrapt": { + "hashes": [ + "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.2" + } + } +} diff --git a/dbrepo-dashboard-service/init/app.py b/dbrepo-dashboard-service/init/app.py new file mode 100644 index 0000000000000000000000000000000000000000..41cfd9a0e5973d663090a95bb8e74088a6d314c3 --- /dev/null +++ b/dbrepo-dashboard-service/init/app.py @@ -0,0 +1,67 @@ +import logging +import os +from logging.config import dictConfig +from typing import List + +from dbrepo.RestClient import RestClient +from dbrepo.api.dto import Database +from dbrepo.core.client.dashboard import DashboardServiceClient + +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': {'wsgi': { + 'class': 'logging.StreamHandler', + 'stream': 'ext://flask.logging.wsgi_errors_stream', + 'formatter': 'simple' # default + }}, + 'root': { + 'level': 'DEBUG', + 'handlers': ['wsgi'] + } +}) + + +def dashboard_client(): + return DashboardServiceClient(os.getenv('DASHBOARD_UI_ENDPOINT', 'http://localhost:3000'), + os.getenv('SYSTEM_USERNAME', 'admin'), os.getenv('SYSTEM_PASSWORD', 'admin')) + + +def rest_client(): + return RestClient(endpoint=os.getenv("METADATA_SERVICE_ENDPOINT", "http://localhost"), + username=os.getenv('SYSTEM_USERNAME', 'admin'), password=os.getenv('SYSTEM_PASSWORD', 'admin')) + + +def fetch_databases() -> List[Database]: + databases = [] + for index, database in enumerate(rest_client().get_databases()): + logging.debug(f"fetching database details for database id: {database.id}") + databases.append(rest_client().get_database(database_id=database.id)) + logging.info(f"Fetched {len(databases)} database(s)") + return databases + + +def upsert_dashboard(database: Database) -> None: + db = dashboard_client().find(database.dashboard_uid)['dashboard'] + if db is None: + db = dashboard_client().create(database.internal_name, database.dashboard_uid)['dashboard'] + rest_client().update_database_dashboard(database.id, db['uid']) + return + dashboard_client().update(database) + + +if __name__ == "__main__": + for database in fetch_databases(): + upsert_dashboard(database) + logging.info("Finished. Exiting.") diff --git a/dbrepo-dashboard-service/init/lib/dbrepo-1.8.0-py3-none-any.whl b/dbrepo-dashboard-service/init/lib/dbrepo-1.8.0-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..a285fef8ff07eaeffb5a1dfbab34dd395c0330d9 Binary files /dev/null and b/dbrepo-dashboard-service/init/lib/dbrepo-1.8.0-py3-none-any.whl differ diff --git a/dbrepo-dashboard-service/init/lib/dbrepo-1.8.0.tar.gz b/dbrepo-dashboard-service/init/lib/dbrepo-1.8.0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..4b3de54c835f7085ce9546cc519400bdbc9480b0 Binary files /dev/null and b/dbrepo-dashboard-service/init/lib/dbrepo-1.8.0.tar.gz differ diff --git a/dbrepo-search-service/init/tests/rsa/rs256.key b/dbrepo-dashboard-service/init/tests/rsa/rs256.key similarity index 100% rename from dbrepo-search-service/init/tests/rsa/rs256.key rename to dbrepo-dashboard-service/init/tests/rsa/rs256.key diff --git a/dbrepo-search-service/init/tests/rsa/rsa256.pkey b/dbrepo-dashboard-service/init/tests/rsa/rsa256.pkey similarity index 100% rename from dbrepo-search-service/init/tests/rsa/rsa256.pkey rename to dbrepo-dashboard-service/init/tests/rsa/rsa256.pkey diff --git a/dbrepo-dashboard-service/init/tests/test_app.py b/dbrepo-dashboard-service/init/tests/test_app.py new file mode 100644 index 0000000000000000000000000000000000000000..60f3ec44cf6f4152b594932a245ec7bf4d8db99c --- /dev/null +++ b/dbrepo-dashboard-service/init/tests/test_app.py @@ -0,0 +1,100 @@ +import unittest + +import requests_mock +from dbrepo.api.dto import Database, Table, Constraints, Column, ColumnType, ConceptBrief, UnitBrief, \ + UserBrief, ContainerBrief, ImageBrief, DatabaseBrief +from dbrepo.api.exceptions import NotExistsError + +from app import fetch_databases + +req = Database(id="209acf92-5c9b-4633-ad99-113c86f6e948", + name="Test", + internal_name="test_tuw1", + owner=UserBrief(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", username="foo"), + contact=UserBrief(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", username="foo"), + exchange_name="dbrepo", + is_public=True, + is_schema_public=True, + is_dashboard_enabled=True, + container=ContainerBrief(id="7efe8b27-6cdc-4387-80e3-92ee28f4a7c5", + name="MariaDB", + internal_name="mariadb", + image=ImageBrief(id="f97791b4-baf4-4b18-8f7d-3084818e6549", + name="mariadb", + version="11.1.3", + default=True)), + tables=[Table(id="f94a6164-cad4-4873-a9fd-3fe5313b2e95", + database_id="209acf92-5c9b-4633-ad99-113c86f6e948", + name="Data", + internal_name="data", + owner=UserBrief(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", username="foo"), + constraints=Constraints(uniques=[], foreign_keys=[], checks=[], primary_key=[]), + is_versioned=False, + queue_name="dbrepo", + routing_key="dbrepo.1.1", + is_public=True, + is_schema_public=True, + columns=[Column(id="7bef7e68-88f1-438e-9b94-0a77afd21471", + database_id="209acf92-5c9b-4633-ad99-113c86f6e948", + table_id="f94a6164-cad4-4873-a9fd-3fe5313b2e95", + name="ID", + ord=0, + internal_name="id", + type=ColumnType.BIGINT, + is_null_allowed=False, + size=20, + d=0, + concept=ConceptBrief(id="fb32ecf6-1f68-49b4-85ee-04e76263cbef", + uri="http://www.wikidata.org/entity/Q2221906"), + unit=UnitBrief(id="a67d735e-32ef-4917-b412-fe099c6757a1", + uri="http://www.ontology-of-units-of-measure.org/resource/om-2/degreeCelsius"), + val_min=0, + val_max=10)] + )]) + + +class AppUnitTest(unittest.TestCase): + + def test_fetch_databases_succeeds(self): + with requests_mock.Mocker() as mock: + # mock + mock.get('/api/database', + json=[DatabaseBrief(id='209acf92-5c9b-4633-ad99-113c86f6e948', + name="Test", + internal_name="test_tuw1", + owner_id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", + is_public=True, + is_schema_public=True, + contact=UserBrief(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", + username="foo")).model_dump()]) + mock.get(f'/api/database/{req.id}', json=req.model_dump()) + # test + response = fetch_databases() + self.assertEqual(1, len(response)) + + def test_fetch_databases_empty_succeeds(self): + with requests_mock.Mocker() as mock: + # mock + mock.get('/api/database', json=[]) + # test + response = fetch_databases() + self.assertEqual(0, len(response)) + + def test_fetch_databases_not_found_fails(self): + with requests_mock.Mocker() as mock: + # mock + mock.get('/api/database', + json=[DatabaseBrief(id='209acf92-5c9b-4633-ad99-113c86f6e948', + name="Test", + internal_name="test_tuw1", + owner_id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", + is_public=True, + is_schema_public=True, + contact=UserBrief(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", + username="foo")).model_dump()]) + mock.get(f'/api/database/{req.id}', status_code=404) + # test + try: + fetch_databases() + except NotExistsError: + pass \ No newline at end of file diff --git a/dbrepo-dashboard-service/lib/dbrepo-1.8.0-py3-none-any.whl b/dbrepo-dashboard-service/lib/dbrepo-1.8.0-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..a285fef8ff07eaeffb5a1dfbab34dd395c0330d9 Binary files /dev/null and b/dbrepo-dashboard-service/lib/dbrepo-1.8.0-py3-none-any.whl differ diff --git a/dbrepo-dashboard-service/lib/dbrepo-1.8.0.tar.gz b/dbrepo-dashboard-service/lib/dbrepo-1.8.0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..4b3de54c835f7085ce9546cc519400bdbc9480b0 Binary files /dev/null and b/dbrepo-dashboard-service/lib/dbrepo-1.8.0.tar.gz differ diff --git a/dbrepo-dashboard-service/panel.py b/dbrepo-dashboard-service/panel.py deleted file mode 100644 index acb3d548bb6c3a736ed56055ef368431e4a1d8de..0000000000000000000000000000000000000000 --- a/dbrepo-dashboard-service/panel.py +++ /dev/null @@ -1,252 +0,0 @@ -import os - -datasource_uid = os.getenv('JSON_DATASOURCE_NAME', 'dbrepojson0') - -statistics_row_title = '${view_id}' - - -def _get_start_index(dashboard: dict) -> int: - return [panel['title'] for panel in dashboard['panels']].index(statistics_row_title) - - -def get_panels(dashboard: dict) -> [dict]: - return [] - - -def map_timeseries_panel(database_id: str) -> dict: - datasource = dict(uid=datasource_uid, - type='yesoreyeram-infinity-datasource') - return dict(title='${view_id}', - type='timeseries', - datasource=datasource, - targets=[dict(datasource=datasource, - format='table', - global_query_id='', - hide=False, - refId='A', - root_selector='', - source='url', - type='json', - url='/api/database/' + database_id + '/view/${view_id}/data', - url_options=dict(data='', - method='GET'))], - gridPos=dict(h=8, - w=12, - x=12, - y=8), - options=dict(legend=dict(displayMode='list', - placement='bottom', - showLegend=True), - tooltip=dict(mode='single', - sort='none')), - fieldConfig=dict( - defaults=dict(color=dict(mode='palette-classic'), - custom=dict( - axisBorderShow=False, - axisCenteredZero=False, - axisColorMode='text', - axisLabel='', - axisPlacement='auto', - barAlignment=0, - drawStyle='line', - fillOpacity=0, - gradientMode='none', - hideFrom=dict(legend=False, - tooltip=False, - viz=False), - insertNulls=False, - lineInterpolation='linear', - lineWidth=1, - pointSize=5, - scaleDistribution=dict(type='linear'), - showPoints='auto', - spanNulls=False, - stacking=dict(group='A', - mode='none'), - thresholdsStyle=dict(mode='absolute'))))) - - -def map_number_panel(database_id: str, title: str, root_selector: str, y: int = 0) -> dict: - datasource = dict(uid=datasource_uid, - type='yesoreyeram-infinity-datasource') - return dict(title=title, - type='stat', - datasource=datasource, - targets=[dict(datasource=datasource, - columns=[], - filters=[], - format='table', - global_query_id='', - hide=False, - refId='A', - root_selector=root_selector, - source='url', - type='json', - url='/api/database/' + database_id + '/view/${view_id}/statistic', - url_options=dict(data='', - method='GET'))], - fieldConfig=dict(defaults=dict(mappings=[], - thresholds=dict(mode='absolute', - steps=[dict(color='blue', - value=None)]), - unit=''), - overrides=[]), - gridPos=dict(h=4, - w=6, - x=18, - y=y), - options=dict(colorMode='background', - graphMode='area', - justifyMode='auto', - orientation='auto', - reduceOptions=dict(calcs=[], - fields='/.*/', - values=True), - showPercentChange=False, - textMode='auto', - wideLayout=True)) - - -def map_statistics_panel(database_id: str) -> dict: - datasource = dict(uid=datasource_uid, - type='yesoreyeram-infinity-datasource') - return dict(title='Statistics', - type='table', - gridPos=dict(h=8, - w=12, - x=0, - y=8), - datasource=datasource, - targets=[dict(datasource=datasource, - columns=[], - filters=[], - format='table', - global_query_id='', - hide=False, - refId='A', - root_selector='columns', - source='url', - type='json', - url='/api/database/' + database_id + '/view/${view_id}/statistic', - url_options=dict(data='', - method='GET'))], - options=dict(cellHeight="sm", - showHeader=True, - footer=dict(countRows=False, - fields="", - reducer=["sum"], - show=False)), - transformations=[dict(id="organize", - options=dict(excludeByName=dict(), - includeByName=dict(), - indexByName=dict(name=0, - val_min=1, - val_max=2, - mean=3, - median=4, - std_dev=5), - renameByName=dict(name="Name", - mean="Mean", - median="Median", - std_dev="std.dev", - val_min="Minimum", - val_max="Maximum")))], - fieldConfig=dict(defaults=dict(custom=dict(align="auto", - filterable="true", - cellOptions=dict(type="auto"), - inspect=False), - mappings=[], - thresholds=dict(mode="absolute", - steps=[dict(color="green", - value=None), - dict(color="red", - value=80) - ])), - overrides=[])) - - -def map_overview_panel(database_id: str) -> dict: - datasource = dict(uid=datasource_uid, - type='yesoreyeram-infinity-datasource') - return dict(title='Datasource Preview', - type='table', - gridPos=dict(h=8, - w=18, - x=0, - y=4), - fieldConfig=dict( - defaults=dict( - color=dict(mode='palette-classic'), - custom=dict(axisBorderShow=False, - axisCenteredZero=False, - axisColorMode='text', - axisLabel='', - axisPlacement='auto', - barAlignment=0, - drawStyle='line', - fillOpacity=0, - gradientMode='none', - hideFrom=dict( - legend=False, - tooltip=False, - viz=False), - insertNulls=False, - lineInterpolation='linear', - lineWidth=1, - pointSize=5, - scaleDistribution=dict( - type='linear'), - showPoints='auto', - spanNulls=False, - stacking=dict(group='A', - mode='none'), - thresholdsStyle=dict( - mode='off'))), - overrides=[]), - options=dict(legend=dict(displayMode='list', - placement='bottom', - showLegend=True, - calcs=[]), - tooltip=dict(mode='single', - sort='none')), - targets=[dict(format='json', - columns=[], - datasource=datasource, - filters=[], - global_query_id='', - refId='A', - root_selector='', - source='url', - type='json', - url='/api/database/' + database_id + '/view/${view_id}/data', - url_options=dict(data='', - method='GET'))], - datasource=datasource) - - -def map_row() -> dict: - datasource = dict(uid=datasource_uid, - type='yesoreyeram-infinity-datasource') - return dict(collapsed=False, - repeat='view_id', - repeatDirection='h', - title=statistics_row_title, - type='row', - panels=[], - targets=[dict(refId='A', - datasource=datasource)], - gridPos=dict(h=1, - w=24, - x=0, - y=0)) - - -def map_panels(dashboard: dict, database: Database) -> [dict]: - if get_statistics_row(dashboard) is None: - dashboard['panels'].append(map_row()) # repeating - dashboard['panels'].append(map_overview_panel(database.id)) # left top - dashboard['panels'].append(map_number_panel(database.id, 'Total Entries', 'rows', 0)) # right top - dashboard['panels'].append(map_number_panel(database.id, 'Variables', '$count(columns)', 4)) # right top - dashboard['panels'].append(map_statistics_panel(database.id)) # left - dashboard['panels'].append(map_timeseries_panel(database.id)) # middle - return dashboard['panels'] diff --git a/dbrepo-dashboard-service/test.sh b/dbrepo-dashboard-service/test.sh new file mode 100644 index 0000000000000000000000000000000000000000..40328cd5dd490542e351668c7e59b33d0bba4965 --- /dev/null +++ b/dbrepo-dashboard-service/test.sh @@ -0,0 +1,7 @@ +#!/bin/bash +PIPENV_PIPFILE=./dbrepo-search-service/Pipfile +source ./dbrepo-search-service/venv/bin/activate +pip install pipenv +pipenv install gunicorn && pipenv install --dev --system --deploy +cd ./dbrepo-search-service/ && coverage run -m pytest test/test_app.py test/test_jwt.py test/test_opensearch_client.py test/test_keycloak_client.py --junitxml=report.xml && coverage html && coverage report > ./coverage.txt +cat ./coverage.txt | grep -o 'TOTAL[^%]*%' \ No newline at end of file diff --git a/dbrepo-dashboard-service/tests/conftest.py b/dbrepo-dashboard-service/tests/conftest.py new file mode 100644 index 0000000000000000000000000000000000000000..da1c56e9ebe82766026155f01414b91ae0528502 --- /dev/null +++ b/dbrepo-dashboard-service/tests/conftest.py @@ -0,0 +1,48 @@ +import logging +import os + +import pytest +from dbrepo.core.client.dashboard import DashboardServiceClient +from tests.grafana import GrafanaContainer + +logging.basicConfig(level=logging.DEBUG) + + +@pytest.fixture(scope="session") +def session(request): + """ + Create one Grafana container per test run only (admin:admin) + :param request: / + :return: The Grafana container + """ + logging.debug("[fixture] creating grafana container") + container = GrafanaContainer() + logging.debug("[fixture] starting grafana container") + container.start() + os.environ['DASHBOARD_UI_ENDPOINT'] = container.get_url() + os.environ['SYSTEM_USERNAME'] = 'admin' + os.environ['SYSTEM_PASSWORD'] = 'admin' + + # destructor + def stop_grafana(): + container.stop() + + request.addfinalizer(stop_grafana) + return container + + +@pytest.fixture(scope="function", autouse=True) +def cleanup(request, session): + """ + Clean up after each test by removing dashboards (=so it's empty again) + :param request: / + :param session: / + :return: + """ + dashboard_client = DashboardServiceClient(os.getenv('DASHBOARD_UI_ENDPOINT', 'http://localhost:3000'), + os.getenv('SYSTEM_USERNAME', 'admin'), + os.getenv('SYSTEM_PASSWORD', 'admin')) + logging.info("[fixture] clean dashboards") + for dashboard in dashboard_client.get_client().search.search_dashboards(): + dashboard_client.get_client().dashboard.delete_dashboard(dashboard['uid']) + logging.debug(f"[fixture] deleted dashboard {dashboard['uid']}") diff --git a/dbrepo-dashboard-service/tests/grafana/__init__.py b/dbrepo-dashboard-service/tests/grafana/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..46e29e9c7636b0539a12f7718b38ed294e74b0d2 --- /dev/null +++ b/dbrepo-dashboard-service/tests/grafana/__init__.py @@ -0,0 +1,28 @@ +import requests +from testcontainers.core.container import DockerContainer +from testcontainers.core.waiting_utils import wait_for_logs, wait_container_is_ready + + +class GrafanaContainer(DockerContainer): + MGMT_PORT = 3000 + + def __init__(self, image: str = "bitnami/grafana:11", **kwargs) -> None: + super().__init__(image=image, **kwargs) + self.with_exposed_ports(self.MGMT_PORT) + + def get_url(self) -> str: + return f"http://{self.get_container_host_ip()}:{self.get_exposed_port(self.MGMT_PORT)}" + + @wait_container_is_ready(requests.exceptions.ConnectionError, requests.exceptions.ReadTimeout) + def _readiness_probe(self) -> None: + try: + response = requests.get(f"{self.get_url()}/api/health", timeout=1) + except requests.exceptions.ConnectionError: + response = requests.get(f"{self.get_url()}/healthz", timeout=1) + response.raise_for_status() + wait_for_logs(self, "HTTP Server Listen") + + def start(self) -> "GrafanaContainer": + super().start() + self._readiness_probe() + return self diff --git a/dbrepo-dashboard-service/tests/rsa/rs256.key b/dbrepo-dashboard-service/tests/rsa/rs256.key new file mode 100644 index 0000000000000000000000000000000000000000..86b3eaf5c6c4c6b83071b6d1e9d69cb22bcd4085 --- /dev/null +++ b/dbrepo-dashboard-service/tests/rsa/rs256.key @@ -0,0 +1,3 @@ +-----BEGIN RSA PRIVATE KEY----- +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== +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/dbrepo-dashboard-service/tests/rsa/rsa256.pkey b/dbrepo-dashboard-service/tests/rsa/rsa256.pkey new file mode 100644 index 0000000000000000000000000000000000000000..857dfb22beeac202c2955d7cc4f782b787492beb --- /dev/null +++ b/dbrepo-dashboard-service/tests/rsa/rsa256.pkey @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB +-----END PUBLIC KEY----- diff --git a/dbrepo-dashboard-service/tests/test_integration_app.py b/dbrepo-dashboard-service/tests/test_integration_app.py new file mode 100644 index 0000000000000000000000000000000000000000..de95ad5abd540c162b218c51edfb60226de1f9c7 --- /dev/null +++ b/dbrepo-dashboard-service/tests/test_integration_app.py @@ -0,0 +1,208 @@ +import time +import unittest + +import jwt +from dbrepo.api.dto import Database, Table, Constraints, Column, ColumnType, ConceptBrief, UnitBrief, \ + UserBrief, ContainerBrief, ImageBrief + +from app import app + +req = Database(id="209acf92-5c9b-4633-ad99-113c86f6e948", + name="Test", + internal_name="test_tuw1", + dashboard_uid="2432cf61e71dea", + owner=UserBrief(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", username="foo"), + contact=UserBrief(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", username="foo"), + exchange_name="dbrepo", + is_public=True, + is_schema_public=True, + is_dashboard_enabled=True, + container=ContainerBrief(id="7efe8b27-6cdc-4387-80e3-92ee28f4a7c5", + name="MariaDB", + internal_name="mariadb", + image=ImageBrief(id="f97791b4-baf4-4b18-8f7d-3084818e6549", + name="mariadb", + version="11.1.3", + default=True)), + tables=[Table(id="f94a6164-cad4-4873-a9fd-3fe5313b2e95", + database_id="209acf92-5c9b-4633-ad99-113c86f6e948", + name="Data", + internal_name="data", + owner=UserBrief(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", username="foo"), + constraints=Constraints(uniques=[], foreign_keys=[], checks=[], primary_key=[]), + is_versioned=False, + queue_name="dbrepo", + routing_key="dbrepo.1.1", + is_public=True, + is_schema_public=True, + columns=[Column(id="7bef7e68-88f1-438e-9b94-0a77afd21471", + database_id="209acf92-5c9b-4633-ad99-113c86f6e948", + table_id="f94a6164-cad4-4873-a9fd-3fe5313b2e95", + name="ID", + ord=0, + internal_name="id", + type=ColumnType.BIGINT, + is_null_allowed=False, + size=20, + d=0, + concept=ConceptBrief(id="fb32ecf6-1f68-49b4-85ee-04e76263cbef", + uri="http://www.wikidata.org/entity/Q2221906"), + unit=UnitBrief(id="a67d735e-32ef-4917-b412-fe099c6757a1", + uri="http://www.ontology-of-units-of-measure.org/resource/om-2/degreeCelsius"), + val_min=0, + val_max=10)] + )]) + + +class AppIntegrationTest(unittest.TestCase): + + def token(self, roles: [str], iat: int = int(time.time())): + claims = { + 'iat': iat, + 'uid': 'c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502', + 'preferred_username': 'foo', + 'realm_access': { + 'roles': roles + } + } + with open('./tests/rsa/rs256.key', 'rb') as fh: + return jwt.JWT().encode(claims, jwt.jwk_from_pem(fh.read()), alg='RS256') + + def test_create_dashboard_fails(self): + with app.test_client() as test_client: + # test + response = test_client.post('/api/dashboard', + headers={'Authorization': f'Bearer {self.token(["system"])}'}) + self.assertEqual(415, response.status_code) + + def test_health_succeeds(self): + with app.test_client() as test_client: + # test + response = test_client.get('/health') + self.assertEqual(200, response.status_code) + + def test_create_dashboard_no_auth_fails(self): + with app.test_client() as test_client: + # test + response = test_client.post('/api/dashboard') + self.assertEqual(401, response.status_code) + + def test_create_dashboard_no_body_fails(self): + with app.test_client() as test_client: + # test + response = test_client.post('/api/dashboard', + headers={'Authorization': f'Bearer {self.token(["system"])}', + 'Content-Type': 'application/json'}) + self.assertEqual(400, response.status_code) + + def test_create_dashboard_empty_body_fails(self): + with app.test_client() as test_client: + # test + response = test_client.post('/api/dashboard', + headers={'Authorization': f'Bearer {self.token(["system"])}', + 'Content-Type': 'application/json'}, + json={}) + self.assertEqual(400, response.status_code) + + def test_create_dashboard_malformed_body_fails(self): + with app.test_client() as test_client: + # test + response = test_client.post('/api/dashboard', + headers={'Authorization': f'Bearer {self.token(["system"])}', + 'Content-Type': 'application/json'}, + json=dict({'is_public': True})) + self.assertEqual(400, response.status_code) + + def test_create_dashboard_succeeds(self): + with app.test_client() as test_client: + # test + response = test_client.post('/api/dashboard', + headers={'Authorization': f'Bearer {self.token(["system"])}', + 'Content-Type': 'application/json'}, + json=dict({'is_public': True, + 'is_schema_public': True, + 'database_name': 'some_database', + 'owner_username': 'foobar'})) + self.assertEqual(201, response.status_code) + + def test_update_dashboard_no_auth_fails(self): + with app.test_client() as test_client: + headers = {'Authorization': f'Bearer {self.token(["system"])}', + 'Content-Type': 'application/json'} + json_payload = dict({'is_public': True, + 'is_schema_public': True, + 'database_name': 'some_database', + 'owner_username': 'foobar'}) + # mock + response = test_client.post('/api/dashboard', headers=headers, json=json_payload) + # test + response = test_client.put(f"/api/dashboard/{response.json['uid']}") + self.assertEqual(401, response.status_code) + + def test_update_dashboard_no_body_fails(self): + with app.test_client() as test_client: + headers = {'Authorization': f'Bearer {self.token(["system"])}', + 'Content-Type': 'application/json'} + json_payload = dict({'is_public': True, + 'is_schema_public': True, + 'database_name': 'some_database', + 'owner_username': 'foobar'}) + # mock + response = test_client.post('/api/dashboard', headers=headers, json=json_payload) + # test + response = test_client.put(f"/api/dashboard/{response.json['uid']}", + headers=headers) + self.assertEqual(400, response.status_code) + + def test_update_dashboard_empty_body_fails(self): + with app.test_client() as test_client: + headers = {'Authorization': f'Bearer {self.token(["system"])}', + 'Content-Type': 'application/json'} + json_payload = dict({'is_public': True, + 'is_schema_public': True, + 'database_name': 'some_database', + 'owner_username': 'foobar'}) + # mock + response = test_client.post('/api/dashboard', headers=headers, json=json_payload) + # test + response = test_client.put(f"/api/dashboard/{response.json['uid']}", headers=headers, json={}) + self.assertEqual(400, response.status_code) + + def test_update_dashboard_malformed_body_fails(self): + with app.test_client() as test_client: + headers = {'Authorization': f'Bearer {self.token(["system"])}', + 'Content-Type': 'application/json'} + json_payload = dict({'is_public': True, + 'is_schema_public': True, + 'database_name': 'some_database', + 'owner_username': 'foobar'}) + # mock + response = test_client.post('/api/dashboard', headers=headers, json=json_payload) + # test + response = test_client.put(f"/api/dashboard/{response.json['uid']}", headers=headers, + json=dict({'is_public': True})) + self.assertEqual(400, response.status_code) + + def test_update_dashboard_succeeds(self): + with app.test_client() as test_client: + headers = {'Authorization': f'Bearer {self.token(["system"])}', + 'Content-Type': 'application/json'} + json_payload = dict({'is_public': True, + 'is_schema_public': True, + 'database_name': 'some_database', + 'owner_username': 'foobar'}) + # mock + response = test_client.post('/api/dashboard', headers=headers, json=json_payload) + req.dashboard_uid = response.json['uid'] + # test + response = test_client.put(f"/api/dashboard/{response.json['uid']}", headers=headers, + json=req.model_dump()) + self.assertEqual(202, response.status_code) + + def test_update_dashboard_not_found_fails(self): + with app.test_client() as test_client: + headers = {'Authorization': f'Bearer {self.token(["system"])}', + 'Content-Type': 'application/json'} + # test + response = test_client.put(f"/api/dashboard/idonotexist", headers=headers, json=req.model_dump()) + self.assertEqual(404, response.status_code) diff --git a/dbrepo-dashboard-ui/Dockerfile b/dbrepo-dashboard-ui/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..07a30f99ab234de910352346acc2032ce9c11cbd --- /dev/null +++ b/dbrepo-dashboard-ui/Dockerfile @@ -0,0 +1,9 @@ +FROM docker.io/bitnami/grafana:11 AS runtime +LABEL org.opencontainers.image.authors="martin.weise@tuwien.ac.at" + +WORKDIR /app + +COPY --chown=grafana:grafana ./dashboards /app/dashboards +COPY --chown=grafana:grafana ./provisioning /etc/grafana/provisioning +COPY --chown=grafana:grafana ./grafana.ini /etc/grafana/grafana.ini +COPY --chown=grafana:grafana ./ldap.toml /etc/grafana/ldap.toml diff --git a/dbrepo-dashboard-service/dashboards/system.json b/dbrepo-dashboard-ui/dashboards/System/dbrepo.json similarity index 96% rename from dbrepo-dashboard-service/dashboards/system.json rename to dbrepo-dashboard-ui/dashboards/System/dbrepo.json index e6f81bda403f662339d11600d46abfd6d18af81a..6ce787d4560b063971bff8255b63b96b055ca9b8 100644 --- a/dbrepo-dashboard-service/dashboards/system.json +++ b/dbrepo-dashboard-ui/dashboards/System/dbrepo.json @@ -30,7 +30,7 @@ "title": "Docs", "tooltip": "", "type": "link", - "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.6/" + "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.7/" } ], "panels": [ @@ -49,7 +49,7 @@ "datasource": { "default": true, "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "description": "Quality of Service", "fieldConfig": { @@ -115,7 +115,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "code", @@ -135,7 +135,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "description": "", "fieldConfig": { @@ -185,7 +185,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "code", @@ -206,7 +206,7 @@ "datasource": { "default": true, "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "fieldConfig": { "defaults": { @@ -253,7 +253,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "builder", @@ -274,7 +274,7 @@ "datasource": { "default": true, "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "fieldConfig": { "defaults": { @@ -321,7 +321,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "builder", @@ -337,7 +337,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "builder", @@ -354,7 +354,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "builder", @@ -389,7 +389,7 @@ "datasource": { "default": true, "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "description": "", "fieldConfig": { @@ -437,7 +437,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "builder", @@ -457,7 +457,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "description": "Top 10 by number of accesses", "fieldConfig": { @@ -511,7 +511,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "editorMode": "code", "expr": "topk(10, dbrepo_datasource_data_get_total)", @@ -540,7 +540,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "description": "", "fieldConfig": { @@ -602,7 +602,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "code", @@ -622,7 +622,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "description": "", "fieldConfig": { @@ -684,7 +684,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "code", @@ -704,7 +704,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "description": "", "fieldConfig": { @@ -754,7 +754,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "code", @@ -774,7 +774,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "description": "", "fieldConfig": { @@ -824,7 +824,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "code", @@ -844,7 +844,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "description": "", "fieldConfig": { @@ -895,7 +895,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "code", @@ -915,7 +915,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "fieldConfig": { "defaults": { @@ -978,7 +978,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "builder", @@ -998,7 +998,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "fieldConfig": { "defaults": { @@ -1078,7 +1078,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "builder", @@ -1111,7 +1111,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "description": "Quality of Service", "fieldConfig": { @@ -1176,7 +1176,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "code", @@ -1196,7 +1196,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "description": "", "fieldConfig": { @@ -1245,7 +1245,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "code", @@ -1265,7 +1265,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "description": "", "fieldConfig": { @@ -1314,7 +1314,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "code", @@ -1334,7 +1334,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "description": "", "fieldConfig": { @@ -1395,7 +1395,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "code", @@ -1415,7 +1415,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "description": "Ready and unacknowledged messages stored in memory", "fieldConfig": { @@ -1476,7 +1476,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "code", @@ -1496,7 +1496,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "description": "Messages delivered to consumers but not yet acknowledged", "fieldConfig": { @@ -1557,7 +1557,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "code", @@ -1577,7 +1577,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "description": "Messages for received protocol messages", "fieldConfig": { @@ -1685,7 +1685,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "code", @@ -1718,7 +1718,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "description": "", "fieldConfig": { @@ -1798,7 +1798,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "code", @@ -1818,7 +1818,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "fieldConfig": { "defaults": { @@ -1889,7 +1889,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "builder", @@ -1909,7 +1909,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "fieldConfig": { "defaults": { @@ -2046,7 +2046,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "builder", @@ -2068,7 +2068,7 @@ "datasource": { "default": true, "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "description": "Heap and non-heap memory summed", "fieldConfig": { @@ -2206,7 +2206,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "disableTextWrap": false, "editorMode": "builder", @@ -2227,7 +2227,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "description": "Top 10 by frequency of access", "fieldConfig": { @@ -2282,7 +2282,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "editorMode": "code", "expr": "topk(10, rate(dbrepo_table_data_get_total[$__range]))", @@ -2298,7 +2298,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "fieldConfig": { "defaults": { @@ -2404,7 +2404,7 @@ { "datasource": { "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "editorMode": "code", "expr": "rate(flask_http_request_duration_seconds_count{status!~\"200|201|202\"}[$__rate_interval])", @@ -2421,8 +2421,14 @@ "refresh": "1m", "schemaVersion": 39, "tags": [ - "provisioned", - "dbrepo" + "ui", + "dashboard", + "metadata", + "data", + "gateway", + "analyse", + "metrics", + "auth" ], "templating": { "list": [] @@ -2433,7 +2439,7 @@ }, "timepicker": {}, "timezone": "browser", - "title": "DBRepo - Overview", + "title": "DBRepo", "uid": "bdz20owu8zn5se", "version": 8, "weekStart": "" diff --git a/dbrepo-dashboard-service/dashboards/rabbitmq.json b/dbrepo-dashboard-ui/dashboards/System/rabbitmq.json similarity index 99% rename from dbrepo-dashboard-service/dashboards/rabbitmq.json rename to dbrepo-dashboard-ui/dashboards/System/rabbitmq.json index a8db65695f2dfef0484ebd91fcb7401f31f9f70d..6958b05e83f7e1437a024b70a37a75063b9848f8 100644 --- a/dbrepo-dashboard-service/dashboards/rabbitmq.json +++ b/dbrepo-dashboard-ui/dashboards/System/rabbitmq.json @@ -41,7 +41,7 @@ "datasource": { "default": true, "type": "prometheus", - "uid": "P18F45E9DC7E75912" + "uid": "dbrepometrics0" }, "description": "", "fieldConfig": { @@ -8056,7 +8056,7 @@ "refresh": "15s", "schemaVersion": 34, "style": "dark", - "tags": ["provisioned", "rabbitmq"], + "tags": ["rabbitmq", "amqp", "mqtt"], "templating": { "list": [ { @@ -8157,7 +8157,7 @@ ] }, "timezone": "", - "title": "RabbitMQ - Overview", + "title": "Broker Service", "uid": "Kn5xm-gZk", "version": 20220805, "weekStart": "", diff --git a/dbrepo-dashboard-service/grafana.ini b/dbrepo-dashboard-ui/grafana.ini similarity index 89% rename from dbrepo-dashboard-service/grafana.ini rename to dbrepo-dashboard-ui/grafana.ini index 1f8d9c1ef376dfd487ebf122789b557237134e35..7b7d22ccb588fbb7414a9fb28104ddadcef0dfa0 100644 --- a/dbrepo-dashboard-service/grafana.ini +++ b/dbrepo-dashboard-ui/grafana.ini @@ -1,7 +1,6 @@ [server] protocol = http domain = localhost -root_url = http://%(domain)s/dashboard/ http_port = 3000 [security] diff --git a/dbrepo-dashboard-service/ldap.toml b/dbrepo-dashboard-ui/ldap.toml similarity index 92% rename from dbrepo-dashboard-service/ldap.toml rename to dbrepo-dashboard-ui/ldap.toml index 452353136104eae051526c536631a10a11352216..c6ca55f79d061d3fbca782538b35a4e1cc495e0d 100644 --- a/dbrepo-dashboard-service/ldap.toml +++ b/dbrepo-dashboard-ui/ldap.toml @@ -12,7 +12,7 @@ timeout = 10 # User search filter, for example "(cn=%s)" or "(sAMAccountName=%s)" or "(uid=%s)" # Allow login from email or username, example "(|(sAMAccountName=%s)(userPrincipalName=%s))" -search_filter = "(cn=%s)" +search_filter = "(uid=%s)" # An array of base dns to search through search_base_dns = ["${LDAP_ROOT}"] @@ -22,11 +22,11 @@ group_search_filter = "(&(objectClass=groupOfNames)(member=cn=%s,ou=users,${LDAP group_search_filter_user_attribute = "uid" [servers.attributes] -name = "givenName" +name = "cn" surname = "sn" -username = "cn" +username = "uid" member_of = "member" -email = "email" +email = "mail" [[servers.group_mappings]] group_dn = "cn=${LDAP_ADMIN_USERNAME},ou=users,${LDAP_ROOT}" diff --git a/dbrepo-dashboard-ui/provisioning/dashboards/provider.yaml b/dbrepo-dashboard-ui/provisioning/dashboards/provider.yaml new file mode 100644 index 0000000000000000000000000000000000000000..a11a2c20b46ab733a92c9a9faede5bbde8ff47bd --- /dev/null +++ b/dbrepo-dashboard-ui/provisioning/dashboards/provider.yaml @@ -0,0 +1,20 @@ +apiVersion: 1 + +providers: + # <string> an unique provider name. Required + - name: 'dbrepo' + # <int> Org id. Default to 1 + orgId: 1 + # <string> provider type. Default to 'file' + type: file + # <bool> disable dashboard deletion + disableDeletion: false + # <int> how often Grafana will scan for changed dashboards + updateIntervalSeconds: 10 + # <bool> allow updating provisioned dashboards from the UI + allowUiUpdates: true + options: + # <string, required> path to dashboard files on disk. Required when using the 'file' type + path: /app/dashboards + # <bool> use folder names from filesystem to create folders in Grafana + foldersFromFilesStructure: true \ No newline at end of file diff --git a/dbrepo-dashboard-ui/provisioning/datasources/infinity.yaml b/dbrepo-dashboard-ui/provisioning/datasources/infinity.yaml new file mode 100644 index 0000000000000000000000000000000000000000..ce1409240e1f2131cf13ac7bcbe6d5afbebf2a6f --- /dev/null +++ b/dbrepo-dashboard-ui/provisioning/datasources/infinity.yaml @@ -0,0 +1,17 @@ +apiVersion: 1 + +datasources: + - name: dbrepo-json + uid: dbrepojson0 + type: yesoreyeram-infinity-datasource + basicAuth: true + basicAuthUser: user + url: http://localhost + jsonData: + auth_method: 'basicAuth' + httpHeaderName1: Accept + allowedHosts: + - 'http://localhost' + secureJsonData: + basicAuthPassword: user + httpHeaderValue1: application/json diff --git a/dbrepo-dashboard-ui/provisioning/datasources/prometheus.yaml b/dbrepo-dashboard-ui/provisioning/datasources/prometheus.yaml new file mode 100644 index 0000000000000000000000000000000000000000..493954f18111d39343311b683a1305f55e73b50f --- /dev/null +++ b/dbrepo-dashboard-ui/provisioning/datasources/prometheus.yaml @@ -0,0 +1,7 @@ +apiVersion: 1 + +datasources: + - name: dbrepo-metrics + type: prometheus + uid: dbrepometrics0 + url: http://metric-db:9090 diff --git a/dbrepo-data-service/Dockerfile b/dbrepo-data-service/Dockerfile index 9edf1375fb6c47f63dbd45f26bba0b3a6fe15255..7468f1c568d033c86d60579ed2c35576bcaac736 100644 --- a/dbrepo-data-service/Dockerfile +++ b/dbrepo-data-service/Dockerfile @@ -1,5 +1,5 @@ ###### FIRST STAGE ###### -FROM dbrepo-metadata-service:build AS dependency +FROM dbrepo-core:build AS dependency LABEL org.opencontainers.image.authors="martin.weise@tuwien.ac.at" ###### SECOND STAGE ###### @@ -10,7 +10,7 @@ COPY ./pom.xml ./ RUN mvn -fn dependency:go-offline -COPY --from=dependency /root/.m2/repository/at/tuwien /root/.m2/repository/at/tuwien +COPY --from=dependency /root/.m2/repository/at/ac/tuwien/ifs/dbrepo /root/.m2/repository/at/ac/tuwien/ifs/dbrepo COPY ./querystore ./querystore COPY ./report ./report @@ -28,7 +28,7 @@ RUN apk add --no-cache curl bash jq WORKDIR /app -RUN adduser -S -u 1001 data-service +RUN adduser -D dbrepo --uid 1001 USER 1001 diff --git a/dbrepo-data-service/pom.xml b/dbrepo-data-service/pom.xml index 338d6a5d73cdd2e93cdd5601c40e17655fb4a48f..bd2a9027b5e6668937ed5534067ff20df10dafd6 100644 --- a/dbrepo-data-service/pom.xml +++ b/dbrepo-data-service/pom.xml @@ -16,7 +16,7 @@ <groupId>at.tuwien</groupId> <artifactId>dbrepo-data-service</artifactId> <name>dbrepo-data-service</name> - <version>1.7.3</version> + <version>1.8.0</version> <description>Service that manages the data</description> @@ -28,7 +28,7 @@ <module>report</module> </modules> - <url>https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.7/</url> + <url>https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.8/</url> <developers> <developer> <name>Martin Weise</name> @@ -94,39 +94,13 @@ <dependencies> <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-validation</artifactId> - </dependency> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-web</artifactId> - </dependency> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-security</artifactId> - </dependency> - <dependency> - <groupId>org.springframework.security</groupId> - <artifactId>spring-security-test</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.springframework.cloud</groupId> - <artifactId>spring-cloud-starter-bootstrap</artifactId> - <version>${spring-cloud.version}</version> - </dependency> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-data-jpa</artifactId> + <groupId>at.ac.tuwien.ifs.dbrepo</groupId> + <artifactId>dbrepo-core</artifactId> + <version>${project.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-actuator</artifactId> - </dependency> - <dependency> - <groupId>com.google.guava</groupId> - <artifactId>guava</artifactId> - <version>${guava.version}</version> + <artifactId>spring-boot-starter-test</artifactId> </dependency> <!-- Spark --> <dependency> @@ -166,13 +140,12 @@ <artifactId>hadoop-aws</artifactId> <version>${hadoop.version}</version> </dependency> - <!-- Open API --> + <!-- Data Source --> <dependency> - <groupId>org.springdoc</groupId> - <artifactId>springdoc-openapi-starter-webmvc-api</artifactId> - <version>${springdoc-openapi.version}</version> + <groupId>org.mariadb.jdbc</groupId> + <artifactId>mariadb-java-client</artifactId> + <version>${mariadb.version}</version> </dependency> - <!-- Data Source --> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> @@ -203,12 +176,6 @@ <version>${micrometer.version}</version> <scope>test</scope> </dependency> - <!-- IDE --> - <dependency> - <groupId>org.projectlombok</groupId> - <artifactId>lombok</artifactId> - <scope>compile</scope> - </dependency> <!-- Mapping --> <dependency> <groupId>org.mapstruct</groupId> @@ -221,11 +188,6 @@ <artifactId>mapstruct</artifactId> <version>${mapstruct.version}</version> </dependency> - <dependency> - <groupId>com.fasterxml.jackson.datatype</groupId> - <artifactId>jackson-datatype-jsr310</artifactId> - <version>${jackson-datatype.version}</version> - </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> @@ -252,29 +214,12 @@ <artifactId>keycloak-admin-client</artifactId> <version>${keycloak.version}</version> </dependency> - <dependency> - <groupId>com.fasterxml.jackson.datatype</groupId> - <artifactId>jackson-datatype-hibernate6</artifactId> - <version>${jackson-datatype.version}</version> - </dependency> <!-- Authentication --> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>${jwt.version}</version> </dependency> - <!-- DTOs --> - <dependency> - <groupId>at.tuwien</groupId> - <artifactId>dbrepo-metadata-service-api</artifactId> - <version>${project.version}</version> - </dependency> - <!-- Exceptions --> - <dependency> - <groupId>at.tuwien</groupId> - <artifactId>dbrepo-metadata-service-repositories</artifactId> - <version>${project.version}</version> - </dependency> <!-- AMPQ --> <dependency> <groupId>org.springframework.amqp</groupId> @@ -293,19 +238,8 @@ </dependency> <!-- Testing --> <dependency> - <groupId>at.tuwien</groupId> - <artifactId>dbrepo-metadata-service-test</artifactId> - <version>${project.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>at.tuwien</groupId> - <artifactId>dbrepo-metadata-service-entities</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-test</artifactId> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> <dependency> @@ -378,7 +312,8 @@ <artifactId>maven-surefire-plugin</artifactId> <!-- Note config is repeated in scalatest config --> <configuration> - <argLine>@{argLine} -ea -Xmx4g -Xss4m -XX:MaxMetaspaceSize=2g -XX:ReservedCodeCacheSize=${CodeCacheSize} + <argLine>@{argLine} -ea -Xmx4g -Xss4m -XX:MaxMetaspaceSize=2g + -XX:ReservedCodeCacheSize=${CodeCacheSize} ${extraJavaTestArgs} </argLine> </configuration> diff --git a/dbrepo-data-service/querystore/pom.xml b/dbrepo-data-service/querystore/pom.xml index 2410a8e9fe888d361eb16e61dff6de237822045d..2e2c7d26745b4a13ee7f13c1ff3be0223e6d265b 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.7.3</version> + <version>1.8.0</version> </parent> <artifactId>dbrepo-data-service-querystore</artifactId> <name>dbrepo-data-service-querystore</name> - <version>1.7.3</version> + <version>1.8.0</version> <dependencies/> diff --git a/dbrepo-data-service/report/pom.xml b/dbrepo-data-service/report/pom.xml index b2dab3ebd05964bbdc77094948599dd59d6c3171..22839d6f4e4176c805e6939c4f84d0bbc5bf697f 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.7.3</version> + <version>1.8.0</version> </parent> <artifactId>report</artifactId> <name>dbrepo-data-service-report</name> - <version>1.7.3</version> + <version>1.8.0</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 c0f90e3cd6fa5882cc06f163cbb1fcae7833c9c8..a8590a762de68ef7e5e07f683c5e71cedc456a78 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.7.3</version> + <version>1.8.0</version> </parent> <artifactId>rest-service</artifactId> <name>dbrepo-data-service-rest-service</name> - <version>1.7.3</version> + <version>1.8.0</version> <dependencies> <dependency> <groupId>at.tuwien</groupId> <artifactId>services</artifactId> - <version>1.7.3</version> + <version>1.8.0</version> </dependency> </dependencies> diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/DbrepoDataServiceApplication.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/DataServiceApplication.java similarity index 57% rename from dbrepo-data-service/rest-service/src/main/java/at/tuwien/DbrepoDataServiceApplication.java rename to dbrepo-data-service/rest-service/src/main/java/at/tuwien/DataServiceApplication.java index 1f38a7920a020f53591ea2bd19bfdc199d9c1d87..95a70f0bb299dda8756f93fa76b2499fa7bd03a1 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/DbrepoDataServiceApplication.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/DataServiceApplication.java @@ -3,13 +3,15 @@ package at.tuwien; import lombok.extern.log4j.Log4j2; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; @Log4j2 +@EnableScheduling @SpringBootApplication -public class DbrepoDataServiceApplication { +public class DataServiceApplication { public static void main(String[] args) { - SpringApplication.run(DbrepoDataServiceApplication.class, args); + SpringApplication.run(DataServiceApplication.class, args); } } 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 ba1a0e76da6d1dda766d64c33b68ab452d509618..91f3e4410b2d5ceefba5842354fabaaeb183e6f3 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,10 +1,10 @@ package at.tuwien.endpoints; -import at.tuwien.api.database.CreateAccessDto; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.error.ApiErrorDto; -import at.tuwien.api.user.UserDto; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.CreateAccessDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.error.ApiErrorDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import at.tuwien.service.AccessService; import at.tuwien.service.CacheService; import io.swagger.v3.oas.annotations.Operation; 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 752aa83196c44f4d08dd7d6a326609f884188ed3..bf6bbc48793d06c1f9411a8c9d49845f5984f935 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,12 +1,12 @@ package at.tuwien.endpoints; -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.error.ApiErrorDto; -import at.tuwien.api.user.internal.UpdateUserPasswordDto; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.api.container.ContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.AccessTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.internal.CreateDatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.error.ApiErrorDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.internal.UpdateUserPasswordDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.AccessService; import at.tuwien.service.CacheService; @@ -94,6 +94,7 @@ public class DatabaseEndpoint extends RestEndpoint { final DatabaseDto database = containerService.createDatabase(container, data); containerService.createQueryStore(container, data.getInternalName()); accessService.create(database, metadataMapper.createDatabaseDtoToPrivilegedUserDto(data), AccessTypeDto.WRITE_ALL); + accessService.create(database, metadataMapper.createDatabaseDtoToReadonlyUserDto(data), AccessTypeDto.READ); return ResponseEntity.status(HttpStatus.CREATED) .body(database); } catch (SQLException e) { diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/RestEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/RestEndpoint.java index 45cea4371c74f61d3cca69d70b08e8341c5e78d3..a9edad96747a32c796ec0e3175d3bbab2c79b13f 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/RestEndpoint.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/RestEndpoint.java @@ -1,6 +1,6 @@ package at.tuwien.endpoints; -import at.tuwien.api.user.UserDetailsDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserDetailsDto; import org.apache.spark.sql.Dataset; import org.apache.spark.sql.Row; import org.springframework.security.core.Authentication; 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 fb076ce3a237646d19258b6fff1ee2562fb264dd..28e7b2ca9c3ca4d59bbff455b5935e1b3da6631c 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,14 @@ package at.tuwien.endpoints; -import at.tuwien.ExportResourceDto; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.ViewColumnDto; -import at.tuwien.api.database.ViewDto; -import at.tuwien.api.database.query.QueryDto; -import at.tuwien.api.database.query.QueryPersistDto; -import at.tuwien.api.database.query.SubsetDto; -import at.tuwien.api.error.ApiErrorDto; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.api.ExportResourceDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.QueryDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.QueryPersistDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.SubsetDto; +import at.ac.tuwien.ifs.dbrepo.core.api.error.ApiErrorDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.mapper.MariaDbMapper; import at.tuwien.service.CacheService; @@ -254,8 +254,8 @@ public class SubsetEndpoint extends RestEndpoint { QueryStoreInsertException, TableMalformedException, PaginationException, QueryNotSupportedException, NotAllowedException, UserNotFoundException, MetadataServiceException, TableNotFoundException, ViewMalformedException, ViewNotFoundException, ImageNotFoundException, FormatNotAvailableException { - log.debug("endpoint create subset in database, databaseId={}, page={}, size={}, timestamp={}", databaseId, - page, size, timestamp); + log.debug("endpoint create subset in database, databaseId={}, page={}, size={}, timestamp={}, data.datasource_id={}", + databaseId, page, size, timestamp, data.getDatasourceId()); /* check */ endpointValidator.validateDataParams(page, size); endpointValidator.validateSubsetParams(data); @@ -469,11 +469,11 @@ public class SubsetEndpoint extends RestEndpoint { public ResponseEntity<QueryDto> persist(@NotNull @PathVariable("databaseId") UUID databaseId, @NotNull @PathVariable("queryId") UUID queryId, @NotNull @Valid @RequestBody QueryPersistDto data, - @NotNull Principal principal) throws NotAllowedException, + Principal principal) throws NotAllowedException, RemoteUnavailableException, DatabaseNotFoundException, QueryStorePersistException, DatabaseUnavailableException, QueryNotFoundException, UserNotFoundException, MetadataServiceException { - log.debug("endpoint persist query, databaseId={}, queryId={}, data.persist={}, principal.name={}", databaseId, - queryId, data.getPersist(), principal.getName()); + log.debug("endpoint persist query, databaseId={}, queryId={}, data.persist={}", databaseId, queryId, + data.getPersist()); final DatabaseDto database = cacheService.getDatabase(databaseId); if (!isSystem(principal)) { cacheService.getAccess(databaseId, getId(principal)); diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java index 8e1fef5bac3d5451b0938f337e623d7e0e39ab56..d699fb920d64efbc0ef838e34a7f453d3de94dd8 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 @@ -1,14 +1,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.query.ImportDto; -import at.tuwien.api.database.table.*; -import at.tuwien.api.database.table.columns.ColumnDto; -import at.tuwien.api.database.table.internal.TableCreateDto; -import at.tuwien.api.error.ApiErrorDto; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.api.ExportResourceDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseAccessDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.ImportDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.internal.TableCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.error.ApiErrorDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.mapper.MariaDbMapper; import at.tuwien.service.*; @@ -297,7 +297,7 @@ public class TableEndpoint extends RestEndpoint { final HttpHeaders headers = new HttpHeaders(); if (request.getMethod().equals("HEAD")) { headers.set("Access-Control-Expose-Headers", "X-Count"); - headers.set("X-Count", "" + tableService.getCount(database, table, timestamp)); + headers.set("X-Count", "" + tableService.getCount(database, table.getInternalName(), timestamp)); return ResponseEntity.ok() .headers(headers) .build(); @@ -364,7 +364,7 @@ public class TableEndpoint extends RestEndpoint { public ResponseEntity<Void> insertRawTuple(@NotNull @PathVariable("databaseId") UUID databaseId, @NotNull @PathVariable("tableId") UUID tableId, @Valid @RequestBody TupleDto data, - @NotNull Principal principal, + Principal principal, @RequestHeader("Authorization") String authorization) throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, TableMalformedException, QueryMalformedException, NotAllowedException, StorageUnavailableException, @@ -418,7 +418,7 @@ public class TableEndpoint extends RestEndpoint { public ResponseEntity<Void> updateRawTuple(@NotNull @PathVariable("databaseId") UUID databaseId, @NotNull @PathVariable("tableId") UUID tableId, @Valid @RequestBody TupleUpdateDto data, - @NotNull Principal principal, + Principal principal, @RequestHeader("Authorization") String authorization) throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, TableMalformedException, QueryMalformedException, NotAllowedException, MetadataServiceException, @@ -473,7 +473,7 @@ public class TableEndpoint extends RestEndpoint { public ResponseEntity<Void> deleteRawTuple(@NotNull @PathVariable("databaseId") UUID databaseId, @NotNull @PathVariable("tableId") UUID tableId, @Valid @RequestBody TupleDeleteDto data, - @NotNull Principal principal, + Principal principal, @RequestHeader("Authorization") String authorization) throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, TableMalformedException, QueryMalformedException, NotAllowedException, MetadataServiceException, @@ -643,7 +643,7 @@ public class TableEndpoint extends RestEndpoint { public ResponseEntity<Void> importDataset(@NotNull @PathVariable("databaseId") UUID databaseId, @NotNull @PathVariable("tableId") UUID tableId, @Valid @RequestBody ImportDto data, - @NotNull Principal principal, + Principal principal, @RequestHeader("Authorization") String authorization) throws RemoteUnavailableException, TableNotFoundException, NotAllowedException, MetadataServiceException, StorageNotFoundException, MalformedException, StorageUnavailableException, QueryMalformedException, @@ -701,8 +701,9 @@ public class TableEndpoint extends RestEndpoint { MetadataServiceException, TableMalformedException, DatabaseNotFoundException { log.debug("endpoint generate table statistic, databaseId={}, tableId={}", databaseId, tableId); final DatabaseDto database = cacheService.getDatabase(databaseId); + final TableDto table = cacheService.getTable(databaseId, tableId); try { - return ResponseEntity.ok(tableService.getStatistics(database, cacheService.getTable(databaseId, tableId))); + return ResponseEntity.ok(tableService.getStatistics(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); diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/UploadEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/UploadEndpoint.java index 9d338e42bfce56b8274d460b121b27709705b54c..41982ebc36d5a56b0fc6c8e07551b9846882c99c 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/UploadEndpoint.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/UploadEndpoint.java @@ -1,9 +1,9 @@ package at.tuwien.endpoints; -import at.tuwien.api.database.ViewDto; -import at.tuwien.api.error.ApiErrorDto; -import at.tuwien.api.file.UploadResponseDto; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.error.ApiErrorDto; +import at.ac.tuwien.ifs.dbrepo.core.api.file.UploadResponseDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import at.tuwien.service.StorageService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; 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 add04964d031225cd7bef3d02cb2d471f9626666..73d88f0bef1eec5db04c941f2be7bd94755b4ea0 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,12 +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.ViewDto; -import at.tuwien.api.error.ApiErrorDto; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.api.ExportResourceDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.CreateViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableStatisticDto; +import at.ac.tuwien.ifs.dbrepo.core.api.error.ApiErrorDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import at.tuwien.mapper.MariaDbMapper; import at.tuwien.service.*; import at.tuwien.validation.EndpointValidator; @@ -56,9 +57,8 @@ public class ViewEndpoint extends RestEndpoint { @Autowired public ViewEndpoint(DSLContext context, ViewService viewService, CacheService cacheService, - MariaDbMapper mariaDbMapper, SubsetService subsetService, - StorageService storageService, DatabaseService databaseService, - EndpointValidator endpointValidator) { + MariaDbMapper mariaDbMapper, SubsetService subsetService, StorageService storageService, + DatabaseService databaseService, EndpointValidator endpointValidator) { this.context = context; this.viewService = viewService; this.cacheService = cacheService; @@ -136,7 +136,7 @@ public class ViewEndpoint extends RestEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), @ApiResponse(responseCode = "404", - description = "Failed to find database in metadata database", + description = "Failed to find database (or table or view) in metadata database", content = {@Content( mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), @@ -154,7 +154,7 @@ public class ViewEndpoint extends RestEndpoint { public ResponseEntity<ViewDto> create(@NotNull @PathVariable("databaseId") UUID databaseId, @Valid @RequestBody CreateViewDto data) throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException, MetadataServiceException, - TableNotFoundException, ImageNotFoundException, QueryMalformedException { + TableNotFoundException, ImageNotFoundException, QueryMalformedException, ViewNotFoundException { log.debug("endpoint create view, databaseId={}, data.name={}", databaseId, data.getName()); /* check */ endpointValidator.validateSubsetParams(data.getQuery()); @@ -339,4 +339,47 @@ public class ViewEndpoint extends RestEndpoint { } } + @GetMapping("/{viewId}/statistic") + @Observed(name = "dbrepo_view_statistic") + @Operation(summary = "Get view statistic", + description = "Gets basic statistical properties (min, max, mean, median, std.dev) of numerical columns of a view with id.", + hidden = true) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Generated view statistic", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = TableStatisticDto.class))}), + @ApiResponse(responseCode = "400", + description = "Failed to obtain column statistic", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), + @ApiResponse(responseCode = "404", + description = "Failed to find view or database in metadata database", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), + @ApiResponse(responseCode = "503", + description = "Failed to establish connection with the metadata service", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), + }) + public ResponseEntity<TableStatisticDto> statistic(@NotNull @PathVariable("databaseId") UUID databaseId, + @NotNull @PathVariable("viewId") UUID viewId) + throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, + MetadataServiceException, TableMalformedException, DatabaseNotFoundException, ViewNotFoundException, + QueryMalformedException { + log.debug("endpoint generate view statistic, databaseId={}, viewId={}", databaseId, viewId); + final DatabaseDto database = cacheService.getDatabase(databaseId); + final ViewDto view = cacheService.getView(databaseId, viewId); + try { + return ResponseEntity.ok(cacheService.getStatistic(database, view)); + } 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/handlers/ApiExceptionHandler.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java index 0926b1cf023a8a67b1712b7f2e2283c58083273c..8485d507c522de3f8b26b064e983bc823f79e947 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java @@ -1,7 +1,7 @@ package at.tuwien.handlers; -import at.tuwien.api.error.ApiErrorDto; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.api.error.ApiErrorDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import io.swagger.v3.oas.annotations.Hidden; import lombok.extern.log4j.Log4j2; import org.springframework.http.HttpHeaders; @@ -115,6 +115,20 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler { return generic_handle(e.getClass(), e.getLocalizedMessage()); } + @Hidden + @ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE) + @ExceptionHandler(DashboardServiceException.class) + public ResponseEntity<ApiErrorDto> handle(DashboardServiceException e) { + return generic_handle(e.getClass(), e.getLocalizedMessage()); + } + + @Hidden + @ResponseStatus(code = HttpStatus.BAD_GATEWAY) + @ExceptionHandler(DashboardServiceConnectionException.class) + public ResponseEntity<ApiErrorDto> handle(DashboardServiceConnectionException e) { + return generic_handle(e.getClass(), e.getLocalizedMessage()); + } + @Hidden @ResponseStatus(code = HttpStatus.EXPECTATION_FAILED) @ExceptionHandler(DatabaseMalformedException.class) 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 655741cc23d89ed41dc9b30f67c38b16b38d69a7..5f8b39704bbdc5ee7799a5335e47a8eb88943e0d 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 @@ -1,13 +1,13 @@ package at.tuwien.validation; -import at.tuwien.api.database.AccessTypeDto; -import at.tuwien.api.database.DatabaseAccessDto; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.query.FilterDto; -import at.tuwien.api.database.query.FilterTypeDto; -import at.tuwien.api.database.query.SubsetDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.AccessTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseAccessDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.FilterDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.FilterTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.SubsetDto; import at.tuwien.endpoints.RestEndpoint; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import at.tuwien.service.CacheService; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; diff --git a/dbrepo-data-service/rest-service/src/main/resources/application.yml b/dbrepo-data-service/rest-service/src/main/resources/application.yml index 53c0858bbd98acd3bb250b0def751534bc920548..a22eb40a207fc436339c4cccdfb788a7e5b513ec 100644 --- a/dbrepo-data-service/rest-service/src/main/resources/application.yml +++ b/dbrepo-data-service/rest-service/src/main/resources/application.yml @@ -17,6 +17,10 @@ spring: time_zone: UTC application: name: data-service + servlet: + multipart: + max-file-size: "${MAX_UPLOAD_SIZE:2GB}" + max-request-size: "${MAX_UPLOAD_SIZE:2GB}" rabbitmq: host: "${BROKER_HOST:broker-service}" virtual-host: "${BROKER_VIRTUALHOST:dbrepo}" @@ -41,6 +45,8 @@ management: enabled: true server: port: 8080 + tomcat: + max-swallow-size: -1 logging: pattern.console: "%d %highlight(%-5level) %msg%n" level: @@ -58,6 +64,8 @@ dbrepo: accessKeyId: "${S3_ACCESS_KEY_ID:seaweedfsadmin}" secretAccessKey: "${S3_SECRET_ACCESS_KEY:seaweedfsadmin}" bucket: "${S3_BUCKET:dbrepo}" + maxAge: "${S3_MAX_AGE:86400}" + cron: "${S3_STALE_CRON:0 */60 * * * *}" system: username: "${SYSTEM_USERNAME:admin}" password: "${SYSTEM_PASSWORD:admin}" @@ -68,14 +76,11 @@ dbrepo: password: "${AUTH_SERVICE_ADMIN_PASSWORD:admin}" client: "${AUTH_SERVICE_CLIENT:dbrepo-client}" clientSecret: "${AUTH_SERVICE_CLIENT_SECRET:MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG}" - sql: - forbidden: "${NOT_SUPPORTED_KEYWORDS:AVG,BIT_AND,BIT_OR,BIT_XOR,COUNT,COUNTDISTINCT,GROUP_CONCAT,JSON_ARRAYAGG,JSON_OBJECTAGG,MAX,MIN,STD,STDDEV,STDDEV_POP,STDDEV_SAMP,SUM,VARIANCE,VAR_POP,VAR_SAMP,--}" grant: default: read: "${GRANT_DEFAULT_READ:SELECT}" write: "${GRANT_DEFAULT_WRITE:SELECT, CREATE, CREATE VIEW, CREATE ROUTINE, CREATE TEMPORARY TABLES, LOCK TABLES, INDEX, TRIGGER, INSERT, UPDATE, DELETE}" - website: "${BASE_URL:http://localhost}" - credentialCacheTimeout: "${CREDENTIAL_CACHE_TIMEOUT:60}" + credentialCacheTimeout: "${CREDENTIAL_CACHE_TIMEOUT:300}" minConcurrent: "${MIN_CONCURRENT_CONSUMERS:2}" maxConcurrent: "${MAX_CONCURRENT_CONSUMERS:6}" requeueRejected: ${REQUEUE_REJECTED:false} 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 e03ea299a229c41ee6a5a5c342ea7af69ebc4bd4..f0b3bb8784b2ff9232f1e16dce2abdf4188c6c3b 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,8 +1,8 @@ package at.tuwien.config; -import at.tuwien.api.container.ContainerDto; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.query.QueryDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.ContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.QueryDto; import lombok.extern.log4j.Log4j2; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java index 7aa18e3b9e5e7aebf6e46ccf7fc0ca1cb0978b2a..2d0e1561173d1b547e3045cadb3b33cbd661ec4a 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java @@ -1,7 +1,8 @@ package at.tuwien.config; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.test.BaseTest; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; +import lombok.extern.log4j.Log4j2; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.testcontainers.containers.MariaDBContainer; @@ -10,8 +11,9 @@ import org.testcontainers.images.PullPolicy; /** * This class configures the MariaDB container for the integration tests. */ +@Log4j2 @Configuration -public class MariaDbContainerConfig extends AbstractUnitTest { +public class MariaDbContainerConfig extends BaseTest { public static CustomMariaDBContainer getContainer() { return CustomMariaDBContainer.getInstance(); @@ -36,7 +38,7 @@ public class MariaDbContainerConfig extends AbstractUnitTest { if (instance == null) { instance = new CustomMariaDBContainer(MARIADB_IMAGE); instance.withImagePullPolicy(PullPolicy.alwaysPull()); - instance.addFixedExposedPort(BaseTest.CONTAINER_1_PORT, BaseTest.IMAGE_1_PORT); + instance.addFixedExposedPort(BaseTest.CONTAINER_1_PORT, IMAGE_1_DEFAULT_PORT); instance.withUsername(BaseTest.CONTAINER_1_PRIVILEGED_USERNAME); instance.withPassword(BaseTest.CONTAINER_1_PRIVILEGED_PASSWORD); instance.withInitScript("init/users.sql"); 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 d41e0609bae2f356a68dd5baddee150d73356a68..36579a1954c4818067c112ddf1838cc0d6e309bb 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,15 +1,14 @@ package at.tuwien.endpoint; -import at.tuwien.api.database.AccessTypeDto; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.user.UserDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.AccessTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import at.tuwien.endpoints.AccessEndpoint; -import at.tuwien.exception.*; import at.tuwien.service.AccessService; import at.tuwien.service.CacheService; -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; @@ -28,7 +27,7 @@ import static org.mockito.Mockito.*; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class AccessEndpointUnitTest extends AbstractUnitTest { +public class AccessEndpointUnitTest extends BaseTest { @Autowired private AccessEndpoint accessEndpoint; @@ -39,11 +38,6 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { @MockBean private AccessService accessService; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) public void create_succeeds() throws UserNotFoundException, NotAllowedException, DatabaseUnavailableException, 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 e2a6c550d04a62dcc08fb2603c50c7c05af750c9..7c318d10ae9fb18c354eda4c98b54b6ed4ac4705 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 @@ -1,17 +1,16 @@ package at.tuwien.endpoint; -import at.tuwien.api.database.AccessTypeDto; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.user.UserDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.AccessTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import at.tuwien.endpoints.DatabaseEndpoint; -import at.tuwien.exception.*; import at.tuwien.service.AccessService; -import at.tuwien.service.ContainerService; import at.tuwien.service.CacheService; +import at.tuwien.service.ContainerService; import at.tuwien.service.DatabaseService; -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; @@ -33,7 +32,7 @@ import static org.mockito.Mockito.*; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class DatabaseEndpointUnitTest extends AbstractUnitTest { +public class DatabaseEndpointUnitTest extends BaseTest { @Autowired private DatabaseEndpoint databaseEndpoint; @@ -50,11 +49,6 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @MockBean private CacheService credentialService; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) public void create_succeeds() throws DatabaseUnavailableException, RemoteUnavailableException, @@ -68,7 +62,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_1_PRIVILEGED_DTO); doNothing() .when(containerService) - .createQueryStore(CONTAINER_1_DTO, DATABASE_1_INTERNALNAME); + .createQueryStore(CONTAINER_1_DTO, DATABASE_1_INTERNAL_NAME); doNothing() .when(accessService) .create(eq(DATABASE_1_PRIVILEGED_DTO), any(UserDto.class), any(AccessTypeDto.class)); @@ -90,7 +84,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_1_PRIVILEGED_DTO); doNothing() .when(containerService) - .createQueryStore(CONTAINER_1_DTO, DATABASE_1_INTERNALNAME); + .createQueryStore(CONTAINER_1_DTO, DATABASE_1_INTERNAL_NAME); doNothing() .when(accessService) .create(eq(DATABASE_1_PRIVILEGED_DTO), any(UserDto.class), any(AccessTypeDto.class)); @@ -148,7 +142,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_1_PRIVILEGED_DTO); doThrow(QueryStoreCreateException.class) .when(containerService) - .createQueryStore(CONTAINER_1_DTO, DATABASE_1_INTERNALNAME); + .createQueryStore(CONTAINER_1_DTO, DATABASE_1_INTERNAL_NAME); /* 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 92bead36748a83f0781917cd2129edb36f787097..7c21fa5ebfe0428877502c640afc9c28ec891cf6 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,23 +1,22 @@ package at.tuwien.endpoint; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.query.QueryDto; -import at.tuwien.api.database.query.QueryPersistDto; -import at.tuwien.api.database.query.SubsetDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.QueryDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.QueryPersistDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.SubsetDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import at.tuwien.endpoints.SubsetEndpoint; -import at.tuwien.exception.*; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.service.CacheService; import at.tuwien.service.DatabaseService; import at.tuwien.service.StorageService; import at.tuwien.service.SubsetService; -import at.tuwien.test.AbstractUnitTest; import jakarta.servlet.http.HttpServletRequest; 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.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -36,13 +35,13 @@ import java.util.List; import java.util.UUID; import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class SubsetEndpointUnitTest extends AbstractUnitTest { +public class SubsetEndpointUnitTest extends BaseTest { @Autowired private SubsetEndpoint subsetEndpoint; @@ -68,11 +67,6 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { @MockBean private MetadataServiceGateway metadataServiceGateway; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test @WithAnonymousUser public void list_publicDataPrivateSchemaAnonymous_succeeds() throws QueryNotFoundException, 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 3a5a62731bc595c2e971a382cf6c3a1c1b5791aa..528c9c16ed58cdc268ccd7410ef24453e7651811 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,24 +1,24 @@ 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.TableCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.AccessTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseAccessDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.ImportDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.internal.TableCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import at.tuwien.endpoints.TableEndpoint; -import at.tuwien.exception.*; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.service.CacheService; 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; 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.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; @@ -27,7 +27,6 @@ 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; -import org.springframework.core.io.InputStreamResource; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.AccessDeniedException; @@ -47,7 +46,7 @@ import static org.mockito.Mockito.*; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class TableEndpointUnitTest extends AbstractUnitTest { +public class TableEndpointUnitTest extends BaseTest { @Autowired private TableEndpoint tableEndpoint; @@ -83,17 +82,12 @@ public class TableEndpointUnitTest extends AbstractUnitTest { public static Stream<Arguments> anyAccess_parameters() { return Stream.of( - Arguments.arguments("read", DATABASE_1_USER_2_READ_ACCESS_DTO), - Arguments.arguments("write_own", DATABASE_1_USER_2_WRITE_OWN_ACCESS_DTO), - Arguments.arguments("write_all", DATABASE_1_USER_2_WRITE_ALL_ACCESS_DTO) + Arguments.arguments("read", AccessTypeDto.READ), + Arguments.arguments("write_own", AccessTypeDto.WRITE_OWN), + Arguments.arguments("write_all", AccessTypeDto.WRITE_ALL) ); } - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) public void create_succeeds() throws DatabaseUnavailableException, TableMalformedException, ViewNotFoundException, @@ -177,7 +171,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { .thenReturn(TABLE_8_DTO); when(credentialService.getDatabase(DATABASE_3_ID)) .thenReturn(DATABASE_3_PRIVILEGED_DTO); - when(tableService.getStatistics(any(DatabaseDto.class), any(TableDto.class))) + when(tableService.getStatistics(any(DatabaseDto.class), anyString())) .thenReturn(TABLE_8_STATISTIC_DTO); /* test */ @@ -197,7 +191,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_3_PRIVILEGED_DTO); doThrow(SQLException.class) .when(tableService) - .getStatistics(any(DatabaseDto.class), any(TableDto.class)); + .getStatistics(any(DatabaseDto.class), anyString()); /* test */ assertThrows(DatabaseUnavailableException.class, () -> { @@ -322,7 +316,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { .thenReturn(TABLE_5_DTO); when(credentialService.getDatabase(DATABASE_2_ID)) .thenReturn(DATABASE_2_PRIVILEGED_DTO); - when(tableService.getCount(any(DatabaseDto.class), any(TableDto.class), any(Instant.class))) + when(tableService.getCount(any(DatabaseDto.class), anyString(), any(Instant.class))) .thenReturn(3L); when(subsetService.getData(eq(DATABASE_2_DTO), anyString())) .thenReturn(mock); @@ -432,7 +426,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @ParameterizedTest @WithMockUser(username = USER_2_USERNAME) @MethodSource("anyAccess_parameters") - public void getData_private_succeeds(String name, DatabaseAccessDto access) throws DatabaseUnavailableException, + public void getData_private_succeeds(String name, AccessTypeDto type) throws DatabaseUnavailableException, TableNotFoundException, QueryMalformedException, RemoteUnavailableException, PaginationException, MetadataServiceException, NotAllowedException, DatabaseNotFoundException, StorageUnavailableException, FormatNotAvailableException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); @@ -443,7 +437,12 @@ public class TableEndpointUnitTest extends AbstractUnitTest { when(credentialService.getDatabase(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); when(credentialService.getAccess(DATABASE_1_ID, USER_2_ID)) - .thenReturn(access); + .thenReturn(DatabaseAccessDto.builder() + .user(USER_2_BRIEF_DTO) + .huserid(USER_2_ID) + .hdbid(DATABASE_1_ID) + .type(type) + .build()); when(subsetService.getData(any(DatabaseDto.class), anyString())) .thenReturn(mock); when(httpServletRequest.getMethod()) @@ -1345,7 +1344,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @ParameterizedTest @WithMockUser(username = USER_2_USERNAME) @MethodSource("anyAccess_parameters") - public void getData_privateDataPrivateSchemaTextCsv_succeeds(String name, DatabaseAccessDto access) + public void getData_privateDataPrivateSchemaTextCsv_succeeds(String name, AccessTypeDto type) throws TableNotFoundException, NotAllowedException, StorageUnavailableException, QueryMalformedException, RemoteUnavailableException, MetadataServiceException, DatabaseNotFoundException, DatabaseUnavailableException, FormatNotAvailableException, PaginationException { @@ -1357,7 +1356,12 @@ public class TableEndpointUnitTest extends AbstractUnitTest { when(credentialService.getDatabase(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); when(credentialService.getAccess(DATABASE_1_ID, USER_2_ID)) - .thenReturn(access); + .thenReturn(DatabaseAccessDto.builder() + .user(USER_2_BRIEF_DTO) + .huserid(USER_2_ID) + .hdbid(DATABASE_1_ID) + .type(type) + .build()); when(credentialService.getDatabase(DATABASE_1_ID)) .thenReturn(DATABASE_1_DTO); when(subsetService.getData(any(DatabaseDto.class), anyString())) 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 5ce2990700a30a18f454d65ccb904fe9f2cd8347..b4215747e3f9a02e91ab8fef2e7f2eb7f3750bfd 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,20 +1,19 @@ package at.tuwien.endpoint; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import at.tuwien.endpoints.ViewEndpoint; -import at.tuwien.exception.*; import at.tuwien.service.CacheService; 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; 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.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -37,7 +36,7 @@ import static org.mockito.Mockito.*; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class ViewEndpointUnitTest extends AbstractUnitTest { +public class ViewEndpointUnitTest extends BaseTest { @MockBean private ViewService viewService; @@ -60,16 +59,11 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @Autowired private SparkSession sparkSession; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) public void create_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException, SQLException, DatabaseUnavailableException, MetadataServiceException, TableNotFoundException, - ImageNotFoundException, QueryMalformedException { + ImageNotFoundException, QueryMalformedException, ViewNotFoundException { /* mock */ when(credentialService.getDatabase(DATABASE_1_ID, true)) diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/InterceptorUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/InterceptorUnitTest.java index b87793a8bcd00c499b74de68748c001750430584..c41b8c326ce46b4c59f430be7497175c76540b8b 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/InterceptorUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/InterceptorUnitTest.java @@ -1,12 +1,10 @@ package at.tuwien.gateway; -import at.tuwien.api.keycloak.TokenDto; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.TokenDto; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -22,17 +20,12 @@ import static org.mockito.Mockito.when; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class InterceptorUnitTest extends AbstractUnitTest { +public class InterceptorUnitTest extends BaseTest { @MockBean @Qualifier("keycloakRestTemplate") private RestTemplate restTemplate; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void intercept_succeeds() { 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 1ea87d2fc15cf72497784e85cfccaf14f796ad17..8052efff553bbba87396439dae15eec2644230d1 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,15 @@ package at.tuwien.gateway; -import at.tuwien.api.container.ContainerDto; -import at.tuwien.api.database.DatabaseAccessDto; -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.exception.*; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.api.container.ContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseAccessDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; 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; @@ -34,7 +33,7 @@ import static org.mockito.Mockito.when; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { +public class MetadataServiceGatewayUnitTest extends BaseTest { @MockBean @Qualifier("internalRestTemplate") @@ -43,11 +42,6 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { @Autowired private MetadataServiceGateway metadataServiceGateway; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void getTableById_succeeds() throws TableNotFoundException, RemoteUnavailableException, MetadataServiceException { @@ -130,7 +124,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { 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-Jdbc-Method", IMAGE_1_JDBC); + headers.set("X-Jdbc-Method", IMAGE_1_JDBC_METHOD); headers.set("Access-Control-Expose-Headers", "X-Username X-Password X-Jdbc-Method X-Host X-Port"); /* mock */ @@ -232,7 +226,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { 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-Jdbc-Method", IMAGE_1_JDBC); + headers.set("X-Jdbc-Method", IMAGE_1_JDBC_METHOD); headers.set("Access-Control-Expose-Headers", "X-Username X-Password X-Jdbc-Method X-Host X-Port"); /* mock */ diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/handlers/ApiExceptionHandlerTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/handlers/ApiExceptionHandlerTest.java index 7dcb0343ac1c10f7e07af87405108cac8d6a6750..063234a01269e100a8259f2651d76c81545d42e2 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/handlers/ApiExceptionHandlerTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/handlers/ApiExceptionHandlerTest.java @@ -1,8 +1,8 @@ package at.tuwien.handlers; -import at.tuwien.api.error.ApiErrorDto; -import at.tuwien.exception.*; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.api.error.ApiErrorDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -21,15 +21,15 @@ import java.util.Arrays; import java.util.List; import java.util.Optional; -import static at.tuwien.test.utils.EndpointUtils.getErrorCodes; -import static at.tuwien.test.utils.EndpointUtils.getExceptions; +import static at.ac.tuwien.ifs.dbrepo.core.test.utils.EndpointUtils.getErrorCodes; +import static at.ac.tuwien.ifs.dbrepo.core.test.utils.EndpointUtils.getExceptions; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @Log4j2 @ExtendWith(SpringExtension.class) @SpringBootTest -public class ApiExceptionHandlerTest extends AbstractUnitTest { +public class ApiExceptionHandlerTest extends BaseTest { @Autowired private ApiExceptionHandler apiExceptionHandler; 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 bf63189bf22e08a6c6c46df6623ef1a782345b98..8400a37cb94c3d2ce76b4c0d606255295eb30ab9 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 @@ -1,16 +1,15 @@ package at.tuwien.listener; +import at.ac.tuwien.ifs.dbrepo.core.exception.DatabaseNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.exception.MetadataServiceException; +import at.ac.tuwien.ifs.dbrepo.core.exception.RemoteUnavailableException; +import at.ac.tuwien.ifs.dbrepo.core.exception.TableNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import at.tuwien.config.MariaDbConfig; import at.tuwien.config.MariaDbContainerConfig; -import at.tuwien.exception.DatabaseNotFoundException; -import at.tuwien.exception.MetadataServiceException; -import at.tuwien.exception.RemoteUnavailableException; -import at.tuwien.exception.TableNotFoundException; import at.tuwien.service.CacheService; -import at.tuwien.test.AbstractUnitTest; import lombok.extern.log4j.Log4j2; 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.amqp.core.Message; @@ -31,7 +30,6 @@ import java.util.HashMap; import static at.tuwien.utils.RabbitMqUtils.buildMessage; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.when; @Log4j2 @@ -40,7 +38,7 @@ import static org.mockito.Mockito.when; @Testcontainers @ExtendWith(SpringExtension.class) @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) -public class DefaultListenerIntegrationTest extends AbstractUnitTest { +public class DefaultListenerIntegrationTest extends BaseTest { @MockBean private CacheService credentialService; @@ -56,7 +54,6 @@ public class DefaultListenerIntegrationTest extends AbstractUnitTest { @BeforeEach public void beforeEach() throws SQLException { - genesis(); /* database */ MariaDbConfig.dropAllDatabases(CONTAINER_1_PRIVILEGED_DTO); MariaDbConfig.createInitDatabase(DATABASE_1_PRIVILEGED_DTO); @@ -78,20 +75,4 @@ public class DefaultListenerIntegrationTest extends AbstractUnitTest { assertTrue(output.getAll().contains("successfully inserted tuple")); } - @Test - @Disabled - public void onMessage_tableNotFound_fails(CapturedOutput output) throws TableNotFoundException, - RemoteUnavailableException, MetadataServiceException { - 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 */ - doThrow(TableNotFoundException.class) - .when(credentialService) - .getTable(DATABASE_1_ID, TABLE_1_ID); - - /* test */ - defaultListener.onMessage(request); - assertTrue(output.getAll().contains("Failed to insert tuple")); - } - } 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 686a134dc56f5c118a5e25b2cb0150eb05ac47fd..ebff4c3fd96317b2c0f0ebdadd4b40e213853dcb 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 @@ -1,13 +1,13 @@ package at.tuwien.listener; +import at.ac.tuwien.ifs.dbrepo.core.exception.DatabaseNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.exception.MetadataServiceException; +import at.ac.tuwien.ifs.dbrepo.core.exception.RemoteUnavailableException; +import at.ac.tuwien.ifs.dbrepo.core.exception.TableNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import at.tuwien.config.MariaDbConfig; import at.tuwien.config.MariaDbContainerConfig; -import at.tuwien.exception.DatabaseNotFoundException; -import at.tuwien.exception.MetadataServiceException; -import at.tuwien.exception.RemoteUnavailableException; -import at.tuwien.exception.TableNotFoundException; import at.tuwien.service.CacheService; -import at.tuwien.test.AbstractUnitTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -36,7 +36,7 @@ import static org.mockito.Mockito.when; @SpringBootTest @ExtendWith({SpringExtension.class, OutputCaptureExtension.class}) @Testcontainers -public class DefaultListenerUnitTest extends AbstractUnitTest { +public class DefaultListenerUnitTest { @MockBean private CacheService credentialService; @@ -50,13 +50,12 @@ public class DefaultListenerUnitTest extends AbstractUnitTest { @Container private static MariaDBContainer<?> mariaDBContainer = MariaDbContainerConfig.getContainer(); - @BeforeEach - public void beforeEach() throws SQLException { - genesis(); - /* metadata database */ - MariaDbConfig.dropAllDatabases(CONTAINER_1_PRIVILEGED_DTO); - MariaDbConfig.createInitDatabase(DATABASE_1_PRIVILEGED_DTO); - } +// @BeforeEach +// public void beforeEach() throws SQLException { +// /* metadata database */ +// MariaDbConfig.dropAllDatabases(CONTAINER_1_PRIVILEGED_DTO); +// MariaDbConfig.createInitDatabase(DATABASE_1_PRIVILEGED_DTO); +// } @Test public void onMessage_routingKeyDatabaseAndTableMissing_fails(CapturedOutput output) { @@ -76,35 +75,35 @@ public class DefaultListenerUnitTest extends AbstractUnitTest { assertTrue(output.getAll().contains("Failed to map database and table")); } - @Test - public void onMessage_messageMalformed_fails(CapturedOutput output) throws TableNotFoundException, - RemoteUnavailableException, MetadataServiceException, DatabaseNotFoundException { - final Message request = buildMessage(TABLE_1_ROUTING_KEY, "{,}", new HashMap<>()); - - /* mock */ - when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID)) - .thenReturn(TABLE_1_DTO); - when(credentialService.getDatabase(DATABASE_1_ID)) - .thenReturn(DATABASE_1_PRIVILEGED_DTO); - - /* test */ - defaultListener.onMessage(request); - assertTrue(output.getAll().contains("Failed to read object")); - } - - @Test - public void onMessage_tableNotFound_fails(CapturedOutput output) throws TableNotFoundException, - RemoteUnavailableException, MetadataServiceException { - final Message request = buildMessage(TABLE_1_ROUTING_KEY, "{\"id\": 1}", new HashMap<>()); - - /* mock */ - doThrow(TableNotFoundException.class) - .when(credentialService) - .getTable(DATABASE_1_ID, TABLE_1_ID); - - /* test */ - defaultListener.onMessage(request); - assertTrue(output.getAll().contains("Failed to find table")); - } +// @Test +// public void onMessage_messageMalformed_fails(CapturedOutput output) throws TableNotFoundException, +// RemoteUnavailableException, MetadataServiceException, DatabaseNotFoundException { +// final Message request = buildMessage(TABLE_1_ROUTING_KEY, "{,}", new HashMap<>()); +// +// /* mock */ +// when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID)) +// .thenReturn(TABLE_1_DTO); +// when(credentialService.getDatabase(DATABASE_1_ID)) +// .thenReturn(DATABASE_1_PRIVILEGED_DTO); +// +// /* test */ +// defaultListener.onMessage(request); +// assertTrue(output.getAll().contains("Failed to read object")); +// } +// +// @Test +// public void onMessage_tableNotFound_fails(CapturedOutput output) throws TableNotFoundException, +// RemoteUnavailableException, MetadataServiceException { +// final Message request = buildMessage(TABLE_1_ROUTING_KEY, "{\"id\": 1}", new HashMap<>()); +// +// /* mock */ +// doThrow(TableNotFoundException.class) +// .when(credentialService) +// .getTable(DATABASE_1_ID, TABLE_1_ID); +// +// /* test */ +// defaultListener.onMessage(request); +// assertTrue(output.getAll().contains("Failed to find table")); +// } } diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mapper/MariaDbMapperUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mapper/MariaDbMapperUnitTest.java index a1a3ef4dad6060f40b60fb956e8b8f9d165228d9..ffd7a9cdcc1fd18c4452babde9fe59cd45c4b3e2 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mapper/MariaDbMapperUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mapper/MariaDbMapperUnitTest.java @@ -1,6 +1,6 @@ package at.tuwien.mapper; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; @@ -12,12 +12,12 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import java.util.stream.Stream; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class MariaDbMapperUnitTest extends AbstractUnitTest { +public class MariaDbMapperUnitTest extends BaseTest { @Autowired private MariaDbMapper mariaDbMapper; diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/ActuatorEndpointMvcTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/ActuatorEndpointMvcTest.java index a7a83a6184cab52aa4739df2005680a60eb7f81b..50f371a9a89349f794d73f59f7de2b809b2d6265 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/ActuatorEndpointMvcTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/ActuatorEndpointMvcTest.java @@ -1,6 +1,6 @@ package at.tuwien.mvc; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -20,7 +20,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @AutoConfigureMockMvc @SpringBootTest @AutoConfigureObservability -public class ActuatorEndpointMvcTest extends AbstractUnitTest { +public class ActuatorEndpointMvcTest extends BaseTest { @Autowired private MockMvc mockMvc; diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/OpenApiEndpointMvcTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/OpenApiEndpointMvcTest.java index b5ed475ea83a42db6f458d95254a081c5de5ae95..a2ef7f201c06a136b50dbe326da1be6e6959c98e 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/OpenApiEndpointMvcTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/OpenApiEndpointMvcTest.java @@ -1,8 +1,8 @@ package at.tuwien.mvc; -import at.tuwien.api.error.ApiErrorDto; +import at.ac.tuwien.ifs.dbrepo.core.api.error.ApiErrorDto; import at.tuwien.endpoints.*; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.responses.ApiResponse; @@ -30,7 +30,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @ExtendWith(SpringExtension.class) @AutoConfigureMockMvc @SpringBootTest -public class OpenApiEndpointMvcTest extends AbstractUnitTest { +public class OpenApiEndpointMvcTest extends BaseTest { @Autowired private MockMvc mockMvc; @@ -68,6 +68,7 @@ public class OpenApiEndpointMvcTest extends AbstractUnitTest { } private void generic_openApiDocs(Class<?> endpoint) { + final String packageScope = "at.ac.tuwien.ifs.dbrepo"; final List<Method> methods = Arrays.stream(endpoint.getMethods()) .filter(m -> m.getDeclaringClass().equals(endpoint)) .toList(); @@ -76,9 +77,9 @@ public class OpenApiEndpointMvcTest extends AbstractUnitTest { final List<Class<?>> exceptions = Arrays.stream(m.getExceptionTypes()) .toList(); final List<Class<?>> invalidExceptions = exceptions.stream() - .filter(e -> !e.getName().startsWith("at.tuwien.")) + .filter(e -> !e.getName().startsWith(packageScope)) .toList(); - assertTrue(invalidExceptions.isEmpty(), "method '" + m.getName() + "' throws exception(s) outside package scope at.tuwien: " + invalidExceptions.stream().map(Class::getName).toList()); + assertTrue(invalidExceptions.isEmpty(), "method '" + m.getName() + "' throws exception(s) outside package scope " + packageScope + ": " + invalidExceptions.stream().map(Class::getName).toList()); exceptions.forEach(exception -> { final int status = exception.getAnnotation(ResponseStatus.class) .code() 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 de1c875e0aef96a54f283e31a8ef90d9e8468de0..164aa99c06f63528fdc92cfae4f480e612c61383 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 @@ -1,16 +1,16 @@ package at.tuwien.mvc; -import at.tuwien.api.database.query.ImportDto; -import at.tuwien.api.database.query.QueryPersistDto; -import at.tuwien.api.database.table.TupleDeleteDto; -import at.tuwien.api.database.table.TupleDto; -import at.tuwien.api.database.table.TupleUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.ImportDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.QueryPersistDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TupleDeleteDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TupleDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TupleUpdateDto; import at.tuwien.config.MetricsConfig; import at.tuwien.endpoints.SubsetEndpoint; import at.tuwien.endpoints.TableEndpoint; import at.tuwien.endpoints.ViewEndpoint; import at.tuwien.listener.DefaultListener; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import io.micrometer.observation.tck.TestObservationRegistry; import jakarta.servlet.http.HttpServletRequest; import lombok.extern.log4j.Log4j2; @@ -42,7 +42,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @SpringBootTest @Import(MetricsConfig.class) @AutoConfigureObservability -public class PrometheusEndpointMvcTest extends AbstractUnitTest { +public class PrometheusEndpointMvcTest extends BaseTest { @Autowired private MockMvc mockMvc; diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/SubsetEndpointMvcTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/SubsetEndpointMvcTest.java index f3f0cb9799660a3a9f2db1bb949cd2983c66d79f..1371d58bb3b8e1841dd90a76d6de73b22738e808 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/SubsetEndpointMvcTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/SubsetEndpointMvcTest.java @@ -2,7 +2,7 @@ package at.tuwien.mvc; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.service.SubsetService; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -25,7 +25,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @AutoConfigureMockMvc @SpringBootTest @AutoConfigureObservability -public class SubsetEndpointMvcTest extends AbstractUnitTest { +public class SubsetEndpointMvcTest extends BaseTest { @MockBean private MetadataServiceGateway metadataServiceGateway; 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 abcfd4a175b2cd62cc8fef73c4f9627bc2077d62..55eacd882cac198f1a8f5aa1de2ffd02199039ba 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 @@ -1,10 +1,10 @@ package at.tuwien.service; -import at.tuwien.api.database.AccessTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.AccessTypeDto; import at.tuwien.config.MariaDbConfig; import at.tuwien.config.MariaDbContainerConfig; -import at.tuwien.exception.DatabaseMalformedException; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.exception.DatabaseMalformedException; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -26,7 +26,7 @@ import static org.junit.jupiter.api.Assertions.*; @SpringBootTest @ExtendWith(SpringExtension.class) @Testcontainers -public class AccessServiceIntegrationTest extends AbstractUnitTest { +public class AccessServiceIntegrationTest extends BaseTest { @Autowired private AccessService accessService; @@ -42,9 +42,8 @@ public class AccessServiceIntegrationTest extends AbstractUnitTest { @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_1_INTERNAL_NAME); MariaDbConfig.createInitDatabase(DATABASE_1_PRIVILEGED_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 index ef4f8713c87058268bdf86c653248c425113a7b8..d495fac3063e19f58d2a98cabe16f3f446953c7a 100644 --- 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 @@ -1,11 +1,11 @@ package at.tuwien.service; -import at.tuwien.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.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 at.ac.tuwien.ifs.dbrepo.core.exception.DatabaseMalformedException; +import at.ac.tuwien.ifs.dbrepo.core.exception.QueryStoreCreateException; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; @@ -28,7 +28,7 @@ import static org.junit.jupiter.api.Assertions.*; @SpringBootTest @ExtendWith(SpringExtension.class) @Testcontainers -public class ContainerServiceIntegrationTest extends AbstractUnitTest { +public class ContainerServiceIntegrationTest extends BaseTest { @Autowired private ContainerService containerService; @@ -43,10 +43,9 @@ public class ContainerServiceIntegrationTest extends AbstractUnitTest { @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); + MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNAL_NAME); + MariaDbConfig.createDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNAL_NAME); Thread.sleep(1000) /* wait for test container some more */; } @@ -54,12 +53,12 @@ public class ContainerServiceIntegrationTest extends AbstractUnitTest { public void create_succeeds() throws SQLException, DatabaseMalformedException { /* mock */ - MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME); + MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNAL_NAME); /* test */ final DatabaseDto response = containerService.createDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL); assertNull(response.getName()); - assertEquals(DATABASE_1_INTERNALNAME, response.getInternalName()); + assertEquals(DATABASE_1_INTERNAL_NAME, response.getInternalName()); assertEquals(EXCHANGE_DBREPO_NAME, response.getExchangeName()); assertNotNull(response.getOwner()); assertEquals(USER_1_ID, response.getOwner().getId()); @@ -82,7 +81,7 @@ public class ContainerServiceIntegrationTest extends AbstractUnitTest { public void createQueryStore_succeeds() throws SQLException, QueryStoreCreateException { /* test */ - createQueryStore_generic(DATABASE_1_INTERNALNAME); + createQueryStore_generic(DATABASE_1_INTERNAL_NAME); } protected void createQueryStore_generic(String databaseName) throws SQLException, QueryStoreCreateException { 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 95121ad704006cd814cf4962597e6382bc72b284..994d01136049e0e10f691818d93accf24519b321 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,15 +1,15 @@ package at.tuwien.service; -import at.tuwien.api.container.ContainerDto; -import at.tuwien.api.database.DatabaseAccessDto; -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.ac.tuwien.ifs.dbrepo.core.api.container.ContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseAccessDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.service.impl.CacheServiceImpl; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -27,7 +27,7 @@ import static org.mockito.Mockito.when; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class CredentialServiceUnitTest extends AbstractUnitTest { +public class CredentialServiceUnitTest extends BaseTest { @Autowired private CacheServiceImpl credentialService; @@ -37,7 +37,6 @@ public class CredentialServiceUnitTest extends AbstractUnitTest { @BeforeEach public void beforeEach() throws SQLException { - genesis(); /* cache */ credentialService.invalidateAll(); } 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 40fdb982ab062bb502597e899ac04caec496b564..cccba468ff1e058949a9d7a6acc401cb392e0ffa 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,25 +1,25 @@ 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.*; -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.ac.tuwien.ifs.dbrepo.core.api.database.ViewColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.ConstraintsDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.CreateTableConstraintsDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign.CreateForeignKeyDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign.ForeignKeyDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign.ForeignKeyReferenceDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign.ReferenceTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.primary.PrimaryKeyDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.unique.UniqueDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.internal.TableCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.internal.UpdateUserPasswordDto; import at.tuwien.config.MariaDbConfig; import at.tuwien.config.MariaDbContainerConfig; -import at.tuwien.exception.*; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; @@ -45,7 +45,7 @@ import static org.junit.jupiter.api.Assertions.*; @SpringBootTest @ExtendWith(SpringExtension.class) @Testcontainers -public class DatabaseServiceIntegrationTest extends AbstractUnitTest { +public class DatabaseServiceIntegrationTest extends BaseTest { @Autowired private DatabaseService databaseService; @@ -60,11 +60,10 @@ public class DatabaseServiceIntegrationTest extends AbstractUnitTest { @BeforeEach public void beforeEach() throws SQLException, InterruptedException { - genesis(); /* metadata database */ - MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME); + MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNAL_NAME); MariaDbConfig.createInitDatabase(DATABASE_1_PRIVILEGED_DTO); - MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_INTERNALNAME); + MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_INTERNAL_NAME); MariaDbConfig.createInitDatabase(DATABASE_2_PRIVILEGED_DTO); Thread.sleep(1000) /* wait for test container some more */; } @@ -113,9 +112,9 @@ public class DatabaseServiceIntegrationTest extends AbstractUnitTest { MariaDbConfig.grantWriteAccess(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME); /* pre-condition */ - MariaDbConfig.mockQuery(CONTAINER_1_HOST, CONTAINER_1_PORT, DATABASE_1_INTERNALNAME, "CREATE SEQUENCE debug NOCACHE", USER_1_USERNAME, USER_1_PASSWORD); + MariaDbConfig.mockQuery(CONTAINER_1_HOST, CONTAINER_1_PORT, DATABASE_1_INTERNAL_NAME, "CREATE SEQUENCE debug NOCACHE", USER_1_USERNAME, USER_1_PASSWORD); try { - MariaDbConfig.mockQuery(CONTAINER_1_HOST, CONTAINER_1_PORT, DATABASE_1_INTERNALNAME, "CREATE SEQUENCE debug NOCACHE", USER_1_USERNAME, USER_2_PASSWORD); + MariaDbConfig.mockQuery(CONTAINER_1_HOST, CONTAINER_1_PORT, DATABASE_1_INTERNAL_NAME, "CREATE SEQUENCE debug NOCACHE", USER_1_USERNAME, USER_2_PASSWORD); fail(); } catch (SQLException e) { /* ignore */ @@ -123,7 +122,7 @@ public class DatabaseServiceIntegrationTest extends AbstractUnitTest { /* test */ databaseService.update(DATABASE_1_PRIVILEGED_DTO, request); - MariaDbConfig.mockQuery(CONTAINER_1_HOST, CONTAINER_1_PORT, DATABASE_1_INTERNALNAME, "CREATE SEQUENCE debug2 NOCACHE", USER_1_USERNAME, USER_2_PASSWORD); + MariaDbConfig.mockQuery(CONTAINER_1_HOST, CONTAINER_1_PORT, DATABASE_1_INTERNAL_NAME, "CREATE SEQUENCE debug2 NOCACHE", USER_1_USERNAME, USER_2_PASSWORD); } @Test @@ -189,7 +188,7 @@ public class DatabaseServiceIntegrationTest extends AbstractUnitTest { assertTrue(response.getIsVersioned()); assertEquals(DATABASE_2_PUBLIC, response.getIsPublic()); assertNotNull(response.getOwner()); - assertEquals(DATABASE_2_OWNER, response.getOwner().getId()); + assertEquals(USER_2_ID, response.getOwner().getId()); assertEquals(USER_2_NAME, response.getOwner().getName()); assertEquals(USER_2_USERNAME, response.getOwner().getUsername()); assertEquals(USER_2_FIRSTNAME, response.getOwner().getFirstname()); @@ -307,8 +306,8 @@ public class DatabaseServiceIntegrationTest extends AbstractUnitTest { assertNotNull(fk0.getOnDelete()); assertNotNull(fk0.getOnUpdate()); assertNotNull(fk0.getReferencedTable()); - assertEquals(TABLE_2_INTERNALNAME, fk0.getReferencedTable().getName()); - assertEquals(TABLE_2_INTERNALNAME, fk0.getReferencedTable().getInternalName()); + assertEquals(TABLE_2_INTERNAL_NAME, fk0.getReferencedTable().getName()); + assertEquals(TABLE_2_INTERNAL_NAME, fk0.getReferencedTable().getInternalName()); } @Test @@ -600,8 +599,8 @@ public class DatabaseServiceIntegrationTest extends AbstractUnitTest { /* 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()); + assertEquals(TABLE_4_INTERNAL_NAME, response.getName()); + assertEquals(TABLE_4_INTERNAL_NAME, 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); @@ -616,7 +615,7 @@ public class DatabaseServiceIntegrationTest extends AbstractUnitTest { @Test public void createTable_malformed_fails() { - final at.tuwien.api.database.table.internal.TableCreateDto request = TableCreateDto.builder() + final at.ac.tuwien.ifs.dbrepo.core.api.database.table.internal.TableCreateDto request = TableCreateDto.builder() .name("missing_foreign_key") .columns(List.of()) .constraints(CreateTableConstraintsDto.builder() @@ -637,7 +636,7 @@ public class DatabaseServiceIntegrationTest extends AbstractUnitTest { @Test public void createTable_compositePrimaryKey_fails() throws TableNotFoundException, TableMalformedException, SQLException, TableExistsException { - final at.tuwien.api.database.table.internal.TableCreateDto request = TableCreateDto.builder() + final at.ac.tuwien.ifs.dbrepo.core.api.database.table.internal.TableCreateDto request = TableCreateDto.builder() .name("composite_primary_key") .columns(List.of(CreateTableColumnDto.builder() .name("name") 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 6996ecb9f49821b329471c6dd91dca0b4fcc74d5..190614876b0a9de04495e14427deb8b0962603a6 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 @@ -2,13 +2,13 @@ package at.tuwien.service; import at.tuwien.config.MariaDbConfig; import at.tuwien.config.MariaDbContainerConfig; -import at.tuwien.exception.DatabaseNotFoundException; -import at.tuwien.exception.MetadataServiceException; -import at.tuwien.exception.RemoteUnavailableException; -import at.tuwien.exception.TableNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.exception.DatabaseNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.exception.MetadataServiceException; +import at.ac.tuwien.ifs.dbrepo.core.exception.RemoteUnavailableException; +import at.ac.tuwien.ifs.dbrepo.core.exception.TableNotFoundException; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.service.impl.QueueServiceRabbitMqImpl; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; @@ -32,7 +32,7 @@ import static org.mockito.Mockito.when; @SpringBootTest @ExtendWith(SpringExtension.class) @Testcontainers -public class QueueServiceIntegrationTest extends AbstractUnitTest { +public class QueueServiceIntegrationTest extends BaseTest { @Autowired private QueueServiceRabbitMqImpl queueService; @@ -50,9 +50,8 @@ public class QueueServiceIntegrationTest extends AbstractUnitTest { @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_1_INTERNAL_NAME); MariaDbConfig.createInitDatabase(DATABASE_1_PRIVILEGED_DTO); } diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/StorageServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/StorageServiceIntegrationTest.java index 4344c9abb3342ca145723b6ebe8c000c147d8393..9d923542a141e25fa30467708d73b291283c52ca 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/StorageServiceIntegrationTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/StorageServiceIntegrationTest.java @@ -1,12 +1,12 @@ package at.tuwien.service; -import at.tuwien.ExportResourceDto; +import at.ac.tuwien.ifs.dbrepo.core.api.ExportResourceDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.MalformedException; +import at.ac.tuwien.ifs.dbrepo.core.exception.StorageNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.exception.StorageUnavailableException; +import at.ac.tuwien.ifs.dbrepo.core.exception.TableMalformedException; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import at.tuwien.config.S3Config; -import at.tuwien.exception.MalformedException; -import at.tuwien.exception.StorageNotFoundException; -import at.tuwien.exception.StorageUnavailableException; -import at.tuwien.exception.TableMalformedException; -import at.tuwien.test.AbstractUnitTest; import lombok.extern.log4j.Log4j2; import org.apache.commons.io.FileUtils; import org.apache.spark.sql.Dataset; @@ -31,6 +31,7 @@ import org.testcontainers.junit.jupiter.Testcontainers; import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.CreateBucketRequest; +import software.amazon.awssdk.services.s3.model.ListObjectsRequest; import software.amazon.awssdk.services.s3.model.PutObjectRequest; import java.io.*; @@ -48,7 +49,7 @@ import static org.junit.jupiter.api.Assertions.*; @SpringBootTest @ExtendWith(SpringExtension.class) @Testcontainers -public class StorageServiceIntegrationTest extends AbstractUnitTest { +public class StorageServiceIntegrationTest extends BaseTest { @Autowired private StorageService storageService; @@ -84,7 +85,6 @@ public class StorageServiceIntegrationTest extends AbstractUnitTest { @BeforeEach public void beforeEach() throws SQLException { - genesis(); /* s3 */ if (s3Client.listBuckets().buckets().stream().noneMatch(b -> b.name().equals(s3Config.getS3Bucket()))) { s3Client.createBucket(CreateBucketRequest.builder() @@ -233,6 +233,35 @@ public class StorageServiceIntegrationTest extends AbstractUnitTest { assertEquals("", lines.get(0)); } + @Test + public void deleteStaleObjects_none_succeeds() { + + /* mock */ + s3Client.putObject(PutObjectRequest.builder() + .key("s3key") + .bucket(s3Config.getS3Bucket()) + .build(), RequestBody.fromFile(new File("src/test/resources/csv/weather_aus.csv"))); + + /* test */ + storageService.deleteStaleObjects(); + assertEquals(1, s3Client.listObjects(ListObjectsRequest.builder().bucket(s3Config.getS3Bucket()).build()).contents().size()); + } + + @Test + public void deleteStaleObjects_succeeds() throws InterruptedException { + + /* mock */ + s3Client.putObject(PutObjectRequest.builder() + .key("s3key") + .bucket(s3Config.getS3Bucket()) + .build(), RequestBody.fromFile(new File("src/test/resources/csv/weather_aus.csv"))); + + /* test */ + Thread.sleep(4000); + storageService.deleteStaleObjects(); + assertEquals(0, s3Client.listObjects(ListObjectsRequest.builder().bucket(s3Config.getS3Bucket()).build()).contents().size()); + } + @ParameterizedTest @Disabled("cannot fix") @MethodSource("loadDataset_arguments") 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 d05979af36b59882a76078bb424aa3e43230933f..f6bd02059b9769538e939cd6934d0049a55610ad 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 @@ -1,12 +1,12 @@ package at.tuwien.service; -import at.tuwien.api.database.query.*; -import at.tuwien.api.identifier.IdentifierBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.*; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierBriefDto; import at.tuwien.config.MariaDbConfig; import at.tuwien.config.MariaDbContainerConfig; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import at.tuwien.gateway.MetadataServiceGateway; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.apache.spark.sql.Dataset; import org.apache.spark.sql.Row; @@ -39,7 +39,7 @@ import static org.mockito.Mockito.when; @SpringBootTest @ExtendWith(SpringExtension.class) @Testcontainers -public class SubsetServiceIntegrationTest extends AbstractUnitTest { +public class SubsetServiceIntegrationTest extends BaseTest { @Autowired private SubsetService subsetService; @@ -60,9 +60,8 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest { @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_1_INTERNAL_NAME); MariaDbConfig.createInitDatabase(DATABASE_1_PRIVILEGED_DTO); } @@ -242,7 +241,7 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest { @Test public void create_succeeds() throws SQLException, QueryStoreInsertException, ViewMalformedException, - TableNotFoundException, QueryMalformedException, ImageNotFoundException { + TableNotFoundException, QueryMalformedException, ImageNotFoundException, ViewNotFoundException { /* test */ final UUID response = subsetService.create(DATABASE_1_PRIVILEGED_DTO, QUERY_1_SUBSET_DTO, QUERY_1_CREATED, USER_1_ID); @@ -253,9 +252,10 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest { @MethodSource("create_arguments") public void create_illegalQuery_succeeds(String name, String injection) throws TableNotFoundException, QueryStoreInsertException, ViewMalformedException, SQLException, QueryMalformedException, - ImageNotFoundException { + ImageNotFoundException, ViewNotFoundException { final SubsetDto request = SubsetDto.builder() - .tableId(TABLE_1_ID) + .datasourceId(TABLE_1_ID) + .datasourceType(DatasourceType.TABLE) .columns(new LinkedList<>(List.of(COLUMN_1_1_ID, COLUMN_1_2_ID, COLUMN_1_3_ID, COLUMN_1_4_ID, COLUMN_1_5_ID))) .filter(new LinkedList<>(List.of(FilterDto.builder() .type(FilterTypeDto.WHERE) 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 77e91361db1ddbc733251c0617ff658bd199ea7a..b46ed8d4847fcf410f493c71ca7bd64e873ae4cb 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java @@ -1,13 +1,13 @@ package at.tuwien.service; -import at.tuwien.api.database.query.ImportDto; -import at.tuwien.api.database.table.*; -import at.tuwien.api.database.table.columns.ColumnStatisticDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.ImportDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnStatisticDto; import at.tuwien.config.MariaDbConfig; import at.tuwien.config.MariaDbContainerConfig; import at.tuwien.config.S3Config; -import at.tuwien.exception.*; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import com.google.common.io.Files; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeAll; @@ -45,7 +45,7 @@ import static org.junit.jupiter.api.Assertions.*; @SpringBootTest @ExtendWith(SpringExtension.class) @Testcontainers -public class TableServiceIntegrationTest extends AbstractUnitTest { +public class TableServiceIntegrationTest extends BaseTest { @Autowired private TableService tableService; @@ -74,11 +74,10 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { @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.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_3_INTERNALNAME); + MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNAL_NAME); + MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_INTERNAL_NAME); + MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_3_INTERNAL_NAME); MariaDbConfig.createInitDatabase(DATABASE_1_PRIVILEGED_DTO); MariaDbConfig.createInitDatabase(DATABASE_3_PRIVILEGED_DTO); /* s3 */ @@ -307,24 +306,28 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { public void getStatistics_succeeds() throws TableMalformedException, SQLException, TableNotFoundException { /* test */ - final TableStatisticDto response = tableService.getStatistics(DATABASE_1_PRIVILEGED_DTO, TABLE_2_DTO); + final TableStatisticDto response = tableService.getStatistics(DATABASE_1_PRIVILEGED_DTO, TABLE_2_INTERNAL_NAME); assertEquals(TABLE_2_COLUMNS.size(), response.getColumns().size()); - log.trace("response rows: {}", response.getRows()); - assertEquals(3L, response.getRows()); - assertEquals(Set.of("location", "lat", "lng"), response.getColumns().keySet()); - final ColumnStatisticDto column0 = response.getColumns().get("location"); + assertEquals(TABLE_2_COLUMNS.size(), response.getTotalColumns()); + log.trace("response rows: {}", response.getTotalRows()); + assertEquals(3L, response.getTotalRows()); + assertEquals(List.of("location", "lat", "lng"), response.getColumns().stream().map(ColumnStatisticDto::getName).toList()); + final ColumnStatisticDto column0 = response.getColumns().get(0); + assertEquals("location", column0.getName()); assertNull(column0.getMin()); assertNull(column0.getMax()); assertNull(column0.getMean()); assertNull(column0.getMedian()); assertNull(column0.getStdDev()); - final ColumnStatisticDto column3 = response.getColumns().get("lat"); + final ColumnStatisticDto column3 = response.getColumns().get(3); + assertEquals("lat", column0.getName()); assertEquals(BigDecimal.valueOf(-36.0653583), column3.getMin()); assertEquals(BigDecimal.valueOf(-33.847927), column3.getMax()); assertNotNull(column3.getMean()); assertNotNull(column3.getMedian()); assertNotNull(column3.getStdDev()); - final ColumnStatisticDto column4 = response.getColumns().get("lng"); + final ColumnStatisticDto column4 = response.getColumns().get(4); + assertEquals("lng", column0.getName()); assertEquals(BigDecimal.valueOf(146.9112214), column4.getMin()); assertEquals(BigDecimal.valueOf(150.6517942), column4.getMax()); assertNotNull(column4.getMean()); @@ -343,7 +346,7 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { public void delete_notFound_fails() throws SQLException { /* mock */ - MariaDbConfig.createDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_INTERNALNAME); + MariaDbConfig.createDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_INTERNAL_NAME); /* test */ assertThrows(QueryMalformedException.class, () -> { @@ -355,7 +358,7 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { public void getCount_succeeds() throws SQLException, QueryMalformedException { /* test */ - final Long response = tableService.getCount(DATABASE_1_PRIVILEGED_DTO, TABLE_1_DTO, null); + final Long response = tableService.getCount(DATABASE_1_PRIVILEGED_DTO, TABLE_1_INTERNAL_NAME, null); assertEquals(3, response); } @@ -363,7 +366,7 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { public void getCount_timestamp_succeeds() throws SQLException, QueryMalformedException { /* test */ - final Long response = tableService.getCount(DATABASE_1_PRIVILEGED_DTO, TABLE_1_DTO, Instant.ofEpochSecond(0)); + final Long response = tableService.getCount(DATABASE_1_PRIVILEGED_DTO, TABLE_1_INTERNAL_NAME, Instant.ofEpochSecond(0)); assertEquals(0, response); } @@ -371,11 +374,11 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { public void getCount_notFound_fails() throws SQLException { /* mock */ - MariaDbConfig.createDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_INTERNALNAME); + MariaDbConfig.createDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_INTERNAL_NAME); /* test */ assertThrows(QueryMalformedException.class, () -> { - tableService.getCount(DATABASE_2_PRIVILEGED_DTO, TABLE_5_DTO, null); + tableService.getCount(DATABASE_2_PRIVILEGED_DTO, TABLE_5_INTERNAL_NAME, null); }); } @@ -395,7 +398,7 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { public void history_notFound_fails() throws SQLException { /* mock */ - MariaDbConfig.createDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_INTERNALNAME); + MariaDbConfig.createDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_INTERNAL_NAME); /* test */ assertThrows(TableNotFoundException.class, () -> { 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 5e99f4afbcf1c144ed3566d62a21dd0cd5f771e4..7f5180e4ab21e4462df78b5efe864266b31e0b5f 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 @@ -2,8 +2,8 @@ package at.tuwien.service; import at.tuwien.config.MariaDbConfig; import at.tuwien.config.MariaDbContainerConfig; -import at.tuwien.exception.ViewMalformedException; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.exception.ViewMalformedException; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -21,7 +21,7 @@ import java.sql.SQLException; @SpringBootTest @ExtendWith(SpringExtension.class) @Testcontainers -public class ViewServiceIntegrationTest extends AbstractUnitTest { +public class ViewServiceIntegrationTest extends BaseTest { @Autowired private ViewService viewService; @@ -31,9 +31,8 @@ public class ViewServiceIntegrationTest extends AbstractUnitTest { @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_1_INTERNAL_NAME); MariaDbConfig.createInitDatabase(DATABASE_1_PRIVILEGED_DTO); } diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/MariaDbUtilTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/MariaDbUtilTest.java index 6ed73e8a01563a6b0b7e950afe5f9bf7c86cfbcf..6a7a08cf26bdddd60c62114654a754391df07850 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/MariaDbUtilTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/MariaDbUtilTest.java @@ -1,6 +1,6 @@ package at.tuwien.utils; -import at.tuwien.api.database.table.columns.ColumnTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnTypeDto; import org.junit.jupiter.api.Test; import org.springframework.amqp.core.Message; import org.springframework.amqp.core.MessageProperties; diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/validation/EndpointValidatorUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/validation/EndpointValidatorUnitTest.java index d833d3fc1a04c1b5f4671859801aa6f070ed6d52..0f865a3929b8c9667adf4d80b5c734daa11c1ca1 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/validation/EndpointValidatorUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/validation/EndpointValidatorUnitTest.java @@ -1,7 +1,7 @@ package at.tuwien.validation; -import at.tuwien.exception.PaginationException; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.exception.PaginationException; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -18,7 +18,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; @AutoConfigureMockMvc @SpringBootTest @AutoConfigureObservability -public class EndpointValidatorUnitTest extends AbstractUnitTest { +public class EndpointValidatorUnitTest extends BaseTest { @Autowired private EndpointValidator endpointValidator; diff --git a/dbrepo-data-service/rest-service/src/test/resources/application.properties b/dbrepo-data-service/rest-service/src/test/resources/application.properties index a0bb7de2bbbdfb31d85a3980355112185e51ca98..f1d57b67866e26b0b9ede1a51bbf7e3dd4444d45 100644 --- a/dbrepo-data-service/rest-service/src/test/resources/application.properties +++ b/dbrepo-data-service/rest-service/src/test/resources/application.properties @@ -33,3 +33,4 @@ spring.rabbitmq.password=guest # s3 dbrepo.s3.accessKeyId=minioadmin dbrepo.s3.secretAccessKey=minioadmin +dbrepo.s3.maxAge=3 diff --git a/dbrepo-data-service/services/pom.xml b/dbrepo-data-service/services/pom.xml index b02ce620c773185e6655b4ada10515a20d053290..27d773f4d2d8aa2a026eaf3f5974aff370384401 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.7.3</version> + <version>1.8.0</version> </parent> <artifactId>services</artifactId> <name>dbrepo-data-service-services</name> - <version>1.7.3</version> + <version>1.8.0</version> <dependencies> <dependency> <groupId>at.tuwien</groupId> <artifactId>dbrepo-data-service-querystore</artifactId> - <version>1.7.3</version> + <version>1.8.0</version> </dependency> </dependencies> diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java b/dbrepo-data-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java index 1e9d1c4bf0653758f4334f44d5c665610b7fc0fa..81590fbe4d5e17b03fd6f8b30c0e492786cbf458 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java @@ -1,7 +1,7 @@ package at.tuwien.auth; -import at.tuwien.api.auth.RealmAccessDto; -import at.tuwien.api.user.UserDetailsDto; +import at.ac.tuwien.ifs.dbrepo.core.api.auth.RealmAccessDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserDetailsDto; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java b/dbrepo-data-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java index 7af0e8cab0d6f7726954eb807c8b95e5d58b006e..047469e772eedd03054f8023a1c1c839e6291ff4 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java @@ -1,6 +1,6 @@ package at.tuwien.auth; -import at.tuwien.api.keycloak.TokenDto; +import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.TokenDto; import at.tuwien.service.CredentialService; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; @@ -28,6 +28,7 @@ public class BasicAuthenticationProvider implements AuthenticationManager { public Authentication authenticate(Authentication auth) throws AuthenticationException { final TokenDto tokenDto = credentialService.getAccessToken(auth.getName(), auth.getCredentials().toString()); final UserDetails userDetails = authTokenFilter.verifyJwt(tokenDto.getAccessToken()); + log.debug("set basic auth principal username: {}", userDetails.getUsername()); return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); } } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java b/dbrepo-data-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java index 5ba81ea4b37212eee6e370a8779618d0b8be8a3d..e5549a35b1931356518d6ada130776717f7f5c6a 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java @@ -1,6 +1,6 @@ package at.tuwien.auth; -import at.tuwien.api.keycloak.TokenDto; +import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.TokenDto; import at.tuwien.config.GatewayConfig; import at.tuwien.service.CredentialService; import lombok.extern.log4j.Log4j2; 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 603491c97005a2633885d7bff2be1b75a8625507..2466f40a2b89975a72cde4855ba908411abd2947 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,12 +1,13 @@ package at.tuwien.config; -import at.tuwien.api.container.ContainerDto; -import at.tuwien.api.database.DatabaseAccessDto; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.ViewDto; -import at.tuwien.api.database.table.TableDto; -import at.tuwien.api.keycloak.TokenDto; -import at.tuwien.api.user.UserDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.ContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseAccessDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableStatisticDto; +import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.TokenDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserDto; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import org.springframework.beans.factory.annotation.Value; @@ -52,6 +53,11 @@ public class CacheConfig { return new ExpiryCache<UUID, ContainerDto>().build(); } + @Bean + public Cache<UUID, TableStatisticDto> statisticCache() { + return new ExpiryCache<UUID, TableStatisticDto>().build(); + } + @Bean public Cache<String, TokenDto> tokenCache() { return new ExpiryCache<String, TokenDto>().build(); diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/config/S3Config.java b/dbrepo-data-service/services/src/main/java/at/tuwien/config/S3Config.java index c5aeb968d52468416c336264232e016e136bfc1a..726692e55db5dc5d2c13f78275df41ff9ea685a4 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/config/S3Config.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/config/S3Config.java @@ -30,6 +30,9 @@ public class S3Config { @Value("${dbrepo.s3.bucket}") private String s3Bucket; + @Value("${dbrepo.s3.maxAge}") + private Integer maxAge; + @Bean public S3Client s3client() { final AwsCredentialsProvider credentialsProvider = StaticCredentialsProvider.create( diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java index 21fbf674db6fbee0890528c2cb465eab53bba1c2..5b23d7c367866e42bc80446a4c8931dcc1d86cd9 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java @@ -1,10 +1,10 @@ package at.tuwien.gateway; -import at.tuwien.api.keycloak.TokenDto; -import at.tuwien.exception.AccountNotSetupException; -import at.tuwien.exception.AuthServiceConnectionException; -import at.tuwien.exception.CredentialsInvalidException; -import at.tuwien.exception.NotAllowedException; +import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.TokenDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.AccountNotSetupException; +import at.ac.tuwien.ifs.dbrepo.core.exception.AuthServiceConnectionException; +import at.ac.tuwien.ifs.dbrepo.core.exception.CredentialsInvalidException; +import at.ac.tuwien.ifs.dbrepo.core.exception.NotAllowedException; import org.springframework.security.authentication.BadCredentialsException; public interface KeycloakGateway { 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 38b28ebcac140827059fa0e510d5250755eaaf37..7d5571da9a660e7f4731862de3ddfc1548b995d7 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,18 +1,18 @@ package at.tuwien.gateway; -import at.tuwien.api.container.ContainerDto; -import at.tuwien.api.database.DatabaseAccessDto; -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.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.api.container.ContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseAccessDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import jakarta.validation.constraints.NotNull; import java.util.List; import java.util.UUID; - +// todo ? public interface MetadataServiceGateway { /** diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java index 1e14a4b4ceec8e3738f7796b4867fb1dd455ea8d..d0f874cb9c639f8c9560cd9ea3c10ac1344ca3d0 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java @@ -1,6 +1,6 @@ package at.tuwien.gateway.impl; -import at.tuwien.api.keycloak.TokenDto; +import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.TokenDto; import at.tuwien.config.KeycloakConfig; import at.tuwien.gateway.KeycloakGateway; import at.tuwien.mapper.MetadataMapper; 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 ab0ab9dea59ce1af070ff3ca3463109b82c41806..959ad34e5d386fc35b241570dcb949c40563ae77 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,14 +1,14 @@ package at.tuwien.gateway.impl; -import at.tuwien.api.container.ContainerDto; -import at.tuwien.api.database.DatabaseAccessDto; -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.ac.tuwien.ifs.dbrepo.core.api.container.ContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseAccessDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserDto; import at.tuwien.config.GatewayConfig; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.mapper.MetadataMapper; import jakarta.validation.constraints.NotNull; @@ -157,7 +157,7 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway { ViewNotFoundException, MetadataServiceException { final ResponseEntity<ViewDto> response; final String url = "/api/database/" + databaseId + "/view/" + id; - log.debug("get 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) { @@ -185,7 +185,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); + log.debug("get user info from metadata service: {}", url); try { response = internalRestTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, UserDto.class); } catch (ResourceAccessException | HttpServerErrorException e) { 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 929ede0a8f3e7ee1467a2def289c836d9823f531..aad70d3f378637fe8902c717287b12a933e9d37e 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,11 +1,11 @@ package at.tuwien.listener; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.table.TableDto; -import at.tuwien.exception.DatabaseNotFoundException; -import at.tuwien.exception.MetadataServiceException; -import at.tuwien.exception.RemoteUnavailableException; -import at.tuwien.exception.TableNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.DatabaseNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.exception.MetadataServiceException; +import at.ac.tuwien.ifs.dbrepo.core.exception.RemoteUnavailableException; +import at.ac.tuwien.ifs.dbrepo.core.exception.TableNotFoundException; import at.tuwien.service.CacheService; import at.tuwien.service.QueueService; import com.fasterxml.jackson.core.type.TypeReference; 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 9692b48b9e171fbf87e534612190e8c4f1ae2bd8..c6e14875fea73e2bbb49950e6dc5137fcccdda77 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 @@ -1,26 +1,24 @@ package at.tuwien.mapper; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.ViewColumnDto; -import at.tuwien.api.database.ViewDto; -import at.tuwien.api.database.query.QueryDto; -import at.tuwien.api.database.table.*; -import at.tuwien.api.database.table.columns.*; -import at.tuwien.api.database.table.constraints.ConstraintsDto; -import at.tuwien.api.database.table.constraints.foreign.ForeignKeyBriefDto; -import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto; -import at.tuwien.api.database.table.constraints.foreign.ForeignKeyReferenceDto; -import at.tuwien.api.database.table.constraints.foreign.ReferenceTypeDto; -import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto; -import at.tuwien.api.database.table.constraints.unique.UniqueDto; -import at.tuwien.api.user.UserBriefDto; -import at.tuwien.exception.TableNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.QueryDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.ConstraintsDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign.ForeignKeyBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign.ForeignKeyDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign.ForeignKeyReferenceDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign.ReferenceTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.primary.PrimaryKeyDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.unique.UniqueDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.TableNotFoundException; import org.apache.hadoop.shaded.com.google.common.hash.Hashing; import org.apache.hadoop.shaded.org.apache.commons.io.FileUtils; import org.jetbrains.annotations.NotNull; import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Mappings; import java.io.File; import java.io.IOException; @@ -104,17 +102,19 @@ public interface DataMapper { default TableStatisticDto resultSetToTableStatistic(ResultSet data) throws SQLException { final TableStatisticDto statistic = TableStatisticDto.builder() - .columns(new LinkedHashMap<>()) + .columns(new LinkedList<>()) .build(); while (data.next()) { final ColumnStatisticDto columnStatistic = ColumnStatisticDto.builder() + .name(data.getString(1)) .min(data.getBigDecimal(2)) .max(data.getBigDecimal(3)) .median(data.getBigDecimal(4)) .mean(data.getBigDecimal(5)) .stdDev(data.getBigDecimal(6)) .build(); - statistic.getColumns().put(data.getString(1), columnStatistic); + statistic.getColumns() + .add(columnStatistic); } return statistic; } @@ -202,6 +202,9 @@ public interface DataMapper { .resultHash(data.getString(6)) .resultNumber(data.getLong(7)) .isPersisted(data.getBoolean(8)) + .owner(UserBriefDto.builder() + .id(UUID.fromString(data.getString(3))) + .build()) .execution(LocalDateTime.parse(data.getString(9), mariaDbFormatter) .atZone(ZoneId.of("UTC")) .toInstant()) 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 a080dfb1636e40a9af41254f3a1bec8b02d708dc..7a0a094e16e8f191cbc1b5ece7b1755485cdded0 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,25 +1,23 @@ package at.tuwien.mapper; -import at.tuwien.api.container.image.OperatorDto; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.query.FilterDto; -import at.tuwien.api.database.query.FilterTypeDto; -import at.tuwien.api.database.query.OrderDto; -import at.tuwien.api.database.query.SubsetDto; -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.ColumnDto; -import at.tuwien.api.database.table.columns.ColumnTypeDto; -import at.tuwien.api.database.table.columns.CreateTableColumnDto; -import at.tuwien.exception.ImageNotFoundException; -import at.tuwien.exception.QueryMalformedException; -import at.tuwien.exception.TableMalformedException; -import at.tuwien.exception.TableNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.OperatorDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.FilterDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.FilterTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.OrderDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.SubsetDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TupleDeleteDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TupleDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TupleUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.CreateTableColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import at.tuwien.utils.MariaDbUtil; -import org.jooq.Record; import org.jooq.*; +import org.jooq.Record; import org.jooq.conf.ParamType; import org.mapstruct.Mapper; import org.mapstruct.Named; @@ -317,7 +315,7 @@ public interface MariaDbMapper { } default String tableCreateDtoToCreateTableRawQuery(String databaseName, - at.tuwien.api.database.table.internal.TableCreateDto data) { + at.ac.tuwien.ifs.dbrepo.core.api.database.table.internal.TableCreateDto data) { final StringBuilder stringBuilder = new StringBuilder("CREATE TABLE `") .append(databaseName) .append("`.`") @@ -895,15 +893,30 @@ public interface MariaDbMapper { } default String subsetDtoToRawQuery(DSLContext context, DatabaseDto database, SubsetDto data) - throws TableNotFoundException, ImageNotFoundException { - final TableDto table = tableIdToTableDto(database, data.getTableId()); - final List<Field<Object>> columns = table.getColumns() - .stream() - .filter(c -> data.getColumns().contains(c.getId())) - .map(c -> field(name(c.getInternalName()))) - .toList(); + throws TableNotFoundException, ImageNotFoundException, ViewNotFoundException { + final String datasourceName; + final List<Field<Object>> columns = switch (data.getDatasourceType()) { + case TABLE -> { + final TableDto table = tableIdToTableDto(database, data.getDatasourceId()); + datasourceName = table.getInternalName(); + yield table.getColumns() + .stream() + .filter(c -> data.getColumns().contains(c.getId())) + .map(c -> field(name(c.getInternalName()))) + .toList(); + } + case VIEW -> { + final ViewDto view = viewIdToViewDto(database, data.getDatasourceId()); + datasourceName = view.getInternalName(); + yield view.getColumns() + .stream() + .filter(c -> data.getColumns().contains(c.getId())) + .map(c -> field(name(c.getInternalName()))) + .toList(); + } + }; final SelectJoinStep<Record> query = context.select(columns) - .from(name(table.getInternalName())); + .from(name(datasourceName)); final SelectConditionStep<Record> where = subsetDtoToSelectConditions(query, database, data); final String sql; if (data.getOrder() == null) { @@ -972,4 +985,17 @@ public interface MariaDbMapper { return optional.get(); } + default ViewDto viewIdToViewDto(DatabaseDto database, UUID viewId) throws ViewNotFoundException { + final Optional<ViewDto> optional = database.getViews() + .stream() + .filter(v -> v.getId().equals(viewId)) + .findFirst(); + if (optional.isEmpty()) { + log.error("Failed to find view with id: {}", viewId); + log.trace("known view ids: {}", database.getViews().stream().map(ViewDto::getId).collect(Collectors.toList())); + throw new ViewNotFoundException("Failed to find view id: " + viewId); + } + return optional.get(); + } + } 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 8539b00432f4cc24acde9b27596543f7329b34c5..ff979bd0886157fdda574c5d3c87a3547417fa3b 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 @@ -1,21 +1,20 @@ package at.tuwien.mapper; -import at.tuwien.api.container.ContainerDto; -import at.tuwien.api.container.image.ImageDto; -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.CreateDatabaseDto; -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.identifier.IdentifierBriefDto; -import at.tuwien.api.identifier.IdentifierDto; -import at.tuwien.api.keycloak.TokenDto; -import at.tuwien.api.user.UserBriefDto; -import at.tuwien.api.user.UserDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.ContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.internal.CreateDatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierDto; +import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.TokenDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserDto; import org.keycloak.representations.AccessTokenResponse; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @@ -37,6 +36,12 @@ public interface MetadataMapper { }) UserDto createDatabaseDtoToPrivilegedUserDto(CreateDatabaseDto data); + @Mappings({ + @Mapping(target = "username", source = "readonlyUsername"), + @Mapping(target = "password", source = "readonlyPassword"), + }) + UserDto createDatabaseDtoToReadonlyUserDto(CreateDatabaseDto data); + DatabaseBriefDto databaseDtoToDatabaseBriefDto(DatabaseDto data); ColumnDto viewColumnDtoToColumnDto(ViewColumnDto 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 c42fc28101ba6498e2723f4b02acca6c6d6c2a1b..71899fc081edef19d4ce5a12040b5b9c84d2391a 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,9 +1,9 @@ package at.tuwien.service; -import at.tuwien.api.database.AccessTypeDto; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.user.UserDto; -import at.tuwien.exception.DatabaseMalformedException; +import at.ac.tuwien.ifs.dbrepo.core.api.database.AccessTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.DatabaseMalformedException; import java.sql.SQLException; diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/CacheService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/CacheService.java index 208d6e755e67b0de50ed4c72db77d325f05b043d..9424af16c24b1e51bd4fb03ce2bec251a4af9d1b 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/CacheService.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/CacheService.java @@ -1,18 +1,30 @@ package at.tuwien.service; -import at.tuwien.api.container.ContainerDto; -import at.tuwien.api.database.DatabaseAccessDto; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.ViewDto; -import at.tuwien.api.database.table.TableDto; -import at.tuwien.api.keycloak.TokenDto; -import at.tuwien.api.user.UserDto; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.api.container.ContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseAccessDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableStatisticDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import java.sql.SQLException; import java.util.UUID; public interface CacheService { + /** + * Gets credentials for a database with given id either from the cache (if not expired) or retrieves them from the + * Metadata Service. + * + * @param id The id. + * @param forceReload If set to true, force a reload of the cached result. Otherwise, use the cached result if it is present. + * @return The credentials. + * @throws DatabaseNotFoundException The database was not found in the metadata service. + * @throws RemoteUnavailableException The remote service is not available. + * @throws MetadataServiceException The remote service returned invalid data. + */ DatabaseDto getDatabase(UUID id, Boolean forceReload) throws DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException; @@ -29,6 +41,9 @@ public interface CacheService { DatabaseDto getDatabase(UUID id) throws DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException; + TableStatisticDto getStatistic(DatabaseDto database, ViewDto view) throws TableNotFoundException, + TableMalformedException, QueryMalformedException, SQLException; + /** * Gets credentials for a container with given id either from the cache (if not expired) or retrieves them from the * Metadata Service. 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 index 4f9e92ed7899149b518ef6018bade9818e1a4bc5..f788a06eebf2cf9a69e57754ca964e3f0dbcb9e2 100644 --- 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 @@ -1,10 +1,10 @@ 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 at.ac.tuwien.ifs.dbrepo.core.api.container.ContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.internal.CreateDatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.DatabaseMalformedException; +import at.ac.tuwien.ifs.dbrepo.core.exception.QueryStoreCreateException; import java.sql.SQLException; 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 b1c28cf1701772eb16f3c79a8f155faf6e8261a9..bb9765c810011f4e89ed0a9ee006cb267f7c73dd 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,6 +1,6 @@ package at.tuwien.service; -import at.tuwien.api.keycloak.TokenDto; +import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.TokenDto; public interface CredentialService { 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 8f07b6bfb29d527e99fc85504bf00c15b5424f89..a12c8e0d4d88decfd94d2695522f6a62076985f7 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,11 +1,11 @@ package at.tuwien.service; -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.internal.TableCreateDto; -import at.tuwien.api.user.internal.UpdateUserPasswordDto; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.internal.TableCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.internal.UpdateUserPasswordDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import java.sql.SQLException; import java.util.List; 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 1e8ba52923af628991d2994236378bab2e991e56..e35f4029bbdd60031fb65fe6c73e4a556cfa7af5 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,7 +1,7 @@ package at.tuwien.service; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; import java.sql.SQLException; import java.util.Map; diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/StorageService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/StorageService.java index 7ba3f93e714135e402ef506793393d0703f5aaa4..0e126e27a6aa58bb24aed6569a07a6cf5b667091 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/StorageService.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/StorageService.java @@ -1,14 +1,15 @@ package at.tuwien.service; -import at.tuwien.ExportResourceDto; -import at.tuwien.exception.MalformedException; -import at.tuwien.exception.StorageNotFoundException; -import at.tuwien.exception.StorageUnavailableException; -import at.tuwien.exception.TableMalformedException; +import at.ac.tuwien.ifs.dbrepo.core.api.ExportResourceDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.MalformedException; +import at.ac.tuwien.ifs.dbrepo.core.exception.StorageNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.exception.StorageUnavailableException; +import at.ac.tuwien.ifs.dbrepo.core.exception.TableMalformedException; import org.apache.spark.sql.Dataset; import org.apache.spark.sql.Row; import java.io.InputStream; +import java.time.Instant; import java.util.List; public interface StorageService { @@ -47,6 +48,10 @@ public interface StorageService { */ byte[] getBytes(String bucket, String key) throws StorageUnavailableException, StorageNotFoundException; + void deleteObject(String bucket, String key); + + void deleteStaleObjects(); + /** * Loads an object of the default export bucket from the Storage Service into an export resource. * 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 30d4baca5c0c4f555206f866cf886a4439dac58e..b57c2b3f106f544cc0b37bfbd17c78b3a315a5e5 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,9 +1,9 @@ package at.tuwien.service; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.query.QueryDto; -import at.tuwien.api.database.query.SubsetDto; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.QueryDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.SubsetDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import org.apache.spark.sql.Dataset; import org.apache.spark.sql.Row; @@ -26,7 +26,7 @@ public interface SubsetService { * @throws SQLException The connection to the database could not be established. */ UUID create(DatabaseDto database, SubsetDto subset, Instant timestamp, UUID userId) - throws QueryStoreInsertException, SQLException, QueryMalformedException, TableNotFoundException, ImageNotFoundException, ViewMalformedException; + throws QueryStoreInsertException, SQLException, QueryMalformedException, TableNotFoundException, ImageNotFoundException, ViewMalformedException, ViewNotFoundException; /** * Counts the subset row count of a query of a given subset in the given database. 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 bb2b53432c41e0a521165c0bbdfb197579936331..7ecc58bef88ad5adb025b6c86759d7c94e9c2c7a 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,9 +1,9 @@ package at.tuwien.service; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.query.ImportDto; -import at.tuwien.api.database.table.*; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.ImportDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.*; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import java.sql.SQLException; import java.time.Instant; @@ -14,14 +14,14 @@ public interface TableService { /** * Generate table statistic for a given table. Only numerical columns are calculated. * - * @param table The table. + * @param tableName The table name. * @return The table statistic, if successful. * @throws SQLException Failed to parse SQL query, contains invalid syntax. * @throws TableMalformedException The table statistic generation was unsuccessful, likely due to a bug in the mapping. * @throws TableNotFoundException The table could not be inspected in the data database. */ - TableStatisticDto getStatistics(DatabaseDto database, TableDto table) throws SQLException, TableMalformedException, - TableNotFoundException; + TableStatisticDto getStatistics(DatabaseDto database, String tableName) throws SQLException, + TableMalformedException, TableNotFoundException; /** * Updating table description. @@ -58,13 +58,13 @@ public interface TableService { /** * Obtains the table data tuples count at time. * - * @param table The table object. + * @param tableName The table name. * @param timestamp The timestamp. * @return Number of tuples, if successful. * @throws SQLException Failed to parse SQL query, contains invalid syntax. * @throws QueryMalformedException The count query is malformed, likely due to a bug in the application. */ - Long getCount(DatabaseDto database, TableDto table, Instant timestamp) throws SQLException, + Long getCount(DatabaseDto database, String tableName, Instant timestamp) throws SQLException, QueryMalformedException; /** 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 7f64f72ebefeb7daa3811aedf5f41765e2ec28d6..7fb1f0bdf855acfe79126873a16b71214e8b5049 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,9 +1,9 @@ package at.tuwien.service; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.ViewDto; -import at.tuwien.exception.QueryMalformedException; -import at.tuwien.exception.ViewMalformedException; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.QueryMalformedException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ViewMalformedException; import java.sql.SQLException; import java.time.Instant; 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 be049663b7eb0e3ff2e0f10ccee8e3ee2fc5b759..fee072d633eeb1bdbbe3b1e0e57d510b97e10756 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,9 +1,9 @@ package at.tuwien.service.impl; -import at.tuwien.api.database.AccessTypeDto; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.user.UserDto; -import at.tuwien.exception.DatabaseMalformedException; +import at.ac.tuwien.ifs.dbrepo.core.api.database.AccessTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.DatabaseMalformedException; import at.tuwien.mapper.MariaDbMapper; import at.tuwien.service.AccessService; import com.mchange.v2.c3p0.ComboPooledDataSource; @@ -66,8 +66,8 @@ public class AccessServiceMariaDbImpl extends DataConnector implements AccessSer } finally { dataSource.close(); } - log.info("Created access to database with internal name {} for user with id {}", database.getInternalName(), - user.getId()); + log.info("Created access to database with internal name {} for user: {}", database.getInternalName(), + user.getUsername()); } @Override diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/CacheServiceImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/CacheServiceImpl.java index 2346fe1071f458ced7f399b7ef3b85c782cd4541..65646d1ad402962b84ecb02cf3549bc3ec65aec9 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/CacheServiceImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/CacheServiceImpl.java @@ -1,25 +1,30 @@ package at.tuwien.service.impl; -import at.tuwien.api.container.ContainerDto; -import at.tuwien.api.database.DatabaseAccessDto; -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.ac.tuwien.ifs.dbrepo.core.api.container.ContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseAccessDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableStatisticDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.service.CacheService; +import at.tuwien.service.TableService; import com.github.benmanes.caffeine.cache.Cache; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.sql.SQLException; +import java.time.Instant; import java.util.UUID; @Log4j2 @Service public class CacheServiceImpl implements CacheService { + private final TableService tableService; private final MetadataServiceGateway gateway; private final Cache<UUID, UserDto> userCache; private final Cache<UUID, ViewDto> viewCache; @@ -27,12 +32,14 @@ public class CacheServiceImpl implements CacheService { private final Cache<UUID, DatabaseDto> databaseCache; private final Cache<UUID, ContainerDto> containerCache; private final Cache<UUID, DatabaseAccessDto> accessCache; + private final Cache<UUID, TableStatisticDto> statisticCache; @Autowired - public CacheServiceImpl(MetadataServiceGateway gateway, Cache<UUID, UserDto> userCache, + public CacheServiceImpl(TableService tableService, MetadataServiceGateway gateway, Cache<UUID, UserDto> userCache, Cache<UUID, ViewDto> viewCache, Cache<UUID, TableDto> tableCache, Cache<UUID, DatabaseAccessDto> accessCache, Cache<UUID, DatabaseDto> databaseCache, - Cache<UUID, ContainerDto> containerCache) { + Cache<UUID, ContainerDto> containerCache, Cache<UUID, TableStatisticDto> statisticCache) { + this.tableService = tableService; this.gateway = gateway; this.userCache = userCache; this.viewCache = viewCache; @@ -40,6 +47,7 @@ public class CacheServiceImpl implements CacheService { this.accessCache = accessCache; this.databaseCache = databaseCache; this.containerCache = containerCache; + this.statisticCache = statisticCache; } @Override @@ -78,6 +86,21 @@ public class CacheServiceImpl implements CacheService { return table; } + @Override + public TableStatisticDto getStatistic(DatabaseDto database, ViewDto view) throws TableNotFoundException, + TableMalformedException, QueryMalformedException, SQLException { + final TableStatisticDto cacheStatistic = statisticCache.getIfPresent(view.getId()); + if (cacheStatistic != null) { + log.trace("found view statistic with id {} in cache", view.getId()); + return cacheStatistic; + } + log.debug("view statistic with id {} not it cache (anymore): reload", view.getId()); + final TableStatisticDto statistic = tableService.getStatistics(database, view.getInternalName()); + statistic.setTotalRows(tableService.getCount(database, view.getInternalName(), Instant.now())); + statisticCache.put(view.getId(), statistic); + return statistic; + } + @Override public ContainerDto getContainer(UUID id) throws RemoteUnavailableException, MetadataServiceException, ContainerNotFoundException { @@ -144,6 +167,7 @@ public class CacheServiceImpl implements CacheService { tableCache.invalidateAll(); databaseCache.invalidateAll(); containerCache.invalidateAll(); + statisticCache.invalidateAll(); } } 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 index 9e35574d8ddb1eb21b9fd566d009abceecf49043..ff14b7329da5cd01666099c8ab17d77c49aa808e 100644 --- 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 @@ -1,12 +1,12 @@ 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.ac.tuwien.ifs.dbrepo.core.api.container.ContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.internal.CreateDatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserBriefDto; import at.tuwien.config.RabbitConfig; -import at.tuwien.exception.DatabaseMalformedException; -import at.tuwien.exception.QueryStoreCreateException; +import at.ac.tuwien.ifs.dbrepo.core.exception.DatabaseMalformedException; +import at.ac.tuwien.ifs.dbrepo.core.exception.QueryStoreCreateException; import at.tuwien.mapper.MariaDbMapper; import at.tuwien.service.ContainerService; import com.mchange.v2.c3p0.ComboPooledDataSource; 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 7cf7d1eff4394ae174b0e724fa8e34455b363578..cbe1912b3a5231a7d3708a75af957ff4bcbf3402 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,6 +1,6 @@ package at.tuwien.service.impl; -import at.tuwien.api.keycloak.TokenDto; +import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.TokenDto; import at.tuwien.gateway.KeycloakGateway; import at.tuwien.service.CredentialService; import com.github.benmanes.caffeine.cache.Cache; @@ -8,6 +8,8 @@ import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.time.Instant; + @Log4j2 @Service public class CredentialServiceImpl implements CredentialService { @@ -25,10 +27,16 @@ public class CredentialServiceImpl implements CredentialService { public TokenDto getAccessToken(String username, String password) { final TokenDto cacheAccessToken = tokenCache.getIfPresent(username); if (cacheAccessToken != null) { - log.trace("found access token for user with username {} in cache", username); - return cacheAccessToken; + final Instant expiry = Instant.ofEpochSecond(cacheAccessToken.getExpiresIn()); + if (!expiry.isBefore(Instant.now())) { + log.trace("found access token for user with username {} in cache", username); + return cacheAccessToken; + } else { + log.debug("access token for user with username {} expired in cache: request new", username); + } + } else { + log.debug("access token for user with username {} not it cache (anymore): request new", username); } - log.debug("access token for user with username {} not it cache (anymore): request new", username); final TokenDto token = keycloakGateway.obtainUserToken(username, password); tokenCache.put(username, token); return token; 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 index 6e6e316b5af1b2e21cbc3f0d1ad1dc7e2232dca4..366afd92a3205e20d01f198ce0dbb2c76e812e05 100644 --- 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 @@ -1,7 +1,7 @@ package at.tuwien.service.impl; -import at.tuwien.api.container.ContainerDto; -import at.tuwien.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.ContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; import com.mchange.v2.c3p0.ComboPooledDataSource; import lombok.extern.log4j.Log4j2; import org.springframework.stereotype.Service; 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 846fa86a4c967c04ed1a6b9c2b60befdbe82096c..c6a0d61595b008d73032f35063ff34bf472d83d3 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,12 +1,12 @@ package at.tuwien.service.impl; -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.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.unique.UniqueDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.internal.TableCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.internal.UpdateUserPasswordDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import at.tuwien.mapper.DataMapper; import at.tuwien.mapper.MariaDbMapper; import at.tuwien.mapper.MetadataMapper; @@ -48,7 +48,7 @@ public class DatabaseServiceMariaDbImpl extends DataConnector implements Databas try { /* obtain only view metadata */ long start = System.currentTimeMillis(); - final PreparedStatement statement1 = connection.prepareStatement(mariaDbMapper.databaseViewSelectRawQuery()); + final PreparedStatement statement1 = connection.prepareStatement(mariaDbMapper.databaseTableSelectRawQuery()); statement1.setString(1, database.getInternalName()); statement1.setString(2, viewName); log.trace("1={}, 2={}", database.getInternalName(), viewName); 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 07b889d536c14719988c768b16998ab9fcc1b55c..541f68e9516505bbc81ba7609c12f8ef4982963d 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,8 +1,8 @@ package at.tuwien.service.impl; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.table.TableDto; -import at.tuwien.api.database.table.columns.ColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnDto; import at.tuwien.mapper.DataMapper; import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.QueueService; diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/StorageServiceS3Impl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/StorageServiceS3Impl.java index 2d421ed0f309a01a3390ab08bd2c5eaebf8c4cdd..bb75d7bac20794bd16d2d47a3337cabbcad051c2 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/StorageServiceS3Impl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/StorageServiceS3Impl.java @@ -1,11 +1,11 @@ package at.tuwien.service.impl; -import at.tuwien.ExportResourceDto; +import at.ac.tuwien.ifs.dbrepo.core.api.ExportResourceDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.MalformedException; +import at.ac.tuwien.ifs.dbrepo.core.exception.StorageNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.exception.StorageUnavailableException; +import at.ac.tuwien.ifs.dbrepo.core.exception.TableMalformedException; import at.tuwien.config.S3Config; -import at.tuwien.exception.MalformedException; -import at.tuwien.exception.StorageNotFoundException; -import at.tuwien.exception.StorageUnavailableException; -import at.tuwien.exception.TableMalformedException; import at.tuwien.service.StorageService; import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.RandomStringUtils; @@ -17,13 +17,12 @@ import org.springframework.core.io.InputStreamResource; import org.springframework.stereotype.Service; import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.services.s3.S3Client; -import software.amazon.awssdk.services.s3.model.GetObjectRequest; -import software.amazon.awssdk.services.s3.model.NoSuchKeyException; -import software.amazon.awssdk.services.s3.model.PutObjectRequest; -import software.amazon.awssdk.services.s3.model.S3Exception; +import software.amazon.awssdk.services.s3.model.*; import java.io.*; import java.nio.charset.Charset; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; @@ -91,6 +90,30 @@ public class StorageServiceS3Impl implements StorageService { } } + @Override + public void deleteObject(String bucket, String key) { + log.trace("delete object with key {} from bucket: {}", key, bucket); + s3Client.deleteObject(DeleteObjectRequest.builder() + .bucket(bucket) + .key(key) + .build()); + } + + @Override + public void deleteStaleObjects() { + log.trace("list stale objects in bucket: {}", s3Config.getS3Bucket()); + final List<String> keys = s3Client.listObjects(ListObjectsRequest.builder() + .bucket(s3Config.getS3Bucket()) + .build()) + .contents() + .stream() + .filter(o -> o.lastModified().isBefore(Instant.now().minus(s3Config.getMaxAge(), ChronoUnit.SECONDS))) + .map(S3Object::key) + .toList(); + keys.forEach(key -> deleteObject(s3Config.getS3Bucket(), key)); + log.info("Deleted {} stale object(s) in bucket: {}", keys.size(), s3Config.getS3Bucket()); + } + @Override public ExportResourceDto getResource(String key) throws StorageNotFoundException, StorageUnavailableException { return getResource(s3Config.getS3Bucket(), key); 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 274654db63e333f4a99fd3bdf800bfac22754f76..bfd52d5d5010f2bafdb897a1061143105d865fef 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,14 +1,15 @@ package at.tuwien.service.impl; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.query.QueryDto; -import at.tuwien.api.database.query.SubsetDto; -import at.tuwien.api.identifier.IdentifierBriefDto; -import at.tuwien.api.identifier.IdentifierTypeDto; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.QueryDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.SubsetDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.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 com.mchange.v2.c3p0.ComboPooledDataSource; import lombok.extern.log4j.Log4j2; @@ -34,15 +35,18 @@ public class SubsetServiceMariaDbImpl extends DataConnector implements SubsetSer private final DataMapper dataMapper; private final SparkSession sparkSession; private final MariaDbMapper mariaDbMapper; + private final MetadataMapper metadataMapper; private final MetadataServiceGateway metadataServiceGateway; @Autowired public SubsetServiceMariaDbImpl(DSLContext context, DataMapper dataMapper, MariaDbMapper mariaDbMapper, - SparkSession sparkSession, MetadataServiceGateway metadataServiceGateway) { + SparkSession sparkSession, MetadataMapper metadataMapper, + MetadataServiceGateway metadataServiceGateway) { this.context = context; this.dataMapper = dataMapper; this.sparkSession = sparkSession; this.mariaDbMapper = mariaDbMapper; + this.metadataMapper = metadataMapper; this.metadataServiceGateway = metadataServiceGateway; } @@ -70,7 +74,7 @@ public class SubsetServiceMariaDbImpl extends DataConnector implements SubsetSer @Override public UUID create(DatabaseDto database, SubsetDto subset, Instant timestamp, UUID userId) throws QueryStoreInsertException, SQLException, QueryMalformedException, TableNotFoundException, - ImageNotFoundException, ViewMalformedException { + ImageNotFoundException, ViewMalformedException, ViewNotFoundException { final String statement = mariaDbMapper.subsetDtoToRawQuery(context, database, subset); return storeQuery(database, statement, timestamp, userId); } @@ -134,8 +138,8 @@ public class SubsetServiceMariaDbImpl extends DataConnector implements SubsetSer } @Override - public QueryDto findById(DatabaseDto database, UUID queryId) throws QueryNotFoundException, - SQLException, RemoteUnavailableException, DatabaseNotFoundException, MetadataServiceException { + public QueryDto findById(DatabaseDto database, UUID queryId) throws QueryNotFoundException, SQLException, + UserNotFoundException, RemoteUnavailableException, MetadataServiceException { final ComboPooledDataSource dataSource = getDataSource(database); final Connection connection = dataSource.getConnection(); try { @@ -148,7 +152,8 @@ public class SubsetServiceMariaDbImpl extends DataConnector implements SubsetSer throw new QueryNotFoundException("Failed to find query"); } final QueryDto query = dataMapper.resultSetToQueryDto(resultSet); - query.setOwner(database.getOwner()); + query.setOwner(metadataMapper.userDtoToUserBriefDto(metadataServiceGateway.getUserById(query.getOwner() + .getId()))); query.setDatabaseId(database.getId()); return query; } catch (SQLException e) { 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 4ca226ffdee8d9abe9023c540c46b2917d4a7458..8e6e6acab3b5b15f855b95393379c53669c54edb 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,12 +1,12 @@ package at.tuwien.service.impl; -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.columns.ColumnDto; -import at.tuwien.api.database.table.columns.ColumnStatisticDto; -import at.tuwien.api.database.table.columns.ColumnTypeDto; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.ImportDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnStatisticDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import at.tuwien.mapper.DataMapper; import at.tuwien.mapper.MariaDbMapper; import at.tuwien.service.DatabaseService; @@ -51,7 +51,7 @@ public class TableServiceMariaDbImpl extends DataConnector implements TableServi } @Override - public TableStatisticDto getStatistics(DatabaseDto database, TableDto table) throws SQLException, TableMalformedException, + public TableStatisticDto getStatistics(DatabaseDto database, String tableName) throws SQLException, TableMalformedException, TableNotFoundException { final ComboPooledDataSource dataSource = getDataSource(database); final Connection connection = dataSource.getConnection(); @@ -59,27 +59,30 @@ public class TableServiceMariaDbImpl extends DataConnector implements TableServi try { /* obtain statistic */ final long start = System.currentTimeMillis(); - final String query = mariaDbMapper.tableColumnStatisticsSelectRawQuery(table.getColumns(), table.getInternalName()); + final TableDto tmpTable = databaseService.inspectTable(database, tableName); + final String query = mariaDbMapper.tableColumnStatisticsSelectRawQuery(tmpTable.getColumns(), tableName); if (query == null) { - log.debug("table {}.{} does not have columns that can be analysed for statistical properties", database.getInternalName(), table.getInternalName()); - statistic = null; - } else { - final ResultSet resultSet = connection.prepareStatement(query) - .executeQuery(); - log.trace("executed statement in {} ms", System.currentTimeMillis() - start); - statistic = dataMapper.resultSetToTableStatistic(resultSet); - final TableDto tmpTable = databaseService.inspectTable(database, table.getInternalName()); - statistic.setAvgRowLength(tmpTable.getAvgRowLength()); - statistic.setDataLength(tmpTable.getDataLength()); - statistic.setMaxDataLength(tmpTable.getMaxDataLength()); - statistic.setRows(tmpTable.getNumRows()); - /* add to statistic dto */ - table.getColumns() - .stream() - .filter(column -> !MariaDbUtil.numericDataTypes.contains(column.getColumnType())) - .forEach(column -> statistic.getColumns().put(column.getInternalName(), new ColumnStatisticDto())); - log.info("Obtained statistics for the table and {} column(s)", statistic.getColumns().size()); + log.debug("table {}.{} does not have columns that can be analysed for statistical properties", database.getInternalName(), tableName); + return null; } + final ResultSet resultSet = connection.prepareStatement(query) + .executeQuery(); + statistic = dataMapper.resultSetToTableStatistic(resultSet); + statistic.setTotalColumns(Long.parseLong("" + tmpTable.getColumns() + .size())); + log.trace("executed statement in {} ms", System.currentTimeMillis() - start); + statistic.setAvgRowLength(tmpTable.getAvgRowLength()); + statistic.setDataLength(tmpTable.getDataLength()); + statistic.setMaxDataLength(tmpTable.getMaxDataLength()); + statistic.setTotalRows(tmpTable.getNumRows()); + /* add to statistic dto */ + tmpTable.getColumns() + .stream() + .filter(column -> !MariaDbUtil.numericDataTypes.contains(column.getColumnType())) + .forEach(column -> ColumnStatisticDto.builder() + .name(column.getInternalName()) + .build()); + log.info("Obtained statistics for the table and {} column(s)", statistic.getColumns().size()); } catch (SQLException e) { connection.rollback(); log.error("Failed to obtain column statistics: {}", e.getMessage()); @@ -168,7 +171,7 @@ public class TableServiceMariaDbImpl extends DataConnector implements TableServi } @Override - public Long getCount(DatabaseDto database, TableDto table, Instant timestamp) throws SQLException, + public Long getCount(DatabaseDto database, String tableName, Instant timestamp) throws SQLException, QueryMalformedException { final ComboPooledDataSource dataSource = getDataSource(database); final Connection connection = dataSource.getConnection(); @@ -177,19 +180,19 @@ public class TableServiceMariaDbImpl extends DataConnector implements TableServi /* find table data */ final long start = System.currentTimeMillis(); final ResultSet resultSet = connection.prepareStatement(mariaDbMapper.selectCountRawQuery( - database.getInternalName(), table.getInternalName(), timestamp)) + database.getInternalName(), tableName, timestamp)) .executeQuery(); log.trace("executed statement in {} ms", System.currentTimeMillis() - start); queryResult = mariaDbMapper.resultSetToNumber(resultSet); connection.commit(); } catch (SQLException e) { connection.rollback(); - log.error("Failed to find row count from table {}.{}: {}", database, table.getInternalName(), e.getMessage()); - throw new QueryMalformedException("Failed to find row count from table " + database + "." + table.getInternalName() + ": " + e.getMessage(), e); + log.error("Failed to find row count from table {}.{}: {}", database, tableName, e.getMessage()); + throw new QueryMalformedException("Failed to find row count from table " + database + "." + tableName + ": " + e.getMessage(), e); } finally { dataSource.close(); } - log.info("Find row count from table {}.{}", database.getInternalName(), table.getInternalName()); + log.info("Find row count from table {}.{}", database.getInternalName(), tableName); return queryResult; } 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 c1ba33ae4ae91639ba14d715a569b4b596880625..0ef62bb025159966d295975ac0810074214eafc6 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,9 +1,9 @@ package at.tuwien.service.impl; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.ViewDto; -import at.tuwien.exception.QueryMalformedException; -import at.tuwien.exception.ViewMalformedException; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.QueryMalformedException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ViewMalformedException; import at.tuwien.mapper.MariaDbMapper; import at.tuwien.service.ViewService; import com.mchange.v2.c3p0.ComboPooledDataSource; diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/timer/StaleObjectTimer.java b/dbrepo-data-service/services/src/main/java/at/tuwien/timer/StaleObjectTimer.java new file mode 100644 index 0000000000000000000000000000000000000000..de30299f3d0b4ccace1a8181e678e5e3ebd2dd87 --- /dev/null +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/timer/StaleObjectTimer.java @@ -0,0 +1,25 @@ +package at.tuwien.timer; + +import at.tuwien.service.StorageService; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Log4j2 +@Component +public class StaleObjectTimer { + + private final StorageService storageService; + + @Autowired + public StaleObjectTimer(StorageService storageService) { + this.storageService = storageService; + } + + @Scheduled(cron = "${dbrepo.s3.cron}") + public void deleteStaleObjects() { + storageService.deleteStaleObjects(); + } + +} diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/utils/MariaDbUtil.java b/dbrepo-data-service/services/src/main/java/at/tuwien/utils/MariaDbUtil.java index a917be6d46899c62e3e166ad0610950c9463bbca..6d831d8d11c393c0148e1543756ee3c7de88015c 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/utils/MariaDbUtil.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/utils/MariaDbUtil.java @@ -1,6 +1,6 @@ package at.tuwien.utils; -import at.tuwien.api.database.table.columns.ColumnTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnTypeDto; import java.util.List; diff --git a/dbrepo-gateway-service/dbrepo.conf b/dbrepo-gateway-service/dbrepo.conf index f181fdf7a70945280453f345f6a639921967abca..fe98534bd8ddc43e42bdb1a55ad0192a86236621 100644 --- a/dbrepo-gateway-service/dbrepo.conf +++ b/dbrepo-gateway-service/dbrepo.conf @@ -12,62 +12,31 @@ proxy_busy_buffers_size 256k; resolver 127.0.0.11 valid=30s; # docker dns -upstream broker { - server broker-service:15672; -} - -upstream analyse { - server analyse-service:8080; -} - -upstream data { - server data-service:8080; -} - -upstream metadata { - server metadata-service:8080; -} - -upstream search { - server search-service:8080; -} - -upstream ui { - server ui:3000; -} - -upstream dashboard-service { - server dashboard-service:3000; -} - -upstream auth-service { - server auth-service:8080; -} - server { listen 8080 default_server; server_name _; - location /dashboard { + location /dashboard/ { rewrite ^/dashboard/(.*) /$1 break; - proxy_set_header Host $host; + proxy_set_header Host $http_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://dashboard-service; + proxy_pass http://dashboard-ui:3000; proxy_read_timeout 90; } # Proxy Grafana Live WebSocket connections. - location /dashboard/api/live { - proxy_set_header Host $host; + location /dashboard/api/live/ { + rewrite ^/dashboard/(.*) /$1 break; + proxy_set_header Host $http_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_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_http_version 1.1; - proxy_pass http://dashboard-service; + proxy_pass http://dashboard-ui:3000; proxy_read_timeout 90; } @@ -77,7 +46,7 @@ server { 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_pass http://auth-service:8080; proxy_read_timeout 90; } @@ -87,7 +56,7 @@ server { 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_pass http://auth-service:8080; proxy_read_timeout 90; } @@ -96,7 +65,25 @@ server { 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://search; + proxy_pass http://search-service:8080; + proxy_read_timeout 90; + } + + location /api/datasource { + 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://dashboard-service:8080; + proxy_read_timeout 90; + } + + location /api/dashboard { + 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://dashboard-service:8080; proxy_read_timeout 90; } @@ -106,7 +93,7 @@ server { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; - proxy_pass http://data; + proxy_pass http://data-service:8080; proxy_read_timeout 90; # Disable request and response buffering proxy_request_buffering off; @@ -119,25 +106,25 @@ server { 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://analyse; + proxy_pass http://analyse-service:8080; proxy_read_timeout 90; } - location ~ "/api/database/([0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/table/([0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/(data|history)" { + location ~ "/api/database/([0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/table/([0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/(data|statistic|history)" { 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://data; + proxy_pass http://data-service:8080; proxy_read_timeout 90; } - location ~ "/api/database/([0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/view/([0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/data" { + location ~ "/api/database/([0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/view/([0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/(data|statistic)" { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; - proxy_pass http://data; + proxy_pass http://data-service:8080; proxy_read_timeout 90; } @@ -146,7 +133,7 @@ server { 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://metadata; + proxy_pass http://metadata-service:8080; proxy_read_timeout 90; } @@ -155,7 +142,7 @@ server { 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://data; + proxy_pass http://data-service:8080; proxy_read_timeout 600; } @@ -164,7 +151,7 @@ server { 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://metadata; + proxy_pass http://metadata-service:8080; proxy_read_timeout 90; } @@ -173,7 +160,7 @@ server { 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://metadata; + proxy_pass http://metadata-service:8080; proxy_read_timeout 90; } @@ -183,7 +170,7 @@ server { 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://metadata; + proxy_pass http://metadata-service:8080; proxy_read_timeout 90; } @@ -192,7 +179,7 @@ server { 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://ui; + proxy_pass http://ui:3000; proxy_read_timeout 90; } } diff --git a/dbrepo-grafana-service/.dockerignore b/dbrepo-grafana-service/.dockerignore new file mode 100644 index 0000000000000000000000000000000000000000..fcdfe8de55e91b3b65fcf598c5980ae256087910 --- /dev/null +++ b/dbrepo-grafana-service/.dockerignore @@ -0,0 +1 @@ +rest-service/src/main/resources/*.csv \ No newline at end of file diff --git a/dbrepo-grafana-service/.gitignore b/dbrepo-grafana-service/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..d39a47ee0fab72fbe4fd7f5ae968ff2f3bc3de78 --- /dev/null +++ b/dbrepo-grafana-service/.gitignore @@ -0,0 +1,43 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### Environment ### +.env + +### Generated ### +ready +mapping.xml +schema.xsd +*.versionsBackup +metrics.txt + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/dbrepo-grafana-service/.mvn/wrapper/MavenWrapperDownloader.java b/dbrepo-grafana-service/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 0000000000000000000000000000000000000000..a45eb6ba269cd38f8965cef786729790945d9537 --- /dev/null +++ b/dbrepo-grafana-service/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,118 @@ +/* + * Copyright 2007-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if (mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if (mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if (!outputFile.getParentFile().exists()) { + if (!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/dbrepo-grafana-service/.mvn/wrapper/maven-wrapper.jar b/dbrepo-grafana-service/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..2cc7d4a55c0cd0092912bf49ae38b3a9e3fd0054 Binary files /dev/null and b/dbrepo-grafana-service/.mvn/wrapper/maven-wrapper.jar differ diff --git a/dbrepo-grafana-service/.mvn/wrapper/maven-wrapper.properties b/dbrepo-grafana-service/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000000000000000000000000000000000000..642d572ce90e5085986bdd9c9204b9404f028084 --- /dev/null +++ b/dbrepo-grafana-service/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/dbrepo-grafana-service/Dockerfile b/dbrepo-grafana-service/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..b01544827f1cdda6398eb0d8e0b927b88fa176f1 --- /dev/null +++ b/dbrepo-grafana-service/Dockerfile @@ -0,0 +1,31 @@ +###### FIRST STAGE ###### +FROM dbrepo-metadata-service:build AS dependency +MAINTAINER Martin Weise <martin.weise@tuwien.ac.at> + +FROM maven:3-openjdk-17 AS build +MAINTAINER Martin Weise <martin.weise@tuwien.ac.at> + +COPY ./pom.xml ./ + +RUN mvn -fn -B dependency:go-offline + +COPY ./rest-service ./rest-service +COPY --from=dependency /root/.m2/repository/at/tuwien /root/.m2/repository/at/tuwien + +# Make sure it compiles +RUN mvn clean package -DskipTests + +###### SECOND STAGE ###### +FROM eclipse-temurin:17-jdk AS runtime +MAINTAINER Martin Weise <martin.weise@tuwien.ac.at> + +WORKDIR /app + +USER 65534 + +COPY --from=build --chown=65534 ./rest-service/target/dbrepo-grafana-service-rest-service-*.jar ./grafana-service.jar + +# non-root port +EXPOSE 8080 + +ENTRYPOINT ["java", "-Dlog4j2.formatMsgNoLookups=true", "-jar", "./grafana-service.jar"] \ No newline at end of file diff --git a/dbrepo-grafana-service/README.md b/dbrepo-grafana-service/README.md new file mode 100644 index 0000000000000000000000000000000000000000..7160f7bbbc743d2bb6425773566c98eb86005143 --- /dev/null +++ b/dbrepo-grafana-service/README.md @@ -0,0 +1,38 @@ +# Metadata Service + +## Test + +Run all unit and integration tests and create an HTML+TXT coverage report located in the `report` module: + +```bash +mvn -pl rest-service clean test verify +``` + +Or run only unit tests +in [`KeycloakGatewayUnitTest.java`](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/blob/master/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/BrokerServiceGatewayTest.java): + +```bash +mvn -pl rest-service -Dtest="KeycloakGatewayUnitTest" clean test +``` + +## Run + +Start the Metadata Database before and then run the Metadata Service: + +```bash +mvn -pl rest-service clean spring-boot:run -Dspring-boot.run.profiles=local +``` + +### Endpoints + +#### Actuator + +- Info: http://localhost:9099/actuator/info +- Health: http://localhost:9099/actuator/health + - Readiness: http://localhost:9099/actuator/health/readiness + - Liveness: http://localhost:9099/actuator/health/liveness +- Prometheus: http://localhost:9099/actuator/prometheus + +#### OpenAPI + +- OpenAPI v3 as .yaml: http://localhost:9099/v3/api-docs.yaml \ No newline at end of file diff --git a/dbrepo-grafana-service/mvnw b/dbrepo-grafana-service/mvnw new file mode 100755 index 0000000000000000000000000000000000000000..a16b5431b4c3cab50323a3f558003fd0abd87dad --- /dev/null +++ b/dbrepo-grafana-service/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/dbrepo-grafana-service/mvnw.cmd b/dbrepo-grafana-service/mvnw.cmd new file mode 100644 index 0000000000000000000000000000000000000000..c8d43372c986d97911cdc21bd87e0cbe3d83bdda --- /dev/null +++ b/dbrepo-grafana-service/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/dbrepo-grafana-service/pom.xml b/dbrepo-grafana-service/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..763aa408f075814db2312778f6112e71b1b3072a --- /dev/null +++ b/dbrepo-grafana-service/pom.xml @@ -0,0 +1,299 @@ +<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-parent</artifactId> + <version>3.0.13</version> + </parent> + + <groupId>at.tuwien</groupId> + <artifactId>dbrepo-grafana-service</artifactId> + <name>dbrepo-grafana-service</name> + <version>1.4.4</version> + + <description>Service that creates automated grafana dashboards</description> + + <packaging>pom</packaging> + <modules> + <module>rest-service</module> + </modules> + + <properties> + <java.version>17</java.version> + <spring-cloud.version>4.0.2</spring-cloud.version> + <mapstruct.version>1.5.5.Final</mapstruct.version> + <rabbitmq.version>5.20.0</rabbitmq.version> + <jackson-datatype.version>2.15.0</jackson-datatype.version> + <commons-io.version>2.15.0</commons-io.version> + <commons-validator.version>1.8.0</commons-validator.version> + <jacoco.version>0.8.11</jacoco.version> + <jwt.version>4.3.0</jwt.version> + <opencsv.version>5.7.1</opencsv.version> + <super-csv.version>2.4.0</super-csv.version> + <jsql.version>4.6</jsql.version> + <springdoc-openapi.version>2.3.0</springdoc-openapi.version> + <hsqldb.version>2.7.2</hsqldb.version> + <testcontainers.version>1.19.1</testcontainers.version> + <jackson.version>2.15.2</jackson.version> + <c3p0.version>0.9.5.5</c3p0.version> + <c3p0-hibernate.version>6.2.2.Final</c3p0-hibernate.version> + <aws-s3.version>2.25.23</aws-s3.version> + <minio.version>8.5.7</minio.version> + <apache-commons.version>1.10.0</apache-commons.version> + </properties> + + <dependencies> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-validation</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-security</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-test</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework.cloud</groupId> + <artifactId>spring-cloud-starter-bootstrap</artifactId> + <version>${spring-cloud.version}</version> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-data-jpa</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-actuator</artifactId> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-text</artifactId> + <version>${apache-commons.version}</version> + + </dependency> + <!-- Caching --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-data-redis</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-cache</artifactId> + </dependency> + <dependency> + <groupId>redis.clients</groupId> + <artifactId>jedis</artifactId> + </dependency> + <!-- Open API --> + <dependency> + <groupId>org.springdoc</groupId> + <artifactId>springdoc-openapi-starter-webmvc-api</artifactId> + <version>${springdoc-openapi.version}</version> + </dependency> + <!-- Data Source --> + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + </dependency> + <dependency> + <groupId>com.mchange</groupId> + <artifactId>c3p0</artifactId> + <version>${c3p0.version}</version> + </dependency> + <dependency> + <groupId>org.hibernate.orm</groupId> + <artifactId>hibernate-c3p0</artifactId> + <version>${c3p0-hibernate.version}</version> + </dependency> + <!-- Monitoring --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-aop</artifactId> + </dependency> + <dependency> + <groupId>io.micrometer</groupId> + <artifactId>micrometer-registry-prometheus</artifactId> + <version>${micrometer.version}</version> + </dependency> + <dependency> + <groupId>io.micrometer</groupId> + <artifactId>micrometer-observation-test</artifactId> + <version>${micrometer.version}</version> + <scope>test</scope> + </dependency> + <!-- IDE --> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <scope>compile</scope> + </dependency> + <!-- Mapping --> + <dependency> + <groupId>org.mapstruct</groupId> + <artifactId>mapstruct-processor</artifactId> + <version>${mapstruct.version}</version> + <optional>true</optional> + </dependency> + <dependency> + <groupId>org.mapstruct</groupId> + <artifactId>mapstruct</artifactId> + <version>${mapstruct.version}</version> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.datatype</groupId> + <artifactId>jackson-datatype-jsr310</artifactId> + <version>${jackson-datatype.version}</version> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>${commons-io.version}</version> + </dependency> + <dependency> + <groupId>commons-validator</groupId> + <artifactId>commons-validator</artifactId> + <version>${commons-validator.version}</version> + </dependency> + <!-- Authentication --> + <dependency> + <groupId>com.auth0</groupId> + <artifactId>java-jwt</artifactId> + <version>${jwt.version}</version> + </dependency> + <!-- DTOs --> + <dependency> + <groupId>at.tuwien</groupId> + <artifactId>dbrepo-metadata-service-api</artifactId> + <version>${project.version}</version> + </dependency> + <!-- AMPQ --> + <dependency> + <groupId>org.springframework.amqp</groupId> + <artifactId>spring-rabbit</artifactId> + </dependency> + <dependency> + <groupId>com.rabbitmq</groupId> + <artifactId>amqp-client</artifactId> + <version>${rabbitmq.version}</version> + </dependency> + <!-- Storage --> + <dependency> + <groupId>software.amazon.awssdk</groupId> + <artifactId>s3</artifactId> + <version>${aws-s3.version}</version> + </dependency> + <!-- Testing --> + <dependency> + <groupId>com.github.jsqlparser</groupId> + <artifactId>jsqlparser</artifactId> + <version>${jsql.version}</version> + </dependency> + <dependency> + <groupId>at.tuwien</groupId> + <artifactId>dbrepo-metadata-service-test</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>rabbitmq</artifactId> + <version>${testcontainers.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>junit-jupiter</artifactId> + <version>${testcontainers.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>mariadb</artifactId> + <version>${testcontainers.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>minio</artifactId> + <version>${testcontainers.version}</version> + </dependency> + <dependency> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>${jacoco.version}</version> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + </dependency> + </dependencies> + <build> + <resources> + <resource> + <directory>${basedir}/src/main/resources</directory> + <filtering>true</filtering> + <includes> + <include>**/application*.yml</include> + <include>**/rdf/*</include> + <include>**/templates/*.txt</include> + <include>**/templates/*.xml</include> + </includes> + </resource> + </resources> + <plugins> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>${jacoco.version}</version> + <configuration> + <excludes> + <exclude>at/tuwien/utils/**/*</exclude> + <exclude>at/tuwien/seeder/**/*</exclude> + <exclude>at/tuwien/mapper/**/*</exclude> + <exclude>at/tuwien/handlers/**/*</exclude> + <exclude>at/tuwien/exception/**/*</exclude> + <exclude>at/tuwien/converters/**/*</exclude> + <exclude>at/tuwien/utils/**/*</exclude> + <exclude>at/tuwien/config/**/*</exclude> + <exclude>at/tuwien/auth/**/*</exclude> + <exclude>at/tuwien/gateway/impl/ApiTemplateInterceptorImpl.class</exclude> + <exclude>**/testcontainers.properties</exclude> + <exclude>**/HibernateConnector.class</exclude> + <exclude>**/DbrepoMetadataServiceApplication.class</exclude> + </excludes> + </configuration> + <executions> + <execution> + <id>default-prepare-agent</id> + <goals> + <goal>prepare-agent</goal> + </goals> + </execution> + <execution> + <id>report</id> + <phase>verify</phase> + <goals> + <goal>report</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> diff --git a/dbrepo-grafana-service/rest-service/pom.xml b/dbrepo-grafana-service/rest-service/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..ace7de5a1cb287e104a93100059b506caba3ab77 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/pom.xml @@ -0,0 +1,35 @@ +<?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> + <artifactId>dbrepo-grafana-service</artifactId> + <groupId>at.tuwien</groupId> + <version>1.4.4</version> + </parent> + + <artifactId>dbrepo-grafana-service-rest-service</artifactId> + <name>dbrepo-grafana-service-rest</name> + <version>1.4.4</version> + + <dependencies> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>repackage</goal><!-- to make it exuteable with $ java -jar ./app.jar --> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/DbrepoGrafanaServiceApplication.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/DbrepoGrafanaServiceApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..79c50fa5ef00adf1cd5c0c4efa9355500e76dba1 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/DbrepoGrafanaServiceApplication.java @@ -0,0 +1,13 @@ +package at.tuwien; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; + +@SpringBootApplication +@EnableCaching +public class DbrepoGrafanaServiceApplication { + public static void main(String[] args) { + SpringApplication.run(DbrepoGrafanaServiceApplication.class, args); + } +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/auth/AuthTokenFilter.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/auth/AuthTokenFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..46ec0e6a24bdd2bc2a9a88f8fad4815467ebff08 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/auth/AuthTokenFilter.java @@ -0,0 +1,96 @@ +package at.tuwien.auth; + +import at.tuwien.api.auth.RealmAccessDto; +import at.tuwien.api.user.UserDetailsDto; +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.interfaces.DecodedJWT; +import com.auth0.jwt.interfaces.Verification; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; +import java.util.Arrays; +import java.util.Base64; +import java.util.stream.Collectors; + +@Slf4j +public class AuthTokenFilter extends OncePerRequestFilter { + + @Value("${dbrepo.jwt.public_key}") + private String publicKey; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + final String jwt = parseJwt(request); + if (jwt != null) { + final UserDetails userDetails = verifyJwt(jwt); + final UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + userDetails, null, userDetails.getAuthorities()); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + + SecurityContextHolder.getContext().setAuthentication(authentication); + } + filterChain.doFilter(request, response); + } + + public UserDetails verifyJwt(String token) throws ServletException { + final KeyFactory kf; + try { + kf = KeyFactory.getInstance("RSA"); + } catch (NoSuchAlgorithmException e) { + log.error("Failed to find RSA algorithm"); + throw new ServletException("Failed to find RSA algorithm", e); + } + final X509EncodedKeySpec keySpecX509 = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey)); + final RSAPublicKey pubKey; + try { + pubKey = (RSAPublicKey) kf.generatePublic(keySpecX509); + } catch (InvalidKeySpecException e) { + log.error("Provided public key is invalid"); + throw new ServletException("Provided public key is invalid", e); + } + final Algorithm algorithm = Algorithm.RSA256(pubKey, null); + final Verification verification = JWT.require(algorithm); + final JWTVerifier verifier = verification.build(); + final DecodedJWT jwt = verifier.verify(token); + final RealmAccessDto realmAccess = jwt.getClaim("realm_access").as(RealmAccessDto.class); + return UserDetailsDto.builder() + .id(jwt.getSubject()) + .username(jwt.getClaim("client_id").asString()) + .authorities(Arrays.stream(realmAccess.getRoles()).map(SimpleGrantedAuthority::new).collect(Collectors.toList())) + .build(); + } + + /** + * Parses the token from the HTTP header of the request + * + * @param request The request. + * @return The token. + */ + public String parseJwt(HttpServletRequest request) { + String headerAuth = request.getHeader("Authorization"); + if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) { + return headerAuth.substring(7, headerAuth.length()); + } + return null; + } +} \ No newline at end of file diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..6cd55e9ef768e47f3d3463001ba99b5378f5351e --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java @@ -0,0 +1,60 @@ +package at.tuwien.auth; + +import at.tuwien.api.keycloak.TokenDto; +import at.tuwien.api.user.UserDetailsDto; +import at.tuwien.config.GatewayConfig; +import at.tuwien.exception.ServiceConnectionException; +import at.tuwien.exception.ServiceException; +import at.tuwien.gateway.KeycloakGateway; +import jakarta.servlet.ServletException; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Log4j2 +@Component +public class BasicAuthenticationProvider implements AuthenticationManager { + + private final GatewayConfig gatewayConfig; + private final AuthTokenFilter authTokenFilter; + private final KeycloakGateway keycloakGateway; + + @Autowired + public BasicAuthenticationProvider(GatewayConfig gatewayConfig, AuthTokenFilter authTokenFilter, + KeycloakGateway keycloakGateway) { + this.gatewayConfig = gatewayConfig; + this.authTokenFilter = authTokenFilter; + this.keycloakGateway = keycloakGateway; + } + + @Override + public Authentication authenticate(Authentication auth) throws AuthenticationException { + if (auth.getName().equals(gatewayConfig.getAdminUsername()) + && auth.getCredentials().toString().equals(gatewayConfig.getAdminPassword())) { + log.trace("current user is {}: skip authentication", gatewayConfig.getAdminUsername()); + final UserDetails userDetails = UserDetailsDto.builder() + .username(auth.getName()) + .authorities(List.of(new SimpleGrantedAuthority("admin"))) + .build(); + return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + } + log.trace("current user is {}: begin authentication", auth.getName()); + try { + final TokenDto tokenDto = keycloakGateway.obtainUserToken(auth.getName(), auth.getCredentials().toString()); + final UserDetails userDetails = authTokenFilter.verifyJwt(tokenDto.getAccessToken()); + return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + } catch (ServletException | ServiceConnectionException | ServiceException e) { + throw new BadCredentialsException("Failed to authenticate with authentication service", e); + } + } +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/config/CacheConfig.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/config/CacheConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..dafb08dafc955fabde7a4ac6df6f16857b5ec173 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/config/CacheConfig.java @@ -0,0 +1,40 @@ +package at.tuwien.config; + +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +import java.time.Duration; + + +@Configuration +@EnableCaching +public class CacheConfig { + + @Bean + public CacheManager cacheManager(RedisConnectionFactory connectionFactory) { + return RedisCacheManager.RedisCacheManagerBuilder + .fromConnectionFactory(connectionFactory) + .withCacheConfiguration("myCache", + RedisCacheConfiguration.defaultCacheConfig() + .entryTtl(Duration.ofSeconds(30)) + ) + .build(); + } + + @Bean + public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { + RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); + return redisTemplate; + } +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/config/GatewayConfig.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/config/GatewayConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..1692f53b296ffe86b9c6b2cb49f9a44225c82a6b --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/config/GatewayConfig.java @@ -0,0 +1,104 @@ +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.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.support.BasicAuthenticationInterceptor; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.DefaultUriBuilderFactory; + +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.util.List; + +@Log4j2 +@Getter +@Configuration +public class GatewayConfig { + + @Value("${dbrepo.endpoints.gatewayService}") + private String gatewayEndpoint; + + @Value("${dbrepo.endpoints.grafana}") + private String grafanaEndpoint; + + @Value("${dbrepo.admin.username}") + private String adminUsername; + + @Value("${dbrepo.admin.password}") + private String adminPassword; + + @Value("${dbrepo.endpoints.dataService}") + private String dataEndpoint; + + @Value("${dbrepo.endpoints.metadataService}") + private String metaDataEndpoint; + + @Value("${dbrepo.grafana.username}") + private String grafanaUsername; + + @Value("${dbrepo.grafana.password}") + private String grafanaPassword; + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + @Bean("grafanaTemplate") + public RestTemplate grafanaTemplate() { + final RestTemplate restTemplate = new RestTemplate(); + restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(grafanaEndpoint)); + restTemplate.getInterceptors().add(grafanaHttpRequestInterceptor()); + return restTemplate; + } + + @Bean + public ClientHttpRequestInterceptor clientHttpRequestInterceptor() { + return (request, body, execution) -> { + final HttpHeaders headers = request.getHeaders(); + headers.add("Accept", MediaType.APPLICATION_JSON_VALUE); + return execution.execute(request, body); + }; + } + + @Bean + public ClientHttpRequestInterceptor grafanaHttpRequestInterceptor() { + return (request, body, execution) -> { + final HttpHeaders headers = request.getHeaders(); + headers.add("Accept", MediaType.APPLICATION_JSON_VALUE); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setBasicAuth(grafanaUsername, grafanaPassword); + return execution.execute(request, body); + }; + } + + @Bean("dataServiceRestTemplate") + public RestTemplate dataServiceRestTemplate() { + final RestTemplate restTemplate = new RestTemplate(); + restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(dataEndpoint)); + log.debug("add basic authentication for internal data service: username={}, password=(hidden)", adminUsername); + + restTemplate.getInterceptors() + .addAll(List.of(new BasicAuthenticationInterceptor(adminUsername, adminPassword), + clientHttpRequestInterceptor())); + + return restTemplate; + } + + @Bean("metaDataServiceRestTemplate") + public RestTemplate metaDataServiceRestTemplate() { + final RestTemplate restTemplate = new RestTemplate(); + restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(metaDataEndpoint)); + restTemplate.getInterceptors().add(clientHttpRequestInterceptor()); + return restTemplate; + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/config/KeycloakConfig.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/config/KeycloakConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..4d258d496aa6ebe825ac2d84a1f00a1b4f9c0298 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/config/KeycloakConfig.java @@ -0,0 +1,50 @@ +package at.tuwien.config; + +import at.tuwien.interceptor.KeycloakInterceptor; +import lombok.Getter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.DefaultUriBuilderFactory; + +import java.util.List; + +@Getter +@Configuration +public class KeycloakConfig { + + @Value("${dbrepo.endpoints.authService}") + private String keycloakEndpoint; + + @Value("${dbrepo.keycloak.username}") + private String keycloakUsername; + + @Value("${dbrepo.keycloak.password}") + private String keycloakPassword; + + @Value("${dbrepo.keycloak.client}") + private String keycloakClient; + + @Value("${dbrepo.keycloak.clientSecret}") + private String keycloakClientSecret; + + private final ClientHttpRequestInterceptor clientHttpRequestInterceptor; + + @Autowired + public KeycloakConfig(ClientHttpRequestInterceptor clientHttpRequestInterceptor) { + this.clientHttpRequestInterceptor = clientHttpRequestInterceptor; + } + + @Bean("keycloakRestTemplate") + public RestTemplate brokerRestTemplate() { + final RestTemplate restTemplate = new RestTemplate(); + restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(keycloakEndpoint)); + restTemplate.getInterceptors() + .addAll(List.of(new KeycloakInterceptor(keycloakUsername, keycloakPassword, keycloakEndpoint), + clientHttpRequestInterceptor)); + return restTemplate; + } +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/config/WebSecurityConfig.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/config/WebSecurityConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..5bb4b2e9705f36d0e4168f5688ac42ca13de8882 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/config/WebSecurityConfig.java @@ -0,0 +1,107 @@ +package at.tuwien.config; + +import at.tuwien.auth.AuthTokenFilter; +import at.tuwien.auth.BasicAuthenticationProvider; +import at.tuwien.gateway.KeycloakGateway; +import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; +import io.swagger.v3.oas.annotations.security.SecurityScheme; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.util.matcher.OrRequestMatcher; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +@SecurityScheme( + name = "bearerAuth", + type = SecuritySchemeType.HTTP, + bearerFormat = "JWT", + scheme = "bearer" +) +@SecurityScheme( + name = "basicAuth", + type = SecuritySchemeType.HTTP, + scheme = "basic" +) +public class WebSecurityConfig { + + @Bean + public AuthTokenFilter authTokenFilter() { + return new AuthTokenFilter(); + } + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http, KeycloakGateway keycloakGateway, + GatewayConfig gatewayConfig) throws Exception { + final OrRequestMatcher internalEndpoints = new OrRequestMatcher( + new AntPathRequestMatcher("/actuator/**", "GET"), + new AntPathRequestMatcher("/v3/api-docs.yaml"), + new AntPathRequestMatcher("/v3/api-docs/**"), + new AntPathRequestMatcher("/swagger-ui/**"), + new AntPathRequestMatcher("/swagger-ui.html") + ); + final OrRequestMatcher publicEndpoints = new OrRequestMatcher( + new AntPathRequestMatcher("/api/**", "GET"), + new AntPathRequestMatcher("/api/**", "HEAD") + ); + /* enable CORS and disable CSRF */ + http = http.cors().and().csrf().disable(); + /* set session management to stateless */ + http = http + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and(); + /* set unauthorized requests exception handler */ + http = http + .exceptionHandling() + .authenticationEntryPoint( + (request, response, ex) -> { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, + ex.getMessage() + ); + } + ).and(); + /* set permissions on endpoints */ + http.authorizeHttpRequests() + /* our internal endpoints */ + .requestMatchers(internalEndpoints).permitAll() + /* our public endpoints */ + .requestMatchers(publicEndpoints).permitAll() + /* our private endpoints */ + .anyRequest().authenticated(); + /* add JWT token filter */ + http.addFilterBefore(authTokenFilter(), + UsernamePasswordAuthenticationFilter.class + ); + http.addFilterBefore(new BasicAuthenticationFilter(new BasicAuthenticationProvider(gatewayConfig, + authTokenFilter(), keycloakGateway)), + UsernamePasswordAuthenticationFilter.class + ); + return http.build(); + } + + @Bean + public CorsFilter corsFilter() { + final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + final CorsConfiguration config = new CorsConfiguration(); + config.setAllowCredentials(true); + config.addAllowedOriginPattern("*"); + config.addAllowedHeader("*"); + config.addAllowedMethod("*"); + source.registerCorsConfiguration("/**", config); + return new CorsFilter(source); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/dto/DashboardConfigDto.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/dto/DashboardConfigDto.java new file mode 100644 index 0000000000000000000000000000000000000000..e93c50362c3e149defa5bd973c4e252176680a4e --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/dto/DashboardConfigDto.java @@ -0,0 +1,46 @@ +package at.tuwien.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Map; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DashboardConfigDto { + /** + * Map containing information to create time series data. + * <p> + * The key of the map represents the table id. + * The value is a list of {@link TimeSeriesDto} objects in this table. + */ + private Map<Long, List<TimeSeriesDto>> timeSeriesDto; + + /** + * Map containing information about params for the PieChartPanel. + * <p> + * The key of the map represents the table id. + * The value is a Map with key = column id and value = {@link PieChartConfigDto}. + */ + private Map<Long, Map<Long, PieChartConfigDto>> pieChartConfigDto; + + /** + * Map containing information about params for the Histogram. + * <p> + * The key of the map represents the table id. + * The value is a Map with key = column id and value = {@link HistogramConfigDto}. + */ + private Map<Long, Map<Long, HistogramConfigDto>> histogramConfigDto; + + /** + * Map containing information about params for the tables. + * <p> + * The key of the map represents the table id. + * The value is a dto {@link TableConfigDto} holding the properties. + */ + private Map<Long, TableConfigDto> tableConfigDto; + private Integer refreshRate; +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/dto/HistogramConfigDto.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/dto/HistogramConfigDto.java new file mode 100644 index 0000000000000000000000000000000000000000..be6f3b21e8e0920671fb5ba2746a622818f1119a --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/dto/HistogramConfigDto.java @@ -0,0 +1,14 @@ +package at.tuwien.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class HistogramConfigDto { + private Integer min; + private Integer max; + private Long size; +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/dto/PieChartConfigDto.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/dto/PieChartConfigDto.java new file mode 100644 index 0000000000000000000000000000000000000000..487d7042bf24244083c3297ca21e463ec5f08a26 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/dto/PieChartConfigDto.java @@ -0,0 +1,14 @@ +package at.tuwien.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PieChartConfigDto { + private String limit; + private String decimalPlace; + private Long size; +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/dto/TableConfigDto.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/dto/TableConfigDto.java new file mode 100644 index 0000000000000000000000000000000000000000..0b21d8571da0b964f6f95d924546e86e65b55de8 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/dto/TableConfigDto.java @@ -0,0 +1,12 @@ +package at.tuwien.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class TableConfigDto { + private Long size; +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/dto/TimeDto.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/dto/TimeDto.java new file mode 100644 index 0000000000000000000000000000000000000000..f78cb3d1c57d9a6a0f47a2de53728fe9c81a59bd --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/dto/TimeDto.java @@ -0,0 +1,17 @@ +package at.tuwien.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class TimeDto { + private Long yearColId; + private Long monthColId; + private Long dayColId; + private Long hourColId; + private Long minuteColId; + private Long secondColId; +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/dto/TimeSeriesDto.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/dto/TimeSeriesDto.java new file mode 100644 index 0000000000000000000000000000000000000000..dd4356d70b9e1e31f8b8ada04afee215b82d72de --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/dto/TimeSeriesDto.java @@ -0,0 +1,14 @@ +package at.tuwien.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class TimeSeriesDto { + private TimeDto timeDto; + private Long valueColId; + private Long size; +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/endpoints/DashboardEndpoint.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/endpoints/DashboardEndpoint.java new file mode 100644 index 0000000000000000000000000000000000000000..bd9cc68b24a39edf8e1d90d5ef19433286e301bd --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/endpoints/DashboardEndpoint.java @@ -0,0 +1,92 @@ +package at.tuwien.endpoints; + +import at.tuwien.api.error.ApiErrorDto; +import at.tuwien.dto.DashboardConfigDto; +import at.tuwien.service.DashboardService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import jakarta.validation.constraints.NotBlank; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@Log4j2 +@RestController +@CrossOrigin(origins = "*") +@RequestMapping(path = "/api/dashboard") +public class DashboardEndpoint { + private final DashboardService dashboardService; + + @Autowired + public DashboardEndpoint(DashboardService dashboardService) { + this.dashboardService = dashboardService; + } + + @PostMapping("/generate/{dbId}") + @Operation(summary = "Generate dashboard", + description = "Generates dashboard for a provided database id.", + security = {@SecurityRequirement(name = "bearerAuth")}) + @ApiResponses(value = { + @ApiResponse(responseCode = "201", + description = "Created a new dashboard", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = String.class))}), + @ApiResponse(responseCode = "500", + description = "Internal error", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}) + }) + public ResponseEntity<String> generateDashboard(@RequestHeader("Authorization") String token, + @NotBlank @PathVariable("dbId") Long dbId, + @RequestBody(required = false) DashboardConfigDto configDto) { + + return ResponseEntity.status(HttpStatus.CREATED) + .body(this.dashboardService.generateDashboard(dbId, token, configDto)); + } + + @RequestMapping(value = "/exists/{dbId}", method = {RequestMethod.GET, RequestMethod.HEAD}) + @Operation(summary = "Check if dashboard exists", + description = "Checks if a dashboard for a provided database id exists.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Returns Boolean if dashboard exsists", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = Boolean.class))}), + @ApiResponse(responseCode = "500", + description = "Internal error", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}) + }) + public ResponseEntity<Boolean> checkIfDashboardExists(@NotBlank @PathVariable("dbId") Long dbId) { + return ResponseEntity.status(HttpStatus.OK) + .body(this.dashboardService.checkIfDashboardExists(dbId)); + } + + @DeleteMapping("/{dbId}") + @Operation(summary = "Delete dashboard in Grafana", + description = "Deletes a dashboard in Grafana for a provided id.", + security = {@SecurityRequirement(name = "bearerAuth")}) + @ApiResponses(value = { + @ApiResponse(responseCode = "202", + description = "Deleted grafana dashbaord"), + @ApiResponse(responseCode = "500", + description = "Internal error", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), + }) + public ResponseEntity<Void> removeDashboard(@NotBlank @PathVariable("dbId") Long dbId) { + this.dashboardService.removeDashboard(dbId); + return ResponseEntity.status(HttpStatus.ACCEPTED).build(); + } +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/endpoints/DataEndpoint.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/endpoints/DataEndpoint.java new file mode 100644 index 0000000000000000000000000000000000000000..6e698347df1c0ab5ebb6d16d5e816c09ca4aaf9c --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/endpoints/DataEndpoint.java @@ -0,0 +1,157 @@ +package at.tuwien.endpoints; + +import at.tuwien.api.error.ApiErrorDto; +import at.tuwien.panels.*; +import at.tuwien.service.DataService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import jakarta.validation.constraints.NotBlank; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.Map; + +@Slf4j +@RestController +@CrossOrigin(origins = "*") +@RequestMapping(path = DataEndpoint.API_PREFIX) +public class DataEndpoint { + public static final String API_PREFIX = "/api/dashboard/data"; + private final DataService dataService; + private static final Long DEFAULT_RESPONSE_SIZE = 100L; + + @Autowired + public DataEndpoint(DataService dataService) { + this.dataService = dataService; + } + + @GetMapping(PieChartPanel.RELATIVE_PATH + "/{dbId}/{viewId}") + @Operation(summary = "Returns data for Pie Chart", + description = "Returns data for Pie Chart for a specific database and view") + @ApiResponses(value = { + @ApiResponse(responseCode = "500", + description = "Internal error", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}) + }) + public Map<String, Object> getPieChart(@NotBlank @PathVariable Long dbId, @NotBlank @PathVariable Long viewId, + @RequestParam(required = false) Long size) { + if (size == null) { + size = DEFAULT_RESPONSE_SIZE; + } + + return dataService.getPieChartData(dbId, viewId, size); + } + + @GetMapping(CntAllPanel.RELATIVE_PATH + "/{dbId}/{viewId}") + @Operation(summary = "Returns data for the Count All Stats Visualization", + description = "Returns data for the Count All Stats Visualization for a specific database and view") + @ApiResponses(value = { + @ApiResponse(responseCode = "500", + description = "Internal error", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}) + }) + public Map<String, Object> getCntAll(@NotBlank @PathVariable Long dbId, @NotBlank @PathVariable Long viewId) { + + return dataService.getCntAllData(dbId, viewId); + } + + @GetMapping(TablePanel.RELATIVE_PATH + "/{dbId}/{tableId}") + @Operation(summary = "Returns data for the Table Visualization", + description = "Returns data for the Table Visualization for a specific database and table") + @ApiResponses(value = { + @ApiResponse(responseCode = "500", + description = "Internal error", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}) + }) + public List<Map<String, Object>> getTable(@NotBlank @PathVariable Long dbId, + @NotBlank @PathVariable Long tableId, + @RequestParam(required = false) Long size) { + if (size == null) { + size = DEFAULT_RESPONSE_SIZE; + } + + return dataService.getTableData(dbId, tableId, size); + } + + @GetMapping(HistogramPanel.RELATIVE_PATH + "/{dbId}/{viewId}") + @Operation(summary = "Returns data for the Histogram Visualization", + description = "Returns data for the Histogram Visualization for a specific database and view") + @ApiResponses(value = { + @ApiResponse(responseCode = "500", + description = "Internal error", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}) + }) + public Map<String, List<Object>> getHistogram(@NotBlank @PathVariable Long dbId, @NotBlank @PathVariable Long viewId, + @RequestParam(required = false) Long size) { + if (size == null) { + size = DEFAULT_RESPONSE_SIZE; + } + + return dataService.getHistogramData(dbId, viewId, size); + } + + @GetMapping(StatsPanel.RELATIVE_PATH + "/{dbId}/{tableId}") + @Operation(summary = "Returns data for the Stats Visualization", + description = "Returns data for the Stats Visualization for a specific database and table") + @ApiResponses(value = { + @ApiResponse(responseCode = "500", + description = "Internal error", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}) + }) + public List<Map<String, Object>> getStats(@NotBlank @PathVariable Long dbId, @NotBlank @PathVariable Long tableId) { + return dataService.getStatsData(dbId, tableId); + } + + @GetMapping(TimeSeriesPanel.RELATIVE_PATH + "/{dbId}/{viewId}") + @Operation(summary = "Returns data for the Time Visualization", + description = "Returns data for the Time Visualization for a specific database and view") + @ApiResponses(value = { + @ApiResponse(responseCode = "500", + description = "Internal error", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}) + }) + public Map<String, List<Map<String, Object>>> getTimeSeries(@NotBlank @PathVariable Long dbId, @NotBlank @PathVariable Long viewId, + @RequestParam(required = false) Long size) { + if (size == null) { + size = DEFAULT_RESPONSE_SIZE; + } + return dataService.getTimeSeriesData(dbId, viewId, size); + } + + @GetMapping(MultiTimeSeriesPanel.RELATIVE_PATH + "/{dbId}/{viewId}") + @Operation(summary = "Returns data for the Multi Time Visualization", + description = "Returns data for the MUlti Time Visualization for a specific database and view") + @ApiResponses(value = { + @ApiResponse(responseCode = "500", + description = "Internal error", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}) + }) + public Map<String, List<Map<String, Object>>> getMultiTimeSeries(@NotBlank @PathVariable Long dbId, @NotBlank @PathVariable Long viewId, + @RequestParam(required = false) Long size) { + if (size == null) { + size = DEFAULT_RESPONSE_SIZE; + } + return dataService.getMultiTimeSeriesData(dbId, viewId, size); + } +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/ContainerNotFoundException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/ContainerNotFoundException.java new file mode 100644 index 0000000000000000000000000000000000000000..a15fcfb8a9ebd2790036be9c1df295176d339ee3 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/ContainerNotFoundException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.NOT_FOUND) +public class ContainerNotFoundException extends Exception { + + public ContainerNotFoundException(String message) { + super(message); + } + + public ContainerNotFoundException(String message, Throwable thr) { + super(message, thr); + } + + public ContainerNotFoundException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/DatabaseMalformedException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/DatabaseMalformedException.java new file mode 100644 index 0000000000000000000000000000000000000000..1ead17c389ee59b69ce6c6c4d994885b2b4e153c --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/DatabaseMalformedException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.BAD_REQUEST) +public class DatabaseMalformedException extends Exception { + + public DatabaseMalformedException(String message) { + super(message); + } + + public DatabaseMalformedException(String message, Throwable thr) { + super(message, thr); + } + + public DatabaseMalformedException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/DatabaseNotFoundException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/DatabaseNotFoundException.java new file mode 100644 index 0000000000000000000000000000000000000000..cb9075c80af9cc4156905350506af772f19bf49a --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/DatabaseNotFoundException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.NOT_FOUND) +public class DatabaseNotFoundException extends Exception { + + public DatabaseNotFoundException(String message) { + super(message); + } + + public DatabaseNotFoundException(String message, Throwable thr) { + super(message, thr); + } + + public DatabaseNotFoundException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/DatabaseUnavailableException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/DatabaseUnavailableException.java new file mode 100644 index 0000000000000000000000000000000000000000..e584390ec9b1fb5ad51529a9c32eade744a35681 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/DatabaseUnavailableException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE) +public class DatabaseUnavailableException extends Exception { + + public DatabaseUnavailableException(String message) { + super(message); + } + + public DatabaseUnavailableException(String message, Throwable thr) { + super(message, thr); + } + + public DatabaseUnavailableException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/FormatNotAvailableException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/FormatNotAvailableException.java new file mode 100644 index 0000000000000000000000000000000000000000..4ca41e346daebd26e5e369d72e8b31260e791d1b --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/FormatNotAvailableException.java @@ -0,0 +1,23 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +import java.io.IOException; + +@ResponseStatus(code = HttpStatus.NOT_ACCEPTABLE) +public class FormatNotAvailableException extends IOException { + + public FormatNotAvailableException(String msg) { + super(msg); + } + + public FormatNotAvailableException(String msg, Throwable thr) { + super(msg + ": " + thr.getLocalizedMessage(), thr); + } + + public FormatNotAvailableException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/JsonProcessingException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/JsonProcessingException.java new file mode 100644 index 0000000000000000000000000000000000000000..66f414018f443dbb63610812797f554badab5783 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/JsonProcessingException.java @@ -0,0 +1,17 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR) +public class JsonProcessingException extends RuntimeException { + + public JsonProcessingException(String message) { + super(message); + } + + public JsonProcessingException(String message, Throwable thr) { + super(message, thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/NotAllowedException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/NotAllowedException.java new file mode 100644 index 0000000000000000000000000000000000000000..341b93a6443e06121d8ba639212aa7e69a6da7af --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/NotAllowedException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.FORBIDDEN) +public class NotAllowedException extends Exception { + + public NotAllowedException(String message) { + super(message); + } + + public NotAllowedException(String message, Throwable thr) { + super(message, thr); + } + + public NotAllowedException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/PaginationException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/PaginationException.java new file mode 100644 index 0000000000000000000000000000000000000000..b47c66c5b37fd78eabb2a6f056cd8050f81e19d1 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/PaginationException.java @@ -0,0 +1,22 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.BAD_REQUEST) +public class PaginationException extends Exception { + + public PaginationException(String msg) { + super(msg); + } + + public PaginationException(String msg, Throwable thr) { + super(msg + ": " + thr.getLocalizedMessage(), thr); + } + + public PaginationException(Throwable thr) { + super(thr); + } + +} + diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/QueryMalformedException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/QueryMalformedException.java new file mode 100644 index 0000000000000000000000000000000000000000..4d89f64f9478bc0e4284980233f8b79f4adbbfc8 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/QueryMalformedException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.BAD_REQUEST) +public class QueryMalformedException extends Exception { + + public QueryMalformedException(String message) { + super(message); + } + + public QueryMalformedException(String message, Throwable thr) { + super(message, thr); + } + + public QueryMalformedException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/QueryNotFoundException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/QueryNotFoundException.java new file mode 100644 index 0000000000000000000000000000000000000000..44fcbf4ceebecf53423624e2374ffe2ae0f99c18 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/QueryNotFoundException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.NOT_FOUND) +public class QueryNotFoundException extends Exception { + + public QueryNotFoundException(String message) { + super(message); + } + + public QueryNotFoundException(String message, Throwable thr) { + super(message, thr); + } + + public QueryNotFoundException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/QueryStoreCreateException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/QueryStoreCreateException.java new file mode 100644 index 0000000000000000000000000000000000000000..e7166363e02e94facafbee299226ec2f45fcfb9c --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/QueryStoreCreateException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.BAD_REQUEST) +public class QueryStoreCreateException extends Exception { + + public QueryStoreCreateException(String message) { + super(message); + } + + public QueryStoreCreateException(String message, Throwable thr) { + super(message, thr); + } + + public QueryStoreCreateException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/QueryStoreGCException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/QueryStoreGCException.java new file mode 100644 index 0000000000000000000000000000000000000000..d1d25bbde1efbd916c8233de0aaf569d9e86ee3d --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/QueryStoreGCException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.BAD_REQUEST) +public class QueryStoreGCException extends Exception { + + public QueryStoreGCException(String message) { + super(message); + } + + public QueryStoreGCException(String message, Throwable thr) { + super(message, thr); + } + + public QueryStoreGCException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/QueryStoreInsertException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/QueryStoreInsertException.java new file mode 100644 index 0000000000000000000000000000000000000000..95c621493e7540df465c0715537409b704bada27 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/QueryStoreInsertException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.BAD_REQUEST) +public class QueryStoreInsertException extends Exception { + + public QueryStoreInsertException(String message) { + super(message); + } + + public QueryStoreInsertException(String message, Throwable thr) { + super(message, thr); + } + + public QueryStoreInsertException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/QueryStorePersistException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/QueryStorePersistException.java new file mode 100644 index 0000000000000000000000000000000000000000..b9250ffefced58fa0833db10df630dace773ff46 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/QueryStorePersistException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.BAD_REQUEST) +public class QueryStorePersistException extends Exception { + + public QueryStorePersistException(String message) { + super(message); + } + + public QueryStorePersistException(String message, Throwable thr) { + super(message, thr); + } + + public QueryStorePersistException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/RemoteUnavailableException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/RemoteUnavailableException.java new file mode 100644 index 0000000000000000000000000000000000000000..d007a65c02b927515a14b0703d4f0b26b2825a39 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/RemoteUnavailableException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE) +public class RemoteUnavailableException extends Exception { + + public RemoteUnavailableException(String message) { + super(message); + } + + public RemoteUnavailableException(String message, Throwable thr) { + super(message, thr); + } + + public RemoteUnavailableException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/RestTemplateExchangeException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/RestTemplateExchangeException.java new file mode 100644 index 0000000000000000000000000000000000000000..6724c3f260f60ac889d2cd6e86b46a1ca683ec95 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/RestTemplateExchangeException.java @@ -0,0 +1,17 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR) +public class RestTemplateExchangeException extends RuntimeException { + + public RestTemplateExchangeException(String message) { + super(message); + } + + public RestTemplateExchangeException(String message, Throwable thr) { + super(message, thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/ServiceConnectionException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/ServiceConnectionException.java new file mode 100644 index 0000000000000000000000000000000000000000..ec36c03e3a0b4cca4b8bd495ba94d8e5bb05ac62 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/ServiceConnectionException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.BAD_GATEWAY) +public class ServiceConnectionException extends Exception { + + public ServiceConnectionException(String msg) { + super(msg); + } + + public ServiceConnectionException(String msg, Throwable thr) { + super(msg + ": " + thr.getLocalizedMessage(), thr); + } + + public ServiceConnectionException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/ServiceException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/ServiceException.java new file mode 100644 index 0000000000000000000000000000000000000000..56004d6a47361250a248cc1d89b155a47ad295d2 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/ServiceException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE) +public class ServiceException extends Exception { + + public ServiceException(String message) { + super(message); + } + + public ServiceException(String message, Throwable thr) { + super(message, thr); + } + + public ServiceException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/SidecarExportException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/SidecarExportException.java new file mode 100644 index 0000000000000000000000000000000000000000..88ac95e2e9476d4b4855ae6aa8c3d150fe292994 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/SidecarExportException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE) +public class SidecarExportException extends Exception { + + public SidecarExportException(String message) { + super(message); + } + + public SidecarExportException(String message, Throwable thr) { + super(message, thr); + } + + public SidecarExportException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/SidecarImportException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/SidecarImportException.java new file mode 100644 index 0000000000000000000000000000000000000000..8dd9a832be21fea6442043e500a3a77eb1399f64 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/SidecarImportException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE) +public class SidecarImportException extends Exception { + + public SidecarImportException(String message) { + super(message); + } + + public SidecarImportException(String message, Throwable thr) { + super(message, thr); + } + + public SidecarImportException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/StorageNotFoundException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/StorageNotFoundException.java new file mode 100644 index 0000000000000000000000000000000000000000..79c3608adcdcfb9d2582e92cb9950f814db97991 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/StorageNotFoundException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.NOT_FOUND) +public class StorageNotFoundException extends Exception { + + public StorageNotFoundException(String message) { + super(message); + } + + public StorageNotFoundException(String message, Throwable thr) { + super(message, thr); + } + + public StorageNotFoundException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/StorageUnavailableException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/StorageUnavailableException.java new file mode 100644 index 0000000000000000000000000000000000000000..96a33f11754716229f87e88d94434b2d6b692b4d --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/StorageUnavailableException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE) +public class StorageUnavailableException extends Exception { + + public StorageUnavailableException(String message) { + super(message); + } + + public StorageUnavailableException(String message, Throwable thr) { + super(message, thr); + } + + public StorageUnavailableException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/SyncDatabaseNotFoundException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/SyncDatabaseNotFoundException.java new file mode 100644 index 0000000000000000000000000000000000000000..f0bedd46ece4c4ff98917aea36b4fc7c84c651e7 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/SyncDatabaseNotFoundException.java @@ -0,0 +1,17 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR) +public class SyncDatabaseNotFoundException extends RuntimeException { + + public SyncDatabaseNotFoundException(String message) { + super(message); + } + + public SyncDatabaseNotFoundException(String message, Throwable thr) { + super(message, thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/TableExistsException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/TableExistsException.java new file mode 100644 index 0000000000000000000000000000000000000000..dbbe0b86e18088992dd7da0236ffcca7b9c8181a --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/TableExistsException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.CONFLICT) +public class TableExistsException extends Exception { + + public TableExistsException(String message) { + super(message); + } + + public TableExistsException(String message, Throwable thr) { + super(message, thr); + } + + public TableExistsException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/TableMalformedException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/TableMalformedException.java new file mode 100644 index 0000000000000000000000000000000000000000..6c959fc55b7a68c2a1a6dc5a9cd7b3df5f1f4a86 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/TableMalformedException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.BAD_REQUEST) +public class TableMalformedException extends Exception { + + public TableMalformedException(String message) { + super(message); + } + + public TableMalformedException(String message, Throwable thr) { + super(message, thr); + } + + public TableMalformedException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/TableNotFoundException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/TableNotFoundException.java new file mode 100644 index 0000000000000000000000000000000000000000..05547bdfe27b63054ef282a79dfeababe11f2618 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/TableNotFoundException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.NOT_FOUND) +public class TableNotFoundException extends Exception { + + public TableNotFoundException(String message) { + super(message); + } + + public TableNotFoundException(String message, Throwable thr) { + super(message, thr); + } + + public TableNotFoundException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/UserNotFoundException.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/UserNotFoundException.java new file mode 100644 index 0000000000000000000000000000000000000000..f3bece1e142206253a058e34d4a8e27ece6103a5 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/exception/UserNotFoundException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.NOT_FOUND) +public class UserNotFoundException extends Exception { + + public UserNotFoundException(String message) { + super(message); + } + + public UserNotFoundException(String message, Throwable thr) { + super(message, thr); + } + + public UserNotFoundException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/gateway/KeycloakGateway.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/gateway/KeycloakGateway.java new file mode 100644 index 0000000000000000000000000000000000000000..a05a75a6ff890feba33e1d14f2bd1a9407845861 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/gateway/KeycloakGateway.java @@ -0,0 +1,11 @@ +package at.tuwien.gateway; + +import at.tuwien.api.keycloak.TokenDto; +import at.tuwien.exception.ServiceConnectionException; +import at.tuwien.exception.ServiceException; + +public interface KeycloakGateway { + + TokenDto obtainUserToken(String username, String password) throws ServiceConnectionException, ServiceException; + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..76f3e83cef138b8d64151757e303fd05555a4591 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java @@ -0,0 +1,81 @@ +package at.tuwien.gateway.impl; + +import at.tuwien.api.keycloak.TokenDto; +import at.tuwien.config.KeycloakConfig; +import at.tuwien.exception.ServiceConnectionException; +import at.tuwien.exception.ServiceException; +import at.tuwien.gateway.KeycloakGateway; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.*; +import org.springframework.stereotype.Service; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.ResourceAccessException; +import org.springframework.web.client.RestTemplate; + +@Log4j2 +@Service +public class KeycloakGatewayImpl implements KeycloakGateway { + + private final RestTemplate restTemplate; + private final KeycloakConfig keycloakConfig; + + public KeycloakGatewayImpl(@Qualifier("keycloakRestTemplate") RestTemplate restTemplate, + KeycloakConfig keycloakConfig) { + this.restTemplate = restTemplate; + this.keycloakConfig = keycloakConfig; + } + + public TokenDto obtainToken() throws ServiceConnectionException, ServiceException { + final HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + final MultiValueMap<String, String> payload = new LinkedMultiValueMap<>(); + payload.add("username", keycloakConfig.getKeycloakUsername()); + payload.add("password", keycloakConfig.getKeycloakPassword()); + payload.add("grant_type", "password"); + payload.add("client_id", "admin-cli"); + final String url = keycloakConfig.getKeycloakEndpoint() + "/realms/master/protocol/openid-connect/token"; + log.debug("request admin token from url {}", url); + final ResponseEntity<TokenDto> response; + try { + response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class); + } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { + log.error("Failed to obtain admin token: {}", e.getMessage()); + throw new ServiceConnectionException("Failed to obtain admin token: " + e.getMessage(), e); + } catch (Exception e) { + log.error("Failed to obtain admin token: remote host answered unexpected: {}", e.getMessage(), e); + throw new ServiceException("Failed to obtain admin token: remote host answered unexpected: " + e.getMessage(), e); + } + return response.getBody(); + } + + @Override + public TokenDto obtainUserToken(String username, String password) throws ServiceConnectionException, ServiceException { + 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 attributes"); + payload.add("client_id", keycloakConfig.getKeycloakClient()); + payload.add("client_secret", keycloakConfig.getKeycloakClientSecret()); + final String url = keycloakConfig.getKeycloakEndpoint() + "/realms/dbrepo/protocol/openid-connect/token"; + log.debug("request user token from url {}", url); + final ResponseEntity<TokenDto> response; + try { + response = new RestTemplate() + .exchange(url, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class); + } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { + log.error("Failed to obtain user token: {}", e.getMessage()); + throw new ServiceConnectionException("Failed to obtain user token: " + e.getMessage(), e); + } catch (Exception e) { + log.error("Failed to obtain user token: unexpected response: {}", e.getMessage(), e); + throw new ServiceException("Failed to obtain user token: unexpected response: " + e.getMessage(), e); + } + return response.getBody(); + } + +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/handlers/DashboardApiExceptionHandler.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/handlers/DashboardApiExceptionHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..80c834f77c8078d9c7d99bddeb438229caabe726 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/handlers/DashboardApiExceptionHandler.java @@ -0,0 +1,52 @@ +package at.tuwien.handlers; + +import at.tuwien.api.error.ApiErrorDto; +import at.tuwien.exception.RestTemplateExchangeException; +import at.tuwien.exception.JsonProcessingException; +import at.tuwien.exception.SyncDatabaseNotFoundException; +import io.swagger.v3.oas.annotations.Hidden; +import lombok.extern.log4j.Log4j2; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; + +@Log4j2 +@ControllerAdvice +public class DashboardApiExceptionHandler { + + @Hidden + @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR) + @ExceptionHandler(JsonProcessingException.class) + public ResponseEntity<ApiErrorDto> handle(JsonProcessingException e) { + return genericHandle(e.getClass(), e.getLocalizedMessage()); + } + + @Hidden + @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR) + @ExceptionHandler(RestTemplateExchangeException.class) + public ResponseEntity<ApiErrorDto> handle(RestTemplateExchangeException e) { + return genericHandle(e.getClass(), e.getLocalizedMessage()); + } + + @Hidden + @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR) + @ExceptionHandler(SyncDatabaseNotFoundException.class) + public ResponseEntity<ApiErrorDto> handle(SyncDatabaseNotFoundException e) { + return genericHandle(e.getClass(), e.getLocalizedMessage()); + } + + private ResponseEntity<ApiErrorDto> genericHandle(Class<?> exceptionClass, String message) { + final HttpHeaders headers = new HttpHeaders(); + headers.set("Content-Type", "application/problem+json"); + final ResponseStatus annotation = exceptionClass.getAnnotation(ResponseStatus.class); + final ApiErrorDto response = ApiErrorDto.builder() + .status(annotation.code()) + .message(message) + .code(annotation.reason()) + .build(); + return new ResponseEntity<>(response, headers, response.getStatus()); + } +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/interceptor/KeycloakInterceptor.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/interceptor/KeycloakInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..78fb5adc61fd2420cfc62e72cb4aa4c700c3b82b --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/interceptor/KeycloakInterceptor.java @@ -0,0 +1,55 @@ +package at.tuwien.interceptor; + +import at.tuwien.api.keycloak.TokenDto; +import lombok.extern.log4j.Log4j2; +import org.springframework.http.*; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.ResourceAccessException; +import org.springframework.web.client.RestTemplate; + +import java.io.IOException; + +@Log4j2 +public class KeycloakInterceptor implements ClientHttpRequestInterceptor { + + private final String adminUsername; + private final String adminPassword; + private final String keycloakEndpoint; + + public KeycloakInterceptor(String adminUsername, String adminPassword, String keycloakEndpoint) { + this.adminUsername = adminUsername; + this.adminPassword = adminPassword; + this.keycloakEndpoint = keycloakEndpoint; + } + + @Override + public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) + throws IOException { + final RestTemplate restTemplate = new RestTemplate(); + final HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + final MultiValueMap<String, String> payload = new LinkedMultiValueMap<>(); + payload.add("username", adminUsername); + payload.add("password", adminPassword); + payload.add("grant_type", "password"); + payload.add("client_id", "admin-cli"); + final ResponseEntity<TokenDto> response; + try { + response = restTemplate.exchange(keycloakEndpoint + "/realms/master/protocol/openid-connect/token", + HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class); + } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { + log.error("Failed to obtain admin token: {}", e.getMessage()); + return execution.execute(request, body); + } + if (response.getBody() == null) { + return execution.execute(request, body); + } + request.getHeaders().set("Authorization", "Bearer " + response.getBody().getAccessToken()); + return execution.execute(request, body); + } +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/AbstractPanel.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/AbstractPanel.java new file mode 100644 index 0000000000000000000000000000000000000000..7d45e439226cdb82abc8c87d99f21b19461c57d7 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/AbstractPanel.java @@ -0,0 +1,47 @@ +package at.tuwien.panels; + +import lombok.Setter; + +public abstract class AbstractPanel { + @Setter + protected static String dataEndpoint; + public static final String DATASRC_UID = "infinityDataSrc"; + + protected static int x; + protected static int y; + private static int prevHeight = -1; + + public static void resetCoordinates() { + x = 0; + y = 0; + } + + public static void addRowPlaceHolder() { + y += 1; + } + + public static void markNewRow() { + x = 0; + } + + + public static void handleOverflow(int height, int width) { + if ( (x + width) > 24) { + x = 0; + y += prevHeight == -1 ? height : prevHeight; + prevHeight = height; + } + } + + public static void updateCoords(int height, int width) { + x += width; + + if (x > 24) { + x = 0; + y += prevHeight == -1 ? height : prevHeight; + } + prevHeight = height; + } + + public abstract String getConstructedPanel(); +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/CntAllPanel.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/CntAllPanel.java new file mode 100644 index 0000000000000000000000000000000000000000..f5af7d56e4afb6047b2b1bf6c18ea21a5ff1fcaa --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/CntAllPanel.java @@ -0,0 +1,69 @@ +package at.tuwien.panels; + +import at.tuwien.endpoints.DataEndpoint; +import lombok.extern.log4j.Log4j2; + +@Log4j2 +public class CntAllPanel extends AbstractPanel { + public static final String RELATIVE_PATH = "/cntAll"; + private static final int HEIGHT = 8; + private static final int WIDTH = 5; + private final String dataAPI; + + public CntAllPanel(Long dbId, Long vId) { + this.dataAPI = String.format("%s%s%s/%d/%d", dataEndpoint, DataEndpoint.API_PREFIX, RELATIVE_PATH, dbId, vId); + } + + @Override + public String getConstructedPanel() { + handleOverflow(HEIGHT, WIDTH); + String panelJson = "{\n" + + " \"datasource\": {\n" + + " \"type\": \"yesoreyeram-infinity-datasource\",\n" + + " \"uid\": \"" + DATASRC_UID + "\"" + + " },\n" + + " \"fieldConfig\": {\n" + + " \"defaults\": {\n" + + " \"color\": {\n" + + " \"fixedColor\": \"#FFFFFF\",\n" + + " \"mode\": \"fixed\"\n" + + " },\n" + + " \"mappings\": []\n" + + " },\n" + + " \"overrides\": []\n" + + " },\n" + + " \"gridPos\": {\n" + + " \"h\": " + HEIGHT + ",\n" + + " \"w\": " + WIDTH + ",\n" + + " \"x\": " + x + ",\n" + + " \"y\": " + y + "\n" + + " },\n" + + " \"targets\": [\n" + + " {\n" + + " \"columns\": [],\n" + + " \"datasource\": {\n" + + " \"type\": \"yesoreyeram-infinity-datasource\",\n" + + " \"uid\": \"" + DATASRC_UID + "\"" + + " },\n" + + " \"filters\": [],\n" + + " \"format\": \"table\",\n" + + " \"global_query_id\": \"\",\n" + + " \"refId\": \"A\",\n" + + " \"root_selector\": \"\",\n" + + " \"source\": \"url\",\n" + + " \"type\": \"json\",\n" + + " \"url\": \"" + this.dataAPI + "\",\n" + + " \"url_options\": {\n" + + " \"data\": \"\",\n" + + " \"method\": \"GET\"\n" + + " }\n" + + " }\n" + + " ],\n" + + " \"title\": \"Total elements\",\n" + + " \"type\": \"stat\"\n" + + " }"; + + updateCoords(HEIGHT, WIDTH); + return panelJson; + } +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/Dashboard.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/Dashboard.java new file mode 100644 index 0000000000000000000000000000000000000000..322485b9094dc76b8867b75d6c2b13f052796e22 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/Dashboard.java @@ -0,0 +1,29 @@ +package at.tuwien.panels; + +import java.util.List; + +public class Dashboard { + + public String getDashboard(List<String> panels, Long dbId, int refreshrate) { + + return "{\n" + + " \"dashboard\": {\n" + + " \"id\": null,\n" + + " \"uid\": \"" + dbId + "\",\n" + + " \"title\": \"automated dashboard_" + dbId + "\",\n" + + " \"tags\": [\n" + + " \"templated\"\n" + + " ],\n" + + " \"timezone\": \"browser\",\n" + + " \"schemaVersion\": 16,\n" + + " \"refresh\": \"" + (refreshrate == 0 ? "" : refreshrate + "s") + "\",\n" + + " \"panels\": [" + + String.join(", ", panels) + + " ]" + + " \n" + + " },\n" + + " \"message\": \"automated creation of dashboard\",\n" + + " \"overwrite\": false\n" + + "}"; + } +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/HistogramPanel.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/HistogramPanel.java new file mode 100644 index 0000000000000000000000000000000000000000..e021f0ab6b98b20eef7694c5b862f014db2cd870 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/HistogramPanel.java @@ -0,0 +1,110 @@ +package at.tuwien.panels; + +import at.tuwien.dto.HistogramConfigDto; +import at.tuwien.endpoints.DataEndpoint; +import lombok.extern.log4j.Log4j2; + +@Log4j2 +public class HistogramPanel extends AbstractPanel { + public static final String RELATIVE_PATH = "/histogram"; + private static final int HEIGHT = 8; + private static final int WIDTH = 5; + private String dataAPI; + private final String colName; + private Integer min; + private Integer max; + + public HistogramPanel(Long dbId, Long vId, String colName, HistogramConfigDto configDto) { + this.dataAPI = String.format("%s%s%s/%d/%d", dataEndpoint, DataEndpoint.API_PREFIX, RELATIVE_PATH, dbId, vId); + this.colName = colName; + + if (configDto != null) { + if (configDto.getMin() != null) { + this.min = configDto.getMin(); + } + + if (configDto.getMax() != null) { + this.max = configDto.getMax(); + } + + if (configDto.getSize() != null) { + dataAPI += String.format("?size=%d", configDto.getSize()); + } + } + } + + @Override + public String getConstructedPanel() { + handleOverflow(HEIGHT, WIDTH); + String panelJson = "{\n" + + " \"datasource\": {\n" + + " \"type\": \"yesoreyeram-infinity-datasource\",\n" + + " \"uid\": \"" + DATASRC_UID + "\"" + + " },\n" + + " \"fieldConfig\": {\n" + + " \"defaults\": {\n" + + " \"color\": {\n" + + " \"mode\": \"palette-classic\"\n" + + " },\n" + + " \"custom\": {\n" + + " \"fillOpacity\": 80,\n" + + " \"gradientMode\": \"none\",\n" + + " \"hideFrom\": {\n" + + " \"legend\": false,\n" + + " \"tooltip\": true,\n" + + " \"viz\": false\n" + + " },\n" + + " \"lineWidth\": 1\n" + + " },\n" + + " \"mappings\": [],\n" + + " \"max\": " + ((max == null) ? "null" : max) + ",\n" + + " \"min\": " + ((min == null) ? "null" : min) + "\n" + + " },\n" + + " \"overrides\": []\n" + + " },\n" + + " \"gridPos\": {\n" + + " \"h\": " + HEIGHT + ",\n" + + " \"w\": " + WIDTH + ",\n" + + " \"x\": " + x + ",\n" + + " \"y\": " + y + "\n" + + " },\n" + + " \"id\": null,\n" + + " \"description\": \"" + "Each bar represents a bucket, and the bar height represents " + + "the frequency of the values from the column " + this.colName + " that fell into that bucket's interval.\",\n" + + " \"options\": {\n" + + " \"legend\": {\n" + + " \"calcs\": [],\n" + + " \"displayMode\": \"list\",\n" + + " \"placement\": \"bottom\",\n" + + " \"showLegend\": false\n" + + " }\n" + + " },\n" + + " \"targets\": [\n" + + " {\n" + + " \"columns\": [],\n" + + " \"datasource\": {\n" + + " \"type\": \"yesoreyeram-infinity-datasource\",\n" + + " \"uid\": \"" + DATASRC_UID + "\"" + + " },\n" + + " \"filters\": [],\n" + + " \"format\": \"table\",\n" + + " \"global_query_id\": \"\",\n" + + " \"refId\": \"A\",\n" + + " \"root_selector\": \"values\",\n" + + " \"source\": \"url\",\n" + + " \"type\": \"json\",\n" + + " \"url\": \"" + this.dataAPI + "\",\n" + + " \"url_options\": {\n" + + " \"data\": \"\",\n" + + " \"method\": \"GET\"\n" + + " }\n" + + " }\n" + + " ],\n" + + " \"title\": \"" + "Distribution of " + this.colName + " \",\n" + + " \"type\": \"histogram\"\n" + + " }"; + + updateCoords(HEIGHT, WIDTH); + return panelJson; + } +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/MultiTimeSeriesPanel.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/MultiTimeSeriesPanel.java new file mode 100644 index 0000000000000000000000000000000000000000..70be0650ee1b026702d74c01fb997b7c368210db --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/MultiTimeSeriesPanel.java @@ -0,0 +1,90 @@ +package at.tuwien.panels; + +import at.tuwien.endpoints.DataEndpoint; +import lombok.extern.log4j.Log4j2; + +@Log4j2 +public class MultiTimeSeriesPanel extends AbstractPanel { + public static final String RELATIVE_PATH = "/multitimeseries"; + public static final String VIEW_MULTI_TIMECOL = "timecol"; + public static final String VIEW_MULTI_SELECTOR_TIME = "time"; + public static final String VIEW_MULTI_SELECTOR_VALUE = "value"; + public static final String VIEW_MULTI_SELECTOR_NAME = "name"; + + + private static final int HEIGHT = 8; + private static final int WIDTH = 5; + private String dataAPI; + + public MultiTimeSeriesPanel(Long dbId, Long vId) { + this.dataAPI = String.format("%s%s%s/%d/%d", dataEndpoint, DataEndpoint.API_PREFIX, RELATIVE_PATH, dbId, vId); + dataAPI += String.format("?size=%d", 100); + } + + @Override + public String getConstructedPanel() { + handleOverflow(HEIGHT, WIDTH); + String panelJson = " {\n" + + "\"datasource\": {\n" + + " \"uid\": \"" + DATASRC_UID + "\",\n" + + " \"type\": \"yesoreyeram-infinity-datasource\"\n" + + " },\n" + + " \"type\": \"timeseries\",\n" + + " \"title\": \"Time Series\",\n" + + " \"gridPos\": {\n" + + " \"h\": " + HEIGHT + ",\n" + + " \"w\": " + WIDTH + ",\n" + + " \"x\": " + x + ",\n" + + " \"y\": " + y + "\n" + + " },\n" + + "\"options\": {\n" + + " \"legend\": {\n" + + " \"calcs\": [],\n" + + " \"displayMode\": \"list\",\n" + + " \"placement\": \"bottom\",\n" + + " \"showLegend\": true\n" + + " },\n" + + " \"tooltip\": {\n" + + " \"mode\": \"single\",\n" + + " \"sort\": \"none\"\n" + + " }\n" + + " },\n" + + " \"targets\": [\n" + + " {\n" + + " \"datasource\": {\n" + + " \"type\": \"yesoreyeram-infinity-datasource\",\n" + + " \"uid\": \"" + DATASRC_UID + "\"" + + " },\n" + + " \"refId\": \"A\",\n" + + " \"type\": \"json\",\n" + + " \"source\": \"url\",\n" + + " \"format\": \"timeseries\",\n" + + " \"url\": \"" + this.dataAPI + "\",\n" + + " \"url_options\": {\n" + + " \"method\": \"GET\",\n" + + " \"data\": \"\"\n" + + " },\n" + + " \"root_selector\": \"time_series\",\n" + + " \"columns\": [\n" + + " {\n" + + " \"selector\": \"" + VIEW_MULTI_SELECTOR_TIME + "\",\n" + + " \"type\": \"timestamp\"\n" + + " },\n" + + " {\n" + + " \"selector\": \"" + VIEW_MULTI_SELECTOR_VALUE + "\",\n" + + " \"type\": \"number\"\n" + + " },\n" + + " {\n" + + " \"selector\": \"" + VIEW_MULTI_SELECTOR_NAME + "\",\n" + + " \"type\": \"string\"\n" + + " }\n" + + " ],\n" + + " \"filters\": [],\n" + + " \"global_query_id\": \"\"\n" + + " }\n" + + " ]}"; + + updateCoords(HEIGHT, WIDTH); + return panelJson; + } +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/PieChartPanel.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/PieChartPanel.java new file mode 100644 index 0000000000000000000000000000000000000000..3b98dec4d0b0bfe94461e6d06b791420c8475ed0 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/PieChartPanel.java @@ -0,0 +1,110 @@ +package at.tuwien.panels; + +import at.tuwien.dto.PieChartConfigDto; +import at.tuwien.endpoints.DataEndpoint; +import lombok.extern.log4j.Log4j2; + +@Log4j2 +public class PieChartPanel extends AbstractPanel { + public static final String RELATIVE_PATH = "/piechart"; + public static final String VIEW_PIE_PERCENTAGE_COL = "percentage"; + + private static final int HEIGHT = 8; + private static final int WIDTH = 7; + private String dataAPI; + private final String colName; + + public PieChartPanel(Long dbId, Long vId, String colName, PieChartConfigDto config) { + this.dataAPI = String.format("%s%s%s/%d/%d", dataEndpoint, DataEndpoint.API_PREFIX, RELATIVE_PATH, dbId, vId); + this.colName = colName; + + if (config != null && config.getSize() != null) { + dataAPI += String.format("?size=%d", config.getSize()); + } + } + + @Override + public String getConstructedPanel() { + handleOverflow(HEIGHT, WIDTH); + String panelJson = "{\n" + + " \"datasource\": {\n" + + " \"type\": \"yesoreyeram-infinity-datasource\",\n" + + " \"uid\": \"" + DATASRC_UID + "\"" + + " },\n" + + " \"fieldConfig\": {\n" + + " \"defaults\": {\n" + + " \"color\": {\n" + + " \"mode\": \"palette-classic\"\n" + + " },\n" + + " \"custom\": {\n" + + " \"hideFrom\": {\n" + + " \"legend\": false,\n" + + " \"tooltip\": false,\n" + + " \"viz\": false\n" + + " }\n" + + " },\n" + + " \"mappings\": []\n" + + " },\n" + + " \"overrides\": []\n" + + " },\n" + + " \"gridPos\": {\n" + + " \"h\": " + HEIGHT + ",\n" + + " \"w\": " + WIDTH + ",\n" + + " \"x\": " + x + ",\n" + + " \"y\": " + y + "\n" + + " },\n" + + " \"options\": {\n" + + " \"displayLabels\": [\n" + + " \"percent\"\n" + + " ],\n" + + " \"legend\": {\n" + + " \"calcs\": [],\n" + + " \"displayMode\": \"list\",\n" + + " \"placement\": \"right\",\n" + + " \"showLegend\": true,\n" + + " \"values\": [\n" + + " \"value\"\n" + + " ]\n" + + " },\n" + + " \"pieType\": \"pie\",\n" + + " \"reduceOptions\": {\n" + + " \"calcs\": [\n" + + " \"lastNotNull\"\n" + + " ],\n" + + " \"fields\": \"\",\n" + + " \"values\": false\n" + + " },\n" + + " \"tooltip\": {\n" + + " \"mode\": \"single\",\n" + + " \"sort\": \"none\"\n" + + " }\n" + + " },\n" + + " \"targets\": [\n" + + " {\n" + + " \"columns\": [],\n" + + " \"datasource\": {\n" + + " \"type\": \"yesoreyeram-infinity-datasource\",\n" + + " \"uid\": \"" + DATASRC_UID + "\"" + + " },\n" + + " \"filters\": [],\n" + + " \"format\": \"table\",\n" + + " \"global_query_id\": \"\",\n" + + " \"refId\": \"A\",\n" + + " \"root_selector\": \"\",\n" + + " \"source\": \"url\",\n" + + " \"type\": \"json\",\n" + + " \"url\": \"" + this.dataAPI + "\",\n" + + " \"url_options\": {\n" + + " \"data\": \"\",\n" + + " \"method\": \"GET\"\n" + + " }\n" + + " }\n" + + " ],\n" + + " \"title\": \"Distribution of Most Frequent " + this.colName + "\",\n" + + " \"type\": \"piechart\"\n" + + " }"; + + updateCoords(HEIGHT, WIDTH); + return panelJson; + } +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/RowPanel.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/RowPanel.java new file mode 100644 index 0000000000000000000000000000000000000000..94ae55b74b10243a0daa8085acc602663a11adea --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/RowPanel.java @@ -0,0 +1,52 @@ +package at.tuwien.panels; + +import at.tuwien.exception.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.log4j.Log4j2; + +import java.util.List; + +@Log4j2 +public class RowPanel extends AbstractPanel { + private static final int HEIGHT = 1; + private static final int WIDTH = 24; + private final String name; + private final List<String> tablePanels; + private final ObjectMapper mapper; + + public RowPanel(String name, List<String> tablePanels) { + this.name = name; + this.tablePanels = tablePanels; + this.mapper = new ObjectMapper(); + } + + @Override + public String getConstructedPanel() { + + int rowY = -1; + try{ + JsonNode rootNode = mapper.readTree(tablePanels.get(0)); + rowY = rootNode.path("gridPos").path("y").asInt() - 1; + } catch (Exception e) { + log.debug("failed to read json of table panel"); + throw new JsonProcessingException("Failed to parse table panel"); + } + + return "{\n" + + " \"collapsed\": true,\n" + + " \"gridPos\": {\n" + + " \"h\": " + HEIGHT + ",\n" + + " \"w\": " + WIDTH + ",\n" + + " \"x\": " + 0 + ",\n" + + " \"y\": " + rowY + "\n" + + " },\n" + + " \"id\": null,\n" + + " \"panels\": [" + + String.join(", ", tablePanels) + + "],\n" + + " \"title\": \"" + name + "\",\n" + + " \"type\": \"row\"\n" + + " }"; + } +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/StatsPanel.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/StatsPanel.java new file mode 100644 index 0000000000000000000000000000000000000000..81e920433647d9ee9bf2b2098ac85e2429c52f88 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/StatsPanel.java @@ -0,0 +1,183 @@ +package at.tuwien.panels; + +import at.tuwien.endpoints.DataEndpoint; +import lombok.extern.log4j.Log4j2; + +@Log4j2 +public class StatsPanel extends AbstractPanel { + public static final String RELATIVE_PATH = "/stats"; + public static final String HEADER_COL = "column"; + public static final String HEADER_MIN = "min"; + public static final String HEADER_MAX = "max"; + public static final String HEADER_STDDEV = "stddev"; + public static final String HEADER_AVG = "median"; + + private static final int HEIGHT = 8; + private static final int WIDTH = 9; + private final String dataAPI; + private final String name; + + public StatsPanel(Long dbId, Long tId, String name) { + this.dataAPI = String.format("%s%s%s/%d/%d", dataEndpoint, DataEndpoint.API_PREFIX, RELATIVE_PATH, dbId, tId); + this.name = name; + } + + @Override + public String getConstructedPanel() { + handleOverflow(HEIGHT, WIDTH); + String panelJson = " {\n" + + " \"datasource\": {\n" + + " \"type\": \"yesoreyeram-infinity-datasource\",\n" + + " \"uid\": \"" + DATASRC_UID + "\"" + + " },\n" + + " \"fieldConfig\": {\n" + + " \"defaults\": {\n" + + " \"custom\": {\n" + + " \"align\": \"auto\",\n" + + " \"filterable\": \"true\",\n" + + " \"cellOptions\": {\n" + + " \"type\": \"auto\"\n" + + " },\n" + + " \"inspect\": false\n" + + " },\n" + + " \"mappings\": [],\n" + + " \"thresholds\": {\n" + + " \"mode\": \"absolute\",\n" + + " \"steps\": [\n" + + " {\n" + + " \"color\": \"green\",\n" + + " \"value\": null\n" + + " },\n" + + " {\n" + + " \"color\": \"red\",\n" + + " \"value\": 80\n" + + " }\n" + + " ]\n" + + " }\n" + + " },\n" + + " \"overrides\": [\n" + + " {\n" + + " \"matcher\": {\n" + + " \"id\": \"byName\",\n" + + " \"options\": \"" + HEADER_COL + "\"\n" + + " },\n" + + " \"properties\": [\n" + + " {\n" + + " \"id\": \"custom.align\",\n" + + " \"value\": \"center\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"matcher\": {\n" + + " \"id\": \"byName\",\n" + + " \"options\": \"" + HEADER_MIN + "\"\n" + + " },\n" + + " \"properties\": [\n" + + " {\n" + + " \"id\": \"custom.width\",\n" + + " \"value\": 115\n" + + " }\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"matcher\": {\n" + + " \"id\": \"byName\",\n" + + " \"options\": \"" + HEADER_MAX + "\"\n" + + " },\n" + + " \"properties\": [\n" + + " {\n" + + " \"id\": \"custom.width\",\n" + + " \"value\": 115\n" + + " }\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"matcher\": {\n" + + " \"id\": \"byName\",\n" + + " \"options\": \"" + HEADER_AVG + "\"\n" + + " },\n" + + " \"properties\": [\n" + + " {\n" + + " \"id\": \"custom.width\",\n" + + " \"value\": 115\n" + + " }\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"matcher\": {\n" + + " \"id\": \"byName\",\n" + + " \"options\": \"" + HEADER_STDDEV + "\"\n" + + " },\n" + + " \"properties\": [\n" + + " {\n" + + " \"id\": \"custom.width\",\n" + + " \"value\": 115\n" + + " }\n" + + " ]\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"gridPos\": {\n" + + " \"h\": " + HEIGHT + ",\n" + + " \"w\": " + WIDTH + ",\n" + + " \"x\": " + x + ",\n" + + " \"y\": " + y + "\n" + + " },\n" + + " \"options\": {\n" + + " \"cellHeight\": \"sm\",\n" + + " \"footer\": {\n" + + " \"countRows\": false,\n" + + " \"fields\": \"\",\n" + + " \"reducer\": [\n" + + " \"sum\"\n" + + " ],\n" + + " \"show\": false\n" + + " },\n" + + " \"showHeader\": true\n" + + " },\n" + + " \"targets\": [\n" + + " {\n" + + " \"columns\": [],\n" + + " \"datasource\": {\n" + + " \"type\": \"yesoreyeram-infinity-datasource\",\n" + + " \"uid\": \"" + DATASRC_UID + "\"" + + " },\n" + + " \"filters\": [],\n" + + " \"format\": \"table\",\n" + + " \"global_query_id\": \"\",\n" + + " \"refId\": \"A\",\n" + + " \"root_selector\": \"\",\n" + + " \"source\": \"url\",\n" + + " \"type\": \"json\",\n" + + " \"url\": \"" + this.dataAPI + "\",\n" + + " \"url_options\": {\n" + + " \"data\": \"\",\n" + + " \"method\": \"GET\"\n" + + " }\n" + + " }\n" + + " ],\n" + + " \"title\": \"Stats for " + name + "\",\n" + + " \"transformations\": [\n" + + " {\n" + + " \"id\": \"organize\",\n" + + " \"options\": {\n" + + " \"excludeByName\": {},\n" + + " \"includeByName\": {},\n" + + " \"indexByName\": {\n" + + " \"" + HEADER_AVG + "\": 3,\n" + + " \"" + HEADER_COL + "\": 0,\n" + + " \"" + HEADER_STDDEV + "\": 4,\n" + + " \"" + HEADER_MAX + "\": 2,\n" + + " \"" + HEADER_MIN + "\": 1\n" + + " }\n" + + " }\n" + + " }\n" + + " ],\n" + + " \"type\": \"table\"\n" + + " }"; + + updateCoords(HEIGHT, WIDTH); + return panelJson; + } +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/TablePanel.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/TablePanel.java new file mode 100644 index 0000000000000000000000000000000000000000..7295f1528d750c6bbdc26708e075535a4162dfe7 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/TablePanel.java @@ -0,0 +1,73 @@ +package at.tuwien.panels; + +import at.tuwien.endpoints.DataEndpoint; +import lombok.extern.log4j.Log4j2; + +@Log4j2 +public class TablePanel extends AbstractPanel { + public static final String RELATIVE_PATH = "/tablepanel"; + private static final int HEIGHT = 8; + private static final int WIDTH = 16; + private final String name; + + private String dataAPI; + + public TablePanel(Long dbId, Long tId, String name, Long size) { + this.name = name; + this.dataAPI = String.format("%s%s%s/%d/%d", dataEndpoint, DataEndpoint.API_PREFIX, RELATIVE_PATH, dbId, tId); + if (size != null) { + dataAPI += String.format("?size=%d", size); + } + } + + @Override + public String getConstructedPanel() { + handleOverflow(HEIGHT, WIDTH); + String panelJson = "{\n" + + " \"datasource\": {\n" + + " \"type\": \"yesoreyeram-infinity-datasource\",\n" + + " \"uid\": \"" + DATASRC_UID + "\"" + + " },\n" + + " \"fieldConfig\": {\n" + + " \"defaults\": {\n" + + " \"custom\": {\n" + + " \"filterable\": true\n" + + " }\n" + + " }\n" + + " }," + + " \"gridPos\": {\n" + + " \"h\": " + HEIGHT + ",\n" + + " \"w\": " + WIDTH + ",\n" + + " \"x\": " + x + ",\n" + + " \"y\": " + y + "\n" + + " },\n" + + " \"id\": null,\n" + + " \"targets\": [\n" + + " {\n" + + " \"columns\": [],\n" + + " \"datasource\": {\n" + + " \"type\": \"yesoreyeram-infinity-datasource\",\n" + + " \"uid\": \"" + DATASRC_UID + "\"" + + " },\n" + + " \"filters\": [],\n" + + " \"format\": \"table\",\n" + + " \"global_query_id\": \"\",\n" + + " \"refId\": \"A\",\n" + + " \"root_selector\": \"\",\n" + + " \"source\": \"url\",\n" + + " \"type\": \"json\",\n" + + " \"url\": \"" + this.dataAPI + "\",\n" + + " \"url_options\": {\n" + + " \"data\": \"\",\n" + + " \"method\": \"GET\"\n" + + " }\n" + + " }\n" + + " ],\n" + + " \"title\": \"" + name + "\",\n" + + " \"type\": \"table\"\n" + + " }"; + + updateCoords(HEIGHT, WIDTH); + return panelJson; + } +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/TimeSeriesPanel.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/TimeSeriesPanel.java new file mode 100644 index 0000000000000000000000000000000000000000..e0f5b305eaf1716af353aa3497bddc6fb04617a5 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/panels/TimeSeriesPanel.java @@ -0,0 +1,93 @@ +package at.tuwien.panels; + +import at.tuwien.endpoints.DataEndpoint; +import lombok.extern.log4j.Log4j2; + +@Log4j2 +public class TimeSeriesPanel extends AbstractPanel { + public static final String RELATIVE_PATH = "/timeseries"; + public static final String TIME_VAL_COL = "value"; + public static final String TIME_YEAR_COL = "year"; + public static final String TIME_MONTH_COL = "month"; + public static final String TIME_DAY_COL = "day"; + public static final String TIME_HOUR_COL = "hour"; + public static final String TIME_MIN_COL = "min"; + public static final String TIME_SECOND_COL = "sec"; + private final String value; + + private static final int HEIGHT = 8; + private static final int WIDTH = 5; + private String dataAPI; + + public TimeSeriesPanel(Long dbId, Long vId, String value, Long size) { + this.dataAPI = String.format("%s%s%s/%d/%d", dataEndpoint, DataEndpoint.API_PREFIX, RELATIVE_PATH, dbId, vId); + this.value = value; + if (size != null) { + dataAPI += String.format("?size=%d", size); + } + } + + @Override + public String getConstructedPanel() { + handleOverflow(HEIGHT, WIDTH); + String panelJson = " {\n" + + "\"datasource\": {\n" + + " \"uid\": \"" + DATASRC_UID + "\",\n" + + " \"type\": \"yesoreyeram-infinity-datasource\"\n" + + " },\n" + + " \"type\": \"timeseries\",\n" + + " \"title\": \"Time Series\",\n" + + " \"gridPos\": {\n" + + " \"h\": " + HEIGHT + ",\n" + + " \"w\": " + WIDTH + ",\n" + + " \"x\": " + x + ",\n" + + " \"y\": " + y + "\n" + + " },\n" + + "\"options\": {\n" + + " \"legend\": {\n" + + " \"calcs\": [],\n" + + " \"displayMode\": \"list\",\n" + + " \"placement\": \"bottom\",\n" + + " \"showLegend\": true\n" + + " },\n" + + " \"tooltip\": {\n" + + " \"mode\": \"single\",\n" + + " \"sort\": \"none\"\n" + + " }\n" + + " },\n" + + " \"targets\": [\n" + + " {\n" + + " \"datasource\": {\n" + + " \"type\": \"yesoreyeram-infinity-datasource\",\n" + + " \"uid\": \"" + DATASRC_UID + "\"" + + " },\n" + + " \"refId\": \"A\",\n" + + " \"type\": \"json\",\n" + + " \"source\": \"url\",\n" + + " \"format\": \"table\",\n" + + " \"url\": \"" + this.dataAPI + "\",\n" + + " \"url_options\": {\n" + + " \"method\": \"GET\",\n" + + " \"data\": \"\"\n" + + " },\n" + + " \"root_selector\": \"time_series\",\n" + + " \"columns\": [\n" + + " {\n" + + " \"selector\": \"time\",\n" + + " \"type\": \"timestamp\"\n" + + " },\n" + + " {\n" + + " \"text\": \"" + value + "\",\n" + + " \"selector\": \"value\",\n" + + " \"type\": \"number\"\n" + + " }\n" + + " ],\n" + + " \"filters\": [],\n" + + " \"global_query_id\": \"\"\n" + + " }\n" + + " ]}"; + + updateCoords(HEIGHT, WIDTH); + return panelJson; + } +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/DashboardService.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/DashboardService.java new file mode 100644 index 0000000000000000000000000000000000000000..26c66d4efeec34e2bc1b1a6fa5bdf7cc84105af2 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/DashboardService.java @@ -0,0 +1,9 @@ +package at.tuwien.service; + +import at.tuwien.dto.DashboardConfigDto; + +public interface DashboardService { + String generateDashboard(Long dbId, String token, DashboardConfigDto configDto); + Boolean checkIfDashboardExists(Long dbId); + void removeDashboard(Long dbId); +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/DataService.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/DataService.java new file mode 100644 index 0000000000000000000000000000000000000000..253fde5ebb351e42299f28adcc9ac5575bed99d0 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/DataService.java @@ -0,0 +1,14 @@ +package at.tuwien.service; + +import java.util.List; +import java.util.Map; + +public interface DataService { + Map<String, Object> getPieChartData(Long dbId, Long viewId, Long size); + Map<String, Object> getCntAllData(Long dbId, Long viewId); + List<Map<String, Object>> getTableData(Long dbId, Long tableId, Long size); + Map<String, List<Object>> getHistogramData(Long dbId, Long viewId, Long size); + List<Map<String, Object>> getStatsData(Long dbId, Long tableId); + Map<String, List<Map<String, Object>>> getTimeSeriesData(Long dbId, Long viewId, Long size); + Map<String, List<Map<String, Object>>> getMultiTimeSeriesData(Long dbId, Long viewId, Long size); +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/DataSourceService.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/DataSourceService.java new file mode 100644 index 0000000000000000000000000000000000000000..070ba1f1d5a0923382d02d0d8da6be4c2e15314d --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/DataSourceService.java @@ -0,0 +1,7 @@ +package at.tuwien.service; + + +public interface DataSourceService { + String addDatasource(); + String getDatasource(); +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/TableService.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/TableService.java new file mode 100644 index 0000000000000000000000000000000000000000..49a5b773dead2d454eb6a34455ac40fe6b03eb8a --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/TableService.java @@ -0,0 +1,16 @@ +package at.tuwien.service; + + +import at.tuwien.api.database.table.TableBriefDto; +import at.tuwien.api.database.table.TableDto; + +import java.util.List; +import java.util.Map; + + +public interface TableService { + + List<TableBriefDto> getAllTables(Long dbId); + TableDto getTableSchemas(Long dbId, Long tId); + List<Map<String, Object>> getTableData(Long dbId, Long tId, Long size); +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/ViewGeneratorService.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/ViewGeneratorService.java new file mode 100644 index 0000000000000000000000000000000000000000..ef7def1323201c0cac13c56b683d42fd50dfd4bf --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/ViewGeneratorService.java @@ -0,0 +1,15 @@ +package at.tuwien.service; + +import at.tuwien.dto.PieChartConfigDto; + +import java.util.List; +import java.util.Map; + +public interface ViewGeneratorService { + Long genCntAllView(Long dbId, String tableName, String token); + Long genPieChartView(Long dbId, String tableName, String colName, PieChartConfigDto config, String token); + Long genHistogramView(Long dbId, String tableName, String colName, String token); + Long genStatisticsView(Long dbId, String tableName, String colName, String token); + Long genTimeSeriesView(Long dbId, String tableName, Map<String, String> timeMap, String token); + Long genMultiTimeSeriesView(Long dbId, String tableName, String timeCol, List<String> numValues, String token); +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/impl/DashboardServiceImpl.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/impl/DashboardServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..b373a8c0f8e42550515863c48af066866e7216ad --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/impl/DashboardServiceImpl.java @@ -0,0 +1,408 @@ +package at.tuwien.service.impl; + +import at.tuwien.api.database.query.QueryResultDto; +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.dto.*; +import at.tuwien.exception.JsonProcessingException; +import at.tuwien.panels.*; +import at.tuwien.service.*; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.*; +import org.springframework.stereotype.Service; +import org.springframework.web.client.*; + +import java.util.*; +import java.util.stream.Collectors; + +import static at.tuwien.panels.TimeSeriesPanel.*; + +@Log4j2 +@Service +public class DashboardServiceImpl implements DashboardService { + + @Value("${dbrepo.endpoints.grafanaService}") + private String grafanaServiceEndpoint; + + @Value("${application.baseurl}") + private String baseUrl; + + @Value("${dbrepo.endpoints.grafanaPort}") + private String grafanaPort; + + @Value("${dbrepo.grafana.default_refreshrate}") + private int defaultRefreshrate; + + private final RestTemplate grafanaRestTemplate; + private final TableService tableService; + private final DataSourceService dataSourceService; + private final ViewGeneratorService viewGeneratorService; + private String token = ""; + + @Autowired + public DashboardServiceImpl(@Qualifier("grafanaTemplate") RestTemplate grafanaRestTemplate, + DataSourceService dataSourceService, TableService tableService, + ViewGeneratorService viewGeneratorService) { + this.grafanaRestTemplate = grafanaRestTemplate; + this.dataSourceService = dataSourceService; + this.tableService = tableService; + this.viewGeneratorService = viewGeneratorService; + } + + @Override + public Boolean checkIfDashboardExists(Long dbId) { + return this.checkForSync(dbId) != null; + } + + @Override + public void removeDashboard(Long dbId) { + String path = String.format("/api/dashboards/uid/%d", dbId); + + try { + ResponseEntity<String> responseEntity = grafanaRestTemplate.exchange( + path, + HttpMethod.DELETE, + null, + String.class + ); + + log.warn(responseEntity.getBody()); + } catch (ResourceAccessException e) { + log.error("Resource access error for accessing URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.DELETE, e); + throw new ResourceAccessException("Resource access error occurred"); + } catch (RestClientException e) { + log.error("RestClient Exception occurred URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.DELETE, e); + throw new ResourceAccessException("RestClient Exception occurred"); + } catch (Exception e) { + log.error("Exception occurred, URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.DELETE, e); + throw new ResourceAccessException("Exception occurred"); + } + } + + @Override + public String generateDashboard(Long dbId, String token, DashboardConfigDto configDto) { + this.token = token; + addDatasourceIfNotPresent(); + + String url = this.checkForSync(dbId); + if (url != null) { + return String.format("%s:%s%s%n", baseUrl, grafanaPort, url); + } + + Map<Long, List<TimeSeriesDto>> timeSeriesParamMap = new HashMap<>(); + Map<Long, Map<Long, PieChartConfigDto>> pieChartParamMap = new HashMap<>(); + Map<Long, Map<Long, HistogramConfigDto>> histogramParamMap = new HashMap<>(); + Map<Long, TableConfigDto> tableParamMap = new HashMap<>(); + DashboardConfigDto dashboardConfigDto = new DashboardConfigDto(); + + if (configDto != null) { + dashboardConfigDto = configDto; + } + + if (dashboardConfigDto.getTimeSeriesDto() != null) { + timeSeriesParamMap = dashboardConfigDto.getTimeSeriesDto(); + } + + if (dashboardConfigDto.getPieChartConfigDto() != null) { + pieChartParamMap = dashboardConfigDto.getPieChartConfigDto(); + } + + if (dashboardConfigDto.getHistogramConfigDto() != null) { + histogramParamMap = dashboardConfigDto.getHistogramConfigDto(); + } + + if (dashboardConfigDto.getTableConfigDto() != null) { + tableParamMap = dashboardConfigDto.getTableConfigDto(); + } + + List<TableBriefDto> tableIds = this.tableService.getAllTables(dbId); + List<Long> idList = tableIds.stream() + .map(TableBriefDto::getId) + .toList(); + + AbstractPanel.setDataEndpoint(grafanaServiceEndpoint); + AbstractPanel.resetCoordinates(); + List<String> rowPanels = new ArrayList<>(); + List<String> tablePanels; + + for (var tId : idList) { + tablePanels = new ArrayList<>(); + TableDto tableSchema = this.tableService.getTableSchemas(dbId, tId); + String tableName = tableSchema.getInternalName(); + + List<ColumnDto> columns = tableSchema.getColumns(); + Set<Long> primaryKeys = tableSchema.getConstraints().getPrimaryKey().stream() + .map(pkDto -> pkDto.getColumn().getId()) + .collect(Collectors.toSet()); + + columns.removeIf(column -> primaryKeys.contains(column.getId())); + + AbstractPanel.addRowPlaceHolder(); + + if (tableParamMap.containsKey(tId)) { + tablePanels.add(generateTablePanel(dbId, tId, tableName, tableParamMap.get(tId).getSize())); + } else { + tablePanels.add(generateTablePanel(dbId, tId, tableName, null)); + } + + tablePanels.add(generateCntAllPanel(dbId, tableName)); + tablePanels.add(generateStatsPanel(dbId, tId, tableName)); + + if (timeSeriesParamMap.containsKey(tId)) { + addTimeSeriesPanel(dbId, tId, tableName, columns, timeSeriesParamMap, tablePanels); + } + + for (var col : columns) { + ColumnTypeDto columnType = col.getColumnType(); + + if (isNumericalColumn(columnType)) { + + if (histogramParamMap.containsKey(tId) && histogramParamMap.get(tId).containsKey(col.getId())) { + tablePanels.add(generateHistogramPanel(dbId, tableName, col.getInternalName(), histogramParamMap.get(tId).get(col.getId()))); + } else { + tablePanels.add(generateHistogramPanel(dbId, tableName, col.getInternalName(), null)); + } + } else if (isStringColumn(columnType)) { + + if (pieChartParamMap.containsKey(tId) && pieChartParamMap.get(tId).containsKey(col.getId())) { + tablePanels.add(generatePieChartPanel(dbId, tableName, col.getInternalName(), pieChartParamMap.get(tId).get(col.getId()))); + } else { + tablePanels.add(generatePieChartPanel(dbId, tableName, col.getInternalName(), null)); + } + } else if (isTimeStamp(columnType)) { + List<String> numColumns = new ArrayList<>(); + + for(var other : columns) { + if (isNumericalColumn(other.getColumnType())) { + numColumns.add(other.getInternalName()); + } + } + + tablePanels.add(generateMultiTimeSeriesPanel(dbId, tableName, col.getInternalName(), numColumns)); + } + } + + rowPanels.add(new RowPanel(tableName, tablePanels).getConstructedPanel()); + AbstractPanel.markNewRow(); + } + + int refreshRate = defaultRefreshrate; + if (dashboardConfigDto.getRefreshRate() != null) { + refreshRate = dashboardConfigDto.getRefreshRate(); + } + + Dashboard d = new Dashboard(); + String dashboardJson = d.getDashboard(rowPanels, dbId, refreshRate); + + String relativeUrl = createDashboard(dashboardJson); + + return String.format("%s:%s%s%n", baseUrl, grafanaPort, relativeUrl); + } + + private String generateCntAllPanel(Long dbId, String tableName) { + Long viewId = this.viewGeneratorService.genCntAllView(dbId, tableName, this.token); + + CntAllPanel panel = new CntAllPanel(dbId, viewId); + return panel.getConstructedPanel(); + } + + private String generatePieChartPanel(Long dbId, String tableName, String colName, PieChartConfigDto config) { + Long viewId = this.viewGeneratorService.genPieChartView(dbId, tableName, colName, config, this.token); + PieChartPanel panel = new PieChartPanel(dbId, viewId, colName, config); + return panel.getConstructedPanel(); + } + + private String generateTablePanel(Long dbId, Long tId, String tableName, Long size) { + TablePanel panel = new TablePanel(dbId, tId, tableName, size); + return panel.getConstructedPanel(); + } + + private String generateHistogramPanel(Long dbId, String tableName, String colName, HistogramConfigDto config) { + Long viewId = this.viewGeneratorService.genHistogramView(dbId, tableName, colName, this.token); + HistogramPanel panel = new HistogramPanel(dbId, viewId, colName, config); + return panel.getConstructedPanel(); + } + + private String generateStatsPanel(Long dbId, Long tId, String tableName) { + StatsPanel panel = new StatsPanel(dbId, tId, tableName); + return panel.getConstructedPanel(); + } + + private String generateTimeSeriesPanel(Long dbId, String tableName, String valueName, Map<String, String> timeMap, Long size) { + Long viewId = this.viewGeneratorService.genTimeSeriesView(dbId, tableName, timeMap, this.token); + TimeSeriesPanel panel = new TimeSeriesPanel(dbId, viewId, valueName, size); + return panel.getConstructedPanel(); + } + + private String generateMultiTimeSeriesPanel(Long dbId, String tableName, String timeCol, List<String> numValues) { + Long viewId = this.viewGeneratorService.genMultiTimeSeriesView(dbId, tableName, timeCol, numValues, this.token); + MultiTimeSeriesPanel panel = new MultiTimeSeriesPanel(dbId, viewId); + return panel.getConstructedPanel(); + } + + private boolean isNumericalColumn(ColumnTypeDto type) { + return switch (type) { + case TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT, FLOAT, DOUBLE, DECIMAL -> true; + default -> false; + }; + } + + private boolean isStringColumn(ColumnTypeDto type) { + return switch (type) { + case CHAR, VARCHAR, TINYTEXT, TEXT, MEDIUMTEXT, LONGTEXT -> true; + default -> false; + }; + } + + private boolean isTimeStamp(ColumnTypeDto type) { + return switch (type) { + case TIMESTAMP -> true; + default -> false; + }; + } + + private void addDatasourceIfNotPresent() { + String jsonString = dataSourceService.getDatasource(); + ObjectMapper objectMapper = new ObjectMapper(); + try { + JsonNode rootNode = objectMapper.readTree(jsonString); + + if (rootNode.isArray()) { + for (JsonNode node : rootNode) { + if (node.has("uid") && node.get("uid").asText().equals(AbstractPanel.DATASRC_UID)) { + return; + } + } + } + + dataSourceService.addDatasource(); + } catch (Exception e) { + log.error("failed to read json of datasource"); + throw new JsonProcessingException("Failed to process datasource json"); + } + } + + private void addTimeSeriesPanel(Long dbId, Long tId, String tableName, List<ColumnDto> columns, + Map<Long, List<TimeSeriesDto>> timeSeriesMap, List<String> tablePanels) { + List<TimeSeriesDto> timeSeriesDtos = timeSeriesMap.get(tId); + + for (TimeSeriesDto timeSeriesDto : timeSeriesDtos) { + TimeDto timeDto = timeSeriesDto.getTimeDto(); + + Map<String, String> timeMap = new HashMap<>(); + String valueName = null; + if (timeDto != null) { + + for (var col : columns) { + Long colId = col.getId(); + String colName = col.getInternalName(); + + if (Objects.equals(timeDto.getYearColId(), colId)) { + timeMap.put(TIME_YEAR_COL, colName); + } else if (Objects.equals(timeDto.getMonthColId(), colId)) { + timeMap.put(TIME_MONTH_COL, colName); + } else if (Objects.equals(timeDto.getDayColId(), colId)) { + timeMap.put(TIME_DAY_COL, colName); + } else if (Objects.equals(timeDto.getHourColId(), colId)) { + timeMap.put(TIME_HOUR_COL, colName); + } else if (Objects.equals(timeDto.getMinuteColId(), colId)) { + timeMap.put(TIME_MIN_COL, colName); + } else if (Objects.equals(timeDto.getSecondColId(), colId)) { + timeMap.put(TIME_SECOND_COL, colName); + } else if (Objects.equals(timeSeriesDto.getValueColId(), colId)) { + valueName = colName; + timeMap.put(TIME_VAL_COL, valueName); + } + } + + if (!timeMap.isEmpty()) { + tablePanels.add(generateTimeSeriesPanel(dbId, tableName, valueName, timeMap, timeSeriesDto.getSize())); + } + } + } + } + + private String checkForSync(Long dbId) { + String path = String.format("/api/dashboards/uid/%d", dbId); + + ResponseEntity<String> responseEntity = null; + try { + responseEntity = grafanaRestTemplate.exchange( + path, + HttpMethod.GET, + null, + String.class + ); + + if (responseEntity.getStatusCode() == HttpStatus.OK) { + log.debug("dashboard with id {} already present", dbId); + + ObjectMapper mapper = new ObjectMapper(); + JsonNode rootNode = mapper.readTree(responseEntity.getBody()); + + return rootNode.get("meta").get("url").asText(); + } + } catch (RestClientException e) { + + if (e.getMessage().startsWith("404")) { + log.debug("dashboard with id {} not present", dbId); + return null; + } + + log.error("RestClient Exception occurred URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.GET, e); + throw new ResourceAccessException("RestClient Exception occurred"); + } catch (Exception e) { + log.error("Exception occurred, URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.GET, e); + throw new ResourceAccessException("Exception occurred"); + } + + return null; + } + + private String createDashboard(String dashboardJson) { + String path = "/api/dashboards/db"; + + HttpEntity<String> requestEntity = new HttpEntity<>(dashboardJson); + + try { + ResponseEntity<String> responseEntity = grafanaRestTemplate.exchange( + path, + HttpMethod.POST, + requestEntity, + String.class + ); + + ObjectMapper mapper = new ObjectMapper(); + String jsonString = responseEntity.getBody(); + JsonNode rootNode = mapper.readTree(jsonString); + + return rootNode.get("url").asText(); + + } catch (ResourceAccessException e) { + log.error("Resource access error for accessing URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Resource access error occurred"); + } catch (RestClientException e) { + log.error("RestClient Exception occurred URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("RestClient Exception occurred"); + } catch (Exception e) { + log.error("Exception occurred, URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Exception occurred"); + } + } + +} \ No newline at end of file diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/impl/DataServiceImpl.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/impl/DataServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..797483b04233281f564f5d49db395a9c7608d4a2 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/impl/DataServiceImpl.java @@ -0,0 +1,405 @@ +package at.tuwien.service.impl; + +import at.tuwien.api.database.query.QueryResultDto; +import at.tuwien.api.database.table.TableStatisticDto; +import at.tuwien.api.database.table.columns.ColumnStatisticDto; +import at.tuwien.panels.StatsPanel; +import at.tuwien.service.DataService; +import at.tuwien.service.TableService; +import lombok.extern.log4j.Log4j2; +import org.json.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import static at.tuwien.panels.MultiTimeSeriesPanel.*; +import static at.tuwien.panels.PieChartPanel.VIEW_PIE_PERCENTAGE_COL; +import static at.tuwien.panels.TimeSeriesPanel.*; + +@Log4j2 +@Service +public class DataServiceImpl implements DataService { + private final RestTemplate dataRestTemplate; + private final TableService tableService; + private final RestTemplate grafanaRestTemplate; + + @Autowired + public DataServiceImpl(@Qualifier("dataServiceRestTemplate") RestTemplate dataRestTemplate, + @Qualifier("grafanaTemplate") RestTemplate grafanaRestTemplate, + TableService tableService) { + this.dataRestTemplate = dataRestTemplate; + this.grafanaRestTemplate = grafanaRestTemplate; + this.tableService = tableService; + } + + @Override + public Map<String, Object> getPieChartData(Long dbId, Long viewId, Long size) { + + Long page = 0L; + String path = String.format("/api/database/%d/view/%d/data?page=%d&size=%d", dbId, viewId, page, size); + + try { + ResponseEntity<QueryResultDto> responseEntity = dataRestTemplate.exchange( + path, + HttpMethod.GET, + null, + QueryResultDto.class + ); + QueryResultDto queryResultDto = responseEntity.getBody(); + assert queryResultDto != null; + + List<Map<String, Object>> res = queryResultDto.getResult(); + Map<String, Object> pieDataMap = new HashMap<>(); + double sum = 0; + + for (Map<String, Object> map : res) { + String key = null; + Object value = null; + + for (Map.Entry<String, Object> entry : map.entrySet()) { + if (!entry.getKey().equals(VIEW_PIE_PERCENTAGE_COL)) { // string column + key = (String) entry.getValue(); + } else { + value = entry.getValue(); + sum += (double) value; + } + } + + if (key != null && value != null) { + pieDataMap.put(key, value); + } + } + + pieDataMap.put("Others", 100 - sum); + return pieDataMap; + } catch (ResourceAccessException e) { + log.error("Resource access error for accessing URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Resource access error occurred"); + } catch (RestClientException e) { + log.error("RestClient Exception occurred URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("RestClient Exception occurred"); + } catch (Exception e) { + log.error("Exception occurred, URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Exception occurred"); + } + } + + @Override + public Map<String, Object> getCntAllData(Long dbId, Long viewId) { + + String path = String.format("/api/database/%d/view/%d/data", dbId, viewId); + + try { + ResponseEntity<QueryResultDto> responseEntity = dataRestTemplate.exchange( + path, + HttpMethod.GET, + null, + QueryResultDto.class + ); + QueryResultDto queryResultDto = responseEntity.getBody(); + assert queryResultDto != null; + return queryResultDto.getResult().get(0); + } catch (ResourceAccessException e) { + log.error("Resource access error for accessing URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Resource access error occurred"); + } catch (RestClientException e) { + log.error("RestClient Exception occurred URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("RestClient Exception occurred"); + } catch (Exception e) { + log.error("Exception occurred, URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Exception occurred"); + } + } + + @Override + public List<Map<String, Object>> getTableData(Long dbId, Long tableId, Long size) { + return tableService.getTableData(dbId, tableId, size); + } + + @Override + public Map<String, List<Object>> getHistogramData(Long dbId, Long viewId, Long size) { + + Long page = 0L; + String path = String.format("/api/database/%d/view/%d/data?page=%d&size=%d", dbId, viewId, page, size); + + try { + ResponseEntity<QueryResultDto> responseEntity = dataRestTemplate.exchange( + path, + HttpMethod.GET, + null, + QueryResultDto.class + ); + QueryResultDto queryResultDto = responseEntity.getBody(); + assert queryResultDto != null; + + List<Map<String, Object>> resultMap = queryResultDto.getResult(); + List<Object> valueList = new ArrayList<>(); + + for (Map<String, Object> map : resultMap) { + if (!map.isEmpty()) { + valueList.add(map.entrySet().iterator().next().getValue()); + } + } + + return Map.of("values", valueList); + } catch (ResourceAccessException e) { + log.error("Resource access error for accessing URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Resource access error occurred"); + } catch (RestClientException e) { + log.error("RestClient Exception occurred URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("RestClient Exception occurred"); + } catch (Exception e) { + log.error("Exception occurred, URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Exception occurred"); + } + } + + @Override + public List<Map<String, Object>> getStatsData(Long dbId, Long tableId) { + + String path = String.format("/api/database/%d/table/%d/statistic", dbId, tableId); + + try { + ResponseEntity<TableStatisticDto> responseEntity = dataRestTemplate.exchange( + path, + HttpMethod.GET, + null, + TableStatisticDto.class + ); + TableStatisticDto columnStatisticDto = responseEntity.getBody(); + assert columnStatisticDto != null; + Map<String, ColumnStatisticDto> map = columnStatisticDto.getColumns(); + + map = map.entrySet().stream() + .filter(entry -> entry.getValue().getMin() != null) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + List<Map<String, Object>> res = new ArrayList<>(); + Map<String, Object> row; + for (Map.Entry<String, ColumnStatisticDto> entry : map.entrySet()) { + row = new HashMap<>(); + + row.put(StatsPanel.HEADER_COL, entry.getKey()); + row.put(StatsPanel.HEADER_MIN, entry.getValue().getMin()); + row.put(StatsPanel.HEADER_MAX, entry.getValue().getMax()); + row.put(StatsPanel.HEADER_AVG, entry.getValue().getMedian()); + row.put(StatsPanel.HEADER_STDDEV, entry.getValue().getStdDev()); + + res.add(row); + } + + return res; + } catch (ResourceAccessException e) { + log.error("Resource access error for accessing URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Resource access error occurred"); + } catch (RestClientException e) { + log.error("RestClient Exception occurred URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("RestClient Exception occurred"); + } catch (Exception e) { + log.error("Exception occurred, URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Exception occurred"); + } + } + + @Override + public Map<String, List<Map<String, Object>>> getTimeSeriesData(Long dbId, Long viewId, Long size) { + + Long page = 0L; + String path = String.format("/api/database/%d/view/%d/data?page=%d&size=%d", dbId, viewId, page, size); + + try { + ResponseEntity<QueryResultDto> responseEntity = dataRestTemplate.exchange( + path, + HttpMethod.GET, + null, + QueryResultDto.class + ); + QueryResultDto queryResultDto = responseEntity.getBody(); + assert queryResultDto != null; + + List<Map<String, Object>> resultMap = queryResultDto.getResult(); + + + Map<String, List<Map<String, Object>>> res = new HashMap<>(); + res.put("time_series", formatTimeData(resultMap)); + + return res; + } catch (ResourceAccessException e) { + log.error("Resource access error for accessing URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Resource access error occurred"); + } catch (RestClientException e) { + log.error("RestClient Exception occurred URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("RestClient Exception occurred"); + } catch (Exception e) { + log.error("Exception occurred, URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Exception occurred"); + } + } + + public Map<String, List<Map<String, Object>>> getMultiTimeSeriesData(Long dbId, Long viewId, Long size) { + Long page = 0L; + String path = String.format("/api/database/%d/view/%d/data?page=%d&size=%d", dbId, viewId, page, size); + + try { + ResponseEntity<QueryResultDto> responseEntity = dataRestTemplate.exchange( + path, + HttpMethod.GET, + null, + QueryResultDto.class + ); + QueryResultDto queryResultDto = responseEntity.getBody(); + assert queryResultDto != null; + + List<Map<String, Object>> resultMap = queryResultDto.getResult(); + List<Map<String, Object>> timeMap = new ArrayList<>(); + + for (Map<String, Object> map : resultMap) { + Object time = map.get(VIEW_MULTI_TIMECOL); + + for (Map.Entry<String, Object> entry : map.entrySet()) { + Map<String, Object> multiTimeEntry = new HashMap<>(); + if (!entry.getKey().equals(VIEW_MULTI_TIMECOL)) { + multiTimeEntry.put(VIEW_MULTI_SELECTOR_NAME, entry.getKey()); + multiTimeEntry.put(VIEW_MULTI_SELECTOR_VALUE, entry.getValue()); + multiTimeEntry.put(VIEW_MULTI_SELECTOR_TIME, time); + + timeMap.add(multiTimeEntry); + } + } + } + Map<String, List<Map<String, Object>>> res = new HashMap<>(); + res.put("time_series", timeMap); + + return res; + } catch (ResourceAccessException e) { + log.error("Resource access error for accessing URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Resource access error occurred"); + } catch (RestClientException e) { + log.error("RestClient Exception occurred URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("RestClient Exception occurred"); + } catch (Exception e) { + log.error("Exception occurred, URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Exception occurred"); + } + } + + private List<Map<String, Object>> formatTimeData(List<Map<String, Object>> resultMap) { + int year, month, day, hour, min, sec; + Object val; + + List<Map<String, Object>> timeValues = new ArrayList<>(); + Map<String, Object> timeValue; + + for (Map<String, Object> map : resultMap) { + year = 0; + month = 1; + day = 1; + hour = 0; + min = 0; + sec = 0; + val = null; + timeValue = new HashMap<>(); + + if(map.containsKey(TIME_YEAR_COL)) { + Object y = map.get(TIME_YEAR_COL); + if (y instanceof Integer) { + year = (int) y; + } + } + + if(map.containsKey(TIME_MONTH_COL)) { + Object m = map.get(TIME_MONTH_COL); + if (m instanceof String) { + month = getMonth(m.toString()); + } else if (m instanceof Integer) { + month = (int) m; + } + } + + if(map.containsKey(TIME_DAY_COL)) { + Object d = map.get(TIME_DAY_COL); + if (d instanceof Integer) { + day = (int) d; + } + } + + if(map.containsKey(TIME_HOUR_COL)) { + Object h = map.get(TIME_HOUR_COL); + if (h instanceof Integer) { + hour = (int) h; + } + } + + if(map.containsKey(TIME_MIN_COL)) { + Object m = map.get(TIME_MIN_COL); + if (m instanceof Integer) { + min = (int) m; + } + } + + if(map.containsKey(TIME_SECOND_COL)) { + Object s = map.get(TIME_SECOND_COL); + if (s instanceof Integer) { + sec = (int) s; + } + } + + if(map.containsKey(TIME_VAL_COL)) { + val = map.get(TIME_VAL_COL); + } + + timeValue.put("time", String.format("%d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, min, sec)); + timeValue.put("value", val); + timeValues.add(timeValue); + } + + return timeValues; + } + + private int getMonth(String month) { + return switch (month.toLowerCase()) { + case "february" -> 2; + case "march" -> 3; + case "april" -> 4; + case "may" -> 5; + case "june" -> 6; + case "july" -> 7; + case "august" -> 8; + case "september" -> 9; + case "october" -> 10; + case "november" -> 11; + case "december" -> 12; + default -> 1; + }; + } +} diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/impl/DataSourceServiceImpl.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/impl/DataSourceServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..f4fde957b38c50fa79edf698d0f6500bb2d8d198 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/impl/DataSourceServiceImpl.java @@ -0,0 +1,99 @@ +package at.tuwien.service.impl; + +import at.tuwien.api.database.query.QueryResultDto; +import at.tuwien.panels.AbstractPanel; +import at.tuwien.service.DataService; +import at.tuwien.service.DataSourceService; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.*; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.Map; + +@Log4j2 +@Service +public class DataSourceServiceImpl implements DataSourceService { + + private final RestTemplate grafanaRestTemplate; + private String addDatasourceJSON = "{\n" + + " \"id\": null,\n" + + " \"uid\": \"" + AbstractPanel.DATASRC_UID + "\",\n" + + " \"name\": \"infinity datasource\",\n" + + " \"type\": \"yesoreyeram-infinity-datasource\",\n" + + " \"access\": \"proxy\"\n" + + "}"; + + @Autowired + public DataSourceServiceImpl(@Qualifier("grafanaTemplate") RestTemplate grafanaRestTemplate) { + this.grafanaRestTemplate = grafanaRestTemplate; + } + + @Override + public String addDatasource() { + String path = "/api/datasources"; + + HttpEntity<String> requestEntity = new HttpEntity<>(addDatasourceJSON); + + try { + ResponseEntity<String> responseEntity = grafanaRestTemplate.exchange( + path, + HttpMethod.POST, + requestEntity, + String.class + ); + return responseEntity.getBody(); + } catch (ResourceAccessException e) { + log.error("Resource access error for accessing URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Resource access error occurred"); + } catch (RestClientException e) { + log.error("RestClient Exception occurred URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("RestClient Exception occurred"); + } catch (Exception e) { + log.error("Exception occurred, URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Exception occurred"); + } + } + + @Override + public String getDatasource() { + String path = "/api/datasources"; + + try { + ResponseEntity<String> responseEntity = grafanaRestTemplate.exchange( + path, + HttpMethod.GET, + null, + String.class + ); + + return responseEntity.getBody(); + } catch (ResourceAccessException e) { + log.error("Resource access error for accessing URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Resource access error occurred"); + } catch (RestClientException e) { + log.error("RestClient Exception occurred URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("RestClient Exception occurred"); + } catch (Exception e) { + log.error("Exception occurred, URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Exception occurred"); + } + } + +} \ No newline at end of file diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/impl/TableServiceImpl.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/impl/TableServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..a3c8fc8622aa8fe8a7fb4e63fe0520cadeb004e4 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/impl/TableServiceImpl.java @@ -0,0 +1,121 @@ +package at.tuwien.service.impl; + +import at.tuwien.api.database.query.QueryResultDto; +import at.tuwien.api.database.table.TableBriefDto; +import at.tuwien.api.database.table.TableDto; +import at.tuwien.service.TableService; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.*; +import org.springframework.stereotype.Service; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.*; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.*; + +@Log4j2 +@Service +public class TableServiceImpl implements TableService { + private final RestTemplate dataRestTemplate; + private final RestTemplate metaDataRestTemplate; + + @Autowired + public TableServiceImpl(@Qualifier("dataServiceRestTemplate") RestTemplate dataRestTemplate, + @Qualifier("metaDataServiceRestTemplate") RestTemplate metaDataRestTemplate) { + this.dataRestTemplate = dataRestTemplate; + this.metaDataRestTemplate = metaDataRestTemplate; + } + + @Override + public List<TableBriefDto> getAllTables(Long dbId) { + String path = String.format("/api/database/%d/table", dbId); + + try { + ResponseEntity<List<TableBriefDto>> responseEntity = metaDataRestTemplate.exchange( + path, + HttpMethod.GET, + null, + new ParameterizedTypeReference<List<TableBriefDto>>() {} + ); + return responseEntity.getBody(); + } catch (ResourceAccessException e) { + log.error("Resource access error for accessing URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Resource access error occurred"); + } catch (RestClientException e) { + log.error("RestClient Exception occurred URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("RestClient Exception occurred"); + } catch (Exception e) { + log.error("Exception occurred, URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Exception occurred"); + } + } + + + @Override + public TableDto getTableSchemas(Long dbId, Long tId) { + String path = String.format("/api/database/%d/table/%d", dbId, tId); + try { + ResponseEntity<TableDto> responseEntity = metaDataRestTemplate.exchange( + path, + HttpMethod.GET, + null, + TableDto.class + ); + + return responseEntity.getBody(); + } catch (ResourceAccessException e) { + log.error("Resource access error for accessing URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Resource access error occurred"); + } catch (RestClientException e) { + log.error("RestClient Exception occurred URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("RestClient Exception occurred"); + } catch (Exception e) { + log.error("Exception occurred, URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Exception occurred"); + } + } + + @Override + public List<Map<String, Object>> getTableData(Long dbId, Long tId, Long size) { + Long page = 0L; + String path = String.format("/api/database/%d/table/%d/data?page=%d&size=%d", dbId, tId, page, size); + + try { + // Send GET request with query parameters + ResponseEntity<QueryResultDto> responseEntity = dataRestTemplate.exchange( + path, + HttpMethod.GET, + null, + QueryResultDto.class + ); + + QueryResultDto responseBody = responseEntity.getBody(); + + return responseBody.getResult(); + + } catch (ResourceAccessException e) { + log.error("Resource access error for accessing URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Resource access error occurred"); + } catch (RestClientException e) { + log.error("RestClient Exception occurred URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("RestClient Exception occurred"); + } catch (Exception e) { + log.error("Exception occurred, URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Exception occurred"); + } + } + +} \ No newline at end of file diff --git a/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/impl/ViewGeneratorServiceImpl.java b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/impl/ViewGeneratorServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..baa258460c157053e6ae3fc31ec441d11dc5adf1 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/java/at/tuwien/service/impl/ViewGeneratorServiceImpl.java @@ -0,0 +1,225 @@ +package at.tuwien.service.impl; + +import at.tuwien.api.database.ViewBriefDto; +import at.tuwien.api.database.ViewCreateDto; +import at.tuwien.dto.PieChartConfigDto; +import at.tuwien.panels.StatsPanel; +import at.tuwien.service.ViewGeneratorService; +import lombok.extern.log4j.Log4j2; +import org.apache.commons.text.StringSubstitutor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static at.tuwien.panels.MultiTimeSeriesPanel.VIEW_MULTI_TIMECOL; +import static at.tuwien.panels.PieChartPanel.VIEW_PIE_PERCENTAGE_COL; +import static at.tuwien.panels.TimeSeriesPanel.TIME_VAL_COL; + +@Log4j2 +@Service +public class ViewGeneratorServiceImpl implements ViewGeneratorService { + + private final RestTemplate metaDataRestTemplate; + private static final String PIE_DEFAULT_LIMIT = "10"; + private static final String PIE_DEFAULT_DEC_PLACE = "2"; + + @Autowired + public ViewGeneratorServiceImpl(@Qualifier("metaDataServiceRestTemplate") RestTemplate metaDataRestTemplate) { + this.metaDataRestTemplate = metaDataRestTemplate; + } + + @Override + public Long genCntAllView(Long dbId, String tableName, String token) { + final String query = String.format("select count(*) from %s", tableName); + + ViewCreateDto viewCreateDto = new ViewCreateDto(); + viewCreateDto.setName(String.format("%d_cntAll_%s", dbId, tableName)); + viewCreateDto.setQuery(query); + viewCreateDto.setIsPublic(true); + + ViewBriefDto createdView = createView(dbId, viewCreateDto, token); + if (createdView == null) { + log.warn("failed to create view {}", viewCreateDto); + return -1L; + } + + return createdView.getId(); + } + + @Override + public Long genPieChartView(Long dbId, String tableName, String colName, PieChartConfigDto config, String token) { + Map<String, String> valueMap = new HashMap<>(); + valueMap.put("col_name", colName); + valueMap.put("table_name", tableName); + valueMap.put("limit", (config != null && config.getLimit() != null) ? config.getLimit() : PIE_DEFAULT_LIMIT); + valueMap.put("dec_place", (config != null && config.getDecimalPlace() != null) ? config.getDecimalPlace() : PIE_DEFAULT_DEC_PLACE); + valueMap.put("percentage", VIEW_PIE_PERCENTAGE_COL); + + final String templateQuery = + "SELECT\n" + + " ${col_name},\n" + + " ROUND( (COUNT(*) / total_count) * 100, ${dec_place}) AS ${percentage}\n" + + " FROM\n" + + " ${table_name},\n" + + " (SELECT COUNT(*) AS total_count FROM ${table_name}) AS t\n" + + " GROUP BY\n" + + " ${col_name}\n" + + " ORDER BY\n" + + " ${percentage} DESC\n" + + " LIMIT ${limit}"; + + StringSubstitutor sub = new StringSubstitutor(valueMap); + + ViewCreateDto viewCreateDto = new ViewCreateDto(); + viewCreateDto.setName(String.format("%d_piechart_%s_%s", dbId, tableName, colName)); + viewCreateDto.setQuery(sub.replace(templateQuery)); + viewCreateDto.setIsPublic(true); + + ViewBriefDto createdView = createView(dbId, viewCreateDto, token); + if (createdView == null) { + log.warn("failed to create view {}", viewCreateDto); + return -1L; + } + + return createdView.getId(); + } + + @Override + public Long genHistogramView(Long dbId, String tableName, String colName, String token) { + final String query = String.format("select %s from %s", colName, tableName); + + ViewCreateDto viewCreateDto = new ViewCreateDto(); + viewCreateDto.setName(String.format("%d_histogram_%s_%s", dbId, tableName, colName)); + viewCreateDto.setQuery(query); + viewCreateDto.setIsPublic(true); + + ViewBriefDto createdView = createView(dbId, viewCreateDto, token); + if (createdView == null) { + log.warn("failed to create view {}", viewCreateDto); + return -1L; + } + + return createdView.getId(); + } + + @Override + public Long genStatisticsView(Long dbId, String tableName, String colName, String token) { + Map<String, String> valueMap = new HashMap<>(); + valueMap.put("col_name", colName); + valueMap.put("table_name", tableName); + valueMap.put("header_col", StatsPanel.HEADER_COL); + valueMap.put("header_min", StatsPanel.HEADER_MIN); + valueMap.put("header_max", StatsPanel.HEADER_MAX); + valueMap.put("header_avg", StatsPanel.HEADER_AVG); + valueMap.put("header_stddev", StatsPanel.HEADER_STDDEV); + + final String templateQuery = "select " + + "min(${col_name}) as ${header_min}, " + + "max(${col_name}) as ${header_max}, " + + "avg(${col_name}) as ${header_avg}, " + + "STDDEV(${col_name}) as ${header_stddev} " + + "from ${table_name}"; + + StringSubstitutor sub = new StringSubstitutor(valueMap); + + ViewCreateDto viewCreateDto = new ViewCreateDto(); + viewCreateDto.setName(String.format("%d_statschart_%s_%s", dbId, tableName, colName)); + viewCreateDto.setQuery(sub.replace(templateQuery)); + viewCreateDto.setIsPublic(true); + + ViewBriefDto createdView = createView(dbId, viewCreateDto, token); + if (createdView == null) { + log.warn("failed to create view {}", viewCreateDto); + return -1L; + } + + return createdView.getId(); + } + + @Override + public Long genTimeSeriesView(Long dbId, String tableName, Map<String, String> timeMap, String token) { + + List<String> colNames = new ArrayList<>(); + for (Map.Entry<String, String> entry : timeMap.entrySet()) { + colNames.add(String.format("%s AS %s", entry.getValue(), entry.getKey())); + } + + final String query = String.format("select %s from %s", String.join(",", colNames), tableName); + + ViewCreateDto viewCreateDto = new ViewCreateDto(); + viewCreateDto.setName(String.format("%d_timeseries_%s_%s", dbId, tableName, timeMap.get(TIME_VAL_COL))); + viewCreateDto.setQuery(query); + viewCreateDto.setIsPublic(true); + + ViewBriefDto createdView = createView(dbId, viewCreateDto, token); + if (createdView == null) { + log.warn("failed to create view {}", viewCreateDto); + return -1L; + } + + return createdView.getId(); + } + + @Override + public Long genMultiTimeSeriesView(Long dbId, String tableName, String timeCol, List<String> numValues, String token) { + + final String query = String.format("select %s AS %s, %s from %s", timeCol, VIEW_MULTI_TIMECOL, String.join(",", numValues), tableName); + ViewCreateDto viewCreateDto = new ViewCreateDto(); + viewCreateDto.setName(String.format("%d_multitimeseries_%s_%s", dbId, tableName, timeCol)); + viewCreateDto.setQuery(query); + viewCreateDto.setIsPublic(true); + + ViewBriefDto createdView = createView(dbId, viewCreateDto, token); + if (createdView == null) { + log.warn("failed to create view {}", viewCreateDto); + return -1L; + } + + return createdView.getId(); + } + + + private ViewBriefDto createView(Long dbId, ViewCreateDto viewCreateDto, String token) { + String path = String.format("/api/database/%d/view", dbId); + + HttpHeaders headers = new HttpHeaders(); + headers.set("Authorization", token); + headers.set("Content-Type", "application/json"); + + HttpEntity<ViewCreateDto> requestEntity = new HttpEntity<>(viewCreateDto, headers); + + try { + ResponseEntity<ViewBriefDto> responseEntity = metaDataRestTemplate.exchange( + path, + HttpMethod.POST, + requestEntity, + ViewBriefDto.class + ); + + return responseEntity.getBody(); + } catch (ResourceAccessException e) { + log.error("Resource access error for accessing URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Resource access error occurred"); + } catch (RestClientException e) { + log.error("RestClient Exception occurred URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("RestClient Exception occurred"); + } catch (Exception e) { + log.error("Exception occurred, URL: {}, Exception message: {}, Request method: {}, Stack Trace: {}", + path, e.getMessage(), HttpMethod.POST, e); + throw new ResourceAccessException("Exception occurred"); + } + } + +} \ No newline at end of file diff --git a/dbrepo-grafana-service/rest-service/src/main/resources/application-local.yml b/dbrepo-grafana-service/rest-service/src/main/resources/application-local.yml new file mode 100644 index 0000000000000000000000000000000000000000..8e99c2d0a9fe8711e142bdc9ba2863337f4f2f5b --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/resources/application-local.yml @@ -0,0 +1,89 @@ +application: + title: DBRepo + version: '@project.version@' +spring: + datasource: + url: jdbc:h2:mem:fda;DB_CLOSE_ON_EXIT=FALSE;INIT=CREATE SCHEMA IF NOT EXISTS FDA;NON_KEYWORDS=value + driver-class-name: org.h2.Driver + username: sa + password: password + rabbitmq: + host: "${BROKER_HOST:broker-service}" + virtual-host: "${BROKER_VIRTUALHOST:dbrepo}" + password: "${BROKER_PASSWORD:fda}" + username: "${BROKER_USERNAME:fda}" + port: ${BROKER_PORT:5672} + jpa: + show-sql: false + database-platform: org.hibernate.dialect.H2Dialect + open-in-view: false + properties: + hibernate: + default_schema: fda + jdbc: + time_zone: UTC + application: + name: grafana-service + main: + banner-mode: off +management: + endpoints: + web: + exposure: + include: health,info,prometheus + endpoint: + health: + probes: + enabled: true + health: + readinessState: + enabled: true + livenessState: + enabled: true +server: + port: 1880 +logging: + pattern.console: "%d %highlight(%-5level) %msg%n" + level: + root: debug + at.tuwien.: "${LOG_LEVEL:info}" + org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver: debug +dbrepo: + endpoints: + grafana: http://grafana:3000 + dataService: http://data-service:8080 + gatewayService: "${GATEWAY_SERVICE_ENDPOINT:http://gateway-service}" + storageService: "${S3_ENDPOINT:http://storage-service:9000}" + authService: "${AUTH_SERVICE_HOST:http://auth-service:8080}" + s3: + accessKeyId: "${S3_ACCESS_KEY_ID:seaweedfsadmin}" + secretAccessKey: "${S3_SECRET_ACCESS_KEY:seaweedfsadmin}" + importBucket: "${S3_IMPORT_BUCKET:dbrepo-upload}" + exportBucket: "${S3_EXPORT_BUCKET:dbrepo-download}" + filePath: "${S3_FILE_PATH:/tmp}" + admin: + username: "${ADMIN_USERNAME:admin}" + password: "${ADMIN_PASSWORD:admin}" + jwt: + public_key: "${JWT_PUBKEY:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB}" + keycloak: + username: "${AUTH_SERVICE_ADMIN:fda}" + password: "${AUTH_SERVICE_ADMIN_PASSWORD:fda}" + client: "${AUTH_SERVICE_CLIENT:dbrepo-client}" + clientSecret: "${AUTH_SERVICE_CLIENT_SECRET:MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG}" + sql: + forbidden: "${NOT_SUPPORTED_KEYWORDS:\\*,AVG,BIT_AND,BIT_OR,BIT_XOR,COUNT,COUNTDISTINCT,GROUP_CONCAT,JSON_ARRAYAGG,JSON_OBJECTAGG,MAX,MIN,STD,STDDEV,STDDEV_POP,STDDEV_SAMP,SUM,VARIANCE,VAR_POP,VAR_SAMP,--}" + grant: + default: + read: "${GRANT_DEFAULT_READ:SELECT}" + write: "${GRANT_DEFAULT_WRITE:SELECT, CREATE, CREATE VIEW, CREATE ROUTINE, CREATE TEMPORARY TABLES, LOCK TABLES, INDEX, TRIGGER, INSERT, UPDATE, DELETE}" + minConcurrent: "${MIN_CONCURRENT_CONSUMERS:2}" + maxConcurrent: "${MAX_CONCURRENT_CONSUMERS:6}" + requeueRejected: ${REQUEUE_REJECTED:false} + queueName: "${BROKER_QUEUE_NAME:dbrepo}" + exchangeName: "${BROKER_EXCHANGE_NAME:dbrepo}" + routingKey: "${BROKER_ROUTING_KEY:#}" + connectionTimeout: ${CONNECTION_TIMEOUT:10000} + defaultDateFormatId: "${DEFAULT_DATE_FORMAT_ID:3}" + defaultTimeFormatId: "${DEFAULT_TIME_FORMAT_ID:4}" + defaultTimestampFormatId: "${DEFAULT_TIMESTAMP_FORMAT_ID:1}" diff --git a/dbrepo-grafana-service/rest-service/src/main/resources/application.yml b/dbrepo-grafana-service/rest-service/src/main/resources/application.yml new file mode 100644 index 0000000000000000000000000000000000000000..b8fcf710c7234ae063c4f2ec4f91baae22150c35 --- /dev/null +++ b/dbrepo-grafana-service/rest-service/src/main/resources/application.yml @@ -0,0 +1,107 @@ +application: + title: DBRepo + version: '@project.version@' + baseurl: ${BASE_URL:http://localhost} +spring: + datasource: + url: jdbc:h2:mem:fda;DB_CLOSE_ON_EXIT=FALSE;INIT=CREATE SCHEMA IF NOT EXISTS FDA;NON_KEYWORDS=value + driver-class-name: org.h2.Driver + username: sa + password: password + rabbitmq: + host: "${BROKER_HOST:broker-service}" + virtual-host: "${BROKER_VIRTUALHOST:dbrepo}" + password: "${BROKER_PASSWORD:fda}" + username: "${BROKER_USERNAME:fda}" + port: ${BROKER_PORT:5672} + jpa: + show-sql: false + database-platform: org.hibernate.dialect.H2Dialect + open-in-view: false + properties: + hibernate: + default_schema: fda + jdbc: + time_zone: UTC + application: + name: grafana-service + main: + banner-mode: off + data: + redis: + host: redis + port: 6379 +management: + endpoints: + web: + exposure: + include: health,info,prometheus + endpoint: + health: + probes: + enabled: true + health: + readinessState: + enabled: true + livenessState: + enabled: true +server: + port: 8080 +logging: + pattern.console: "%d %highlight(%-5level) %msg%n" + level: + root: warn + at.tuwien.: "${LOG_LEVEL:info}" + org: + springframework: + web: + client: + RestTemplate: DEBUG + org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver: debug +dbrepo: + endpoints: + grafana: http://grafana:3000 + grafanaPort: 3000 + grafanaService: http://grafana-service:8080 + dataService: http://data-service:8080 + metadataService: http://metadata-service:8080 + gatewayService: "${GATEWAY_SERVICE_ENDPOINT:http://gateway-service}" + storageService: "${S3_ENDPOINT:http://storage-service:9000}" + authService: "${AUTH_SERVICE_HOST:http://auth-service:8080}" + s3: + accessKeyId: "${S3_ACCESS_KEY_ID:seaweedfsadmin}" + secretAccessKey: "${S3_SECRET_ACCESS_KEY:seaweedfsadmin}" + importBucket: "${S3_IMPORT_BUCKET:dbrepo-upload}" + exportBucket: "${S3_EXPORT_BUCKET:dbrepo-download}" + filePath: "${S3_FILE_PATH:/tmp}" + admin: + username: "${ADMIN_USERNAME:kper}" + password: "${ADMIN_PASSWORD:k1a1r1l1o1}" + jwt: + public_key: "${JWT_PUBKEY:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB}" + keycloak: + username: "${AUTH_SERVICE_ADMIN:fda}" + password: "${AUTH_SERVICE_ADMIN_PASSWORD:fda}" + client: "${AUTH_SERVICE_CLIENT:dbrepo-client}" + clientSecret: "${AUTH_SERVICE_CLIENT_SECRET:MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG}" + grafana: + username: "${GRAFANA_USERNAME:admin}" + password: "${GRAFANA_PASSWORD:admin}" + default_refreshrate: 0 + sql: + forbidden: "${NOT_SUPPORTED_KEYWORDS:\\*,AVG,BIT_AND,BIT_OR,BIT_XOR,COUNT,COUNTDISTINCT,GROUP_CONCAT,JSON_ARRAYAGG,JSON_OBJECTAGG,MAX,MIN,STD,STDDEV,STDDEV_POP,STDDEV_SAMP,SUM,VARIANCE,VAR_POP,VAR_SAMP,--}" + grant: + default: + read: "${GRANT_DEFAULT_READ:SELECT}" + write: "${GRANT_DEFAULT_WRITE:SELECT, CREATE, CREATE VIEW, CREATE ROUTINE, CREATE TEMPORARY TABLES, LOCK TABLES, INDEX, TRIGGER, INSERT, UPDATE, DELETE}" + minConcurrent: "${MIN_CONCURRENT_CONSUMERS:2}" + maxConcurrent: "${MAX_CONCURRENT_CONSUMERS:6}" + requeueRejected: ${REQUEUE_REJECTED:false} + queueName: "${BROKER_QUEUE_NAME:dbrepo}" + exchangeName: "${BROKER_EXCHANGE_NAME:dbrepo}" + routingKey: "${BROKER_ROUTING_KEY:#}" + connectionTimeout: ${CONNECTION_TIMEOUT:10000} + defaultDateFormatId: "${DEFAULT_DATE_FORMAT_ID:3}" + defaultTimeFormatId: "${DEFAULT_TIME_FORMAT_ID:4}" + defaultTimestampFormatId: "${DEFAULT_TIMESTAMP_FORMAT_ID:1}" + diff --git a/dbrepo-search-service/init/omlib/__init__.py b/dbrepo-grafana-service/rest-service/src/test/resources/application.properties similarity index 100% rename from dbrepo-search-service/init/omlib/__init__.py rename to dbrepo-grafana-service/rest-service/src/test/resources/application.properties diff --git a/dbrepo-metadata-db/1_setup-schema.sql b/dbrepo-metadata-db/1_setup-schema.sql index 7e7978cad83580c330a28ef03ce3fd84623ee01e..4ba9d70b174dca5b3481d8042f47c332afc4cf2b 100644 --- a/dbrepo-metadata-db/1_setup-schema.sql +++ b/dbrepo-metadata-db/1_setup-schema.sql @@ -52,6 +52,8 @@ CREATE TABLE IF NOT EXISTS `mdb_containers` privileged_username VARCHAR(255) NOT NULL, privileged_password VARCHAR(255) NOT NULL, quota INT, + readonly_username VARCHAR(255) NOT NULL, + readonly_password VARCHAR(255) NOT NULL, PRIMARY KEY (`id`), FOREIGN KEY (`image_id`) REFERENCES mdb_images (`id`) ) WITH SYSTEM VERSIONING; @@ -67,20 +69,22 @@ CREATE TABLE IF NOT EXISTS `mdb_licenses` CREATE TABLE IF NOT EXISTS `mdb_databases` ( - id VARCHAR(36) NOT NULL DEFAULT UUID(), - cid VARCHAR(36) NOT NULL, - name VARCHAR(255) NOT NULL, - internal_name VARCHAR(255) NOT NULL, - exchange_name VARCHAR(255) NOT NULL, - description TEXT, - engine VARCHAR(20), - is_public BOOLEAN NOT NULL DEFAULT TRUE, - is_schema_public BOOLEAN NOT NULL DEFAULT TRUE, - image LONGBLOB, - owned_by VARCHAR(36) NOT NULL, - contact_person VARCHAR(36) NOT NULL, - created TIMESTAMP NOT NULL DEFAULT NOW(), - last_modified TIMESTAMP, + id VARCHAR(36) NOT NULL DEFAULT UUID(), + cid VARCHAR(36) NOT NULL, + grafana_dashboard_uid character varying(255), + name VARCHAR(255) NOT NULL, + internal_name VARCHAR(255) NOT NULL, + exchange_name VARCHAR(255) NOT NULL, + description TEXT, + engine VARCHAR(20), + is_public BOOLEAN NOT NULL DEFAULT TRUE, + is_schema_public BOOLEAN NOT NULL DEFAULT TRUE, + is_dashboard_enabled BOOLEAN NOT NULL DEFAULT TRUE, + image LONGBLOB, + owned_by VARCHAR(36) NOT NULL, + contact_person VARCHAR(36) NOT NULL, + created TIMESTAMP NOT NULL DEFAULT NOW(), + last_modified TIMESTAMP, PRIMARY KEY (`id`), FOREIGN KEY (`cid`) REFERENCES mdb_containers (`id`), FOREIGN KEY (`owned_by`) REFERENCES mdb_users (`id`), @@ -291,7 +295,7 @@ CREATE TABLE IF NOT EXISTS `mdb_messages` type ENUM ('ERROR', 'WARNING', 'INFO') NOT NULL DEFAULT 'INFO', message TEXT NOT NULL, link TEXT NULL, - link_TEXT VARCHAR(255) NULL, + link_text VARCHAR(255) NULL, display_start TIMESTAMP NULL, display_end TIMESTAMP NULL, PRIMARY KEY (`id`) diff --git a/dbrepo-metadata-db/2_setup-data.sql b/dbrepo-metadata-db/2_setup-data.sql index dc4917cd8bd1ce95be2159bb225b1524383081e7..611efbbde1e0f3d2522792eb1b7aadf40e2bebc6 100644 --- a/dbrepo-metadata-db/2_setup-data.sql +++ b/dbrepo-metadata-db/2_setup-data.sql @@ -1,8 +1,8 @@ BEGIN; INSERT INTO `mdb_containers` (id, name, internal_name, image_id, host, port, ui_host, ui_port, privileged_username, - privileged_password) + privileged_password, readonly_username, readonly_password) VALUES ('6cfb3b8e-1792-4e46-871a-f3d103527203', 'mariadb:11.1.3-debian-11-r6', 'mariadb_11_1_3', - 'd79cb089-363c-488b-9717-649e44d8fcc5', 'data-db', 3306, 'localhost', 3306, 'root', 'dbrepo'); + 'd79cb089-363c-488b-9717-649e44d8fcc5', 'data-db', 3306, 'localhost', 3306, 'root', 'dbrepo', 'user', 'user'); COMMIT; diff --git a/dbrepo-metadata-db/migration/16/schema.sql b/dbrepo-metadata-db/migration/16/schema.sql index 68a87f1a67ab770fbb24df68584beeba53d47859..5c96c2337539e099208d1a266db576a027449b10 100644 --- a/dbrepo-metadata-db/migration/16/schema.sql +++ b/dbrepo-metadata-db/migration/16/schema.sql @@ -376,6 +376,8 @@ ALTER TABLE mdb_users DROP SYSTEM VERSIONING; ALTER TABLE mdb_users CHANGE COLUMN id id VARCHAR(36) NOT NULL DEFAULT UUID(); +ALTER TABLE mdb_users + DROP COLUMN email; -- mdb_images ALTER TABLE mdb_images ADD PRIMARY KEY (id); diff --git a/dbrepo-metadata-db/migration/16/update_id.sql b/dbrepo-metadata-db/migration/16/update_id.sql new file mode 100644 index 0000000000000000000000000000000000000000..a3f161cc2a2305cc55042ec1761015e2b09e7034 --- /dev/null +++ b/dbrepo-metadata-db/migration/16/update_id.sql @@ -0,0 +1,11 @@ +SET FOREIGN_KEY_CHECKS = 0; +BEGIN; +UPDATE mdb_users SET id = :old_id WHERE id = :new_id; +UPDATE mdb_have_access SET user_id = :old_id WHERE user_id = :new_id; +UPDATE mdb_databases SET owned_by = :old_id WHERE owned_by = :new_id; +UPDATE mdb_databases SET contact_person = :old_id WHERE contact_person = :new_id; +UPDATE mdb_tables SET owned_by = :old_id WHERE owned_by = :new_id; +UPDATE mdb_view SET owned_by = :old_id WHERE owned_by = :new_id; +UPDATE mdb_identifiers SET owned_by = :old_id WHERE owned_by = :new_id; +COMMIT; +SET FOREIGN_KEY_CHECKS = 1; \ No newline at end of file diff --git a/dbrepo-metadata-service/Dockerfile b/dbrepo-metadata-service/Dockerfile index fa92b799eeaac75f9daea7b5a1eec11560b04647..8d01865d85a0d1cad2cad9f2f7849a655b9e0259 100644 --- a/dbrepo-metadata-service/Dockerfile +++ b/dbrepo-metadata-service/Dockerfile @@ -1,32 +1,27 @@ ###### FIRST STAGE ###### +FROM dbrepo-core:build AS dependency +LABEL org.opencontainers.image.authors="martin.weise@tuwien.ac.at" + +###### SECOND STAGE ###### FROM maven:3-amazoncorretto-17 AS build LABEL org.opencontainers.image.authors="martin.weise@tuwien.ac.at" COPY ./pom.xml ./ -COPY ./api/pom.xml ./api/ -COPY ./entities/pom.xml ./entities/ -COPY ./oai/pom.xml ./oai/ -COPY ./report/pom.xml ./report/ -COPY ./repositories/pom.xml ./repositories/ -COPY ./rest-service/pom.xml ./rest-service/ -COPY ./services/pom.xml ./services/ -COPY ./test/pom.xml ./test/ - -RUN mvn dependency:go-offline - -COPY ./api ./api -COPY ./entities ./entities + +RUN mvn -fn dependency:go-offline + +COPY --from=dependency /root/.m2/repository/at/ac/tuwien/ifs/dbrepo /root/.m2/repository/at/ac/tuwien/ifs/dbrepo + COPY ./oai ./oai COPY ./report ./report COPY ./repositories ./repositories COPY ./rest-service ./rest-service COPY ./services ./services -COPY ./test ./test # Make sure it compiles -RUN mvn clean install -DskipTests +RUN mvn -fn clean package -DskipTests -###### SECOND STAGE ###### +###### THIRD STAGE ###### FROM amazoncorretto:17-alpine3.19 AS runtime LABEL org.opencontainers.image.authors="martin.weise@tuwien.ac.at" @@ -34,6 +29,8 @@ RUN apk add --no-cache curl bash jq WORKDIR /app +RUN adduser -D dbrepo --uid 1001 + USER 1001 COPY --from=build --chown=1001 ./rest-service/target/dbrepo-metadata-service-rest-service-*.jar ./metadata-service.jar @@ -41,4 +38,6 @@ COPY --from=build --chown=1001 ./rest-service/target/dbrepo-metadata-service-res # non-root port EXPOSE 8080 -ENTRYPOINT ["java", "-Dlog4j2.formatMsgNoLookups=true", "-jar", "./metadata-service.jar"] +ENV JAVA_OPTS="-Dlog4j2.formatMsgNoLookups=true" + +ENTRYPOINT exec java $JAVA_OPTS -jar ./metadata-service.jar \ No newline at end of file diff --git a/dbrepo-metadata-service/api/pom.xml b/dbrepo-metadata-service/api/pom.xml deleted file mode 100644 index 96b717f3aad4c37289ee008ce8da6c3bce5793e6..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/api/pom.xml +++ /dev/null @@ -1,45 +0,0 @@ -<?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>at.tuwien</groupId> - <artifactId>dbrepo-metadata-service</artifactId> - <version>1.7.3</version> - </parent> - - <artifactId>dbrepo-metadata-service-api</artifactId> - <name>dbrepo-metadata-service-api</name> - <version>1.7.3</version> - - <dependencies> - <dependency> - <groupId>at.tuwien</groupId> - <artifactId>dbrepo-metadata-service-entities</artifactId> - <version>1.7.3</version> - <scope>compile</scope> - </dependency> - </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <configuration> - <source>${java.version}</source> - <target>${java.version}</target> - <annotationProcessorPaths> - <path> - <groupId>org.projectlombok</groupId> - <artifactId>lombok</artifactId> - <version>${lombok.version}</version> - </path> - </annotationProcessorPaths> - </configuration> - </plugin> - </plugins> - </build> - -</project> \ No newline at end of file diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ExecuteStatementDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ExecuteStatementDto.java deleted file mode 100644 index fbc8bfebe0b58bfe48e976af1c2e00fcc159e12d..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ExecuteStatementDto.java +++ /dev/null @@ -1,22 +0,0 @@ -package at.tuwien.api.database.query; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; - -import jakarta.validation.constraints.NotBlank; -import lombok.extern.jackson.Jacksonized; - -@Getter -@Setter -@Builder -@NoArgsConstructor -@AllArgsConstructor -@Jacksonized -@ToString -public class ExecuteStatementDto { - - @NotBlank - @Schema(example = "SELECT `id` FROM `air_quality`") - private String statement; - -} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ExportDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/AffiliationDto.java similarity index 53% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ExportDto.java rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/AffiliationDto.java index 36a13b348770945035292c8bbe32722688f8eea9..807c03f48df24d122757da14161f0b98404ba5c1 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ExportDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/AffiliationDto.java @@ -1,7 +1,6 @@ -package at.tuwien.api.database.query; +package at.tuwien.api.doi; import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotBlank; import lombok.*; import lombok.extern.jackson.Jacksonized; @@ -13,9 +12,9 @@ import lombok.extern.jackson.Jacksonized; @AllArgsConstructor @Jacksonized @ToString -public class ExportDto { +public class AffiliationDto { + + @Schema(example = "ISE, TU Wien, Data Science Research Unit, Vienna, Austria") + private String name; - @NotBlank - @Schema(example = "/tmp/file.csv") - private String location; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/AuthorDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/AuthorDto.java new file mode 100644 index 0000000000000000000000000000000000000000..8f8bbb61ffc64341119614f7de3395c40beac92e --- /dev/null +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/AuthorDto.java @@ -0,0 +1,35 @@ +package at.tuwien.api.doi; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.extern.jackson.Jacksonized; + +import java.util.List; + +@Getter +@Setter +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Jacksonized +@ToString +public class AuthorDto { + + @Schema(example = "Weise") + private String family; + + @Schema(example = "Martin") + private String given; + + @JsonProperty("ORCID") + @Schema(example = "http://orcid.org/0000-0003-4216-302X") + private String orcid; + + @Schema(example = "first") + private String sequence; + + private List<AffiliationDto> affiliation; + +} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/DoiDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/DoiDto.java new file mode 100644 index 0000000000000000000000000000000000000000..af0cd5bcc64bf8797c81197fb6e9abc0cede6a7f --- /dev/null +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/DoiDto.java @@ -0,0 +1,82 @@ +package at.tuwien.api.doi; + +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.List; + +@Getter +@Setter +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Jacksonized +@ToString +public class DoiDto { + + @NotNull + @Schema(example = "https://doi.org/10.5334/dsj-2022-004") + private String id; + + @NotNull + private TimeRepresentationDto indexed; + + private TimeRepresentationDto deposited; + + private TimeRepresentationDto issued; + + private TimeRepresentationDto published; + + @JsonProperty("DOI") + @Schema(example = "10.5334/dsj-2022-004") + private String doi; + + @NotNull + @Schema(example = "dataset") + private String type; + + private List<AuthorDto> author; + + @Schema(example = "Crossref") + private String source; + + @Schema(example = "DBRepo: A Data Repository System for Research Data in Databases") + private String title; + + @Schema(example = "10.1109") + private String prefix; + + @Schema(example = "21") + private String volume; + + @JsonProperty("is-referenced-by-count") + @Schema(example = "0") + private Integer isReferencedByCount; + + @JsonProperty("reference-count") + @Schema(example = "28") + private Integer referenceCount; + + @Schema(example = "IEEE") + private String publisher; + + @Schema(example = "322-331") + private String page; + + private String member; + + @Schema(example = "2024 IEEE International Conference on Big Data (BigData)") + private String event; + + private List<ReferenceDto> reference; + + private Integer score; + + @JsonProperty("URL") + private String url; + +} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/LicenseDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/LicenseDto.java new file mode 100644 index 0000000000000000000000000000000000000000..32f5ffcd2aced054dfffd72a44a79b9994a6658b --- /dev/null +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/LicenseDto.java @@ -0,0 +1,32 @@ +package at.tuwien.api.doi; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.extern.jackson.Jacksonized; + +@Getter +@Setter +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Jacksonized +@ToString +public class LicenseDto { + + private TimeRepresentationDto start; + + @JsonProperty("content-version") + @Schema(example = "stm-asf") + private String contentVersion; + + @JsonProperty("delay-in-days") + @Schema(example = "0") + private Integer delayInDays; + + @JsonProperty("URL") + @Schema(example = "https://doi.org/10.15223/policy-029") + private String url; + +} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/LinkDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/LinkDto.java new file mode 100644 index 0000000000000000000000000000000000000000..5f70696091c7cf14abb0c717627f18a1e3eff9de --- /dev/null +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/LinkDto.java @@ -0,0 +1,35 @@ +package at.tuwien.api.doi; + +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; + +@Getter +@Setter +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Jacksonized +@ToString +public class LinkDto { + + @JsonProperty("URL") + @Schema(example = "http://xplorestaging.ieee.org/ielx8/10824975/10824942/10825401.pdf?arnumber=10825401") + private String url; + + @JsonProperty("content-type") + @Schema(example = "unspecified") + private String contentType; + + @JsonProperty("content-version") + @Schema(example = "vor") + private String contentVersion; + + @JsonProperty("intended-application") + @Schema(example = "similarity-checking") + private String intendedApplication; + +} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/ReferenceDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/ReferenceDto.java new file mode 100644 index 0000000000000000000000000000000000000000..9458c0f9192a2f6fa71adad4e910b4e8e7b609ef --- /dev/null +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/ReferenceDto.java @@ -0,0 +1,55 @@ +package at.tuwien.api.doi; + +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.List; + +@Getter +@Setter +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Jacksonized +@ToString +public class ReferenceDto { + + @NotNull + @Schema(example = "ref1") + private String key; + + @JsonProperty("doi-asserted-by") + @Schema(example = "publisher") + private String doiAssertedBy; + + @JsonProperty("DOI") + @Schema(example = "10.1038/sdata.2016.18") + private String doi; + + @Schema(example = "2024") + private String year; + + @JsonProperty("article-title") + @Schema(example = "The Dryad Data Repository: a Singapore Framework metadata Architecture in a DSpace Environment") + private String articleTitle; + + @JsonProperty("volume-title") + @Schema(example = "Proceedings of the 2008 International Conference on Dublin Core and Metadata Applications") + private String volumeTitle; + + @JsonProperty("journal-title") + @Schema(example = "Libraries Research Publications") + private String journalTitle; + + @Schema(example = "Witt") + private String author; + + @JsonProperty("first-page") + @Schema(example = "157") + private String firstPage; + +} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/ResourceDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/ResourceDto.java new file mode 100644 index 0000000000000000000000000000000000000000..a2543c2834def88d4ae0421d92dcc1efd34ddaf7 --- /dev/null +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/ResourceDto.java @@ -0,0 +1,20 @@ +package at.tuwien.api.doi; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.extern.jackson.Jacksonized; + +@Getter +@Setter +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Jacksonized +@ToString +public class ResourceDto { + + private ResourceRepresentationDto primary; + +} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/ResourceRepresentationDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/ResourceRepresentationDto.java new file mode 100644 index 0000000000000000000000000000000000000000..bf2312a6488a27498b83bd8039064d4c0badd75b --- /dev/null +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/ResourceRepresentationDto.java @@ -0,0 +1,20 @@ +package at.tuwien.api.doi; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; +import lombok.extern.jackson.Jacksonized; + +@Getter +@Setter +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Jacksonized +@ToString +public class ResourceRepresentationDto { + + @JsonProperty("URL") + private String url; + +} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/TimeRepresentationDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/TimeRepresentationDto.java new file mode 100644 index 0000000000000000000000000000000000000000..fe649217e9b6b963138b38702abf39b539ba8d08 --- /dev/null +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/doi/TimeRepresentationDto.java @@ -0,0 +1,33 @@ +package at.tuwien.api.doi; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.extern.jackson.Jacksonized; + +import java.time.Instant; +import java.util.List; + +@Getter +@Setter +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Jacksonized +@ToString +public class TimeRepresentationDto { + + @JsonProperty("date-parts") + @Schema(example = "[[2025,1,18]]") + private List<List<Integer>> dateParts; + + @JsonProperty("date-time") + @Schema(example = "2021-03-12T15:26:21Z") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssX", timezone = "UTC") + private Instant dateTime; + + private Long timestamp; + +} 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 deleted file mode 100644 index f883a034f55bd5f04d3059f8eb50ef50a3867c79..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/summary/organization/disambiguated/OrcidDisambiguatedSourceTypeDto.java +++ /dev/null @@ -1,6 +0,0 @@ -package at.tuwien.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated; - -public enum OrcidDisambiguatedSourceTypeDto { - RINGGOLD, - ROR -} diff --git a/dbrepo-metadata-service/entities/pom.xml b/dbrepo-metadata-service/entities/pom.xml deleted file mode 100644 index 0140b7347791c63135c31cd829cce72744e6f574..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/entities/pom.xml +++ /dev/null @@ -1,38 +0,0 @@ -<?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>at.tuwien</groupId> - <artifactId>dbrepo-metadata-service</artifactId> - <version>1.7.3</version> - </parent> - - <artifactId>dbrepo-metadata-service-entities</artifactId> - <name>dbrepo-metadata-service-entity</name> - <version>1.7.3</version> - - <dependencies/> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <configuration> - <source>${java.version}</source> - <target>${java.version}</target> - <annotationProcessorPaths> - <path> - <groupId>org.projectlombok</groupId> - <artifactId>lombok</artifactId> - <version>${lombok.version}</version> - </path> - </annotationProcessorPaths> - </configuration> - </plugin> - </plugins> - </build> - -</project> \ No newline at end of file diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/NameType.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/NameType.java deleted file mode 100644 index 5f0790fbab6b1437ebce7a19292735af0431f4e4..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/NameType.java +++ /dev/null @@ -1,9 +0,0 @@ -package at.tuwien.entities.identifier; - -import lombok.Getter; - -@Getter -public enum NameType { - PERSONAL, - ORGANIZATIONAL; -} diff --git a/dbrepo-metadata-service/oai/pom.xml b/dbrepo-metadata-service/oai/pom.xml index 3fcbaa59bd619a6de4bb66a17ec7104dd3f3ac32..d075e57506e1ccf37400b2f9e17a3db64fe63e8a 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.7.3</version> + <version>1.8.0</version> </parent> <artifactId>dbrepo-metadata-service-oai</artifactId> <name>dbrepo-metadata-service-oai</name> - <version>1.7.3</version> + <version>1.8.0</version> <dependencies/> diff --git a/dbrepo-metadata-service/oai/src/main/java/at/tuwien/oaipmh/OaiErrorType.java b/dbrepo-metadata-service/oai/src/main/java/at/ac/tuwien/ifs/dbrepo/oaipmh/OaiErrorType.java similarity index 91% rename from dbrepo-metadata-service/oai/src/main/java/at/tuwien/oaipmh/OaiErrorType.java rename to dbrepo-metadata-service/oai/src/main/java/at/ac/tuwien/ifs/dbrepo/oaipmh/OaiErrorType.java index 2fe750a9adaf60b89865d6beed08413205f7e534..e2a13d7762d9beb17c017ef5c359dfc39fe3e297 100644 --- a/dbrepo-metadata-service/oai/src/main/java/at/tuwien/oaipmh/OaiErrorType.java +++ b/dbrepo-metadata-service/oai/src/main/java/at/ac/tuwien/ifs/dbrepo/oaipmh/OaiErrorType.java @@ -1,4 +1,4 @@ -package at.tuwien.oaipmh; +package at.ac.tuwien.ifs.dbrepo.oaipmh; import lombok.Getter; @@ -14,8 +14,8 @@ public enum OaiErrorType { BAD_RESUMPTION_TOKEN("badResumptionToken", "The value of the resumptionToken argument is invalid or expired."), BAD_ARGUMENT("badArgument", "The request includes illegal arguments, is missing required arguments, includes a repeated argument, or values for arguments have an illegal syntax."); - private String errorCode; - private String errorText; + private final String errorCode; + private final String errorText; OaiErrorType(String errorCode, String errorText) { this.errorCode = errorCode; diff --git a/dbrepo-metadata-service/oai/src/main/java/at/tuwien/oaipmh/OaiListIdentifiersParameters.java b/dbrepo-metadata-service/oai/src/main/java/at/ac/tuwien/ifs/dbrepo/oaipmh/OaiListIdentifiersParameters.java similarity index 97% rename from dbrepo-metadata-service/oai/src/main/java/at/tuwien/oaipmh/OaiListIdentifiersParameters.java rename to dbrepo-metadata-service/oai/src/main/java/at/ac/tuwien/ifs/dbrepo/oaipmh/OaiListIdentifiersParameters.java index 721175ed17359a1f680931dee4ee763d6cf7dc9c..d55f1b994f8982c9c1b2f369d54822d38f1a4fb8 100644 --- a/dbrepo-metadata-service/oai/src/main/java/at/tuwien/oaipmh/OaiListIdentifiersParameters.java +++ b/dbrepo-metadata-service/oai/src/main/java/at/ac/tuwien/ifs/dbrepo/oaipmh/OaiListIdentifiersParameters.java @@ -1,4 +1,4 @@ -package at.tuwien.oaipmh; +package at.ac.tuwien.ifs.dbrepo.oaipmh; import lombok.*; import org.apache.commons.lang3.StringUtils; diff --git a/dbrepo-metadata-service/oai/src/main/java/at/tuwien/oaipmh/OaiListRecordsParameters.java b/dbrepo-metadata-service/oai/src/main/java/at/ac/tuwien/ifs/dbrepo/oaipmh/OaiListRecordsParameters.java similarity index 97% rename from dbrepo-metadata-service/oai/src/main/java/at/tuwien/oaipmh/OaiListRecordsParameters.java rename to dbrepo-metadata-service/oai/src/main/java/at/ac/tuwien/ifs/dbrepo/oaipmh/OaiListRecordsParameters.java index a18f0b0aec1e50b8fd814e8221c15c89ff0cb8ab..b7eb9ce37ed359625275b8a3d09c5629a0a57de7 100644 --- a/dbrepo-metadata-service/oai/src/main/java/at/tuwien/oaipmh/OaiListRecordsParameters.java +++ b/dbrepo-metadata-service/oai/src/main/java/at/ac/tuwien/ifs/dbrepo/oaipmh/OaiListRecordsParameters.java @@ -1,4 +1,4 @@ -package at.tuwien.oaipmh; +package at.ac.tuwien.ifs.dbrepo.oaipmh; import lombok.*; import org.apache.commons.lang3.StringUtils; diff --git a/dbrepo-metadata-service/oai/src/main/java/at/tuwien/oaipmh/OaiRecordParameters.java b/dbrepo-metadata-service/oai/src/main/java/at/ac/tuwien/ifs/dbrepo/oaipmh/OaiRecordParameters.java similarity index 93% rename from dbrepo-metadata-service/oai/src/main/java/at/tuwien/oaipmh/OaiRecordParameters.java rename to dbrepo-metadata-service/oai/src/main/java/at/ac/tuwien/ifs/dbrepo/oaipmh/OaiRecordParameters.java index da0433c0b67964af3d75c8dba5577f276c111bb5..3b24e111dd91ab618377b378b7a5025de376227a 100644 --- a/dbrepo-metadata-service/oai/src/main/java/at/tuwien/oaipmh/OaiRecordParameters.java +++ b/dbrepo-metadata-service/oai/src/main/java/at/ac/tuwien/ifs/dbrepo/oaipmh/OaiRecordParameters.java @@ -1,4 +1,4 @@ -package at.tuwien.oaipmh; +package at.ac.tuwien.ifs.dbrepo.oaipmh; import lombok.*; diff --git a/dbrepo-metadata-service/oai/src/main/java/at/tuwien/oaipmh/RequestParameters.java b/dbrepo-metadata-service/oai/src/main/java/at/ac/tuwien/ifs/dbrepo/oaipmh/RequestParameters.java similarity index 90% rename from dbrepo-metadata-service/oai/src/main/java/at/tuwien/oaipmh/RequestParameters.java rename to dbrepo-metadata-service/oai/src/main/java/at/ac/tuwien/ifs/dbrepo/oaipmh/RequestParameters.java index 3f3d9f1a0468f006a24a0467c0a11f09671d1035..1af3449b1e1882d24a169e488e83a28739d35cd3 100644 --- a/dbrepo-metadata-service/oai/src/main/java/at/tuwien/oaipmh/RequestParameters.java +++ b/dbrepo-metadata-service/oai/src/main/java/at/ac/tuwien/ifs/dbrepo/oaipmh/RequestParameters.java @@ -1,4 +1,4 @@ -package at.tuwien.oaipmh; +package at.ac.tuwien.ifs.dbrepo.oaipmh; import org.apache.commons.lang3.StringUtils; diff --git a/dbrepo-metadata-service/pom.xml b/dbrepo-metadata-service/pom.xml index 65f8f7333b5a85a8cb2f23596d141ec4e788619c..df4596e8eadbfc3c5126bff315bd2aa5e5c3998d 100644 --- a/dbrepo-metadata-service/pom.xml +++ b/dbrepo-metadata-service/pom.xml @@ -16,23 +16,20 @@ <groupId>at.tuwien</groupId> <artifactId>dbrepo-metadata-service</artifactId> <name>dbrepo-metadata-service</name> - <version>1.7.3</version> + <version>1.8.0</version> <description>Service that manages the metadata</description> <packaging>pom</packaging> <modules> - <module>api</module> - <module>entities</module> <module>oai</module> - <module>test</module> <module>repositories</module> <module>services</module> <module>rest-service</module> <module>report</module> </modules> - <url>https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.7/</url> + <url>https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.8/</url> <developers> <developer> <name>Martin Weise</name> @@ -43,10 +40,8 @@ <properties> <java.version>17</java.version> - <spring-cloud.version>4.1.4</spring-cloud.version> - <mapstruct.version>1.5.5.Final</mapstruct.version> + <mapstruct.version>1.6.3</mapstruct.version> <rabbitmq.version>5.20.0</rabbitmq.version> - <jackson-datatype.version>2.15.0</jackson-datatype.version> <commons-io.version>2.17.0</commons-io.version> <commons-validator.version>1.8.0</commons-validator.version> <guava.version>33.0.0-jre</guava.version> @@ -57,8 +52,6 @@ <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>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> <keycloak-testcontainer.version>3.2.0</keycloak-testcontainer.version> @@ -73,44 +66,9 @@ <dependencies> <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-validation</artifactId> - </dependency> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-web</artifactId> - </dependency> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-security</artifactId> - </dependency> - <dependency> - <groupId>org.springframework.security</groupId> - <artifactId>spring-security-test</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.springframework.cloud</groupId> - <artifactId>spring-cloud-starter-bootstrap</artifactId> - <version>${spring-cloud.version}</version> - </dependency> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-thymeleaf</artifactId> - </dependency> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-data-jpa</artifactId> - </dependency> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-actuator</artifactId> - </dependency> - <!-- Open API --> - <dependency> - <groupId>org.springdoc</groupId> - <artifactId>springdoc-openapi-starter-webmvc-api</artifactId> - <version>${springdoc-openapi.version}</version> + <groupId>at.ac.tuwien.ifs.dbrepo</groupId> + <artifactId>dbrepo-core</artifactId> + <version>1.8.0</version> </dependency> <!-- Data Source --> <dependency> @@ -150,12 +108,6 @@ <version>${micrometer.version}</version> <scope>test</scope> </dependency> - <!-- IDE --> - <dependency> - <groupId>org.projectlombok</groupId> - <artifactId>lombok</artifactId> - <scope>compile</scope> - </dependency> <!-- Mapping --> <dependency> <groupId>org.mapstruct</groupId> @@ -168,11 +120,6 @@ <artifactId>mapstruct</artifactId> <version>${mapstruct.version}</version> </dependency> - <dependency> - <groupId>com.fasterxml.jackson.datatype</groupId> - <artifactId>jackson-datatype-jsr310</artifactId> - <version>${jackson-datatype.version}</version> - </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> @@ -183,22 +130,7 @@ <artifactId>commons-validator</artifactId> <version>${commons-validator.version}</version> </dependency> - <dependency> - <groupId>com.fasterxml.jackson.datatype</groupId> - <artifactId>jackson-datatype-hibernate6</artifactId> - <version>${jackson-datatype.version}</version> - </dependency> <!-- Authentication --> - <dependency> - <groupId>org.keycloak</groupId> - <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> @@ -236,6 +168,11 @@ <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> </dependency> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-test</artifactId> + <scope>test</scope> + </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> diff --git a/dbrepo-metadata-service/report/pom.xml b/dbrepo-metadata-service/report/pom.xml index ed1592ddaaa1a39b3a9208e7b0fe50af3f8b3fff..114d9d1cbd84b0d085a620699ef9570ecaa9bee7 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.7.3</version> + <version>1.8.0</version> </parent> <artifactId>dbrepo-metadata-service-report</artifactId> <name>dbrepo-metadata-service-report</name> - <version>1.7.3</version> + <version>1.8.0</version> <dependencies> <dependency> diff --git a/dbrepo-metadata-service/repositories/pom.xml b/dbrepo-metadata-service/repositories/pom.xml index b2e76ac0d703432a26ad951e0014888c84b937c3..3bc1da72f57821ddc2c1cc1b226a55053c4e30c5 100644 --- a/dbrepo-metadata-service/repositories/pom.xml +++ b/dbrepo-metadata-service/repositories/pom.xml @@ -6,17 +6,17 @@ <parent> <artifactId>dbrepo-metadata-service</artifactId> <groupId>at.tuwien</groupId> - <version>1.7.3</version> + <version>1.8.0</version> </parent> <artifactId>dbrepo-metadata-service-repositories</artifactId> <name>dbrepo-metadata-service-repositories</name> - <version>1.7.3</version> + <version>1.8.0</version> <dependencies> <dependency> - <groupId>at.tuwien</groupId> - <artifactId>dbrepo-metadata-service-api</artifactId> + <groupId>at.ac.tuwien.ifs.dbrepo</groupId> + <artifactId>dbrepo-core</artifactId> <version>${project.version}</version> </dependency> <dependency> @@ -24,37 +24,7 @@ <artifactId>dbrepo-metadata-service-oai</artifactId> <version>${project.version}</version> </dependency> - <dependency> - <groupId>at.tuwien</groupId> - <artifactId>dbrepo-metadata-service-entities</artifactId> - <version>${project.version}</version> - </dependency> - </dependencies> - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <configuration> - <source>${java.version}</source> - <target>${java.version}</target> - <annotationProcessorPaths> - <path> - <groupId>org.projectlombok</groupId> - <artifactId>lombok</artifactId> - <version>${lombok.version}</version> - </path> - <!-- keep this order https://stackoverflow.com/questions/47676369/mapstruct-and-lombok-not-working-together#answer-65021876 --> - <path> - <groupId>org.mapstruct</groupId> - <artifactId>mapstruct-processor</artifactId> - <version>${mapstruct.version}</version> - </path> - </annotationProcessorPaths> - </configuration> - </plugin> - </plugins> - </build> + </dependencies> </project> diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/SparqlMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/mapper/SparqlMapper.java similarity index 97% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/SparqlMapper.java rename to dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/mapper/SparqlMapper.java index dff867970fa59c9d0ddd5c0b7ed60750dd508e3b..2ca00f05dbef64403a9a25c5603e4e8ebe951bf4 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/SparqlMapper.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/mapper/SparqlMapper.java @@ -1,6 +1,6 @@ -package at.tuwien.mapper; +package at.ac.tuwien.ifs.dbrepo.mapper; -import at.tuwien.entities.semantics.Ontology; +import at.ac.tuwien.ifs.dbrepo.core.entity.semantics.Ontology; import org.mapstruct.Mapper; import java.util.List; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/BannerMessageRepository.java b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/BannerMessageRepository.java similarity index 72% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/BannerMessageRepository.java rename to dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/BannerMessageRepository.java index c12dc7b83f562ec1237dc7941db60700a78f1a59..655b530bb62b2ef13b2a414295f773b2af9514e6 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/BannerMessageRepository.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/BannerMessageRepository.java @@ -1,6 +1,6 @@ -package at.tuwien.repository; +package at.ac.tuwien.ifs.dbrepo.repository; -import at.tuwien.entities.maintenance.BannerMessage; +import at.ac.tuwien.ifs.dbrepo.core.entity.maintenance.BannerMessage; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ConceptRepository.java b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/ConceptRepository.java similarity index 71% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ConceptRepository.java rename to dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/ConceptRepository.java index 1e70cfdfb245c7de9cda405444c6bd43176cca14..546243b1ac1ec95ee9d7c09d5124505ef5a8b0ff 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ConceptRepository.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/ConceptRepository.java @@ -1,6 +1,6 @@ -package at.tuwien.repository; +package at.ac.tuwien.ifs.dbrepo.repository; -import at.tuwien.entities.database.table.columns.TableColumnConcept; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumnConcept; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ContainerRepository.java b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/ContainerRepository.java similarity index 81% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ContainerRepository.java rename to dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/ContainerRepository.java index 536802cf4165e746dc8a27ed796c058ed86d44e5..9d258ed78158ec9e5d09fcdf1c3263d9dffc3c38 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ContainerRepository.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/ContainerRepository.java @@ -1,6 +1,6 @@ -package at.tuwien.repository; +package at.ac.tuwien.ifs.dbrepo.repository; -import at.tuwien.entities.container.Container; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.Container; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/DatabaseRepository.java b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/DatabaseRepository.java similarity index 87% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/DatabaseRepository.java rename to dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/DatabaseRepository.java index d984cb333737851a03c9227e1a76b0643a8282b6..2d61108679fffd08c13660d63e91a5e9a1127050 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/DatabaseRepository.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/DatabaseRepository.java @@ -1,6 +1,6 @@ -package at.tuwien.repository; +package at.ac.tuwien.ifs.dbrepo.repository; -import at.tuwien.entities.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/IdentifierRepository.java b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/IdentifierRepository.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/IdentifierRepository.java rename to dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/IdentifierRepository.java index 9e49f2aa1c5e530dfe60a65aa1e1b4a35fdb0e01..4011a8d1683329af5181d387b6031cefa8fd461b 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/IdentifierRepository.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/IdentifierRepository.java @@ -1,6 +1,6 @@ -package at.tuwien.repository; +package at.ac.tuwien.ifs.dbrepo.repository; -import at.tuwien.entities.identifier.Identifier; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.Identifier; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ImageRepository.java b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/ImageRepository.java similarity index 77% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ImageRepository.java rename to dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/ImageRepository.java index 6282ed90405ba08a69cadb9a8ec0a7fd01f17888..55af367a638bdee8a10827675962fb1d820582c9 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ImageRepository.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/ImageRepository.java @@ -1,6 +1,6 @@ -package at.tuwien.repository; +package at.ac.tuwien.ifs.dbrepo.repository; -import at.tuwien.entities.container.image.ContainerImage; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.image.ContainerImage; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/LicenseRepository.java b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/LicenseRepository.java similarity index 73% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/LicenseRepository.java rename to dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/LicenseRepository.java index f180cdf901439d363a9a84b88a37efa2fa4db769..e04b1ffb7e02c09f070e5ff804ef254fc129a788 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/LicenseRepository.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/LicenseRepository.java @@ -1,6 +1,6 @@ -package at.tuwien.repository; +package at.ac.tuwien.ifs.dbrepo.repository; -import at.tuwien.entities.database.License; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.License; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/OntologyRepository.java b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/OntologyRepository.java similarity index 78% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/OntologyRepository.java rename to dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/OntologyRepository.java index 69b4e204be72c14d60f45ff9535fa89bc9de7629..35460fc0507cfc40110b28e99f457a6f9efe2b4c 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/OntologyRepository.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/OntologyRepository.java @@ -1,6 +1,6 @@ -package at.tuwien.repository; +package at.ac.tuwien.ifs.dbrepo.repository; -import at.tuwien.entities.semantics.Ontology; +import at.ac.tuwien.ifs.dbrepo.core.entity.semantics.Ontology; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/TableRepository.java b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/TableRepository.java similarity index 69% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/TableRepository.java rename to dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/TableRepository.java index bc126eaa27660e84b9e71d5adea18859e1be4fe7..e6d36701010c01e27fd4a856096f62f392ec9924 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/TableRepository.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/TableRepository.java @@ -1,6 +1,6 @@ -package at.tuwien.repository; +package at.ac.tuwien.ifs.dbrepo.repository; -import at.tuwien.entities.database.table.Table; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.Table; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/UnitRepository.java b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/UnitRepository.java similarity index 71% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/UnitRepository.java rename to dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/UnitRepository.java index 6676410730a1f562638e1bc32053b2b8a5fc5c2b..ed4c6c778cbc16c886a68efda3ebb0f797b8b6cc 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/UnitRepository.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/UnitRepository.java @@ -1,6 +1,6 @@ -package at.tuwien.repository; +package at.ac.tuwien.ifs.dbrepo.repository; -import at.tuwien.entities.database.table.columns.TableColumnUnit; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumnUnit; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/UserRepository.java b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/UserRepository.java similarity index 80% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/UserRepository.java rename to dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/UserRepository.java index 30f2f20c1670f550f7463265f1d2d6afde967777..f270810ac1f37358baf6ddbe10420a9f555ab50d 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/UserRepository.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/UserRepository.java @@ -1,6 +1,6 @@ -package at.tuwien.repository; +package at.ac.tuwien.ifs.dbrepo.repository; -import at.tuwien.entities.user.User; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ViewRepository.java b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/ViewRepository.java similarity index 71% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ViewRepository.java rename to dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/ViewRepository.java index 50544822e50db796ca862be696640b8edf3c73a1..d35ed6e337cd3a8147942386e32a27ff22c3f6bb 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ViewRepository.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/repository/ViewRepository.java @@ -1,6 +1,6 @@ -package at.tuwien.repository; +package at.ac.tuwien.ifs.dbrepo.repository; -import at.tuwien.entities.database.View; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.View; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/utils/EnumToStringConverter.java b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/utils/EnumToStringConverter.java similarity index 92% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/utils/EnumToStringConverter.java rename to dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/utils/EnumToStringConverter.java index 2e53ae6cdc17dcf9b915bc9aef3793701cba98e8..158d5be8087253b6ccc74d88394f0017729f52a1 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/utils/EnumToStringConverter.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/ac/tuwien/ifs/dbrepo/utils/EnumToStringConverter.java @@ -1,4 +1,4 @@ -package at.tuwien.utils; +package at.ac.tuwien.ifs.dbrepo.utils; import org.mapstruct.TargetType; diff --git a/dbrepo-metadata-service/rest-service/pom.xml b/dbrepo-metadata-service/rest-service/pom.xml index d8021b4c104453174e6be58cf3b4561e3360d3bb..ed5cacbdeb86b8a80b6ca3d12c5242fc9a98fd5c 100644 --- a/dbrepo-metadata-service/rest-service/pom.xml +++ b/dbrepo-metadata-service/rest-service/pom.xml @@ -6,22 +6,17 @@ <parent> <artifactId>dbrepo-metadata-service</artifactId> <groupId>at.tuwien</groupId> - <version>1.7.3</version> + <version>1.8.0</version> </parent> <artifactId>dbrepo-metadata-service-rest-service</artifactId> <name>dbrepo-metadata-service-rest</name> - <version>1.7.3</version> + <version>1.8.0</version> <dependencies> <dependency> - <groupId>at.tuwien</groupId> - <artifactId>dbrepo-metadata-service-api</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>at.tuwien</groupId> - <artifactId>dbrepo-metadata-service-entities</artifactId> + <groupId>at.ac.tuwien.ifs.dbrepo</groupId> + <artifactId>dbrepo-core</artifactId> <version>${project.version}</version> </dependency> <dependency> @@ -29,11 +24,6 @@ <artifactId>dbrepo-metadata-service-services</artifactId> <version>${project.version}</version> </dependency> - <dependency> - <groupId>at.tuwien</groupId> - <artifactId>dbrepo-metadata-service-test</artifactId> - <version>${project.version}</version> - </dependency> </dependencies> <build> diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/DbrepoMetadataServiceApplication.java b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/MetadataServiceApplication.java similarity index 64% rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/DbrepoMetadataServiceApplication.java rename to dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/MetadataServiceApplication.java index e931ce75091c91fc5264347103d22f4134cd1a7b..de133ba720fe790fa0819ab45b8ad791c5eaaea1 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/DbrepoMetadataServiceApplication.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/MetadataServiceApplication.java @@ -1,4 +1,4 @@ -package at.tuwien; +package at.ac.tuwien.ifs.dbrepo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -9,13 +9,13 @@ import org.springframework.transaction.annotation.EnableTransactionManagement; @EnableJpaAuditing @EnableTransactionManagement -@EntityScan(basePackages = {"at.tuwien.entities"}) -@EnableJpaRepositories(basePackages = {"at.tuwien.repository"}) +@EntityScan(basePackages = {"at.ac.tuwien.ifs.dbrepo.core.entity"}) +@EnableJpaRepositories(basePackages = {"at.ac.tuwien.ifs.dbrepo.repository"}) @SpringBootApplication -public class DbrepoMetadataServiceApplication { +public class MetadataServiceApplication { public static void main(String[] args) { - SpringApplication.run(DbrepoMetadataServiceApplication.class, args); + SpringApplication.run(MetadataServiceApplication.class, args); } } 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/ac/tuwien/ifs/dbrepo/config/MvcConfig.java similarity index 71% rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/config/MvcConfig.java rename to dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/config/MvcConfig.java index 6bdb80973176bc7ae5722b932e7f7b1a2a183d45..70ed7ea611f7c5aa21e72b77a3f9353ba95f4c22 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/config/MvcConfig.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/config/MvcConfig.java @@ -1,7 +1,7 @@ -package at.tuwien.config; +package at.ac.tuwien.ifs.dbrepo.config; -import at.tuwien.converters.IdentifierStatusTypeDtoConverter; -import at.tuwien.converters.IdentifierTypeDtoConverter; +import at.ac.tuwien.ifs.dbrepo.converters.IdentifierStatusTypeDtoConverter; +import at.ac.tuwien.ifs.dbrepo.converters.IdentifierTypeDtoConverter; import org.springframework.context.annotation.Configuration; import org.springframework.format.FormatterRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/config/SwaggerConfig.java b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/config/SwaggerConfig.java similarity index 98% rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/config/SwaggerConfig.java rename to dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/config/SwaggerConfig.java index 7830213b8ebe029c4a314601ce8c76417e22c987..21881faa1ff4f29b677d0596c8ea8148895ac238 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/config/SwaggerConfig.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/config/SwaggerConfig.java @@ -1,4 +1,4 @@ -package at.tuwien.config; +package at.ac.tuwien.ifs.dbrepo.config; import io.swagger.v3.oas.models.ExternalDocumentation; import io.swagger.v3.oas.models.OpenAPI; 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/ac/tuwien/ifs/dbrepo/converters/IdentifierStatusTypeDtoConverter.java similarity index 75% rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierStatusTypeDtoConverter.java rename to dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/converters/IdentifierStatusTypeDtoConverter.java index 96e67f63d2bb85bb0aaebd02237a2d8aaa6ecdfa..cb59169cfd0e3078b620ca5b4d8291f4849d26b1 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierStatusTypeDtoConverter.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/converters/IdentifierStatusTypeDtoConverter.java @@ -1,6 +1,6 @@ -package at.tuwien.converters; +package at.ac.tuwien.ifs.dbrepo.converters; -import at.tuwien.api.identifier.IdentifierStatusTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierStatusTypeDto; import org.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Component; diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierTypeDtoConverter.java b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/converters/IdentifierTypeDtoConverter.java similarity index 75% rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierTypeDtoConverter.java rename to dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/converters/IdentifierTypeDtoConverter.java index 61e169604fa2cf1e10c464fdb1d1bc310ea7f125..6c0fc163bd729265cce077d844b1b361c8e45ac3 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierTypeDtoConverter.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/converters/IdentifierTypeDtoConverter.java @@ -1,6 +1,6 @@ -package at.tuwien.converters; +package at.ac.tuwien.ifs.dbrepo.converters; -import at.tuwien.api.identifier.IdentifierTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierTypeDto; import org.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Component; diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/AbstractEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/AbstractEndpoint.java new file mode 100644 index 0000000000000000000000000000000000000000..b6f5f65cf9821971ed253e1a769c4ed3dc7cbabc --- /dev/null +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/AbstractEndpoint.java @@ -0,0 +1,136 @@ +package at.ac.tuwien.ifs.dbrepo.endpoints; + +import at.ac.tuwien.ifs.dbrepo.core.api.container.ContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserDetailsDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.DatabaseAccess; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.View; +import at.ac.tuwien.ifs.dbrepo.core.exception.NotAllowedException; +import lombok.extern.log4j.Log4j2; +import org.springframework.security.core.Authentication; + +import java.security.Principal; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +@Log4j2 +public abstract class AbstractEndpoint { + + public boolean hasRole(Principal principal, String role) { + if (principal == null || role == null) { + return false; + } + final Authentication authentication = (Authentication) principal; + return authentication.getAuthorities() + .stream() + .anyMatch(a -> a.getAuthority().equals(role)); + } + + public boolean isSystem(Principal principal) { + if (principal == null) { + return false; + } + final Authentication authentication = (Authentication) principal; + return authentication.getAuthorities() + .stream() + .anyMatch(a -> a.getAuthority().equals("system")); + } + + public UUID getId(Principal principal) { + if (principal == null) { + return null; + } + final Authentication authentication = (Authentication) principal; + if (authentication.getPrincipal() instanceof UserDetailsDto user) { + if (user.getId() == null) { + throw new IllegalArgumentException("Principal has no id"); + } + return UUID.fromString(user.getId()); + } + 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); + } + + public Database filterDatabase(Database database, Principal principal) throws NotAllowedException { + if (principal != null) { + if (isSystem(principal)) { + log.trace("filter database: system principal, skip"); + return database; + } + final Optional<DatabaseAccess> optional = database.getAccesses() + .stream() + .filter(a -> a.getUser().getId().equals(getId(principal))) + .findFirst(); + if (!database.getIsPublic() && !database.getIsSchemaPublic() && optional.isEmpty()) { + log.error("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 */ + if (!database.getOwner().getId().equals(getId(principal))) { + log.trace("authenticated user is not owner: remove access list"); + database.setAccesses(List.of()); + } + final int tables = database.getTables() + .size(); + database.setTables(database.getTables() + .stream() + .filter(t -> t.getIsPublic() || t.getIsSchemaPublic() || optional.isPresent()) + .toList()); + log.trace("filtered database tables from {} to {}", tables, database.getTables().size()); + final int views = database.getViews() + .size(); + database.setViews(database.getViews() + .stream() + .filter(v -> v.getIsPublic() || v.getIsSchemaPublic() || optional.isPresent()) + .toList()); + log.trace("filtered database views from {} to {}", views, database.getViews().size()); + return database; + } + if (!database.getIsPublic() && !database.getIsSchemaPublic()) { + log.error("Failed to find database: not public and not authenticated"); + throw new NotAllowedException("Failed to find database: not public and not authenticated"); + } + /* reduce metadata */ + 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()); + return database; + } + + public List<View> filterViews(Database database, Principal principal) { + final List<View> views = database.getViews(); + DatabaseAccess access = null; + if (principal != null) { + if (isSystem(principal)) { + return views; + } + final Optional<DatabaseAccess> optional = database.getAccesses() + .stream() + .filter(a -> a.getHdbid().equals(getId(principal))) + .findFirst(); + if (optional.isPresent()) { + access = optional.get(); + } + } + final Boolean hasAccess = access != null; + return views.stream() + .filter(v -> v.getIsPublic() || v.getIsSchemaPublic() || hasAccess) + .toList(); + } + +} 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/ac/tuwien/ifs/dbrepo/endpoints/AccessEndpoint.java similarity index 86% rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java rename to dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/AccessEndpoint.java index 79dc5fd8e987dfad2d8e59dcd14ac156803fab91..a605ec126fdafb30369ed594ef18d74b3ce900b7 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/ac/tuwien/ifs/dbrepo/endpoints/AccessEndpoint.java @@ -1,16 +1,17 @@ -package at.tuwien.endpoints; +package at.ac.tuwien.ifs.dbrepo.endpoints; -import at.tuwien.api.database.DatabaseAccessDto; -import at.tuwien.api.database.CreateAccessDto; -import at.tuwien.api.error.ApiErrorDto; -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.ac.tuwien.ifs.dbrepo.core.api.database.CreateAccessDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseAccessDto; +import at.ac.tuwien.ifs.dbrepo.core.api.error.ApiErrorDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.DatabaseAccess; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.service.AccessService; +import at.ac.tuwien.ifs.dbrepo.service.DashboardService; +import at.ac.tuwien.ifs.dbrepo.service.DatabaseService; +import at.ac.tuwien.ifs.dbrepo.service.UserService; import io.micrometer.observation.annotation.Observed; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; @@ -40,14 +41,16 @@ public class AccessEndpoint extends AbstractEndpoint { private final AccessService accessService; private final MetadataMapper metadataMapper; private final DatabaseService databaseService; + private final DashboardService dashboardService; @Autowired public AccessEndpoint(UserService userService, AccessService accessService, MetadataMapper metadataMapper, - DatabaseService databaseService) { + DatabaseService databaseService, DashboardService dashboardService) { this.userService = userService; this.accessService = accessService; this.metadataMapper = metadataMapper; this.databaseService = databaseService; + this.dashboardService = dashboardService; } @PostMapping("/{userId}") @@ -92,9 +95,10 @@ public class AccessEndpoint extends AbstractEndpoint { public ResponseEntity<DatabaseAccessDto> create(@NotNull @PathVariable("databaseId") UUID databaseId, @PathVariable("userId") UUID userId, @Valid @RequestBody CreateAccessDto data, - @NotNull Principal principal) throws NotAllowedException, DataServiceException, - DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException, - SearchServiceException, SearchServiceConnectionException { + Principal principal) throws NotAllowedException, + DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException, + AccessNotFoundException, SearchServiceException, SearchServiceConnectionException, + DashboardServiceException, DashboardServiceConnectionException { log.debug("endpoint give access to database, databaseId={}, userId={}, access.type={}", databaseId, userId, data.getType()); final Database database = databaseService.findById(databaseId); @@ -111,6 +115,7 @@ public class AccessEndpoint extends AbstractEndpoint { /* ignore */ } accessService.create(database, user, data.getType()); + dashboardService.updateAccess(database, user, data.getType()); return ResponseEntity.accepted() .build(); } @@ -154,11 +159,12 @@ public class AccessEndpoint extends AbstractEndpoint { public ResponseEntity<Void> update(@NotNull @PathVariable("databaseId") UUID databaseId, @PathVariable("userId") UUID userId, @Valid @RequestBody CreateAccessDto data, - @NotNull Principal principal) throws NotAllowedException, + Principal principal) throws NotAllowedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException, - AccessNotFoundException, SearchServiceException, SearchServiceConnectionException { - log.debug("endpoint modify database access, databaseId={}, userId={}, access.type={}, principal.name={}", - databaseId, userId, data.getType(), principal.getName()); + AccessNotFoundException, SearchServiceException, SearchServiceConnectionException, + DashboardServiceException, DashboardServiceConnectionException { + log.debug("endpoint modify database access, databaseId={}, userId={}, access.type={}", databaseId, userId, + data.getType()); final Database database = databaseService.findById(databaseId); if (!database.getOwner().getId().equals(getId(principal))) { log.error("Failed to update access: not owner"); @@ -170,11 +176,12 @@ public class AccessEndpoint extends AbstractEndpoint { } final User user = userService.findById(userId); if (user.getIsInternal()) { - log.error("Failed to update access: the internal user must have write-all access"); - throw new NotAllowedException("Failed to update access: the internal user must have write-all access"); + log.error("Failed to update access: cannot modify access of internal users"); + throw new NotAllowedException("Failed to update access: cannot modify access of internal users"); } accessService.find(database, user); accessService.update(database, user, data.getType()); + dashboardService.updateAccess(database, user, data.getType()); return ResponseEntity.accepted() .build(); } @@ -205,10 +212,9 @@ public class AccessEndpoint extends AbstractEndpoint { }) public ResponseEntity<DatabaseAccessDto> find(@NotNull @PathVariable("databaseId") UUID databaseId, @PathVariable("userId") UUID userId, - @NotNull Principal principal) throws DatabaseNotFoundException, + Principal principal) throws DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException, NotAllowedException { - log.debug("endpoint get database access, databaseId={}, userId={}, principal.name={}", databaseId, userId, - principal.getName()); + log.debug("endpoint get database access, databaseId={}, userId={}", databaseId, userId); if (!userId.equals(getId(principal))) { if (!hasRole(principal, "check-foreign-database-access")) { log.error("Failed to find access: foreign user"); @@ -260,9 +266,10 @@ public class AccessEndpoint extends AbstractEndpoint { }) public ResponseEntity<Void> revoke(@NotNull @PathVariable("databaseId") UUID databaseId, @PathVariable("userId") UUID userId, - @NotNull Principal principal) throws NotAllowedException, DataServiceException, + Principal principal) throws NotAllowedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException, - SearchServiceException, SearchServiceConnectionException { + SearchServiceException, SearchServiceConnectionException, DashboardServiceException, + DashboardServiceConnectionException { log.debug("endpoint revoke database access, databaseId={}, userId={}", databaseId, userId); final Database database = databaseService.findById(databaseId); if (!database.getOwner().getId().equals(getId(principal))) { @@ -280,6 +287,7 @@ public class AccessEndpoint extends AbstractEndpoint { } accessService.find(database, user); accessService.delete(database, user); + dashboardService.updateAccess(database, user, null); return ResponseEntity.accepted() .build(); } diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ConceptEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/ConceptEndpoint.java similarity index 90% rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ConceptEndpoint.java rename to dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/ConceptEndpoint.java index acf6a31ca2a583a91ba9bf9e1e4e3c544342eb65..11b2d8ea0c8fb564e05cbf6290854da85476c6a9 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ConceptEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/ConceptEndpoint.java @@ -1,8 +1,8 @@ -package at.tuwien.endpoints; +package at.ac.tuwien.ifs.dbrepo.endpoints; -import at.tuwien.api.database.table.columns.concepts.ConceptDto; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.service.ConceptService; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.concepts.ConceptDto; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.service.ConceptService; import io.micrometer.observation.annotation.Observed; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.ArraySchema; 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/ac/tuwien/ifs/dbrepo/endpoints/ContainerEndpoint.java similarity index 92% rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java rename to dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/ContainerEndpoint.java index 266430372d0796408030364a8f61f9642c05e415..d98901f53595da0bbcfb0f77c1b53118b09a8d48 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/ac/tuwien/ifs/dbrepo/endpoints/ContainerEndpoint.java @@ -1,15 +1,15 @@ -package at.tuwien.endpoints; +package at.ac.tuwien.ifs.dbrepo.endpoints; -import at.tuwien.api.container.ContainerBriefDto; -import at.tuwien.api.container.ContainerDto; -import at.tuwien.api.container.CreateContainerDto; -import at.tuwien.api.error.ApiErrorDto; -import at.tuwien.entities.container.Container; -import at.tuwien.exception.ContainerAlreadyExistsException; -import at.tuwien.exception.ContainerNotFoundException; -import at.tuwien.exception.ImageNotFoundException; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.service.ContainerService; +import at.ac.tuwien.ifs.dbrepo.core.api.container.ContainerBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.ContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.CreateContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.api.error.ApiErrorDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.Container; +import at.ac.tuwien.ifs.dbrepo.core.exception.ContainerAlreadyExistsException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ContainerNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ImageNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.service.ContainerService; import io.micrometer.observation.annotation.Observed; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.ArraySchema; 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/ac/tuwien/ifs/dbrepo/endpoints/DatabaseEndpoint.java similarity index 86% rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java rename to dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/DatabaseEndpoint.java index 9eadffd0df3ded54ec74af23f8cd6baedb347416..0474215e01fce6ccd392441e8ea1cfef8ccd6726 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/ac/tuwien/ifs/dbrepo/endpoints/DatabaseEndpoint.java @@ -1,17 +1,14 @@ -package at.tuwien.endpoints; +package at.ac.tuwien.ifs.dbrepo.endpoints; -import at.tuwien.api.database.*; -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.user.User; -import at.tuwien.exception.*; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.service.ContainerService; -import at.tuwien.service.DatabaseService; -import at.tuwien.service.StorageService; -import at.tuwien.service.UserService; +import at.ac.tuwien.ifs.dbrepo.core.api.database.*; +import at.ac.tuwien.ifs.dbrepo.core.api.error.ApiErrorDto; +import at.ac.tuwien.ifs.dbrepo.core.api.grafana.CreateDashboardResponseDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.Container; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.service.*; import io.micrometer.observation.annotation.Observed; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.headers.Header; @@ -35,7 +32,6 @@ import org.springframework.web.bind.annotation.*; import java.security.Principal; import java.util.List; -import java.util.Optional; import java.util.UUID; @Log4j2 @@ -49,15 +45,18 @@ public class DatabaseEndpoint extends AbstractEndpoint { private final StorageService storageService; private final DatabaseService databaseService; private final ContainerService containerService; + private final DashboardService dashboardService; @Autowired public DatabaseEndpoint(UserService userService, MetadataMapper metadataMapper, StorageService storageService, - DatabaseService databaseService, ContainerService containerService) { + DatabaseService databaseService, ContainerService containerService, + DashboardService dashboardService) { this.userService = userService; this.metadataMapper = metadataMapper; this.storageService = storageService; this.databaseService = databaseService; this.containerService = containerService; + this.dashboardService = dashboardService; } @RequestMapping(method = {RequestMethod.GET, RequestMethod.HEAD}) @@ -164,10 +163,10 @@ public class DatabaseEndpoint extends AbstractEndpoint { schema = @Schema(implementation = ApiErrorDto.class))}), }) public ResponseEntity<DatabaseBriefDto> create(@Valid @RequestBody CreateDatabaseDto data, - @NotNull Principal principal) throws DataServiceException, + Principal principal) throws DataServiceException, DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, ContainerNotFoundException, SearchServiceException, SearchServiceConnectionException, - ContainerQuotaException { + ContainerQuotaException, DashboardServiceException, DashboardServiceConnectionException { log.debug("endpoint create database, data.name={}", data.getName()); final Container container = containerService.find(data.getCid()); if (container.getQuota() != null && container.getDatabases().size() + 1 > container.getQuota()) { @@ -175,9 +174,12 @@ public class DatabaseEndpoint extends AbstractEndpoint { throw new ContainerQuotaException("Failed to create database: quota of " + container.getQuota() + " exceeded"); } final User caller = userService.findById(getId(principal)); + final Database database = databaseService.create(container, data, caller, userService.findAllInternalUsers()); + /* find in dashboard service */ + final CreateDashboardResponseDto dashboard = dashboardService.create(database); + database.setDashboardUid(dashboard.getUid()); return ResponseEntity.status(HttpStatus.CREATED) - .body(metadataMapper.databaseDtoToDatabaseBriefDto(metadataMapper.databaseToDatabaseDto( - databaseService.create(container, data, caller, userService.findAllInternalUsers())))); + .body(metadataMapper.databaseToDatabaseBriefDto(database)); } @PutMapping("/{databaseId}/metadata/table") @@ -220,10 +222,9 @@ public class DatabaseEndpoint extends AbstractEndpoint { schema = @Schema(implementation = ApiErrorDto.class))}), }) public ResponseEntity<DatabaseBriefDto> refreshTableMetadata(@NotNull @PathVariable("databaseId") UUID databaseId, - @NotNull Principal principal) throws DataServiceException, + Principal principal) throws DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, - SearchServiceConnectionException, NotAllowedException, QueryNotFoundException, MalformedException, - TableNotFoundException { + SearchServiceConnectionException, NotAllowedException, MalformedException, TableNotFoundException { log.debug("endpoint refresh database metadata, databaseId={}", databaseId); final Database database = databaseService.findById(databaseId); if (!database.getOwner().getId().equals(getId(principal))) { @@ -269,10 +270,10 @@ public class DatabaseEndpoint extends AbstractEndpoint { schema = @Schema(implementation = ApiErrorDto.class))}), }) public ResponseEntity<DatabaseBriefDto> refreshViewMetadata(@NotNull @PathVariable("databaseId") UUID databaseId, - @NotNull Principal principal) throws DataServiceException, + Principal principal) throws DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, - SearchServiceConnectionException, NotAllowedException, QueryNotFoundException, ViewNotFoundException { - log.debug("endpoint refresh database metadata, databaseId={}, principal.name={}", databaseId, principal.getName()); + SearchServiceConnectionException, NotAllowedException, ViewNotFoundException { + log.debug("endpoint refresh database metadata, databaseId={}", databaseId); final Database database = databaseService.findById(databaseId); if (!database.getOwner().getId().equals(getId(principal))) { log.error("Failed to refresh database views metadata: not owner"); @@ -323,14 +324,17 @@ public class DatabaseEndpoint extends AbstractEndpoint { }) public ResponseEntity<DatabaseBriefDto> visibility(@NotNull @PathVariable("databaseId") UUID databaseId, @Valid @RequestBody DatabaseModifyVisibilityDto data, - @NotNull Principal principal) throws DatabaseNotFoundException, - NotAllowedException, SearchServiceException, SearchServiceConnectionException, UserNotFoundException { + Principal principal) throws DatabaseNotFoundException, + NotAllowedException, SearchServiceException, SearchServiceConnectionException, DashboardServiceException, + DashboardServiceConnectionException { log.debug("endpoint modify database visibility, databaseId={}, data={}", databaseId, data); final Database database = databaseService.findById(databaseId); if (!database.getOwner().getId().equals(getId(principal))) { log.error("Failed to modify database visibility: not owner"); throw new NotAllowedException("Failed to modify database visibility: not owner"); } + final Database database1 = databaseService.modifyVisibility(database, data); + dashboardService.update(database1); return ResponseEntity.accepted() .body(metadataMapper.databaseDtoToDatabaseBriefDto(metadataMapper.databaseToDatabaseDto( databaseService.modifyVisibility(database, data)))); @@ -377,7 +381,7 @@ public class DatabaseEndpoint extends AbstractEndpoint { }) public ResponseEntity<DatabaseBriefDto> transfer(@NotNull @PathVariable("databaseId") UUID databaseId, @Valid @RequestBody DatabaseTransferDto data, - @NotNull Principal principal) throws NotAllowedException, + Principal principal) throws NotAllowedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException, SearchServiceException, SearchServiceConnectionException { log.debug("endpoint transfer database, databaseId={}, transferDto.id={}", databaseId, data.getId()); @@ -433,7 +437,7 @@ public class DatabaseEndpoint extends AbstractEndpoint { }) public ResponseEntity<DatabaseBriefDto> modifyImage(@NotNull @PathVariable("databaseId") UUID databaseId, @Valid @RequestBody DatabaseModifyImageDto data, - @NotNull Principal principal) throws NotAllowedException, + Principal principal) throws NotAllowedException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException, StorageUnavailableException, StorageNotFoundException { log.debug("endpoint modify database image, databaseId={}, data.key={}", databaseId, data.getKey()); @@ -451,6 +455,50 @@ public class DatabaseEndpoint extends AbstractEndpoint { databaseService.modifyImage(database, image)))); } + @PutMapping("/{databaseId}/dashboard") + @Transactional + @PreAuthorize("hasAuthority('system')") + @Observed(name = "dbrepo_database_dashboard") + @Operation(summary = "Update database dashboard uid", + description = "Updates the dashboard uid for a database with given id. Only the database owner can perform this operation. Requires role `system`.", + security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) + @ApiResponses(value = { + @ApiResponse(responseCode = "202", + description = "Modify of dashboard uid was successful", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = DatabaseBriefDto.class))}), + @ApiResponse(responseCode = "400", + description = "Malformed payload", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), + @ApiResponse(responseCode = "404", + description = "Database could not be found", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), + @ApiResponse(responseCode = "502", + description = "Connection to search service failed", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), + @ApiResponse(responseCode = "503", + description = "Failed to save in search service", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}) + }) + public ResponseEntity<DatabaseBriefDto> modifyDashboard(@NotNull @PathVariable("databaseId") UUID databaseId, + @Valid @RequestBody DatabaseModifyDashboardDto data) + throws DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException { + log.debug("endpoint modify database dashboard uid, databaseId={}, data.uid={}", databaseId, data.getUid()); + final Database database = databaseService.findById(databaseId); + return ResponseEntity.accepted() + .body(metadataMapper.databaseDtoToDatabaseBriefDto(metadataMapper.databaseToDatabaseDto( + databaseService.modifyDashboard(database, data.getUid())))); + } + @GetMapping("/{databaseId}/image") @Transactional @Observed(name = "dbrepo_database_image_view") @@ -504,54 +552,7 @@ public class DatabaseEndpoint extends AbstractEndpoint { Principal principal) throws DatabaseNotFoundException, NotAllowedException { log.debug("endpoint find database, databaseId={}", databaseId); - final Database database = databaseService.findById(databaseId); - if (principal != null) { - final Optional<DatabaseAccess> optional = database.getAccesses() - .stream() - .filter(a -> a.getUser().getId().equals(getId(principal))) - .findFirst(); - optional.ifPresentOrElse(access -> log.trace("user has access: {}", access), () -> log.trace("user has no access")); - if (!database.getIsPublic() && !database.getIsSchemaPublic() && optional.isEmpty() && !isSystem(principal)) { - log.error("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 */ - final int tables = database.getTables() - .size(); - database.setTables(database.getTables() - .stream() - .filter(t -> t.getIsPublic() || t.getIsSchemaPublic() || optional.isPresent() || isSystem(principal)) - .toList()); - log.trace("filtered database tables from {} to {}", tables, database.getTables().size()); - final int views = database.getViews() - .size(); - database.setViews(database.getViews() - .stream() - .filter(v -> v.getIsPublic() || v.getIsSchemaPublic() || optional.isPresent() || isSystem(principal)) - .toList()); - log.trace("filtered database views from {} to {}", views, database.getViews().size()); - if (!isSystem(principal) && !database.getOwner().getId().equals(getId(principal))) { - log.trace("authenticated user {} is not owner: remove access list", principal.getName()); - database.setAccesses(List.of()); - } - } else { - if (!database.getIsPublic() && !database.getIsSchemaPublic()) { - log.error("Failed to find database: not public and not authenticated"); - throw new NotAllowedException("Failed to find database: not public and not authenticated"); - } - /* reduce metadata */ - 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 Database database = filterDatabase(databaseService.findById(databaseId), principal); final DatabaseDto dto = metadataMapper.databaseToDatabaseDto(database); final HttpHeaders headers = new HttpHeaders(); if (isSystem(principal)) { 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/ac/tuwien/ifs/dbrepo/endpoints/IdentifierEndpoint.java similarity index 96% rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java rename to dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/IdentifierEndpoint.java index 96deaea775defd1562aba3601d9ba513b771f401..ea6e569e52d8c0e575fe85b78106b5297eb1caf2 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/ac/tuwien/ifs/dbrepo/endpoints/IdentifierEndpoint.java @@ -1,19 +1,19 @@ -package at.tuwien.endpoints; +package at.ac.tuwien.ifs.dbrepo.endpoints; -import at.tuwien.api.error.ApiErrorDto; -import at.tuwien.api.identifier.*; -import at.tuwien.api.identifier.ld.LdDatasetDto; -import at.tuwien.api.user.external.ExternalMetadataDto; -import at.tuwien.config.EndpointConfig; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.database.DatabaseAccess; -import at.tuwien.entities.identifier.Identifier; -import at.tuwien.entities.identifier.IdentifierStatusType; -import at.tuwien.entities.user.User; -import at.tuwien.exception.*; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.service.*; -import at.tuwien.validation.EndpointValidator; +import at.ac.tuwien.ifs.dbrepo.config.EndpointConfig; +import at.ac.tuwien.ifs.dbrepo.core.api.error.ApiErrorDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.*; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.ld.LdDatasetDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.external.ExternalMetadataDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.DatabaseAccess; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.Identifier; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.IdentifierStatusType; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.service.*; +import at.ac.tuwien.ifs.dbrepo.validation.EndpointValidator; import io.micrometer.observation.annotation.Observed; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.ArraySchema; @@ -374,13 +374,13 @@ public class IdentifierEndpoint extends AbstractEndpoint { }) public ResponseEntity<IdentifierDto> save(@NotNull @PathVariable("identifierId") UUID identifierId, @NotNull @Valid @RequestBody IdentifierSaveDto data, - @NotNull Principal principal) throws UserNotFoundException, + Principal principal) throws UserNotFoundException, DatabaseNotFoundException, MalformedException, NotAllowedException, DataServiceException, DataServiceConnectionException, SearchServiceException, QueryNotFoundException, SearchServiceConnectionException, IdentifierNotFoundException, ViewNotFoundException, TableNotFoundException, ExternalServiceException { - log.debug("endpoint save identifier, identifierId={}, data.id={}, principal.name={}", identifierId, - data.getId(), principal.getName()); + log.debug("endpoint save identifier, identifierId={}, data.id={}", identifierId, + data.getId()); final Database database = databaseService.findById(data.getDatabaseId()); final User caller = userService.findById(getId(principal)); final Identifier identifier = identifierService.find(identifierId); @@ -475,7 +475,7 @@ public class IdentifierEndpoint extends AbstractEndpoint { schema = @Schema(implementation = ApiErrorDto.class))}), }) public ResponseEntity<IdentifierDto> create(@NotNull @Valid @RequestBody CreateIdentifierDto data, - @NotNull Principal principal) throws DatabaseNotFoundException, + Principal principal) throws DatabaseNotFoundException, UserNotFoundException, NotAllowedException, MalformedException, DataServiceConnectionException, SearchServiceException, DataServiceException, QueryNotFoundException, SearchServiceConnectionException, IdentifierNotFoundException, ViewNotFoundException, ExternalServiceException { diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/ImageEndpoint.java similarity index 89% rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java rename to dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/ImageEndpoint.java index 62c00d1ee8d4ef5a395b22e77595859c44774c56..3137e08a6833617afb27e075b1de9980867568da 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/ImageEndpoint.java @@ -1,16 +1,16 @@ -package at.tuwien.endpoints; +package at.ac.tuwien.ifs.dbrepo.endpoints; -import at.tuwien.api.container.image.ImageBriefDto; -import at.tuwien.api.container.image.ImageChangeDto; -import at.tuwien.api.container.image.ImageCreateDto; -import at.tuwien.api.container.image.ImageDto; -import at.tuwien.api.error.ApiErrorDto; -import at.tuwien.entities.container.image.ContainerImage; -import at.tuwien.exception.ImageAlreadyExistsException; -import at.tuwien.exception.ImageInvalidException; -import at.tuwien.exception.ImageNotFoundException; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.service.ImageService; +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageChangeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageDto; +import at.ac.tuwien.ifs.dbrepo.core.api.error.ApiErrorDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.image.ContainerImage; +import at.ac.tuwien.ifs.dbrepo.core.exception.ImageAlreadyExistsException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ImageInvalidException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ImageNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.service.ImageService; import io.micrometer.observation.annotation.Observed; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.ArraySchema; @@ -95,9 +95,9 @@ public class ImageEndpoint extends AbstractEndpoint { schema = @Schema(implementation = ApiErrorDto.class))}), }) public ResponseEntity<ImageDto> create(@Valid @RequestBody ImageCreateDto data, - @NotNull Principal principal) throws ImageAlreadyExistsException, + Principal principal) throws ImageAlreadyExistsException, ImageInvalidException { - log.debug("endpoint create image, data={}, principal.name={}", data, principal.getName()); + log.debug("endpoint create image, data={}", data); return ResponseEntity.status(HttpStatus.CREATED) .body(metadataMapper.containerImageToImageDto( imageService.create(data, principal))); diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/LicenseEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/LicenseEndpoint.java similarity index 91% rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/LicenseEndpoint.java rename to dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/LicenseEndpoint.java index 18d5e93ca26a824f1b445e39fb82213b0f7fe649..f82127b86a5f554fe585b3472d955a207bdc25b2 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/LicenseEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/LicenseEndpoint.java @@ -1,8 +1,8 @@ -package at.tuwien.endpoints; +package at.ac.tuwien.ifs.dbrepo.endpoints; -import at.tuwien.api.database.LicenseDto; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.service.LicenseService; +import at.ac.tuwien.ifs.dbrepo.core.api.database.LicenseDto; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.service.LicenseService; import io.micrometer.observation.annotation.Observed; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.ArraySchema; diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/MessageEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/MessageEndpoint.java similarity index 92% rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/MessageEndpoint.java rename to dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/MessageEndpoint.java index 656279a86d680877849d9d2aa6fce327b6ba8ecb..6d6f3c8591a9a00393866f9031d305509d44e9ac 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/MessageEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/MessageEndpoint.java @@ -1,14 +1,14 @@ -package at.tuwien.endpoints; +package at.ac.tuwien.ifs.dbrepo.endpoints; -import at.tuwien.api.error.ApiErrorDto; -import at.tuwien.api.maintenance.BannerMessageBriefDto; -import at.tuwien.api.maintenance.BannerMessageCreateDto; -import at.tuwien.api.maintenance.BannerMessageDto; -import at.tuwien.api.maintenance.BannerMessageUpdateDto; -import at.tuwien.entities.maintenance.BannerMessage; -import at.tuwien.exception.MessageNotFoundException; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.service.BannerMessageService; +import at.ac.tuwien.ifs.dbrepo.core.api.error.ApiErrorDto; +import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageDto; +import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.maintenance.BannerMessage; +import at.ac.tuwien.ifs.dbrepo.core.exception.MessageNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.service.BannerMessageService; import io.micrometer.observation.annotation.Observed; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.ArraySchema; diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/MetadataEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/MetadataEndpoint.java similarity index 94% rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/MetadataEndpoint.java rename to dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/MetadataEndpoint.java index 8a36471816ee9a4d2a89e3fee2edcde59f7361ae..4916ed8612ea04ba16375d645e3ac08424dc56a6 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/MetadataEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/MetadataEndpoint.java @@ -1,10 +1,10 @@ -package at.tuwien.endpoints; +package at.ac.tuwien.ifs.dbrepo.endpoints; -import at.tuwien.exception.IdentifierNotFoundException; -import at.tuwien.oaipmh.OaiErrorType; -import at.tuwien.oaipmh.OaiListIdentifiersParameters; -import at.tuwien.oaipmh.OaiRecordParameters; -import at.tuwien.service.MetadataService; +import at.ac.tuwien.ifs.dbrepo.core.exception.IdentifierNotFoundException; +import at.ac.tuwien.ifs.dbrepo.oaipmh.OaiErrorType; +import at.ac.tuwien.ifs.dbrepo.oaipmh.OaiListIdentifiersParameters; +import at.ac.tuwien.ifs.dbrepo.oaipmh.OaiRecordParameters; +import at.ac.tuwien.ifs.dbrepo.service.MetadataService; import io.micrometer.observation.annotation.Observed; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/OntologyEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/OntologyEndpoint.java similarity index 93% rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/OntologyEndpoint.java rename to dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/OntologyEndpoint.java index c723568556ce097c600ece7b8aad9b57d3914b77..da48971adb762783ab7812d513a327cca94c3886 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/OntologyEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/OntologyEndpoint.java @@ -1,15 +1,15 @@ -package at.tuwien.endpoints; +package at.ac.tuwien.ifs.dbrepo.endpoints; -import at.tuwien.api.error.ApiErrorDto; -import at.tuwien.api.semantics.*; -import at.tuwien.entities.semantics.Ontology; -import at.tuwien.exception.FilterBadRequestException; -import at.tuwien.exception.MalformedException; -import at.tuwien.exception.OntologyNotFoundException; -import at.tuwien.exception.UriMalformedException; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.service.EntityService; -import at.tuwien.service.OntologyService; +import at.ac.tuwien.ifs.dbrepo.core.api.error.ApiErrorDto; +import at.ac.tuwien.ifs.dbrepo.core.api.semantics.*; +import at.ac.tuwien.ifs.dbrepo.core.entity.semantics.Ontology; +import at.ac.tuwien.ifs.dbrepo.core.exception.FilterBadRequestException; +import at.ac.tuwien.ifs.dbrepo.core.exception.MalformedException; +import at.ac.tuwien.ifs.dbrepo.core.exception.OntologyNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.exception.UriMalformedException; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.service.EntityService; +import at.ac.tuwien.ifs.dbrepo.service.OntologyService; import io.micrometer.observation.annotation.Observed; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.ArraySchema; @@ -104,8 +104,8 @@ public class OntologyEndpoint extends AbstractEndpoint { schema = @Schema(implementation = OntologyDto.class))}) }) public ResponseEntity<OntologyDto> create(@NotNull @Valid @RequestBody OntologyCreateDto data, - @NotNull Principal principal) { - log.debug("endpoint create ontology, data={}, principal.name={}", data, principal.getName()); + Principal principal) { + log.debug("endpoint create ontology, data={}", data); return ResponseEntity.status(HttpStatus.CREATED) .body(metadataMapper.ontologyToOntologyDto(ontologyService.create(data, principal))); } 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/ac/tuwien/ifs/dbrepo/endpoints/TableEndpoint.java similarity index 86% rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java rename to dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/TableEndpoint.java index f04f66eb8e5c3d7527e84abcb0ef1861cb02dc42..211efe731e673919223103aabcb5f8c0f8aa58cc 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/ac/tuwien/ifs/dbrepo/endpoints/TableEndpoint.java @@ -1,20 +1,21 @@ -package at.tuwien.endpoints; +package at.ac.tuwien.ifs.dbrepo.endpoints; -import at.tuwien.api.database.table.CreateTableDto; -import at.tuwien.api.database.table.TableBriefDto; -import at.tuwien.api.database.table.TableDto; -import at.tuwien.api.database.table.TableUpdateDto; -import at.tuwien.api.database.table.columns.ColumnDto; -import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto; -import at.tuwien.api.error.ApiErrorDto; -import at.tuwien.api.semantics.EntityDto; -import at.tuwien.api.semantics.TableColumnEntityDto; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.database.table.Table; -import at.tuwien.exception.*; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.service.*; -import at.tuwien.validation.EndpointValidator; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.CreateTableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.concepts.ColumnSemanticsUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.error.ApiErrorDto; +import at.ac.tuwien.ifs.dbrepo.core.api.semantics.EntityDto; +import at.ac.tuwien.ifs.dbrepo.core.api.semantics.TableColumnEntityDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.DatabaseAccess; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.Table; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.service.*; +import at.ac.tuwien.ifs.dbrepo.validation.EndpointValidator; import io.micrometer.observation.annotation.Observed; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.ArraySchema; @@ -35,6 +36,7 @@ import org.springframework.web.bind.annotation.*; import java.security.Principal; import java.util.List; +import java.util.Optional; import java.util.UUID; import java.util.stream.Collectors; @@ -47,21 +49,21 @@ public class TableEndpoint extends AbstractEndpoint { private final UserService userService; private final TableService tableService; private final EntityService entityService; - private final AccessService accessService; private final MetadataMapper metadataMapper; private final DatabaseService databaseService; + private final DashboardService dashboardService; private final EndpointValidator endpointValidator; @Autowired public TableEndpoint(UserService userService, TableService tableService, EntityService entityService, - AccessService accessService, MetadataMapper metadataMapper, DatabaseService databaseService, - EndpointValidator endpointValidator) { + MetadataMapper metadataMapper, DatabaseService databaseService, + DashboardService dashboardService, EndpointValidator endpointValidator) { this.userService = userService; this.tableService = tableService; this.entityService = entityService; - this.accessService = accessService; this.metadataMapper = metadataMapper; this.databaseService = databaseService; + this.dashboardService = dashboardService; this.endpointValidator = endpointValidator; } @@ -95,13 +97,33 @@ public class TableEndpoint extends AbstractEndpoint { final Database database = databaseService.findById(databaseId); endpointValidator.validateOnlyPrivateSchemaAccess(database, principal); endpointValidator.validateOnlyPrivateSchemaHasRole(database, principal, "list-tables"); - return ResponseEntity.ok(database.getTables() + return ResponseEntity.ok(filterTables(database, principal) .stream() - .filter(t -> t.getIsPublic() || t.getIsSchemaPublic() || (principal != null && isSystem(principal))) .map(metadataMapper::tableToTableBriefDto) .collect(Collectors.toList())); } + public List<Table> filterTables(Database database, Principal principal) { + final List<Table> tables = database.getTables(); + DatabaseAccess access = null; + if (principal != null) { + if (isSystem(principal)) { + return tables; + } + final Optional<DatabaseAccess> optional = database.getAccesses() + .stream() + .filter(a -> a.getHdbid().equals(getId(principal))) + .findFirst(); + if (optional.isPresent()) { + access = optional.get(); + } + } + final Boolean hasAccess = access != null; + return tables.stream() + .filter(t -> t.getIsPublic() || t.getIsSchemaPublic() || hasAccess) + .toList(); + } + @GetMapping("/{tableId}/suggest") @Transactional(readOnly = true) @PreAuthorize("hasAuthority('table-semantic-analyse')") @@ -143,10 +165,9 @@ public class TableEndpoint extends AbstractEndpoint { }) public ResponseEntity<List<EntityDto>> analyseTable(@NotNull @PathVariable("databaseId") UUID databaseId, @NotNull @PathVariable("tableId") UUID tableId, - @NotNull Principal principal) + Principal principal) throws MalformedException, TableNotFoundException, DatabaseNotFoundException, NotAllowedException { - log.debug("endpoint analyse table semantics, databaseId={}, tableId={}, principal.name={}", databaseId, tableId, - principal); + log.debug("endpoint analyse table semantics, databaseId={}, tableId={}", databaseId, tableId); final Database database = databaseService.findById(databaseId); final Table table = tableService.findById(database, tableId); if (!table.getOwner().getId().equals(getId(principal))) { @@ -195,11 +216,10 @@ public class TableEndpoint extends AbstractEndpoint { }) public ResponseEntity<Void> updateStatistic(@NotNull @PathVariable("databaseId") UUID databaseId, @NotNull @PathVariable("tableId") UUID tableId, - @NotNull Principal principal) + Principal principal) throws TableNotFoundException, DatabaseNotFoundException, SearchServiceException, NotAllowedException, SearchServiceConnectionException, MalformedException, DataServiceException, DataServiceConnectionException { - log.debug("endpoint update table statistics, databaseId={}, tableId={}, principal.name={}", databaseId, tableId, - principal.getName()); + log.debug("endpoint update table statistics, databaseId={}, tableId={}", databaseId, tableId); final Database database = databaseService.findById(databaseId); final Table table = tableService.findById(database, tableId); if (!table.getOwner().getId().equals(getId(principal)) && !isSystem(principal)) { @@ -254,12 +274,12 @@ public class TableEndpoint extends AbstractEndpoint { @NotNull @PathVariable("tableId") UUID tableId, @NotNull @PathVariable("columnId") UUID columnId, @NotNull @Valid @RequestBody ColumnSemanticsUpdateDto updateDto, - @NotNull Principal principal) throws NotAllowedException, + Principal principal) throws NotAllowedException, MalformedException, DataServiceException, DataServiceConnectionException, UserNotFoundException, TableNotFoundException, DatabaseNotFoundException, AccessNotFoundException, SearchServiceException, SearchServiceConnectionException, OntologyNotFoundException, SemanticEntityNotFoundException { - log.debug("endpoint update table, databaseId={}, tableId={}, columnId={}, principal.name={}", databaseId, - tableId, columnId, principal.getName()); + log.debug("endpoint update table, databaseId={}, tableId={}, columnId={}", databaseId, + tableId, columnId); final Database database = databaseService.findById(databaseId); final Table table = tableService.findById(database, tableId); if (!hasRole(principal, "modify-foreign-table-column-semantics")) { @@ -303,10 +323,10 @@ public class TableEndpoint extends AbstractEndpoint { public ResponseEntity<List<TableColumnEntityDto>> analyseTableColumn(@NotNull @PathVariable("databaseId") UUID databaseId, @NotNull @PathVariable("tableId") UUID tableId, @NotNull @PathVariable("columnId") UUID columnId, - @NotNull Principal principal) + Principal principal) throws MalformedException, TableNotFoundException, DatabaseNotFoundException { - log.debug("endpoint analyse table column semantics, databaseId={}, tableId={}, columnId={}, principal.name={}", - databaseId, tableId, columnId, principal.getName()); + log.debug("endpoint analyse table column semantics, databaseId={}, tableId={}, columnId={}", + databaseId, tableId, columnId); return ResponseEntity.ok() .body(entityService.suggestByColumn( tableService.findColumnById( @@ -359,18 +379,19 @@ public class TableEndpoint extends AbstractEndpoint { }) public ResponseEntity<TableBriefDto> create(@NotNull @PathVariable("databaseId") UUID databaseId, @NotNull @Valid @RequestBody CreateTableDto data, - @NotNull Principal principal) throws NotAllowedException, MalformedException, + Principal principal) throws NotAllowedException, MalformedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException, TableNotFoundException, TableExistsException, SearchServiceException, - SearchServiceConnectionException, OntologyNotFoundException, SemanticEntityNotFoundException { - log.debug("endpoint create table, databaseId={}, data.name={}, principal.name={}", databaseId, data.getName(), - principal.getName()); + SearchServiceConnectionException, OntologyNotFoundException, SemanticEntityNotFoundException, + DashboardServiceException, DashboardServiceConnectionException { + log.debug("endpoint create table, databaseId={}, data.name={}", databaseId, data.getName()); final Database database = databaseService.findById(databaseId); endpointValidator.validateOnlyAccess(database, principal, true); endpointValidator.validateColumnCreateConstraints(data); + final Table table = tableService.createTable(database, data, principal); + dashboardService.update(table.getDatabase()); return ResponseEntity.status(HttpStatus.CREATED) - .body(metadataMapper.tableToTableBriefDto( - tableService.createTable(database, data, principal))); + .body(metadataMapper.tableToTableBriefDto(table)); } @PutMapping("/{tableId}") @@ -415,20 +436,22 @@ public class TableEndpoint extends AbstractEndpoint { public ResponseEntity<TableBriefDto> update(@NotNull @PathVariable("databaseId") UUID databaseId, @NotNull @PathVariable("tableId") UUID tableId, @NotNull @Valid @RequestBody TableUpdateDto data, - @NotNull Principal principal) throws NotAllowedException, + 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={}", - databaseId, data.getIsPublic(), data.getIsSchemaPublic(), principal.getName()); + SearchServiceException, SearchServiceConnectionException, DashboardServiceException, + DashboardServiceConnectionException { + log.debug("endpoint update table, databaseId={}, data.is_public={}, data.is_schema_public={}", + databaseId, data.getIsPublic(), data.getIsSchemaPublic()); final Database database = databaseService.findById(databaseId); final Table table = tableService.findById(database, tableId); if (!table.getOwner().getId().equals(getId(principal))) { log.error("Failed to update table: not owner"); throw new NotAllowedException("Failed to update table: not owner"); } + final Table table1 = tableService.updateTable(table, data); + dashboardService.update(table1.getDatabase()); return ResponseEntity.accepted() - .body(metadataMapper.tableToTableBriefDto( - tableService.updateTable(table, data))); + .body(metadataMapper.tableToTableBriefDto(table1)); } @GetMapping("/{tableId}") @@ -461,28 +484,23 @@ public class TableEndpoint extends AbstractEndpoint { log.debug("endpoint find table, databaseId={}, tableId={}", databaseId, tableId); final Database database = databaseService.findById(databaseId); final Table table = tableService.findById(database, tableId); - boolean isOwner = false; if (principal != null) { - isOwner = table.getOwner().getId().equals(getId(principal)); - if (!table.getIsSchemaPublic()) { - try { - accessService.find(table.getDatabase(), userService.findById(getId(principal))); - } catch (UserNotFoundException | AccessNotFoundException e) { - if (!isOwner && !isSystem(principal)) { - log.error("Failed to find table with id {}: private and no access permission", table); - throw new NotAllowedException("Failed to find table with id " + tableId + ": private and no access permission"); - } - } + if (isSystem(principal)) { + return ResponseEntity.ok(metadataMapper.tableToTableDto(table)); + } + final Optional<DatabaseAccess> optional = database.getAccesses() + .stream() + .filter(a -> a.getHuserid().equals(getId(principal))) + .findFirst(); + if (table.getIsPublic() || table.getIsSchemaPublic() || optional.isPresent()) { + return ResponseEntity.ok(metadataMapper.tableToTableDto(table)); } } - if (!table.getIsSchemaPublic() && !isOwner && !isSystem(principal)) { - log.debug("remove schema from table: {}.{}", database.getInternalName(), table.getInternalName()); - table.setColumns(List.of()); - table.setConstraints(null); + if (!table.getIsPublic() && !table.getIsSchemaPublic()) { + log.error("Failed to find table: not public and no access found"); + throw new NotAllowedException("Failed to find table: not public and no access found"); } - final TableDto dto = metadataMapper.tableToTableDto(table); - return ResponseEntity.ok() - .body(dto); + return ResponseEntity.ok(metadataMapper.tableToTableDto(table)); } @DeleteMapping("/{tableId}") @@ -523,11 +541,11 @@ public class TableEndpoint extends AbstractEndpoint { }) public ResponseEntity<Void> delete(@NotNull @PathVariable("databaseId") UUID databaseId, @NotNull @PathVariable("tableId") UUID tableId, - @NotNull Principal principal) throws NotAllowedException, + Principal principal) throws NotAllowedException, DataServiceException, DataServiceConnectionException, TableNotFoundException, DatabaseNotFoundException, - SearchServiceException, SearchServiceConnectionException { - log.debug("endpoint delete table, databaseId={}, tableId={}, principal.name={}", databaseId, tableId, - principal.getName()); + SearchServiceException, SearchServiceConnectionException, DashboardServiceException, + DashboardServiceConnectionException { + log.debug("endpoint delete table, databaseId={}, tableId={}", databaseId, tableId); final Database database = databaseService.findById(databaseId); final Table table = tableService.findById(database, tableId); /* roles */ @@ -542,6 +560,7 @@ public class TableEndpoint extends AbstractEndpoint { } /* delete table */ tableService.deleteTable(table); + dashboardService.update(databaseService.findById(databaseId)); return ResponseEntity.accepted() .build(); } diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UnitEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/UnitEndpoint.java similarity index 90% rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UnitEndpoint.java rename to dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/UnitEndpoint.java index 45aef3645ba93cb1298c6da2e658656f645778ed..a0f5630c7ab219b473839b3a0936ea3f85f58322 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UnitEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/UnitEndpoint.java @@ -1,8 +1,8 @@ -package at.tuwien.endpoints; +package at.ac.tuwien.ifs.dbrepo.endpoints; -import at.tuwien.api.database.table.columns.concepts.UnitDto; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.service.UnitService; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.concepts.UnitDto; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.service.UnitService; import io.micrometer.observation.annotation.Observed; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.ArraySchema; 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/ac/tuwien/ifs/dbrepo/endpoints/UserEndpoint.java similarity index 91% rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java rename to dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/UserEndpoint.java index 8f3e15529e962e279454e40b194217accb9e2d39..1de29eef1b25d267901b3dbbff75c329fd099940 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/ac/tuwien/ifs/dbrepo/endpoints/UserEndpoint.java @@ -1,16 +1,16 @@ -package at.tuwien.endpoints; +package at.ac.tuwien.ifs.dbrepo.endpoints; -import at.tuwien.api.auth.CreateUserDto; -import at.tuwien.api.error.ApiErrorDto; -import at.tuwien.api.user.UserBriefDto; -import at.tuwien.api.user.UserDto; -import at.tuwien.api.user.UserUpdateDto; -import at.tuwien.entities.user.User; -import at.tuwien.exception.AuthServiceException; -import at.tuwien.exception.NotAllowedException; -import at.tuwien.exception.UserNotFoundException; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.service.UserService; +import at.ac.tuwien.ifs.dbrepo.core.api.auth.CreateUserDto; +import at.ac.tuwien.ifs.dbrepo.core.api.error.ApiErrorDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.AuthServiceException; +import at.ac.tuwien.ifs.dbrepo.core.exception.NotAllowedException; +import at.ac.tuwien.ifs.dbrepo.core.exception.UserNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.service.UserService; import io.micrometer.observation.annotation.Observed; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.ArraySchema; @@ -132,9 +132,9 @@ public class UserEndpoint extends AbstractEndpoint { schema = @Schema(implementation = ApiErrorDto.class))}), }) public ResponseEntity<UserDto> find(@NotNull @PathVariable("userId") UUID userId, - @NotNull Principal principal) throws NotAllowedException, + Principal principal) throws NotAllowedException, UserNotFoundException { - log.debug("endpoint find a user, userId={}, principal.name={}", userId, principal.getName()); + log.debug("endpoint find a user, userId={}", userId); /* check */ final User user = userService.findById(userId); if (!user.getId().equals(getId(principal)) && !hasRole(principal, "find-foreign-user")) { @@ -192,7 +192,7 @@ public class UserEndpoint extends AbstractEndpoint { }) public ResponseEntity<UserBriefDto> modify(@NotNull @PathVariable("userId") UUID userId, @NotNull @Valid @RequestBody UserUpdateDto data, - @NotNull Principal principal) throws NotAllowedException, + Principal principal) throws NotAllowedException, UserNotFoundException, AuthServiceException { log.debug("endpoint modify a user, userId={}, data={}", userId, data); final User user = userService.findById(userId); 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/ac/tuwien/ifs/dbrepo/endpoints/ViewEndpoint.java similarity index 83% rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java rename to dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/endpoints/ViewEndpoint.java index 2cc187c884e658a6d6dae8a76ce6ffdeb94a2d61..2c4bfd4e44d22e7def2846da883b6c555e0d2551 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/ac/tuwien/ifs/dbrepo/endpoints/ViewEndpoint.java @@ -1,18 +1,19 @@ -package at.tuwien.endpoints; +package at.ac.tuwien.ifs.dbrepo.endpoints; -import at.tuwien.api.database.CreateViewDto; -import at.tuwien.api.database.ViewBriefDto; -import at.tuwien.api.database.ViewDto; -import at.tuwien.api.database.ViewUpdateDto; -import at.tuwien.api.error.ApiErrorDto; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.database.View; -import at.tuwien.entities.user.User; -import at.tuwien.exception.*; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.service.DatabaseService; -import at.tuwien.service.UserService; -import at.tuwien.service.ViewService; +import at.ac.tuwien.ifs.dbrepo.core.api.database.CreateViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.error.ApiErrorDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.DatabaseAccess; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.View; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.service.DashboardService; +import at.ac.tuwien.ifs.dbrepo.service.DatabaseService; +import at.ac.tuwien.ifs.dbrepo.service.UserService; +import at.ac.tuwien.ifs.dbrepo.service.ViewService; import io.micrometer.observation.annotation.Observed; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.ArraySchema; @@ -33,6 +34,7 @@ import org.springframework.web.bind.annotation.*; import java.security.Principal; import java.util.List; +import java.util.Optional; import java.util.UUID; import java.util.stream.Collectors; @@ -46,14 +48,16 @@ public class ViewEndpoint extends AbstractEndpoint { private final ViewService viewService; private final MetadataMapper metadataMapper; private final DatabaseService databaseService; + private final DashboardService dashboardService; @Autowired public ViewEndpoint(UserService userService, ViewService viewService, MetadataMapper metadataMapper, - DatabaseService databaseService) { + DatabaseService databaseService, DashboardService dashboardService) { this.userService = userService; this.viewService = viewService; this.metadataMapper = metadataMapper; this.databaseService = databaseService; + this.dashboardService = dashboardService; } @GetMapping @@ -79,13 +83,7 @@ public class ViewEndpoint extends AbstractEndpoint { DatabaseNotFoundException { log.debug("endpoint find all views, databaseId={}", databaseId); final Database database = databaseService.findById(databaseId); - final User caller; - if (principal != null) { - caller = userService.findById(getId(principal)); - } else { - caller = null; - } - return ResponseEntity.ok(viewService.findAll(database, caller) + return ResponseEntity.ok(filterViews(database, principal) .stream() .map(metadataMapper::viewToViewBriefDto) .collect(Collectors.toList())); @@ -142,10 +140,10 @@ public class ViewEndpoint extends AbstractEndpoint { }) public ResponseEntity<ViewBriefDto> create(@NotNull @PathVariable("databaseId") UUID databaseId, @NotNull @Valid @RequestBody CreateViewDto data, - @NotNull Principal principal) throws NotAllowedException, + Principal principal) throws NotAllowedException, MalformedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException, SearchServiceException, SearchServiceConnectionException, TableNotFoundException, - ImageNotFoundException, ViewExistsException { + ImageNotFoundException, ViewExistsException, DashboardServiceException, DashboardServiceConnectionException { log.debug("endpoint create view, databaseId={}, data.name={}", databaseId, data.getName()); final Database database = databaseService.findById(databaseId); if (!database.getOwner().getId().equals(getId(principal))) { @@ -156,9 +154,10 @@ public class ViewEndpoint extends AbstractEndpoint { log.error("Failed to create view: name exists"); throw new ViewExistsException("Failed to create view: name exists"); } + final View view = viewService.create(database, userService.findById(getId(principal)), data); + dashboardService.update(view.getDatabase()); return ResponseEntity.status(HttpStatus.CREATED) - .body(metadataMapper.viewToViewBriefDto( - viewService.create(database, userService.findById(getId(principal)), data))); + .body(metadataMapper.viewToViewBriefDto(view)); } @GetMapping("/{viewId}") @@ -187,12 +186,27 @@ public class ViewEndpoint extends AbstractEndpoint { public ResponseEntity<ViewDto> find(@NotNull @PathVariable("databaseId") UUID databaseId, @NotNull @PathVariable("viewId") UUID viewId, Principal principal) throws DatabaseNotFoundException, - ViewNotFoundException { + ViewNotFoundException, NotAllowedException { log.debug("endpoint find view, databaseId={}, viewId={}", databaseId, viewId); final Database database = databaseService.findById(databaseId); final View view = viewService.findById(database, viewId); - return ResponseEntity.status(HttpStatus.OK) - .body(metadataMapper.viewToViewDto(view)); + if (principal != null) { + if (isSystem(principal)) { + return ResponseEntity.ok(metadataMapper.viewToViewDto(view)); + } + final Optional<DatabaseAccess> optional = database.getAccesses() + .stream() + .filter(a -> a.getHuserid().equals(getId(principal))) + .findFirst(); + if (view.getIsPublic() || view.getIsSchemaPublic() || optional.isPresent()) { + return ResponseEntity.ok(metadataMapper.viewToViewDto(view)); + } + } + if (!view.getIsPublic() && !view.getIsSchemaPublic()) { + log.error("Failed to find view: not public and no access found"); + throw new NotAllowedException("Failed to find view: not public and no access found"); + } + return ResponseEntity.ok(metadataMapper.viewToViewDto(view)); } @DeleteMapping("/{viewId}") @@ -238,9 +252,10 @@ public class ViewEndpoint extends AbstractEndpoint { }) public ResponseEntity<Void> delete(@NotNull @PathVariable("databaseId") UUID databaseId, @NotNull @PathVariable("viewId") UUID viewId, - @NotNull Principal principal) throws NotAllowedException, DataServiceException, + Principal principal) throws NotAllowedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, ViewNotFoundException, SearchServiceException, - SearchServiceConnectionException, UserNotFoundException { + SearchServiceConnectionException, UserNotFoundException, DashboardServiceException, + DashboardServiceConnectionException { log.debug("endpoint delete view, databaseId={}, viewId={}", databaseId, viewId); final Database database = databaseService.findById(databaseId); if (!database.getOwner().getId().equals(getId(principal))) { @@ -249,6 +264,7 @@ public class ViewEndpoint extends AbstractEndpoint { } final View view = viewService.findById(database, viewId); viewService.delete(view); + dashboardService.update(databaseService.findById(databaseId)); return ResponseEntity.accepted() .build(); } @@ -292,9 +308,10 @@ public class ViewEndpoint extends AbstractEndpoint { public ResponseEntity<ViewBriefDto> update(@NotNull @PathVariable("databaseId") UUID databaseId, @NotNull @PathVariable("viewId") UUID viewId, @NotNull @Valid @RequestBody ViewUpdateDto data, - @NotNull Principal principal) throws NotAllowedException, + Principal principal) throws NotAllowedException, DataServiceConnectionException, DatabaseNotFoundException, ViewNotFoundException, SearchServiceException, - SearchServiceConnectionException, UserNotFoundException { + SearchServiceConnectionException, UserNotFoundException, DashboardServiceException, + DashboardServiceConnectionException { log.debug("endpoint update view, databaseId={}, viewId={}", databaseId, viewId); final Database database = databaseService.findById(databaseId); final View view = viewService.findById(database, viewId); @@ -302,9 +319,10 @@ public class ViewEndpoint extends AbstractEndpoint { log.error("Failed to update view: not the database- or view owner"); throw new NotAllowedException("Failed to update view: not the database- or view owner"); } + final View view1 = viewService.update(view, data); + dashboardService.update(view1.getDatabase()); return ResponseEntity.accepted() - .body(metadataMapper.viewToViewBriefDto( - viewService.update(database, view, data))); + .body(metadataMapper.viewToViewBriefDto(view1)); } } diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/handlers/ApiExceptionHandler.java similarity index 96% rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java rename to dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/handlers/ApiExceptionHandler.java index eadce489d9e2cb689012e5f9f4eaafeed0093566..0d4a6170016a3f138d734e872939905e5e17278d 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/handlers/ApiExceptionHandler.java @@ -1,7 +1,7 @@ -package at.tuwien.handlers; +package at.ac.tuwien.ifs.dbrepo.handlers; -import at.tuwien.api.error.ApiErrorDto; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.api.error.ApiErrorDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import com.auth0.jwt.exceptions.TokenExpiredException; import io.swagger.v3.oas.annotations.Hidden; import jakarta.ws.rs.NotAuthorizedException; @@ -130,6 +130,20 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler { return generic_handle(e.getClass(), e.getLocalizedMessage()); } + @Hidden + @ResponseStatus(code = HttpStatus.BAD_GATEWAY) + @ExceptionHandler(DashboardServiceConnectionException.class) + public ResponseEntity<ApiErrorDto> handle(DashboardServiceConnectionException e) { + return generic_handle(e.getClass(), e.getLocalizedMessage()); + } + + @Hidden + @ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE) + @ExceptionHandler(DashboardServiceException.class) + public ResponseEntity<ApiErrorDto> handle(DashboardServiceException e) { + return generic_handle(e.getClass(), e.getLocalizedMessage()); + } + @Hidden @ResponseStatus(code = HttpStatus.EXPECTATION_FAILED) @ExceptionHandler(DatabaseMalformedException.class) 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/ac/tuwien/ifs/dbrepo/validation/EndpointValidator.java similarity index 94% rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java rename to dbrepo-metadata-service/rest-service/src/main/java/at/ac/tuwien/ifs/dbrepo/validation/EndpointValidator.java index 6fe29c118bd47683874cd4a92397c62317de3a83..8068a8d734102988195943163733b0e2cb35cd5f 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/ac/tuwien/ifs/dbrepo/validation/EndpointValidator.java @@ -1,19 +1,19 @@ -package at.tuwien.validation; +package at.ac.tuwien.ifs.dbrepo.validation; -import at.tuwien.SortType; -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; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.database.DatabaseAccess; -import at.tuwien.entities.database.table.Table; -import at.tuwien.entities.user.User; -import at.tuwien.exception.*; -import at.tuwien.service.AccessService; -import at.tuwien.service.UserService; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.CreateTableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.SortType; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.CreateTableColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierSaveDto; +import at.ac.tuwien.ifs.dbrepo.endpoints.AbstractEndpoint; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.AccessType; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.DatabaseAccess; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.Table; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.service.AccessService; +import at.ac.tuwien.ifs.dbrepo.service.UserService; import lombok.extern.log4j.Log4j2; import org.apache.commons.validator.GenericValidator; import org.springframework.beans.factory.annotation.Autowired; 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 deleted file mode 100644 index 7ec1471f4d1f110e9d6eefff902b6190a4dbde5b..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AbstractEndpoint.java +++ /dev/null @@ -1,53 +0,0 @@ -package at.tuwien.endpoints; - -import at.tuwien.api.container.ContainerDto; -import at.tuwien.api.user.UserDetailsDto; -import org.springframework.security.core.Authentication; - -import java.security.Principal; -import java.util.UUID; - -public abstract class AbstractEndpoint { - - public boolean hasRole(Principal principal, String role) { - if (principal == null || role == null) { - return false; - } - final Authentication authentication = (Authentication) principal; - return authentication.getAuthorities() - .stream() - .anyMatch(a -> a.getAuthority().equals(role)); - } - - public boolean isSystem(Principal principal) { - if (principal == null) { - return false; - } - final Authentication authentication = (Authentication) principal; - return authentication.getAuthorities() - .stream() - .anyMatch(a -> a.getAuthority().equals("system")); - } - - public UUID getId(Principal principal) { - if (principal == null) { - return null; - } - final Authentication authentication = (Authentication) principal; - if (authentication.getPrincipal() instanceof UserDetailsDto user) { - if (user.getId() == null) { - throw new IllegalArgumentException("Principal has no id"); - } - return UUID.fromString(user.getId()); - } - 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/resources/application.yml b/dbrepo-metadata-service/rest-service/src/main/resources/application.yml index a8a16759829dcf376b75b1de02029cfb16fddc80..681a6db8dde2656bca3378aff80431e39ee4e304 100644 --- a/dbrepo-metadata-service/rest-service/src/main/resources/application.yml +++ b/dbrepo-metadata-service/rest-service/src/main/resources/application.yml @@ -48,15 +48,22 @@ logging: at.tuwien.: "${LOG_LEVEL:info}" org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver: debug dbrepo: + datacite: + url: "${DATACITE_URL:https://api.datacite.org}" + prefix: "${DATACITE_PREFIX}" + username: "${DATACITE_USERNAME}" + password: "${DATACITE_PASSWORD}" endpoints: analyseService: "${ANALYSE_SERVICE_ENDPOINT:http://analyse-service:8080}" - searchService: "${SEARCH_SERVICE_ENDPOINT:http://search-service:8080}" - dataService: "${DATA_SERVICE_ENDPOINT:http://data-service:8080}" - brokerService: "${BROKER_SERVICE_ENDPOINT:http://broker-service:15672}" authService: "${AUTH_SERVICE_ENDPOINT:http://auth-service:8080}" - storageService: "${S3_ENDPOINT:http://storage-service:9000}" - rorService: "${ROR_ENDPOINT:https://api.ror.org}" + brokerService: "${BROKER_SERVICE_ENDPOINT:http://broker-service:15672}" crossRefService: "${CROSSREF_ENDPOINT:http://data.crossref.org}" + dashboardService: "${DASHBOARD_SERVICE_ENDPOINT:http://dashboard-service:8080}" + doiService: "${DOI_ENDPOINT:https://doi.org}" + dataService: "${DATA_SERVICE_ENDPOINT:http://data-service:8080}" + rorService: "${ROR_ENDPOINT:https://api.ror.org}" + searchService: "${SEARCH_SERVICE_ENDPOINT:http://search-service:8080}" + storageService: "${S3_ENDPOINT:http://storage-service:9000}" s3: accessKeyId: "${S3_ACCESS_KEY_ID:seaweedfsadmin}" secretAccessKey: "${S3_SECRET_ACCESS_KEY:seaweedfsadmin}" diff --git a/dbrepo-metadata-service/rest-service/src/main/resources/datatypes.json b/dbrepo-metadata-service/rest-service/src/main/resources/datatypes.json deleted file mode 100644 index 3779d12cbe32b67fa163cf6b0285b9e01f7dc681..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/rest-service/src/main/resources/datatypes.json +++ /dev/null @@ -1,15 +0,0 @@ -[ - { - "name": "", - "size": { - "min": 0, - "required": true - }, - "d": { - "required": false - }, - "documentation": "https://mariadb.com/kb/en/bigint/", - "quoted": false, - "buildable": true - } -] \ No newline at end of file diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/ApplicationIntegrationTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/ApplicationIntegrationTest.java similarity index 86% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/ApplicationIntegrationTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/ApplicationIntegrationTest.java index 33c7bc76c552c70989dbc4ffc39e317fdb5826ac..30b82efb1f626c07a866f9f7f157149a905e6556 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/ApplicationIntegrationTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/ApplicationIntegrationTest.java @@ -1,4 +1,4 @@ -package at.tuwien; +package at.ac.tuwien.ifs.dbrepo; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.Test; @@ -17,7 +17,7 @@ public class ApplicationIntegrationTest { public void main_succeeds() { /* test */ - DbrepoMetadataServiceApplication.main(new String[]{}); + MetadataServiceApplication.main(new String[]{}); } } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/config/ObjectMapperConfig.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/config/ObjectMapperConfig.java similarity index 95% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/config/ObjectMapperConfig.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/config/ObjectMapperConfig.java index 6cbf682c8d26d93fef6884a45159a8f238e6f953..508540f52a345246feec8269f351377063d02bdd 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/config/ObjectMapperConfig.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/config/ObjectMapperConfig.java @@ -1,4 +1,4 @@ -package at.tuwien.config; +package at.ac.tuwien.ifs.dbrepo.config; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/config/RabbitConfig.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/config/RabbitConfig.java similarity index 91% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/config/RabbitConfig.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/config/RabbitConfig.java index f8a83baf85c36852073f120f182f1819280dec67..3dddb8cf33d8adade6efc587daf0d50dec057acb 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/config/RabbitConfig.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/config/RabbitConfig.java @@ -1,6 +1,6 @@ -package at.tuwien.config; +package at.ac.tuwien.ifs.dbrepo.config; -import at.tuwien.test.BaseTest; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.Getter; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Value; @@ -11,6 +11,8 @@ import org.springframework.http.client.support.BasicAuthenticationInterceptor; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.DefaultUriBuilderFactory; +import java.io.IOException; + @Getter @Log4j2 @Configuration 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/ac/tuwien/ifs/dbrepo/converters/IdentifierStatusTypeDtoConverterUnitTest.java similarity index 75% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierStatusTypeDtoConverterUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/converters/IdentifierStatusTypeDtoConverterUnitTest.java index 8c7316b3d15590979652ea4a04498271f068d2fc..20f1f615eb786b1f44697f9fa7a50b2671a3baa2 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierStatusTypeDtoConverterUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/converters/IdentifierStatusTypeDtoConverterUnitTest.java @@ -1,28 +1,24 @@ -package at.tuwien.converters; +package at.ac.tuwien.ifs.dbrepo.converters; -import at.tuwien.api.identifier.IdentifierStatusTypeDto; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierStatusTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; 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 java.io.IOException; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @Log4j2 @SpringBootTest -public class IdentifierStatusTypeDtoConverterUnitTest extends AbstractUnitTest { +public class IdentifierStatusTypeDtoConverterUnitTest extends BaseTest { @Autowired private IdentifierStatusTypeDtoConverter identifierStatusTypeDtoConverter; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void identifierStatusTypeDtoConverter_succeeds() { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeDtoConverterUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/converters/IdentifierTypeDtoConverterUnitTest.java similarity index 75% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeDtoConverterUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/converters/IdentifierTypeDtoConverterUnitTest.java index 98abd668d8ec0e30a0f420682a0c7b7fd3e5704d..1d73cc34452a120c9da246457693fff9dd6615f4 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeDtoConverterUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/converters/IdentifierTypeDtoConverterUnitTest.java @@ -1,28 +1,24 @@ -package at.tuwien.converters; +package at.ac.tuwien.ifs.dbrepo.converters; -import at.tuwien.api.identifier.IdentifierTypeDto; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; 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 java.io.IOException; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @Log4j2 @SpringBootTest -public class IdentifierTypeDtoConverterUnitTest extends AbstractUnitTest { +public class IdentifierTypeDtoConverterUnitTest extends BaseTest { @Autowired private IdentifierTypeDtoConverter identifierTypeDtoConverter; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void IdentifierTypeDtoConverter_succeeds() { 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/ac/tuwien/ifs/dbrepo/endpoints/AbstractEndpointUnitTest.java similarity index 56% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AbstractEndpointUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/AbstractEndpointUnitTest.java index dfa4924957b9c300aeda92ad2ed305a4dd29b444..52ffe690fa39b99d37308277005391f72f568093 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AbstractEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/AbstractEndpointUnitTest.java @@ -1,53 +1,27 @@ -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; +package at.ac.tuwien.ifs.dbrepo.endpoints; + +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserDetailsDto; 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 { +public class AbstractEndpointUnitTest extends BaseTest { @Autowired private AccessEndpoint accessEndpoint; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void hasRole_noPrincipal_fails() { 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/ac/tuwien/ifs/dbrepo/endpoints/AccessEndpointUnitTest.java similarity index 86% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/AccessEndpointUnitTest.java index 49b5d48de8602ad79473142a3f05e36c336d97b9..3c041352ea8b74846cf1693176799ac66fbed5fd 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/ac/tuwien/ifs/dbrepo/endpoints/AccessEndpointUnitTest.java @@ -1,18 +1,19 @@ -package at.tuwien.endpoints; - -import at.tuwien.api.database.AccessTypeDto; -import at.tuwien.api.database.DatabaseAccessDto; -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; +package at.ac.tuwien.ifs.dbrepo.endpoints; + +import at.ac.tuwien.ifs.dbrepo.core.api.database.AccessTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseAccessDto; +import at.ac.tuwien.ifs.dbrepo.core.api.grafana.CreateDashboardResponseDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.DatabaseAccess; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; +import at.ac.tuwien.ifs.dbrepo.service.AccessService; +import at.ac.tuwien.ifs.dbrepo.service.DashboardService; +import at.ac.tuwien.ifs.dbrepo.service.DatabaseService; +import at.ac.tuwien.ifs.dbrepo.service.UserService; 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; @@ -37,7 +38,7 @@ import static org.mockito.Mockito.*; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class AccessEndpointUnitTest extends AbstractUnitTest { +public class AccessEndpointUnitTest extends BaseTest { @MockBean private AccessService accessService; @@ -48,17 +49,15 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { @MockBean private UserService userService; + @MockBean + private DashboardService dashboardService; + @Autowired private AccessEndpoint accessEndpoint; @Autowired private MetadataMapper metadataMapper; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test @WithAnonymousUser public void create_anonymous_fails() { @@ -113,7 +112,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_1_USERNAME, authorities = {"create-database-access"}) public void create_succeeds() throws DataServiceException, DataServiceConnectionException, NotAllowedException, DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException, SearchServiceException, - SearchServiceConnectionException { + SearchServiceConnectionException, DashboardServiceException, DashboardServiceConnectionException { /* mock */ when(accessService.create(eq(DATABASE_1), eq(USER_2), any(AccessTypeDto.class))) @@ -208,7 +207,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_1_USERNAME, authorities = {"update-database-access"}) public void update_succeeds() throws NotAllowedException, DataServiceException, DataServiceConnectionException, AccessNotFoundException, DatabaseNotFoundException, UserNotFoundException, SearchServiceException, - SearchServiceConnectionException { + SearchServiceConnectionException, DashboardServiceException, DashboardServiceConnectionException { /* mock */ doNothing() @@ -216,7 +215,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { .update(eq(DATABASE_1), eq(USER_2), any(AccessTypeDto.class)); /* test */ - generic_update(USER_1_PRINCIPAL, USER_1, USER_2_ID, USER_2, DATABASE_1_USER_2_WRITE_OWN_ACCESS); + generic_update(USER_1_PRINCIPAL, USER_1, USER_2_ID, USER_2, DATABASE_1_USER_1_READ_ACCESS); } @Test @@ -293,7 +292,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-database-access"}) public void revoke_succeeds() throws NotAllowedException, DataServiceException, DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, AccessNotFoundException, SearchServiceException, - SearchServiceConnectionException { + SearchServiceConnectionException, DashboardServiceException, DashboardServiceConnectionException { /* mock */ doNothing() @@ -311,7 +310,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { protected void generic_create(Principal principal, User principalUser, UUID userId, User user, DatabaseAccess access) throws NotAllowedException, DataServiceException, DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, AccessNotFoundException, SearchServiceException, - SearchServiceConnectionException { + SearchServiceConnectionException, DashboardServiceException, DashboardServiceConnectionException { /* mock */ when(databaseService.findById(DATABASE_1_ID)) @@ -340,6 +339,10 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { .when(userService) .findById(any(UUID.class)); } + when(dashboardService.create(DATABASE_1)) + .thenReturn(CreateDashboardResponseDto.builder() + .uid(DATABASE_1_DASHBOARD_UID) + .build()); /* test */ final ResponseEntity<?> response = accessEndpoint.create(DATABASE_1_ID, userId, UPDATE_DATABASE_ACCESS_READ_DTO, principal); @@ -384,7 +387,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { protected void generic_update(Principal principal, User principalUser, UUID userId, User user, DatabaseAccess access) throws NotAllowedException, DataServiceException, DataServiceConnectionException, AccessNotFoundException, UserNotFoundException, DatabaseNotFoundException, - SearchServiceException, SearchServiceConnectionException { + SearchServiceException, SearchServiceConnectionException, DashboardServiceException, DashboardServiceConnectionException { /* mock */ when(databaseService.findById(DATABASE_1_ID)) @@ -415,6 +418,9 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { .when(userService) .findByUsername(anyString()); } + doNothing() + .when(dashboardService) + .updateAccess(DATABASE_1, user, AccessTypeDto.READ); /* test */ final ResponseEntity<?> response = accessEndpoint.update(DATABASE_1_ID, userId, UPDATE_DATABASE_ACCESS_READ_DTO, principal); @@ -425,7 +431,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { protected void generic_revoke(Principal principal, User principalUser, UUID userId, User user) throws DataServiceConnectionException, NotAllowedException, DataServiceException, UserNotFoundException, DatabaseNotFoundException, AccessNotFoundException, SearchServiceException, - SearchServiceConnectionException { + SearchServiceConnectionException, DashboardServiceException, DashboardServiceConnectionException { /* mock */ when(databaseService.findById(DATABASE_1_ID)) @@ -436,6 +442,9 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { } when(userService.findById(userId)) .thenReturn(user); + doNothing() + .when(dashboardService) + .updateAccess(DATABASE_1, user, null); /* test */ final ResponseEntity<?> response = accessEndpoint.revoke(DATABASE_1_ID, userId, principal); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ActuatorComponentTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/ActuatorComponentTest.java similarity index 85% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ActuatorComponentTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/ActuatorComponentTest.java index 78b7f086c300b546c808ed161abef2e3712e64c3..f86a8c4e8b4641ad05d9d2b62a233b56df38953a 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ActuatorComponentTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/ActuatorComponentTest.java @@ -1,8 +1,7 @@ -package at.tuwien.endpoints; +package at.ac.tuwien.ifs.dbrepo.endpoints; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; 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; @@ -11,6 +10,8 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; +import java.io.IOException; + 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.jsonPath; @@ -20,16 +21,11 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @ExtendWith(SpringExtension.class) @AutoConfigureMockMvc @SpringBootTest -public class ActuatorComponentTest extends AbstractUnitTest { +public class ActuatorComponentTest extends BaseTest { @Autowired private MockMvc mockMvc; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void actuatorInfo_succeeds() throws Exception { this.mockMvc.perform(get("/actuator/info")) diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ConceptEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/ConceptEndpointUnitTest.java similarity index 77% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ConceptEndpointUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/ConceptEndpointUnitTest.java index d48317f119cbbdf51087b16fc4c8df999bd519bb..ba1d324299c2dc1541345a53376a9dadb08572ed 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ConceptEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/ConceptEndpointUnitTest.java @@ -1,10 +1,9 @@ -package at.tuwien.endpoints; +package at.ac.tuwien.ifs.dbrepo.endpoints; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.api.database.table.columns.concepts.ConceptDto; -import at.tuwien.service.ConceptService; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.concepts.ConceptDto; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; +import at.ac.tuwien.ifs.dbrepo.service.ConceptService; 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; @@ -18,13 +17,14 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import java.util.List; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.Mockito.when; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class ConceptEndpointUnitTest extends AbstractUnitTest { +public class ConceptEndpointUnitTest extends BaseTest { @MockBean private ConceptService conceptService; @@ -32,11 +32,6 @@ public class ConceptEndpointUnitTest extends AbstractUnitTest { @Autowired private ConceptEndpoint conceptEndpoint; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test @WithAnonymousUser public void findAllConcepts_anonymous_succeeds() { @@ -46,7 +41,7 @@ public class ConceptEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_4_USERNAME, authorities = {}) + @WithMockUser(username = USER_4_USERNAME) public void findAllConcepts_noRole_succeeds() { /* test */ @@ -70,5 +65,5 @@ public class ConceptEndpointUnitTest extends AbstractUnitTest { assertNotNull(body); assertEquals(2, body.size()); } - + } 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/ac/tuwien/ifs/dbrepo/endpoints/ContainerEndpointUnitTest.java similarity index 85% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ContainerEndpointUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/ContainerEndpointUnitTest.java index 67078ee40971e42f91d04b764cc5bd0f4ac2d088..0933ab65ef5cb699f35b3c45691c450fcdacedd7 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/ac/tuwien/ifs/dbrepo/endpoints/ContainerEndpointUnitTest.java @@ -1,16 +1,15 @@ -package at.tuwien.endpoints; - -import at.tuwien.api.container.ContainerBriefDto; -import at.tuwien.api.container.ContainerDto; -import at.tuwien.api.container.CreateContainerDto; -import at.tuwien.entities.container.Container; -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; +package at.ac.tuwien.ifs.dbrepo.endpoints; + +import at.ac.tuwien.ifs.dbrepo.core.api.container.ContainerBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.ContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.CreateContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.Container; +import at.ac.tuwien.ifs.dbrepo.core.exception.ContainerAlreadyExistsException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ContainerNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ImageNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; +import at.ac.tuwien.ifs.dbrepo.service.impl.ContainerServiceImpl; 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; @@ -34,7 +33,7 @@ import static org.mockito.Mockito.when; @Log4j2 @ExtendWith(SpringExtension.class) @SpringBootTest -public class ContainerEndpointUnitTest extends AbstractUnitTest { +public class ContainerEndpointUnitTest extends BaseTest { @MockBean private ContainerServiceImpl containerService; @@ -42,11 +41,6 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest { @Autowired private ContainerEndpoint containerEndpoint; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test @WithAnonymousUser public void findById_anonymous_succeeds() throws ContainerNotFoundException { @@ -74,7 +68,7 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest { assertEquals(List.of("" + CONTAINER_1_PORT), headers.get("X-Port")); 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(IMAGE_1_JDBC), headers.get("X-Jdbc-Method")); + assertEquals(List.of(IMAGE_1_JDBC_METHOD), headers.get("X-Jdbc-Method")); assertEquals(List.of("X-Username X-Password X-Jdbc-Method X-Host X-Port"), headers.get("Access-Control-Expose-Headers")); } @@ -135,7 +129,7 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest { public void create_anonymous_fails() { final CreateContainerDto request = CreateContainerDto.builder() .name(CONTAINER_1_NAME) - .imageId(IMAGE_1_ID) + .imageId(CONTAINER_1_ID) .build(); /* test */ @@ -149,7 +143,7 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest { public void create_hasRole_succeeds() throws ContainerAlreadyExistsException, ImageNotFoundException { final CreateContainerDto request = CreateContainerDto.builder() .name(CONTAINER_1_NAME) - .imageId(IMAGE_1_ID) + .imageId(CONTAINER_1_ID) .build(); /* test */ @@ -161,7 +155,7 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest { public void create_noRole_fails() { final CreateContainerDto request = CreateContainerDto.builder() .name(CONTAINER_1_NAME) - .imageId(IMAGE_1_ID) + .imageId(CONTAINER_1_ID) .build(); /* test */ @@ -226,11 +220,11 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest { final ContainerBriefDto container1 = body.get(0); assertEquals(CONTAINER_1_ID, container1.getId()); assertEquals(CONTAINER_1_NAME, container1.getName()); - assertEquals(CONTAINER_1_INTERNALNAME, container1.getInternalName()); + assertEquals(CONTAINER_1_INTERNAL_NAME, container1.getInternalName()); final ContainerBriefDto container2 = body.get(1); assertEquals(CONTAINER_2_ID, container2.getId()); assertEquals(CONTAINER_2_NAME, container2.getName()); - assertEquals(CONTAINER_2_INTERNALNAME, container2.getInternalName()); + assertEquals(CONTAINER_2_INTERNAL_NAME, container2.getInternalName()); } public void create_generic(CreateContainerDto data) throws ContainerAlreadyExistsException, ImageNotFoundException { 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/ac/tuwien/ifs/dbrepo/endpoints/DatabaseEndpointUnitTest.java similarity index 88% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/DatabaseEndpointUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/DatabaseEndpointUnitTest.java index a52a0a8880420651c649776c48ff77814c31d34f..7f185fd98968c15d0b5dcdc17a9225ec1f22345e 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/ac/tuwien/ifs/dbrepo/endpoints/DatabaseEndpointUnitTest.java @@ -1,14 +1,14 @@ -package at.tuwien.endpoints; - -import at.tuwien.api.database.*; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.user.User; -import at.tuwien.exception.*; -import at.tuwien.service.*; -import at.tuwien.service.impl.DatabaseServiceImpl; -import at.tuwien.test.AbstractUnitTest; +package at.ac.tuwien.ifs.dbrepo.endpoints; + +import at.ac.tuwien.ifs.dbrepo.core.api.database.*; +import at.ac.tuwien.ifs.dbrepo.core.api.grafana.CreateDashboardResponseDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; +import at.ac.tuwien.ifs.dbrepo.service.*; +import at.ac.tuwien.ifs.dbrepo.service.impl.DatabaseServiceImpl; 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; @@ -34,7 +34,7 @@ import static org.mockito.Mockito.*; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class DatabaseEndpointUnitTest extends AbstractUnitTest { +public class DatabaseEndpointUnitTest extends BaseTest { @MockBean private BrokerService messageQueueService; @@ -54,21 +54,20 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @MockBean private StorageService storageService; + @MockBean + private DashboardService dashboardService; + @Autowired private DatabaseEndpoint databaseEndpoint; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test @WithAnonymousUser public void create_anonymous_fails() { final CreateDatabaseDto request = CreateDatabaseDto.builder() .cid(CONTAINER_1_ID) - .name(DATABASE_1_NAME) - .isPublic(DATABASE_1_PUBLIC) + .name(DATABASE_1.getName()) + .isPublic(DATABASE_1.getIsPublic()) + .isSchemaPublic(DATABASE_1.getIsSchemaPublic()) .build(); /* test */ @@ -81,9 +80,10 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_4_USERNAME) public void create_noRole_fails() { final CreateDatabaseDto request = CreateDatabaseDto.builder() - .cid(CONTAINER_3_ID) - .name(DATABASE_3_NAME) - .isPublic(DATABASE_3_PUBLIC) + .cid(CONTAINER_1_ID) + .name(DATABASE_3.getName()) + .isPublic(DATABASE_3.getIsPublic()) + .isSchemaPublic(DATABASE_3.getIsSchemaPublic()) .build(); /* test */ @@ -97,11 +97,12 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { public void create_succeeds() throws DataServiceException, DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, ContainerNotFoundException, SearchServiceException, SearchServiceConnectionException, AuthServiceException, AuthServiceConnectionException, - BrokerServiceException, BrokerServiceConnectionException, ContainerQuotaException { + BrokerServiceException, BrokerServiceConnectionException, ContainerQuotaException, + DashboardServiceException, DashboardServiceConnectionException { final CreateDatabaseDto request = CreateDatabaseDto.builder() .cid(CONTAINER_1_ID) - .name(DATABASE_1_NAME) - .isPublic(DATABASE_1_PUBLIC) + .name(DATABASE_1.getName()) + .isPublic(DATABASE_1.getIsPublic()) .build(); /* mock */ @@ -122,13 +123,13 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_1_USERNAME, authorities = {"create-database"}) public void create_quotaExceeded_fails() throws UserNotFoundException, ContainerNotFoundException { final CreateDatabaseDto request = CreateDatabaseDto.builder() - .cid(CONTAINER_4_ID) - .name(DATABASE_1_NAME) - .isPublic(DATABASE_1_PUBLIC) + .cid(CONTAINER_4.getId()) + .name(DATABASE_1.getName()) + .isPublic(DATABASE_1.getIsPublic()) .build(); /* mock */ - when(containerService.find(CONTAINER_4_ID)) + when(containerService.find(CONTAINER_4.getId())) .thenReturn(CONTAINER_4); when(userService.findById(USER_1_ID)) .thenReturn(USER_1); @@ -203,8 +204,8 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"find-database"}) public void refreshViewMetadata_succeeds() throws UserNotFoundException, SearchServiceException, - NotAllowedException, DataServiceException, QueryNotFoundException, DatabaseNotFoundException, - SearchServiceConnectionException, DataServiceConnectionException, ViewNotFoundException { + NotAllowedException, DataServiceException, DatabaseNotFoundException, SearchServiceConnectionException, + DataServiceConnectionException, ViewNotFoundException { /* mock */ when(databaseService.findById(DATABASE_1_ID)) @@ -285,7 +286,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { public void list_hasRole_succeeds() { /* pre-condition */ - assertTrue(DATABASE_3_PUBLIC); + assertTrue(DATABASE_3.getIsPublic()); /* mock */ when(databaseService.findAllPublicOrSchemaPublicOrReadAccess(any(UUID.class))) @@ -300,7 +301,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { public void list_hasRoleForeign_succeeds() { /* pre-condition */ - assertTrue(DATABASE_3_PUBLIC); + assertTrue(DATABASE_3.getIsPublic()); /* mock */ when(databaseService.findAllPublicOrSchemaPublicOrReadAccess(USER_1_ID)) @@ -315,11 +316,11 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { public void list_hasRoleFilter_succeeds() { /* mock */ - when(databaseService.findAllPublicOrSchemaPublicOrReadAccessByInternalName(USER_1_ID, DATABASE_3_INTERNALNAME)) + when(databaseService.findAllPublicOrSchemaPublicOrReadAccessByInternalName(USER_1_ID, DATABASE_3.getInternalName())) .thenReturn(List.of(DATABASE_3)); /* test */ - list_generic(DATABASE_3_INTERNALNAME, USER_1_PRINCIPAL, 1); + list_generic(DATABASE_3.getInternalName(), USER_1_PRINCIPAL, 1); } @Test @@ -351,11 +352,11 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { public void list_hasSystemRoleFilterByName_succeeds() { /* mock */ - when(databaseService.findByInternalName(DATABASE_1_INTERNALNAME)) + when(databaseService.findByInternalName(DATABASE_1.getInternalName())) .thenReturn(List.of(DATABASE_1)); /* test */ - list_generic(DATABASE_1_INTERNALNAME, USER_LOCAL_ADMIN_PRINCIPAL, 1); + list_generic(DATABASE_1.getInternalName(), USER_LOCAL_ADMIN_PRINCIPAL, 1); } @Test @@ -386,7 +387,8 @@ 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 { + DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException, + DashboardServiceException, DashboardServiceConnectionException { final DatabaseModifyVisibilityDto request = DatabaseModifyVisibilityDto.builder() .isPublic(true) .build(); @@ -654,7 +656,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { /* mock */ when(accessService.list(DATABASE_1)) - .thenReturn(List.of(DATABASE_1_USER_1_WRITE_ALL_ACCESS, DATABASE_1_USER_2_READ_ACCESS)); + .thenReturn(List.of(DATABASE_1.getAccesses().get(0), DATABASE_1.getAccesses().get(1))); /* test */ final ResponseEntity<DatabaseDto> response = findById_generic(DATABASE_1_ID, DATABASE_1, USER_1_PRINCIPAL); @@ -671,7 +673,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { /* mock */ when(accessService.list(DATABASE_1)) - .thenReturn(List.of(DATABASE_1_USER_1_WRITE_ALL_ACCESS, DATABASE_1_USER_2_READ_ACCESS)); + .thenReturn(List.of(DATABASE_1.getAccesses().get(0), DATABASE_1.getAccesses().get(1))); /* test */ final ResponseEntity<DatabaseDto> response = findById_generic(DATABASE_1_ID, DATABASE_1, USER_2_PRINCIPAL); @@ -688,7 +690,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { /* mock */ when(accessService.list(DATABASE_1)) - .thenReturn(List.of(DATABASE_1_USER_1_WRITE_ALL_ACCESS, DATABASE_1_USER_2_READ_ACCESS)); + .thenReturn(List.of(DATABASE_1.getAccesses().get(0), DATABASE_1.getAccesses().get(1))); /* test */ final ResponseEntity<DatabaseDto> response = findById_generic(DATABASE_1_ID, DATABASE_1, USER_1_PRINCIPAL); @@ -730,7 +732,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { assertEquals(List.of("" + CONTAINER_1_PORT), headers.get("X-Port")); 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(IMAGE_1_JDBC), headers.get("X-Jdbc-Method")); + assertEquals(List.of(IMAGE_1_JDBC_METHOD), headers.get("X-Jdbc-Method")); assertEquals(List.of("X-Username X-Password X-Jdbc-Method X-Host X-Port"), headers.get("Access-Control-Expose-Headers")); } @@ -795,9 +797,10 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { } public void create_generic(CreateDatabaseDto data, Principal principal, User user) throws DataServiceException, - DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, + DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, BrokerServiceException, ContainerNotFoundException, SearchServiceException, SearchServiceConnectionException, - BrokerServiceException, BrokerServiceConnectionException, ContainerQuotaException { + BrokerServiceConnectionException, ContainerQuotaException, DashboardServiceException, + DashboardServiceConnectionException { /* mock */ doNothing() @@ -805,6 +808,10 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { .setVirtualHostPermissions(user); when(databaseService.findById(any(UUID.class))) .thenReturn(DATABASE_1); + when(dashboardService.create(DATABASE_1)) + .thenReturn(CreateDashboardResponseDto.builder() + .uid(DATABASE_1_DASHBOARD_UID) + .build()); /* test */ final ResponseEntity<DatabaseBriefDto> response = databaseEndpoint.create(data, principal); @@ -814,7 +821,8 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { public void visibility_generic(UUID databaseId, Database database, DatabaseModifyVisibilityDto data, Principal principal) throws NotAllowedException, DatabaseNotFoundException, - SearchServiceException, SearchServiceConnectionException, UserNotFoundException { + SearchServiceException, SearchServiceConnectionException, DashboardServiceException, + DashboardServiceConnectionException { /* mock */ if (database != null) { 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/ac/tuwien/ifs/dbrepo/endpoints/IdentifierEndpointUnitTest.java similarity index 92% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/IdentifierEndpointUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/IdentifierEndpointUnitTest.java index 59aca6a405cf0086fb1cc39e033d4865a33df082..38b8ee221794b7fd353e1fa86e7a11a3b8405106 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/ac/tuwien/ifs/dbrepo/endpoints/IdentifierEndpointUnitTest.java @@ -1,22 +1,20 @@ -package at.tuwien.endpoints; - -import at.tuwien.api.identifier.*; -import at.tuwien.api.identifier.ld.LdDatasetDto; -import at.tuwien.config.EndpointConfig; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.database.DatabaseAccess; -import at.tuwien.entities.identifier.Identifier; -import at.tuwien.entities.identifier.IdentifierType; -import at.tuwien.entities.user.User; -import at.tuwien.exception.*; -import at.tuwien.gateway.DataServiceGateway; -import at.tuwien.service.*; -import at.tuwien.test.AbstractUnitTest; +package at.ac.tuwien.ifs.dbrepo.endpoints; + +import at.ac.tuwien.ifs.dbrepo.config.EndpointConfig; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.*; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.ld.LdDatasetDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.DatabaseAccess; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.Identifier; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.IdentifierType; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; +import at.ac.tuwien.ifs.dbrepo.gateway.DataServiceGateway; +import at.ac.tuwien.ifs.dbrepo.service.*; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.log4j.Log4j2; import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -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; @@ -37,7 +35,6 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.security.Principal; import java.util.List; @@ -50,7 +47,7 @@ import static org.mockito.Mockito.*; @Log4j2 @ExtendWith(SpringExtension.class) @SpringBootTest -public class IdentifierEndpointUnitTest extends AbstractUnitTest { +public class IdentifierEndpointUnitTest extends BaseTest { @MockBean private IdentifierService identifierService; @@ -84,10 +81,10 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { public static Stream<Arguments> save_parameters() { return Stream.of( - Arguments.arguments("foreign_subset", DATABASE_2_ID, DATABASE_2, null, IDENTIFIER_5, IDENTIFIER_5_SAVE_DTO, USER_1_PRINCIPAL, USER_1), - Arguments.arguments("foreign_database", DATABASE_1_ID, DATABASE_1, null, IDENTIFIER_1, IDENTIFIER_1_SAVE_DTO, USER_1_PRINCIPAL, USER_1), - Arguments.arguments("foreign_view", DATABASE_1_ID, DATABASE_1, null, IDENTIFIER_3, IDENTIFIER_3_SAVE_DTO, USER_1_PRINCIPAL, USER_1), - Arguments.arguments("foreign_table", DATABASE_1_ID, DATABASE_1, null, IDENTIFIER_4, IDENTIFIER_4_SAVE_DTO, USER_1_PRINCIPAL, USER_1) + Arguments.arguments("foreign_subset", 2, 5, 1), + Arguments.arguments("foreign_database", 1, 1, 1), + Arguments.arguments("foreign_view", 1, 3, 1), + Arguments.arguments("foreign_table", 1, 4, 1) ); } @@ -143,22 +140,22 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { public static Stream<Arguments> findAll_filterDatabase_parameters() { return Stream.of( - 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, 1, 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("database_dbid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, null, null, 1, 1), + Arguments.arguments("database_qid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, QUERY_1_ID, null, null, 1, 1), + Arguments.arguments("database_vid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, VIEW_1_ID, null, 0, 1), + Arguments.arguments("database_tid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, null, TABLE_1_ID, 0, 1), + Arguments.arguments("subset_dbid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, null, null, null, 1, 1), + Arguments.arguments("subset_qid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, QUERY_1_ID, null, null, 1, 1), + Arguments.arguments("subset_vid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, null, VIEW_1_ID, null, 0, 1), + Arguments.arguments("subset_tid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, null, null, TABLE_1_ID, 0, 1), + Arguments.arguments("view_dbid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, null, null, null, 1, 1), + Arguments.arguments("view_qid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, QUERY_1_ID, null, null, 0, 1), + Arguments.arguments("view_vid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, null, VIEW_1_ID, null, 1, 1), + Arguments.arguments("view_tid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, null, null, TABLE_1_ID, 0, 1), + Arguments.arguments("table_dbid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, null, null, null, 1, 1), + Arguments.arguments("table_qid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, QUERY_1_ID, null, null, 0, 1), + Arguments.arguments("table_vid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, null, VIEW_1_ID, null, 0, 1), + Arguments.arguments("table_tid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, null, null, TABLE_1_ID, 1, 1), 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, 1, null), Arguments.arguments("anon_database_vid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, VIEW_1_ID, null, 0, null), @@ -180,17 +177,12 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { public static Stream<Arguments> save_foreign_parameters() { return Stream.of( - Arguments.arguments("view", IDENTIFIER_3, IDENTIFIER_3_SAVE_DTO), - Arguments.arguments("table", IDENTIFIER_4, IDENTIFIER_4_SAVE_DTO), - Arguments.arguments("subset", IDENTIFIER_2, IDENTIFIER_2_SAVE_DTO) + Arguments.arguments("view", 3), + Arguments.arguments("table", 4), + Arguments.arguments("subset", 2) ); } - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test @WithAnonymousUser public void findAll_empty_succeeds() { @@ -290,7 +282,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void findAll_filterDatabase_succeeds(String name, IdentifierTypeDto type, IdentifierStatusTypeDto status, UUID databaseId, UUID queryId, UUID viewId, UUID tableId, - Integer expectedSize, Principal principal) throws ViewNotFoundException, + Integer expectedSize, Integer idx) throws ViewNotFoundException, TableNotFoundException, DatabaseNotFoundException { /* mock */ @@ -304,6 +296,12 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { when(tableService.findById(DATABASE_1, TABLE_1_ID)) .thenReturn(TABLE_1); } + final Principal principal; + if (idx == null) { + principal = null; + } else { + principal = USER_1_PRINCIPAL; + } /* test */ final ResponseEntity<?> response = identifierEndpoint.findAll(type, status, databaseId, queryId, viewId, tableId, "application/json", principal); @@ -430,11 +428,11 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { final IdentifierDto compare = objectMapper.readValue(FileUtils.readFileToString(new File("src/test/resources/json/metadata0.json"), StandardCharsets.UTF_8), IdentifierDto.class); /* mock */ - when(identifierService.find(IDENTIFIER_7_ID)) + when(identifierService.find(IDENTIFIER_7.getId())) .thenReturn(IDENTIFIER_7); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept, USER_4_PRINCIPAL); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7.getId(), accept, USER_4_PRINCIPAL); assertEquals(HttpStatus.OK, response.getStatusCode()); final IdentifierDto body = (IdentifierDto) response.getBody(); assertNotNull(body); @@ -535,12 +533,12 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { /* mock */ when(identifierService.exportBibliography(IDENTIFIER_7, BibliographyTypeDto.APA)) .thenReturn(compare); - when(identifierService.find(IDENTIFIER_7_ID)) + when(identifierService.find(IDENTIFIER_7.getId())) .thenReturn(IDENTIFIER_7); /* test */ assertThrows(NotAllowedException.class, () -> { - identifierEndpoint.find(IDENTIFIER_7_ID, accept, null); + identifierEndpoint.find(IDENTIFIER_7.getId(), accept, null); }); } @@ -556,11 +554,11 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { /* mock */ when(identifierService.exportBibliography(IDENTIFIER_7, BibliographyTypeDto.APA)) .thenReturn(compare); - when(identifierService.find(IDENTIFIER_7_ID)) + when(identifierService.find(IDENTIFIER_7.getId())) .thenReturn(IDENTIFIER_7); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept, USER_4_PRINCIPAL); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7.getId(), accept, USER_4_PRINCIPAL); assertEquals(HttpStatus.OK, response.getStatusCode()); final String body = (String) response.getBody(); assertNotNull(body); @@ -649,7 +647,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { when(identifierService.exportBibliography(any(Identifier.class), eq(BibliographyTypeDto.APA))) .thenReturn(compare); when(identifierService.find(IDENTIFIER_1_ID)) - .thenReturn(IDENTIFIER_1_WITH_DOI); + .thenReturn(IDENTIFIER_1); /* test */ final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null); @@ -671,11 +669,11 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { /* mock */ when(identifierService.exportBibliography(IDENTIFIER_7, BibliographyTypeDto.IEEE)) .thenReturn(compare); - when(identifierService.find(IDENTIFIER_7_ID)) + when(identifierService.find(IDENTIFIER_7.getId())) .thenReturn(IDENTIFIER_7); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept, USER_4_PRINCIPAL); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7.getId(), accept, USER_4_PRINCIPAL); assertEquals(HttpStatus.OK, response.getStatusCode()); final String body = (String) response.getBody(); assertNotNull(body); @@ -741,7 +739,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { when(identifierService.exportBibliography(any(Identifier.class), eq(BibliographyTypeDto.IEEE))) .thenReturn(compare); when(identifierService.find(IDENTIFIER_1_ID)) - .thenReturn(IDENTIFIER_1_WITH_DOI); + .thenReturn(IDENTIFIER_1); /* test */ final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null); @@ -763,11 +761,11 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { /* mock */ when(identifierService.exportBibliography(IDENTIFIER_7, BibliographyTypeDto.BIBTEX)) .thenReturn(compare); - when(identifierService.find(IDENTIFIER_7_ID)) + when(identifierService.find(IDENTIFIER_7.getId())) .thenReturn(IDENTIFIER_7); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept, USER_4_PRINCIPAL); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7.getId(), accept, USER_4_PRINCIPAL); assertEquals(HttpStatus.OK, response.getStatusCode()); final String body = (String) response.getBody(); assertNotNull(body); @@ -833,7 +831,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { when(identifierService.exportBibliography(any(Identifier.class), eq(BibliographyTypeDto.BIBTEX))) .thenReturn(compare); when(identifierService.find(IDENTIFIER_1_ID)) - .thenReturn(IDENTIFIER_1_WITH_DOI); + .thenReturn(IDENTIFIER_1); /* test */ final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null); @@ -867,12 +865,12 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { final String accept = "text/csv"; /* mock */ - when(identifierService.find(IDENTIFIER_7_ID)) + when(identifierService.find(IDENTIFIER_7.getId())) .thenReturn(IDENTIFIER_7); /* test */ assertThrows(NotAllowedException.class, () -> { - identifierEndpoint.find(IDENTIFIER_7_ID, accept, null); + identifierEndpoint.find(IDENTIFIER_7.getId(), accept, null); }); } @@ -900,7 +898,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_1_USERNAME, authorities = {}) + @WithMockUser(username = USER_1_USERNAME) public void delete_noRole_fails() { /* test */ @@ -919,9 +917,8 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_2_USERNAME, authorities = {"delete-identifier"}) - public void delete_alreadyPublished_fails() throws DataServiceException, DataServiceConnectionException, - DatabaseNotFoundException, IdentifierNotFoundException, SearchServiceException, - SearchServiceConnectionException { + public void delete_alreadyPublished_fails() throws DatabaseNotFoundException, IdentifierNotFoundException, + SearchServiceException, SearchServiceConnectionException { /* mock */ when(identifierService.find(IDENTIFIER_1_ID)) @@ -1270,16 +1267,35 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @ParameterizedTest @MethodSource("save_foreign_parameters") @WithMockUser(username = USER_1_USERNAME, authorities = {"create-identifier"}) - public void save_foreign_fails(String name, Identifier identifier, IdentifierSaveDto data) + public void save_foreign_fails(String name, Integer idx) throws UserNotFoundException { /* mock */ when(userService.findById(USER_1_ID)) .thenReturn(USER_1); + final Identifier identifier; + final IdentifierSaveDto identifierSave = switch (idx) { + case 2 -> { + identifier = IDENTIFIER_2; + yield IDENTIFIER_2_SAVE_DTO; + } + case 3 -> { + identifier = IDENTIFIER_3; + yield IDENTIFIER_3_SAVE_DTO; + } + case 4 -> { + identifier = IDENTIFIER_4; + yield IDENTIFIER_4_SAVE_DTO; + } + default -> { + identifier = null; + yield null; + } + }; /* test */ assertThrows(NotAllowedException.class, () -> { - generic_save(DATABASE_1_ID, DATABASE_1, null, identifier, data, USER_1_PRINCIPAL, USER_1); + generic_save(DATABASE_1_ID, DATABASE_1, null, identifier, identifierSave, USER_1_PRINCIPAL, USER_1); }); } @@ -1309,12 +1325,60 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @ParameterizedTest @MethodSource("save_parameters") @WithMockUser(username = USER_1_USERNAME, authorities = {"create-identifier"}) - public void save_noForeign_fails(String name, UUID databaseId, Database database, DatabaseAccess access, - Identifier identifier, IdentifierSaveDto data, Principal principal, User user) { + public void save_noForeign_fails(String name, Integer dbIdx, Integer idIdx, Integer uIdx) { + final UUID databaseId; + final Database database = switch (dbIdx) { + case 1 -> { + databaseId = DATABASE_1_ID; + yield DATABASE_1; + } + case 2 -> { + databaseId = DATABASE_2_ID; + yield DATABASE_2; + } + default -> { + databaseId = null; + yield null; + } + }; + final IdentifierSaveDto identifierSave; + final Identifier identifier = switch (idIdx) { + case 1 -> { + identifierSave = IDENTIFIER_1_SAVE_DTO; + yield IDENTIFIER_1; + } + case 3 -> { + identifierSave = IDENTIFIER_3_SAVE_DTO; + yield IDENTIFIER_3; + } + case 4 -> { + identifierSave = IDENTIFIER_4_SAVE_DTO; + yield IDENTIFIER_4; + } + case 5 -> { + identifierSave = IDENTIFIER_5_SAVE_DTO; + yield IDENTIFIER_5; + } + default -> { + identifierSave = null; + yield null; + } + }; + final Principal principal; + final User user = switch (uIdx) { + case 1 -> { + principal = USER_1_PRINCIPAL; + yield USER_1; + } + default -> { + principal = null; + yield null; + } + }; /* test */ assertThrows(NotAllowedException.class, () -> { - generic_save(databaseId, database, access, identifier, data, principal, user); + generic_save(databaseId, database, null, identifier, identifierSave, principal, user); }); } @@ -1356,7 +1420,8 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { .thenReturn(IDENTIFIER_1); /* test */ - final ResponseEntity<IdentifierDto> response = identifierEndpoint.create(IDENTIFIER_1_CREATE_DTO, USER_1_PRINCIPAL); + final ResponseEntity<IdentifierDto> response = identifierEndpoint.create(IDENTIFIER_1_CREATE_DTO, + USER_1_PRINCIPAL); assertEquals(HttpStatus.CREATED, response.getStatusCode()); final IdentifierDto body = response.getBody(); assertNotNull(body); @@ -1496,14 +1561,14 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { SearchServiceConnectionException { /* mock */ - when(identifierService.find(IDENTIFIER_7_ID)) + when(identifierService.find(IDENTIFIER_7.getId())) .thenReturn(IDENTIFIER_7); doNothing() .when(identifierService) .delete(IDENTIFIER_7); /* test */ - final ResponseEntity<?> response = identifierEndpoint.delete(IDENTIFIER_7_ID); + final ResponseEntity<?> response = identifierEndpoint.delete(IDENTIFIER_7.getId()); assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); assertNull(response.getBody()); } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ImageEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/ImageEndpointUnitTest.java similarity index 76% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ImageEndpointUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/ImageEndpointUnitTest.java index b5be98cfb6f8ce6fc0ed840c065dca5524b10502..9a1289a86b3b3884d030e0b4a63203ee16cd9cf1 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ImageEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/ImageEndpointUnitTest.java @@ -1,17 +1,17 @@ -package at.tuwien.endpoints; - -import at.tuwien.api.container.image.ImageBriefDto; -import at.tuwien.api.container.image.ImageChangeDto; -import at.tuwien.api.container.image.ImageCreateDto; -import at.tuwien.api.container.image.ImageDto; -import at.tuwien.entities.container.image.ContainerImage; -import at.tuwien.exception.ImageAlreadyExistsException; -import at.tuwien.exception.ImageInvalidException; -import at.tuwien.exception.ImageNotFoundException; -import at.tuwien.service.impl.ImageServiceImpl; -import at.tuwien.test.AbstractUnitTest; +package at.ac.tuwien.ifs.dbrepo.endpoints; + +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageChangeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.image.ContainerImage; +import at.ac.tuwien.ifs.dbrepo.core.exception.ImageAlreadyExistsException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ImageInvalidException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ImageNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; +import at.ac.tuwien.ifs.dbrepo.service.impl.ImageServiceImpl; 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; @@ -33,7 +33,7 @@ import static org.mockito.Mockito.*; @Log4j2 @ExtendWith(SpringExtension.class) @SpringBootTest -public class ImageEndpointUnitTest extends AbstractUnitTest { +public class ImageEndpointUnitTest extends BaseTest { @MockBean private ImageServiceImpl imageService; @@ -41,10 +41,8 @@ public class ImageEndpointUnitTest extends AbstractUnitTest { @Autowired private ImageEndpoint imageEndpoint; - @BeforeEach - public void beforeEach() { - genesis(); - } + @Autowired + private MetadataMapper metadataMapper; @Test @WithAnonymousUser @@ -76,9 +74,9 @@ public class ImageEndpointUnitTest extends AbstractUnitTest { final ImageCreateDto request = ImageCreateDto.builder() .name(IMAGE_1_NAME) .version(IMAGE_1_VERSION) - .defaultPort(IMAGE_1_PORT) + .defaultPort(IMAGE_1_DEFAULT_PORT) .dialect(IMAGE_1_DIALECT) - .jdbcMethod(IMAGE_1_JDBC) + .jdbcMethod(IMAGE_1_JDBC_METHOD) .build(); /* test */ @@ -93,9 +91,9 @@ public class ImageEndpointUnitTest extends AbstractUnitTest { final ImageCreateDto request = ImageCreateDto.builder() .name(IMAGE_1_NAME) .version(IMAGE_1_VERSION) - .defaultPort(IMAGE_1_PORT) + .defaultPort(IMAGE_1_DEFAULT_PORT) .dialect(IMAGE_1_DIALECT) - .jdbcMethod(IMAGE_1_JDBC) + .jdbcMethod(IMAGE_1_JDBC_METHOD) .build(); /* test */ @@ -110,9 +108,9 @@ public class ImageEndpointUnitTest extends AbstractUnitTest { final ImageCreateDto request = ImageCreateDto.builder() .name(IMAGE_1_NAME) .version(IMAGE_1_VERSION) - .defaultPort(IMAGE_1_PORT) + .defaultPort(IMAGE_1_DEFAULT_PORT) .dialect(IMAGE_1_DIALECT) - .jdbcMethod(IMAGE_1_JDBC) + .jdbcMethod(IMAGE_1_JDBC_METHOD) .build(); /* test */ @@ -126,14 +124,14 @@ public class ImageEndpointUnitTest extends AbstractUnitTest { public void create_succeeds() throws ImageAlreadyExistsException, ImageInvalidException { /* test */ - create_generic(IMAGE_1_CREATE_DTO, USER_1_PRINCIPAL); + create_generic(metadataMapper.containerImageToImageCreateDto(IMAGE_1), USER_1_PRINCIPAL); } @Test public void findById_anonymous_succeeds() throws ImageNotFoundException { /* test */ - findById_generic(IMAGE_1_ID, IMAGE_1); + findById_generic(CONTAINER_1_ID, IMAGE_1); } @Test @@ -156,7 +154,7 @@ public class ImageEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { - delete_generic(IMAGE_1_ID, IMAGE_1); + delete_generic(CONTAINER_1_ID, IMAGE_1); }); } @@ -166,7 +164,7 @@ public class ImageEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { - delete_generic(IMAGE_1_ID, IMAGE_1); + delete_generic(CONTAINER_1_ID, IMAGE_1); }); } @@ -180,22 +178,22 @@ public class ImageEndpointUnitTest extends AbstractUnitTest { .delete(IMAGE_1); /* test */ - delete_generic(IMAGE_1_ID, IMAGE_1); + delete_generic(CONTAINER_1_ID, IMAGE_1); } @Test @WithAnonymousUser public void modify_anonymous_fails() { final ImageChangeDto request = ImageChangeDto.builder() - .defaultPort(IMAGE_1_PORT) + .defaultPort(IMAGE_1_DEFAULT_PORT) .dialect(IMAGE_1_DIALECT) - .jdbcMethod(IMAGE_1_JDBC) - .driverClass(IMAGE_1_DRIVER) + .jdbcMethod(IMAGE_1_JDBC_METHOD) + .driverClass(IMAGE_1.getDriverClass()) .build(); /* test */ assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { - modify_generic(IMAGE_1_ID, IMAGE_1, request); + modify_generic(CONTAINER_1_ID, IMAGE_1, request); }); } @@ -203,15 +201,15 @@ public class ImageEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_4_USERNAME) public void modify_noRole_fails() { final ImageChangeDto request = ImageChangeDto.builder() - .defaultPort(IMAGE_1_PORT) + .defaultPort(IMAGE_1_DEFAULT_PORT) .dialect(IMAGE_1_DIALECT) - .jdbcMethod(IMAGE_1_JDBC) - .driverClass(IMAGE_1_DRIVER) + .jdbcMethod(IMAGE_1_JDBC_METHOD) + .driverClass(IMAGE_1.getDriverClass()) .build(); /* test */ assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { - modify_generic(IMAGE_1_ID, IMAGE_1, request); + modify_generic(CONTAINER_1_ID, IMAGE_1, request); }); } @@ -219,15 +217,15 @@ public class ImageEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_2_USERNAME, authorities = {"modify-image"}) public void modify_hasRole_succeeds() throws ImageNotFoundException { final ImageChangeDto request = ImageChangeDto.builder() - .registry(IMAGE_1_REGISTRY) - .defaultPort(IMAGE_1_PORT) + .registry(IMAGE_1.getRegistry()) + .defaultPort(IMAGE_1_DEFAULT_PORT) .dialect(IMAGE_1_DIALECT) - .jdbcMethod(IMAGE_1_JDBC) - .driverClass(IMAGE_1_DRIVER) + .jdbcMethod(IMAGE_1_JDBC_METHOD) + .driverClass(IMAGE_1.getDriverClass()) .build(); /* test */ - modify_generic(IMAGE_1_ID, IMAGE_1, request); + modify_generic(CONTAINER_1_ID, IMAGE_1, request); } /* ################################################################################################### */ diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/LicenseEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/LicenseEndpointUnitTest.java similarity index 82% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/LicenseEndpointUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/LicenseEndpointUnitTest.java index f45dd85fb4d13423451599e8ffc3cd046a8ebdca..765d16dc834d717659f08eecaa81e1021cc75ce5 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/LicenseEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/LicenseEndpointUnitTest.java @@ -1,10 +1,9 @@ -package at.tuwien.endpoints; +package at.ac.tuwien.ifs.dbrepo.endpoints; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.api.database.LicenseDto; -import at.tuwien.repository.LicenseRepository; +import at.ac.tuwien.ifs.dbrepo.core.api.database.LicenseDto; +import at.ac.tuwien.ifs.dbrepo.repository.LicenseRepository; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; 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; @@ -23,7 +22,7 @@ import static org.mockito.Mockito.when; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class LicenseEndpointUnitTest extends AbstractUnitTest { +public class LicenseEndpointUnitTest extends BaseTest { @MockBean private LicenseRepository licenseRepository; @@ -31,11 +30,6 @@ public class LicenseEndpointUnitTest extends AbstractUnitTest { @Autowired private LicenseEndpoint licenseEndpoint; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void list_succeeds() { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/MessageEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/MessageEndpointUnitTest.java similarity index 87% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/MessageEndpointUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/MessageEndpointUnitTest.java index 0fabc67c9175fdde835e8c14a8cbbabdc14d158f..f31518e8e20bce9c0bbd6c2b296d91469dc9c693 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/MessageEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/MessageEndpointUnitTest.java @@ -1,14 +1,13 @@ -package at.tuwien.endpoints; - -import at.tuwien.exception.MessageNotFoundException; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.api.maintenance.BannerMessageCreateDto; -import at.tuwien.api.maintenance.BannerMessageDto; -import at.tuwien.api.maintenance.BannerMessageUpdateDto; -import at.tuwien.entities.maintenance.BannerMessage; -import at.tuwien.service.BannerMessageService; +package at.ac.tuwien.ifs.dbrepo.endpoints; + +import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageDto; +import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.maintenance.BannerMessage; +import at.ac.tuwien.ifs.dbrepo.core.exception.MessageNotFoundException; +import at.ac.tuwien.ifs.dbrepo.service.BannerMessageService; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; 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; @@ -29,7 +28,7 @@ import static org.mockito.Mockito.*; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class MessageEndpointUnitTest extends AbstractUnitTest { +public class MessageEndpointUnitTest extends BaseTest { @MockBean private BannerMessageService bannerMessageService; @@ -37,11 +36,6 @@ public class MessageEndpointUnitTest extends AbstractUnitTest { @Autowired private MessageEndpoint messageEndpoint; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test @WithAnonymousUser public void list_anonymous_succeeds() { @@ -127,7 +121,7 @@ public class MessageEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"create-maintenance-message"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"create-maintenance-message"}) public void create_hasRole_succeeds() { /* test */ @@ -155,7 +149,7 @@ public class MessageEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"update-maintenance-message"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"update-maintenance-message"}) public void update_hasRole_succeeds() throws MessageNotFoundException { /* test */ @@ -183,7 +177,7 @@ public class MessageEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"delete-maintenance-message"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"delete-maintenance-message"}) public void delete_hasRole_succeeds() throws MessageNotFoundException { /* test */ @@ -191,7 +185,7 @@ public class MessageEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"delete-maintenance-message"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"delete-maintenance-message"}) public void delete_hasRoleNotFound_fails() { /* test */ diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/MetadataEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/MetadataEndpointUnitTest.java similarity index 92% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/MetadataEndpointUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/MetadataEndpointUnitTest.java index 98f756a1c0a0de2674ecca8732dd319411a95223..012ca1f1c0dc4f8545959870357a96db674a8675 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/MetadataEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/MetadataEndpointUnitTest.java @@ -1,12 +1,11 @@ -package at.tuwien.endpoints; +package at.ac.tuwien.ifs.dbrepo.endpoints; -import at.tuwien.oaipmh.OaiListIdentifiersParameters; -import at.tuwien.oaipmh.OaiRecordParameters; -import at.tuwien.repository.IdentifierRepository; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.utils.XmlUtils; +import at.ac.tuwien.ifs.dbrepo.oaipmh.OaiListIdentifiersParameters; +import at.ac.tuwien.ifs.dbrepo.oaipmh.OaiRecordParameters; +import at.ac.tuwien.ifs.dbrepo.repository.IdentifierRepository; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; +import at.ac.tuwien.ifs.dbrepo.utils.XmlUtils; 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; @@ -27,7 +26,7 @@ import static org.mockito.Mockito.when; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class MetadataEndpointUnitTest extends AbstractUnitTest { +public class MetadataEndpointUnitTest extends BaseTest { @MockBean private IdentifierRepository identifierRepository; @@ -35,11 +34,6 @@ public class MetadataEndpointUnitTest extends AbstractUnitTest { @Autowired private MetadataEndpoint metadataEndpoint; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test @WithAnonymousUser public void identify_succeeds() { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/OntologyEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/OntologyEndpointUnitTest.java similarity index 91% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/OntologyEndpointUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/OntologyEndpointUnitTest.java index ab3d0775ad1a694d9f33d822e65e37ae8772b032..3055de08cd09da60386ab44572e60c628697089a 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/OntologyEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/OntologyEndpointUnitTest.java @@ -1,18 +1,17 @@ -package at.tuwien.endpoints; - -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.api.semantics.*; -import at.tuwien.entities.semantics.Ontology; -import at.tuwien.entities.user.User; -import at.tuwien.exception.*; -import at.tuwien.service.EntityService; -import at.tuwien.service.OntologyService; -import at.tuwien.service.UserService; +package at.ac.tuwien.ifs.dbrepo.endpoints; + +import at.ac.tuwien.ifs.dbrepo.core.api.semantics.*; +import at.ac.tuwien.ifs.dbrepo.core.entity.semantics.Ontology; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.service.EntityService; +import at.ac.tuwien.ifs.dbrepo.service.OntologyService; +import at.ac.tuwien.ifs.dbrepo.service.UserService; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.apache.jena.sys.JenaSystem; import org.hibernate.HibernateException; 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; @@ -34,7 +33,7 @@ import static org.mockito.Mockito.*; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class OntologyEndpointUnitTest extends AbstractUnitTest { +public class OntologyEndpointUnitTest extends BaseTest { @MockBean private OntologyService ontologyService; @@ -53,11 +52,6 @@ public class OntologyEndpointUnitTest extends AbstractUnitTest { JenaSystem.init(); } - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test @WithAnonymousUser public void findAll_anonymous_succeeds() { @@ -142,11 +136,11 @@ public class OntologyEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_3_USERNAME, authorities = {"create-ontology"}) + @WithMockUser(username =USER_3_USERNAME, authorities = {"create-ontology"}) public void create_hasRole_succeeds() throws UserNotFoundException { /* test */ - create_generic(ONTOLOGY_1_CREATE_DTO, USER_3_PRINCIPAL, USER_3_USERNAME, USER_3, ONTOLOGY_1); + create_generic(ONTOLOGY_1_CREATE_DTO, USER_3_PRINCIPAL, USER_3.getUsername(), USER_3, ONTOLOGY_1); } @Test @@ -170,7 +164,7 @@ public class OntologyEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_3_USERNAME, authorities = {"update-ontology"}) + @WithMockUser(username =USER_3_USERNAME, authorities = {"update-ontology"}) public void update_hasRole_succeeds() throws OntologyNotFoundException { /* test */ @@ -198,7 +192,7 @@ public class OntologyEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_3_USERNAME, authorities = {"delete-ontology"}) + @WithMockUser(username =USER_3_USERNAME, authorities = {"delete-ontology"}) public void delete_hasRole_succeeds() throws OntologyNotFoundException { /* test */ @@ -216,7 +210,7 @@ public class OntologyEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_4_USERNAME, authorities = {}) + @WithMockUser(username = USER_4_USERNAME) public void find_noRole_fails() { /* test */ 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/ac/tuwien/ifs/dbrepo/endpoints/TableEndpointUnitTest.java similarity index 78% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/TableEndpointUnitTest.java index 12b6e0a2477246c22a29414fc2d5a1794574e689..9c756b8311dd606157991343626a5e1ac84b1bcb 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/ac/tuwien/ifs/dbrepo/endpoints/TableEndpointUnitTest.java @@ -1,29 +1,28 @@ -package at.tuwien.endpoints; - -import at.tuwien.api.database.table.CreateTableDto; -import at.tuwien.api.database.table.TableBriefDto; -import at.tuwien.api.database.table.TableDto; -import at.tuwien.api.database.table.TableUpdateDto; -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.columns.concepts.ColumnSemanticsUpdateDto; -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; -import at.tuwien.entities.database.DatabaseAccess; -import at.tuwien.entities.database.table.Table; -import at.tuwien.entities.database.table.columns.TableColumn; -import at.tuwien.entities.user.User; -import at.tuwien.exception.*; -import at.tuwien.service.*; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.validation.EndpointValidator; +package at.ac.tuwien.ifs.dbrepo.endpoints; + +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.CreateTableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.CreateTableColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.concepts.ColumnSemanticsUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.CreateTableConstraintsDto; +import at.ac.tuwien.ifs.dbrepo.core.api.semantics.EntityDto; +import at.ac.tuwien.ifs.dbrepo.core.api.semantics.TableColumnEntityDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.DatabaseAccess; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.Table; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumn; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.service.*; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; +import at.ac.tuwien.ifs.dbrepo.validation.EndpointValidator; import lombok.extern.log4j.Log4j2; import org.apache.jena.sys.JenaSystem; 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.junit.jupiter.params.ParameterizedTest; @@ -49,7 +48,7 @@ import static org.mockito.Mockito.*; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class TableEndpointUnitTest extends AbstractUnitTest { +public class TableEndpointUnitTest extends BaseTest { @MockBean private DatabaseService databaseService; @@ -57,12 +56,6 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @MockBean private AccessService accessService; - @MockBean - private UnitService unitService; - - @MockBean - private ConceptService conceptService; - @MockBean private TableService tableService; @@ -101,11 +94,6 @@ public class TableEndpointUnitTest extends AbstractUnitTest { JenaSystem.init(); } - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test @WithAnonymousUser public void list_publicDataPrivateSchemaAnonymous_fails() { @@ -141,7 +129,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { UserNotFoundException, DatabaseNotFoundException, AccessNotFoundException { /* test */ - final ResponseEntity<List<TableBriefDto>> response = generic_list(DATABASE_3_ID, DATABASE_3, USER_1_PRINCIPAL, USER_1, DATABASE_1_USER_1_READ_ACCESS); + final ResponseEntity<List<TableBriefDto>> response = generic_list(DATABASE_3_ID, DATABASE_3, USER_1_PRINCIPAL, USER_1, DATABASE_1.getAccesses().get(0)); assertEquals(HttpStatus.OK, response.getStatusCode()); final List<TableBriefDto> body = response.getBody(); assertNotNull(body); @@ -208,7 +196,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) + @WithMockUser(username =USER_3_USERNAME, authorities = {"create-table"}) public void create_publicDecimalColumnSizeTooSmall_fails() { final CreateTableDto request = CreateTableDto.builder() .name("Some Table") @@ -229,7 +217,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) + @WithMockUser(username =USER_3_USERNAME, authorities = {"create-table"}) public void create_publicDecimalColumnDTooSmall_fails() { final CreateTableDto request = CreateTableDto.builder() .name("Some Table") @@ -251,9 +239,12 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @ParameterizedTest @MethodSource("canHaveSize_parameters") - @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 { + @WithMockUser(username =USER_3_USERNAME, authorities = {"create-table"}) + public void create_publicOptionalSizeNone_succeeds(ColumnTypeDto columnType) throws UserNotFoundException, + SearchServiceException, NotAllowedException, SemanticEntityNotFoundException, TableNotFoundException, + DataServiceConnectionException, MalformedException, DataServiceException, DatabaseNotFoundException, + AccessNotFoundException, OntologyNotFoundException, TableExistsException, SearchServiceConnectionException, + DashboardServiceException, DashboardServiceConnectionException { final CreateTableDto request = CreateTableDto.builder() .name("Some Table") .description("Some Description") @@ -282,9 +273,12 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @ParameterizedTest @MethodSource("canHaveSize_parameters") - @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 { + @WithMockUser(username =USER_3_USERNAME, authorities = {"create-table"}) + public void create_publicOptionalSize_succeeds(ColumnTypeDto columnType) throws UserNotFoundException, + SearchServiceException, NotAllowedException, SemanticEntityNotFoundException, TableNotFoundException, + DataServiceConnectionException, MalformedException, DataServiceException, DatabaseNotFoundException, + AccessNotFoundException, OntologyNotFoundException, TableExistsException, SearchServiceConnectionException, + DashboardServiceException, DashboardServiceConnectionException { final CreateTableDto request = CreateTableDto.builder() .name("Some Table") .description("Some Description") @@ -307,9 +301,12 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @ParameterizedTest @MethodSource("needNothing_parameters") - @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 { + @WithMockUser(username =USER_3_USERNAME, authorities = {"create-table"}) + public void create_publicNeedNothing_succeeds(ColumnTypeDto columnType) throws UserNotFoundException, + SearchServiceException, NotAllowedException, SemanticEntityNotFoundException, TableNotFoundException, + DataServiceConnectionException, MalformedException, DataServiceException, DatabaseNotFoundException, + AccessNotFoundException, OntologyNotFoundException, TableExistsException, SearchServiceConnectionException, + DashboardServiceException, DashboardServiceConnectionException { final CreateTableDto request = CreateTableDto.builder() .name("Some Table") .description("Some Description") @@ -333,9 +330,12 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @ParameterizedTest @MethodSource("needSize_parameters") - @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 { + @WithMockUser(username =USER_3_USERNAME, authorities = {"create-table"}) + public void create_publicNeedSize_succeeds(ColumnTypeDto columnType) throws UserNotFoundException, + SearchServiceException, NotAllowedException, SemanticEntityNotFoundException, TableNotFoundException, + DataServiceConnectionException, MalformedException, DataServiceException, DatabaseNotFoundException, + AccessNotFoundException, OntologyNotFoundException, TableExistsException, SearchServiceConnectionException, + DashboardServiceException, DashboardServiceConnectionException { final CreateTableDto request = CreateTableDto.builder() .name("Some Table") .description("Some Description") @@ -358,7 +358,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @ParameterizedTest @MethodSource("needSize_parameters") - @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) + @WithMockUser(username =USER_3_USERNAME, authorities = {"create-table"}) public void create_publicNeedSizeNone_fails(ColumnTypeDto columnType) { final CreateTableDto request = CreateTableDto.builder() .name("Some Table") @@ -378,145 +378,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { }); } - @Test - @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) - public void create_sets_succeeds() throws UserNotFoundException, SearchServiceException, NotAllowedException, - SemanticEntityNotFoundException, DataServiceConnectionException, TableNotFoundException, MalformedException, - DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, - TableExistsException, SearchServiceConnectionException { - final CreateTableDto request = CreateTableDto.builder() - .name("Some Table") - .description("Some Description") - .columns(List.of(CreateTableColumnDto.builder() - .name("sex") - .type(ColumnTypeDto.SET) - .sets(List.of("male", "female")) - .build())) - .build(); - - /* test */ - generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_PRINCIPAL, USER_1, DATABASE_3_USER_1_WRITE_OWN_ACCESS); - } - - @Test - @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) - public void create_enum_succeeds() throws UserNotFoundException, SearchServiceException, NotAllowedException, - SemanticEntityNotFoundException, DataServiceConnectionException, TableNotFoundException, MalformedException, - DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, - TableExistsException, SearchServiceConnectionException { - final CreateTableDto request = CreateTableDto.builder() - .name("Some Table") - .description("Some Description") - .columns(List.of(CreateTableColumnDto.builder() - .name("sex") - .type(ColumnTypeDto.ENUM) - .enums(List.of("male", "female")) - .build())) - .build(); - - /* test */ - generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_PRINCIPAL, USER_1, DATABASE_3_USER_1_WRITE_OWN_ACCESS); - } - - @Test - @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) - public void create_hasUnit_succeeds() throws UserNotFoundException, SearchServiceException, NotAllowedException, - SemanticEntityNotFoundException, DataServiceConnectionException, TableNotFoundException, MalformedException, - DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, - TableExistsException, SearchServiceConnectionException, UnitNotFoundException { - final CreateTableDto request = CreateTableDto.builder() - .name("Some Table") - .description("Some Description") - .columns(List.of(CreateTableColumnDto.builder() - .name(UNIT_1_NAME) - .type(ColumnTypeDto.INT) - .unitUri(UNIT_1_URI) - .build())) - .build(); - - /* mock */ - when(unitService.find(UNIT_1_URI)) - .thenReturn(UNIT_1); - - /* test */ - generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_PRINCIPAL, USER_1, DATABASE_3_USER_1_WRITE_OWN_ACCESS); - } - - @Test - @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) - public void create_hasUnitNotFound_succeeds() throws UserNotFoundException, SearchServiceException, NotAllowedException, - SemanticEntityNotFoundException, DataServiceConnectionException, TableNotFoundException, MalformedException, - DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, - TableExistsException, SearchServiceConnectionException { - final CreateTableDto request = CreateTableDto.builder() - .name("Some Table") - .description("Some Description") - .columns(List.of(CreateTableColumnDto.builder() - .name(UNIT_1_NAME) - .type(ColumnTypeDto.INT) - .unitUri(UNIT_1_URI) - .build())) - .build(); - - /* mock */ - when(unitService.create(UNIT_1)) - .thenReturn(UNIT_1); - - /* test */ - generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_PRINCIPAL, USER_1, DATABASE_3_USER_1_WRITE_OWN_ACCESS); - } - - @Test - @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) - public void create_hasConcept_succeeds() throws UserNotFoundException, SearchServiceException, NotAllowedException, - SemanticEntityNotFoundException, DataServiceConnectionException, TableNotFoundException, MalformedException, - DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, - TableExistsException, SearchServiceConnectionException, ConceptNotFoundException { - final CreateTableDto request = CreateTableDto.builder() - .name("Some Table") - .description("Some Description") - .columns(List.of(CreateTableColumnDto.builder() - .name(CONCEPT_1_NAME) - .type(ColumnTypeDto.INT) - .conceptUri(UNIT_1_URI) - .build())) - .build(); - - /* mock */ - when(conceptService.find(CONCEPT_1_URI)) - .thenReturn(CONCEPT_1); - - /* test */ - generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_PRINCIPAL, USER_1, DATABASE_3_USER_1_WRITE_OWN_ACCESS); - } - - @Test - @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) - public void create_hasConceptNotFound_succeeds() throws UserNotFoundException, SearchServiceException, NotAllowedException, - SemanticEntityNotFoundException, DataServiceConnectionException, TableNotFoundException, MalformedException, - DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, - TableExistsException, SearchServiceConnectionException { - final CreateTableDto request = CreateTableDto.builder() - .name("Some Table") - .description("Some Description") - .columns(List.of(CreateTableColumnDto.builder() - .name("precipitation") - .type(ColumnTypeDto.INT) - .conceptUri(UNIT_1_URI) - .build())) - .build(); - - /* mock */ - when(conceptService.create(CONCEPT_1)) - .thenReturn(CONCEPT_1); - - /* test */ - generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_PRINCIPAL, USER_1, DATABASE_3_USER_1_WRITE_OWN_ACCESS); - } - @ParameterizedTest @MethodSource("canHaveSizeAndD_parameters") - @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) + @WithMockUser(username =USER_3_USERNAME, authorities = {"create-table"}) public void create_publicCanHaveSizeAndDSizeNone_fails(ColumnTypeDto columnType) { final CreateTableDto request = CreateTableDto.builder() .name("Some Table") @@ -538,7 +402,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @ParameterizedTest @MethodSource("canHaveSizeAndD_parameters") - @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) + @WithMockUser(username =USER_3_USERNAME, authorities = {"create-table"}) public void create_publicCanHaveSizeAndDDNone_fails(ColumnTypeDto columnType) { final CreateTableDto request = CreateTableDto.builder() .name("Some Table") @@ -560,12 +424,12 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @ParameterizedTest @MethodSource("canHaveSizeAndD_parameters") - @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) + @WithMockUser(username =USER_3_USERNAME, authorities = {"create-table"}) public void create_publicCanHaveSizeAndDBothNone_succeeds(ColumnTypeDto columnType) throws UserNotFoundException, SearchServiceException, NotAllowedException, SemanticEntityNotFoundException, DataServiceConnectionException, TableNotFoundException, MalformedException, DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, TableExistsException, - SearchServiceConnectionException { + SearchServiceConnectionException, DashboardServiceException, DashboardServiceConnectionException { final CreateTableDto request = CreateTableDto.builder() .name("Some Table") .description("Some Description") @@ -587,7 +451,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) + @WithMockUser(username =USER_3_USERNAME, authorities = {"create-table"}) public void create_publicHasMultipleSerial_fails() { final CreateTableDto request = CreateTableDto.builder() .name("Some Table") @@ -615,7 +479,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) + @WithMockUser(username =USER_3_USERNAME, authorities = {"create-table"}) public void create_publicSerialNullAllowed_fails() { final CreateTableDto request = CreateTableDto.builder() .name("Some Table") @@ -638,12 +502,12 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @ParameterizedTest @MethodSource("canHaveSizeAndD_parameters") - @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) + @WithMockUser(username =USER_3_USERNAME, authorities = {"create-table"}) public void create_publicCanHaveSizeAndDBothNotNone_succeeds(ColumnTypeDto columnType) throws UserNotFoundException, SearchServiceException, NotAllowedException, SemanticEntityNotFoundException, DataServiceConnectionException, TableNotFoundException, MalformedException, DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, TableExistsException, - SearchServiceConnectionException { + SearchServiceConnectionException, DashboardServiceException, DashboardServiceConnectionException { final CreateTableDto request = CreateTableDto.builder() .name("Some Table") .description("Some Description") @@ -679,7 +543,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(TableNotFoundException.class, () -> { - generic_findById(DATABASE_3_ID, DATABASE_3, TABLE_8_ID, null, USER_1_PRINCIPAL, USER_1, DATABASE_1_USER_1_READ_ACCESS); + generic_findById(DATABASE_3_ID, DATABASE_3, TABLE_8_ID, null, USER_1_PRINCIPAL, USER_1, DATABASE_1.getAccesses().get(0)); }); } @@ -689,7 +553,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(DatabaseNotFoundException.class, () -> { - generic_findById(DATABASE_3_ID, null, TABLE_8_ID, TABLE_8, USER_1_PRINCIPAL, USER_1, DATABASE_1_USER_1_READ_ACCESS); + generic_findById(DATABASE_3_ID, null, TABLE_8_ID, TABLE_8, USER_1_PRINCIPAL, USER_1, DATABASE_1.getAccesses().get(0)); }); } @@ -699,7 +563,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { TableNotFoundException, NotAllowedException, DatabaseNotFoundException, AccessNotFoundException { /* test */ - final ResponseEntity<TableDto> response = generic_findById(DATABASE_3_ID, DATABASE_3, TABLE_8_ID, TABLE_8, USER_1_PRINCIPAL, USER_1, DATABASE_1_USER_1_READ_ACCESS); + final ResponseEntity<TableDto> response = generic_findById(DATABASE_3_ID, DATABASE_3, TABLE_8_ID, TABLE_8, USER_1_PRINCIPAL, USER_1, DATABASE_1.getAccesses().get(0)); assertEquals(HttpStatus.OK, response.getStatusCode()); final TableDto body = response.getBody(); assertNotNull(body); @@ -840,7 +704,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"modify-table-column-semantics"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"modify-table-column-semantics"}) public void update_publicHasRoleForeignHasOwnWriteAccess_fails() { final ColumnSemanticsUpdateDto request = ColumnSemanticsUpdateDto.builder() .unitUri(UNIT_1_URI) @@ -868,7 +732,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"modify-table-column-semantics"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"modify-table-column-semantics"}) public void update_publicHasRoleForeignHasAllWriteAccess_succeeds() throws MalformedException, DataServiceException, NotAllowedException, DataServiceConnectionException, UserNotFoundException, TableNotFoundException, DatabaseNotFoundException, AccessNotFoundException, SearchServiceException, @@ -924,7 +788,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { generic_updateColumn(DATABASE_1_ID, DATABASE_1, TABLE_1_ID, TABLE_1, TABLE_1_COLUMNS.get(0).getId(), - TABLE_1_COLUMNS.get(0), USER_1_PRINCIPAL, USER_1, request, DATABASE_1_USER_1_READ_ACCESS); + TABLE_1_COLUMNS.get(0), USER_1_PRINCIPAL, USER_1, request, DATABASE_1.getAccesses().get(0)); }); } @@ -944,7 +808,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"modify-table-column-semantics"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"modify-table-column-semantics"}) public void update_privateHasRoleForeignHasOwnWriteAccess_fails() { final ColumnSemanticsUpdateDto request = ColumnSemanticsUpdateDto.builder() .unitUri(UNIT_1_URI) @@ -972,7 +836,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"modify-table-column-semantics"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"modify-table-column-semantics"}) public void update_privateHasRoleForeignHasAllWriteAccess_succeeds() throws MalformedException, DataServiceException, NotAllowedException, DataServiceConnectionException, UserNotFoundException, TableNotFoundException, DatabaseNotFoundException, AccessNotFoundException, SearchServiceException, @@ -993,7 +857,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(DatabaseNotFoundException.class, () -> { - generic_list(DATABASE_1_ID, null, USER_1_PRINCIPAL, USER_1, DATABASE_1_USER_1_READ_ACCESS); + generic_list(DATABASE_1_ID, null, USER_1_PRINCIPAL, USER_1, DATABASE_1.getAccesses().get(0)); }); } @@ -1003,7 +867,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { UserNotFoundException, DatabaseNotFoundException, AccessNotFoundException { /* test */ - final ResponseEntity<List<TableBriefDto>> response = generic_list(DATABASE_1_ID, DATABASE_1, USER_1_PRINCIPAL, USER_1, DATABASE_1_USER_1_READ_ACCESS); + final ResponseEntity<List<TableBriefDto>> response = generic_list(DATABASE_1_ID, DATABASE_1, USER_1_PRINCIPAL, USER_1, DATABASE_1.getAccesses().get(0)); assertEquals(HttpStatus.OK, response.getStatusCode()); final List<TableBriefDto> body = response.getBody(); assertNotNull(body); @@ -1055,7 +919,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - generic_create(DATABASE_1_ID, DATABASE_1, TABLE_5_CREATE_DTO, USER_1_PRINCIPAL, USER_1, DATABASE_1_USER_1_READ_ACCESS); + generic_create(DATABASE_1_ID, DATABASE_1, TABLE_5_CREATE_DTO, USER_1_PRINCIPAL, USER_1, DATABASE_1.getAccesses().get(0)); }); } @@ -1086,7 +950,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(TableNotFoundException.class, () -> { - generic_findById(DATABASE_1_ID, DATABASE_1, TABLE_1_ID, null, USER_1_PRINCIPAL, USER_1, DATABASE_1_USER_1_READ_ACCESS); + generic_findById(DATABASE_1_ID, DATABASE_1, TABLE_1_ID, null, USER_1_PRINCIPAL, USER_1, DATABASE_1.getAccesses().get(0)); }); } @@ -1096,7 +960,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(DatabaseNotFoundException.class, () -> { - generic_findById(DATABASE_1_ID, null, TABLE_1_ID, TABLE_1, USER_1_PRINCIPAL, USER_1, DATABASE_1_USER_1_READ_ACCESS); + generic_findById(DATABASE_1_ID, null, TABLE_1_ID, TABLE_1, USER_1_PRINCIPAL, USER_1, DATABASE_1.getAccesses().get(0)); }); } @@ -1106,21 +970,12 @@ public class TableEndpointUnitTest extends AbstractUnitTest { TableNotFoundException, NotAllowedException, DatabaseNotFoundException, AccessNotFoundException { /* test */ final ResponseEntity<TableDto> response = generic_findById(DATABASE_1_ID, DATABASE_1, TABLE_1_ID, TABLE_1, - USER_1_PRINCIPAL, USER_1, DATABASE_1_USER_1_READ_ACCESS); + USER_1_PRINCIPAL, USER_1, DATABASE_1.getAccesses().get(0)); assertEquals(HttpStatus.OK, response.getStatusCode()); final TableDto body = response.getBody(); assertNotNull(body); } - @Test - @WithMockUser(username = USER_4_USERNAME) - public void findById_privateDatabasePrivateDataPrivateSchemaNoRole_succeeds() throws UserNotFoundException, - TableNotFoundException, NotAllowedException, DatabaseNotFoundException, AccessNotFoundException { - - /* test */ - generic_findById(DATABASE_1_ID, DATABASE_1, TABLE_1_ID, TABLE_1, USER_4_PRINCIPAL, USER_4, DATABASE_1_USER_4_READ_ACCESS); - } - @Test @WithMockUser(username = USER_4_USERNAME) public void delete_privateNoRole_fails() { @@ -1135,14 +990,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-table"}) public void delete_succeeds() throws NotAllowedException, DataServiceException, DataServiceConnectionException, TableNotFoundException, DatabaseNotFoundException, SearchServiceException, - SearchServiceConnectionException { + SearchServiceConnectionException, DashboardServiceException, DashboardServiceConnectionException { /* test */ generic_delete(USER_1_PRINCIPAL, TABLE_1); } @Test - @WithMockUser(username = USER_3_USERNAME, authorities = {"delete-table"}) + @WithMockUser(username =USER_3_USERNAME, authorities = {"delete-table"}) public void delete_foreign_fails() { /* test */ @@ -1155,14 +1010,15 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_5_USERNAME, authorities = {"delete-foreign-table"}) public void delete_foreign_succeeds() throws NotAllowedException, DataServiceConnectionException, TableNotFoundException, DatabaseNotFoundException, SearchServiceException, - SearchServiceConnectionException, DataServiceException { + SearchServiceConnectionException, DataServiceException, DashboardServiceException, + DashboardServiceConnectionException { /* test */ generic_delete(USER_5_PRINCIPAL, TABLE_1); } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"delete-table"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"delete-table"}) public void delete_hasIdentifiers_fails() { final Table response = Table.builder() .identifiers(List.of(IDENTIFIER_1)) @@ -1180,7 +1036,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_1_USERNAME, authorities = {"update-table"}) public void update_succeeds() throws TableNotFoundException, SearchServiceException, NotAllowedException, DataServiceException, DatabaseNotFoundException, SearchServiceConnectionException, - DataServiceConnectionException { + DataServiceConnectionException, DashboardServiceException, DashboardServiceConnectionException { final TableUpdateDto request = TableUpdateDto.builder() .isPublic(true) .isSchemaPublic(true) @@ -1194,7 +1050,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"update-table"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"update-table"}) public void update_notOwner_fails() { final TableUpdateDto request = TableUpdateDto.builder() .isPublic(true) @@ -1209,7 +1065,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"update-table-statistic"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"update-table-statistic"}) public void updateStatistic_notOwner_fails() { /* test */ @@ -1311,7 +1167,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { throws MalformedException, NotAllowedException, DataServiceException, DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, AccessNotFoundException, TableNotFoundException, TableExistsException, SearchServiceException, SearchServiceConnectionException, OntologyNotFoundException, - SemanticEntityNotFoundException { + SemanticEntityNotFoundException, DashboardServiceException, DashboardServiceConnectionException { /* mock */ if (principal != null) { @@ -1384,7 +1240,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest { protected ResponseEntity<?> generic_delete(Principal principal, Table table) throws NotAllowedException, DataServiceException, DataServiceConnectionException, TableNotFoundException, DatabaseNotFoundException, - SearchServiceException, SearchServiceConnectionException { + SearchServiceException, SearchServiceConnectionException, DashboardServiceException, + DashboardServiceConnectionException { /* mock */ when(databaseService.findById(DATABASE_1_ID)) @@ -1443,7 +1300,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest { protected ResponseEntity<TableBriefDto> generic_update(TableUpdateDto data, Principal caller) throws TableNotFoundException, SearchServiceException, NotAllowedException, DataServiceException, - DatabaseNotFoundException, SearchServiceConnectionException, DataServiceConnectionException { + DatabaseNotFoundException, SearchServiceConnectionException, DataServiceConnectionException, + DashboardServiceException, DashboardServiceConnectionException { /* mock */ when(databaseService.findById(DATABASE_1_ID)) diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UnitEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/UnitEndpointUnitTest.java similarity index 77% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UnitEndpointUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/UnitEndpointUnitTest.java index 7d74e615be3a24dfd16af29c825774361f1a7ffc..77f8bebaa2c5f6f7172b43244de6434fda3ac548 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UnitEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/UnitEndpointUnitTest.java @@ -1,10 +1,9 @@ -package at.tuwien.endpoints; +package at.ac.tuwien.ifs.dbrepo.endpoints; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.api.database.table.columns.concepts.UnitDto; -import at.tuwien.service.UnitService; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.concepts.UnitDto; +import at.ac.tuwien.ifs.dbrepo.service.UnitService; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; 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; @@ -18,13 +17,14 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import java.util.List; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.Mockito.when; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class UnitEndpointUnitTest extends AbstractUnitTest { +public class UnitEndpointUnitTest extends BaseTest { @MockBean private UnitService unitService; @@ -32,11 +32,6 @@ public class UnitEndpointUnitTest extends AbstractUnitTest { @Autowired private UnitEndpoint unitEndpoint; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test @WithAnonymousUser public void findAllUnits_anonymous_succeeds() { @@ -46,7 +41,7 @@ public class UnitEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_4_USERNAME, authorities = {}) + @WithMockUser(username = USER_4_USERNAME) public void findAllUnits_noRole_succeeds() { /* test */ 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/ac/tuwien/ifs/dbrepo/endpoints/UserEndpointUnitTest.java similarity index 88% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UserEndpointUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/UserEndpointUnitTest.java index 5f0341fa7b53d828554d01f166acbc1c81241860..c24461a16400e5187ae3ac8656073fa9b0d7223f 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/ac/tuwien/ifs/dbrepo/endpoints/UserEndpointUnitTest.java @@ -1,17 +1,16 @@ -package at.tuwien.endpoints; - -import at.tuwien.api.auth.CreateUserDto; -import at.tuwien.api.user.UserBriefDto; -import at.tuwien.api.user.UserDto; -import at.tuwien.api.user.UserUpdateDto; -import at.tuwien.entities.user.User; -import at.tuwien.exception.AuthServiceException; -import at.tuwien.exception.NotAllowedException; -import at.tuwien.exception.UserNotFoundException; -import at.tuwien.service.UserService; -import at.tuwien.test.AbstractUnitTest; +package at.ac.tuwien.ifs.dbrepo.endpoints; + +import at.ac.tuwien.ifs.dbrepo.core.api.auth.CreateUserDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.AuthServiceException; +import at.ac.tuwien.ifs.dbrepo.core.exception.NotAllowedException; +import at.ac.tuwien.ifs.dbrepo.core.exception.UserNotFoundException; +import at.ac.tuwien.ifs.dbrepo.service.UserService; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; 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; @@ -37,7 +36,7 @@ import static org.mockito.Mockito.when; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class UserEndpointUnitTest extends AbstractUnitTest { +public class UserEndpointUnitTest extends BaseTest { @MockBean private UserService userService; @@ -45,11 +44,6 @@ public class UserEndpointUnitTest extends AbstractUnitTest { @Autowired private UserEndpoint userEndpoint; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test @WithAnonymousUser public void findAll_anonymous_succeeds() throws UserNotFoundException { @@ -123,7 +117,7 @@ public class UserEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_3_USERNAME, authorities = {"find-foreign-user"}) + @WithMockUser(username =USER_3_USERNAME, authorities = {"find-foreign-user"}) public void find_hasRoleForeign_succeeds() throws UserNotFoundException, NotAllowedException { final Principal principal = new UsernamePasswordAuthenticationToken(USER_3_DETAILS, USER_3_PASSWORD, List.of( new SimpleGrantedAuthority("find-foreign-user"))); @@ -133,7 +127,7 @@ public class UserEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_3_USERNAME, authorities = {"system"}) + @WithMockUser(username =USER_3_USERNAME, authorities = {"system"}) public void find_system_succeeds() throws UserNotFoundException, NotAllowedException { final Principal principal = new UsernamePasswordAuthenticationToken(USER_3_DETAILS, USER_3_PASSWORD, List.of( new SimpleGrantedAuthority("system"))); @@ -141,7 +135,7 @@ public class UserEndpointUnitTest extends AbstractUnitTest { /* test */ final ResponseEntity<UserDto> response = find_generic(USER_3_ID, USER_3, principal); assertNotNull(response.getHeaders().get("X-Username")); - assertEquals(USER_3_USERNAME, response.getHeaders().get("X-Username").get(0)); + assertEquals(USER_3.getUsername(), response.getHeaders().get("X-Username").get(0)); assertNotNull(response.getHeaders().get("X-Password")); assertNotEquals(USER_3_PASSWORD, response.getHeaders().get("X-Password").get(0)); assertEquals(USER_3_DATABASE_PASSWORD, response.getHeaders().get("X-Password").get(0)); @@ -192,7 +186,7 @@ public class UserEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"modify-user-information"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"modify-user-information"}) public void modify_hasRoleForeign_fails() { final UserUpdateDto request = UserUpdateDto.builder() .firstname(USER_1_FIRSTNAME) @@ -232,7 +226,7 @@ public class UserEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME) + @WithMockUser(username =USER_2_USERNAME) public void create_notInternalUser_fails() { /* test */ 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/ac/tuwien/ifs/dbrepo/endpoints/ViewEndpointUnitTest.java similarity index 77% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ViewEndpointUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/endpoints/ViewEndpointUnitTest.java index ac5a8ef524fe8c4bc40c47e7b8ba0325508a7cc5..d0cb350758e2de484a6ab82871690f1f76183a80 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/ac/tuwien/ifs/dbrepo/endpoints/ViewEndpointUnitTest.java @@ -1,27 +1,22 @@ -package at.tuwien.endpoints; - -import at.tuwien.api.database.CreateViewDto; -import at.tuwien.api.database.ViewBriefDto; -import at.tuwien.api.database.ViewDto; -import at.tuwien.api.database.ViewUpdateDto; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.database.DatabaseAccess; -import at.tuwien.entities.database.View; -import at.tuwien.entities.user.User; -import at.tuwien.exception.*; -import at.tuwien.service.AccessService; -import at.tuwien.service.DatabaseService; -import at.tuwien.service.UserService; -import at.tuwien.service.ViewService; -import at.tuwien.test.AbstractUnitTest; +package at.ac.tuwien.ifs.dbrepo.endpoints; + +import at.ac.tuwien.ifs.dbrepo.core.api.database.CreateViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.DatabaseAccess; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.View; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.service.*; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; 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.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.AccessDeniedException; @@ -39,7 +34,7 @@ import static org.mockito.Mockito.*; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class ViewEndpointUnitTest extends AbstractUnitTest { +public class ViewEndpointUnitTest extends BaseTest { @MockBean private DatabaseService databaseService; @@ -50,17 +45,15 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @MockBean private ViewService viewService; + @MockBean + private DashboardService dashboardService; + @MockBean private UserService userService; @Autowired private ViewEndpoint viewEndpoint; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test @WithAnonymousUser public void findAll_publicAnonymous_succeeds() throws UserNotFoundException, AccessNotFoundException, @@ -71,7 +64,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"list-views"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"list-views"}) public void findAll_publicHasRole_succeeds() throws UserNotFoundException, AccessNotFoundException, DatabaseNotFoundException { @@ -80,7 +73,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"list-views"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"list-views"}) public void findAll_publicHasRoleHasAccess_succeeds() throws UserNotFoundException, AccessNotFoundException, DatabaseNotFoundException { @@ -89,7 +82,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME) + @WithMockUser(username =USER_2_USERNAME) public void findAll_publicNoRole_succeeds() throws UserNotFoundException, AccessNotFoundException, DatabaseNotFoundException { @@ -108,7 +101,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"create-database-view"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"create-database-view"}) public void create_publicHasRole_fails() { /* test */ @@ -118,17 +111,17 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"create-database-view"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"create-database-view"}) public void create_publicHasRoleHasAccess_fails() { /* test */ assertThrows(NotAllowedException.class, () -> { - create_generic(DATABASE_3_ID, DATABASE_3, "View", USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2_USER_1_READ_ACCESS); + create_generic(DATABASE_3_ID, DATABASE_3, "View", USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2.getAccesses().get(0)); }); } @Test - @WithMockUser(username = USER_2_USERNAME) + @WithMockUser(username =USER_2_USERNAME) public void create_publicNoRole_fails() { /* test */ @@ -141,8 +134,8 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_1_USERNAME, authorities = {"create-database-view"}) public void create_succeeds() throws UserNotFoundException, SearchServiceException, MalformedException, NotAllowedException, DataServiceException, DatabaseNotFoundException, AccessNotFoundException, - SearchServiceConnectionException, DataServiceConnectionException, TableNotFoundException, - ImageNotFoundException, ViewExistsException { + SearchServiceConnectionException, DataServiceConnectionException, DashboardServiceException, + DashboardServiceConnectionException, TableNotFoundException, ViewExistsException, ImageNotFoundException { /* test */ create_generic(DATABASE_1_ID, DATABASE_1, "View", USER_1_PRINCIPAL, USER_1_ID, USER_1, DATABASE_1_USER_1_WRITE_ALL_ACCESS); @@ -161,37 +154,37 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser public void find_publicAnonymous_succeeds() throws UserNotFoundException, DatabaseNotFoundException, - AccessNotFoundException, ViewNotFoundException { + AccessNotFoundException, ViewNotFoundException, NotAllowedException { /* test */ find_generic(DATABASE_3_ID, DATABASE_3, null, null, null, null); } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"find-database-view"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"find-database-view"}) public void find_publicHasRole_succeeds() throws UserNotFoundException, DatabaseNotFoundException, - AccessNotFoundException, ViewNotFoundException { + AccessNotFoundException, ViewNotFoundException, NotAllowedException { /* test */ - find_generic(DATABASE_3_ID, DATABASE_3, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2_USER_1_READ_ACCESS); + find_generic(DATABASE_3_ID, DATABASE_3, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2.getAccesses().get(0)); } @Test - @WithMockUser(username = USER_2_USERNAME) + @WithMockUser(username =USER_2_USERNAME) public void find_publicNoRole_succeeds() throws UserNotFoundException, DatabaseNotFoundException, - AccessNotFoundException, ViewNotFoundException { + AccessNotFoundException, ViewNotFoundException, NotAllowedException { /* test */ - find_generic(DATABASE_3_ID, DATABASE_3, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2_USER_1_READ_ACCESS); + find_generic(DATABASE_3_ID, DATABASE_3, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2.getAccesses().get(0)); } @Test - @WithMockUser(username = USER_2_USERNAME) + @WithMockUser(username =USER_2_USERNAME) public void find_publicHasRoleHasAccess_succeeds() throws UserNotFoundException, DatabaseNotFoundException, - AccessNotFoundException, ViewNotFoundException { + AccessNotFoundException, ViewNotFoundException, NotAllowedException { /* test */ - find_generic(DATABASE_3_ID, DATABASE_3, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2_USER_1_READ_ACCESS); + find_generic(DATABASE_3_ID, DATABASE_3, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2.getAccesses().get(0)); } @Test @@ -205,30 +198,31 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"delete-database-view"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"delete-database-view"}) public void delete_publicHasRole_fails() { /* test */ assertThrows(NotAllowedException.class, () -> { - delete_generic(DATABASE_3_ID, DATABASE_3, VIEW_1_ID, VIEW_1, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2_USER_1_READ_ACCESS); + delete_generic(DATABASE_3_ID, DATABASE_3, VIEW_1_ID, VIEW_1, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2.getAccesses().get(0)); }); } @Test - @WithMockUser(username = USER_2_USERNAME) + @WithMockUser(username =USER_2_USERNAME) public void delete_publicNoRole_fails() { /* test */ assertThrows(AccessDeniedException.class, () -> { - delete_generic(DATABASE_3_ID, DATABASE_3, VIEW_1_ID, VIEW_1, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2_USER_1_READ_ACCESS); + delete_generic(DATABASE_3_ID, DATABASE_3, VIEW_1_ID, VIEW_1, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2.getAccesses().get(0)); }); } @Test - @WithMockUser(username = USER_3_USERNAME, authorities = {"delete-database-view"}) + @WithMockUser(username =USER_3_USERNAME, authorities = {"delete-database-view"}) public void delete_publicOwner_succeeds() throws NotAllowedException, DataServiceException, UserNotFoundException, DataServiceConnectionException, DatabaseNotFoundException, AccessNotFoundException, ViewNotFoundException, - SearchServiceException, SearchServiceConnectionException { + SearchServiceException, SearchServiceConnectionException, DashboardServiceException, + DashboardServiceConnectionException { /* test */ delete_generic(DATABASE_3_ID, DATABASE_3, VIEW_5_ID, VIEW_5, USER_3_PRINCIPAL, USER_3_ID, USER_3, DATABASE_3_USER_1_WRITE_ALL_ACCESS); @@ -248,7 +242,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"list-views"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"list-views"}) public void findAll_privateHasRole_succeeds() throws UserNotFoundException, AccessNotFoundException, DatabaseNotFoundException { @@ -257,7 +251,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"list-views"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"list-views"}) public void findAll_privateHasRoleHasAccess_succeeds() throws UserNotFoundException, AccessNotFoundException, DatabaseNotFoundException { @@ -266,7 +260,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME) + @WithMockUser(username =USER_2_USERNAME) public void findAll_privateNoRole_succeeds() throws UserNotFoundException, AccessNotFoundException, DatabaseNotFoundException { @@ -285,7 +279,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"create-database-view"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"create-database-view"}) public void create_privateHasRole_fails() { /* test */ @@ -295,17 +289,17 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"create-database-view"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"create-database-view"}) public void create_privateHasRoleHasAccess_fails() { /* test */ assertThrows(NotAllowedException.class, () -> { - create_generic(DATABASE_1_ID, DATABASE_1, "View", USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2_USER_1_READ_ACCESS); + create_generic(DATABASE_1_ID, DATABASE_1, "View", USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2.getAccesses().get(0)); }); } @Test - @WithMockUser(username = USER_2_USERNAME) + @WithMockUser(username =USER_2_USERNAME) public void create_privateNoRole_fails() { /* test */ @@ -317,37 +311,37 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser public void find_privateAnonymous_succeeds() throws UserNotFoundException, DatabaseNotFoundException, - AccessNotFoundException, ViewNotFoundException { + AccessNotFoundException, ViewNotFoundException, NotAllowedException { /* test */ find_generic(DATABASE_1_ID, DATABASE_1, null, null, null, null); } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"find-database-view"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"find-database-view"}) public void find_privateHasRole_succeeds() throws UserNotFoundException, DatabaseNotFoundException, - AccessNotFoundException, ViewNotFoundException { + AccessNotFoundException, ViewNotFoundException, NotAllowedException { /* test */ - find_generic(DATABASE_1_ID, DATABASE_1, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2_USER_1_READ_ACCESS); + find_generic(DATABASE_1_ID, DATABASE_1, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2.getAccesses().get(0)); } @Test - @WithMockUser(username = USER_2_USERNAME) + @WithMockUser(username =USER_2_USERNAME) public void find_privateNoRole_succeeds() throws UserNotFoundException, DatabaseNotFoundException, - AccessNotFoundException, ViewNotFoundException { + AccessNotFoundException, ViewNotFoundException, NotAllowedException { /* test */ - find_generic(DATABASE_1_ID, DATABASE_1, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2_USER_1_READ_ACCESS); + find_generic(DATABASE_1_ID, DATABASE_1, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2.getAccesses().get(0)); } @Test - @WithMockUser(username = USER_2_USERNAME) + @WithMockUser(username =USER_2_USERNAME) public void find_privateHasRoleHasAccess_succeeds() throws UserNotFoundException, DatabaseNotFoundException, - AccessNotFoundException, ViewNotFoundException { + AccessNotFoundException, ViewNotFoundException, NotAllowedException { /* test */ - find_generic(DATABASE_1_ID, DATABASE_1, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2_USER_1_READ_ACCESS); + find_generic(DATABASE_1_ID, DATABASE_1, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2.getAccesses().get(0)); } @Test @@ -361,22 +355,22 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"delete-database-view"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"delete-database-view"}) public void delete_privateHasRole_fails() { /* test */ assertThrows(NotAllowedException.class, () -> { - delete_generic(DATABASE_1_ID, DATABASE_1, VIEW_1_ID, VIEW_1, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2_USER_1_READ_ACCESS); + delete_generic(DATABASE_1_ID, DATABASE_1, VIEW_1_ID, VIEW_1, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2.getAccesses().get(0)); }); } @Test - @WithMockUser(username = USER_2_USERNAME) + @WithMockUser(username =USER_2_USERNAME) public void delete_privateNoRole_fails() { /* test */ assertThrows(AccessDeniedException.class, () -> { - delete_generic(DATABASE_1_ID, DATABASE_1, VIEW_1_ID, VIEW_1, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2_USER_1_READ_ACCESS); + delete_generic(DATABASE_1_ID, DATABASE_1, VIEW_1_ID, VIEW_1, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2.getAccesses().get(0)); }); } @@ -384,7 +378,8 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-database-view"}) public void delete_privateOwner_succeeds() throws NotAllowedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, AccessNotFoundException, SearchServiceException, - SearchServiceConnectionException, ViewNotFoundException, UserNotFoundException { + SearchServiceConnectionException, ViewNotFoundException, UserNotFoundException, DashboardServiceException, + DashboardServiceConnectionException { /* test */ delete_generic(DATABASE_1_ID, DATABASE_1, VIEW_1_ID, VIEW_1, USER_1_PRINCIPAL, USER_1_ID, USER_1, DATABASE_1_USER_1_WRITE_ALL_ACCESS); @@ -411,7 +406,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_2_USERNAME, authorities = {"modify-view-visibility"}) + @WithMockUser(username =USER_2_USERNAME, authorities = {"modify-view-visibility"}) public void update_notOwner_fails() { /* test */ @@ -423,7 +418,8 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-view-visibility"}) public void update_succeeds() throws NotAllowedException, DataServiceConnectionException, DatabaseNotFoundException, - SearchServiceException, SearchServiceConnectionException, ViewNotFoundException, UserNotFoundException { + SearchServiceException, SearchServiceConnectionException, ViewNotFoundException, UserNotFoundException, + DashboardServiceException, DashboardServiceConnectionException { /* test */ update_generic(USER_1_PRINCIPAL); @@ -448,32 +444,24 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { log.trace("mock access of database with id {} and user id {}", databaseId, userId); when(accessService.find(database, user)) .thenReturn(access); - when(viewService.findAll(database, user)) - .thenReturn(List.of(VIEW_1, VIEW_2)); } else { log.trace("mock no access of database with id {} and user id {}", databaseId, userId); when(accessService.find(database, user)) .thenThrow(AccessNotFoundException.class); - when(viewService.findAll(database, user)) - .thenReturn(List.of(VIEW_1)); } /* test */ final ResponseEntity<List<ViewBriefDto>> response = viewEndpoint.findAll(databaseId, principal); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); - if (access == null) { - assertEquals(1, response.getBody().size()); - } else { - assertEquals(2, response.getBody().size()); - } } protected void create_generic(UUID databaseId, Database database, String viewName, Principal principal, UUID userId, User user, DatabaseAccess access) throws MalformedException, DataServiceException, DataServiceConnectionException, NotAllowedException, UserNotFoundException, DatabaseNotFoundException, AccessNotFoundException, SearchServiceException, SearchServiceConnectionException, TableNotFoundException, - ImageNotFoundException, ViewExistsException { + ImageNotFoundException, ViewExistsException, DashboardServiceException, + DashboardServiceConnectionException { final CreateViewDto request = CreateViewDto.builder() .name(viewName) .query(VIEW_1_SUBSET_DTO) @@ -509,7 +497,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { protected ResponseEntity<ViewDto> find_generic(UUID databaseId, Database database, Principal principal, UUID userId, User user, DatabaseAccess access) - throws DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException, ViewNotFoundException { + throws DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException, ViewNotFoundException, NotAllowedException { /* mock */ when(databaseService.findById(databaseId)) @@ -544,7 +532,8 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { protected void delete_generic(UUID databaseId, Database database, UUID viewId, View view, Principal principal, UUID userId, User user, DatabaseAccess access) throws NotAllowedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, AccessNotFoundException, - SearchServiceException, SearchServiceConnectionException, ViewNotFoundException, UserNotFoundException { + SearchServiceException, SearchServiceConnectionException, ViewNotFoundException, UserNotFoundException, + DashboardServiceException, DashboardServiceConnectionException { /* mock */ when(databaseService.findById(databaseId)) @@ -561,6 +550,9 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { doNothing() .when(viewService) .delete(view); + doNothing() + .when(dashboardService) + .update(database); /* test */ final ResponseEntity<?> response = viewEndpoint.delete(databaseId, viewId, principal); @@ -569,7 +561,8 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { protected void update_generic(Principal principal) throws SearchServiceException, NotAllowedException, DatabaseNotFoundException, SearchServiceConnectionException, DataServiceConnectionException, - ViewNotFoundException, UserNotFoundException { + ViewNotFoundException, UserNotFoundException, DashboardServiceException, + DashboardServiceConnectionException { final ViewUpdateDto request = ViewUpdateDto.builder() .isPublic(true) .isSchemaPublic(true) @@ -580,7 +573,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_1); when(viewService.findById(DATABASE_1, VIEW_1_ID)) .thenReturn(VIEW_1); - when(viewService.update(DATABASE_1, VIEW_1, request)) + when(viewService.update(VIEW_1, request)) .thenReturn(VIEW_1); /* test */ diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/entities/EntitiesUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/entity/EntitiesUnitTest.java similarity index 64% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/entities/EntitiesUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/entity/EntitiesUnitTest.java index 4fdb83bcd73535f5c0aae86cccdd29ab7b6361d5..32f5b79f667b36135c06cb7f3447a36dd29d08c1 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/entities/EntitiesUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/entity/EntitiesUnitTest.java @@ -1,6 +1,6 @@ -package at.tuwien.entities; +package at.ac.tuwien.ifs.dbrepo.core.entity; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.Test; @@ -9,7 +9,7 @@ import java.util.UUID; import static org.junit.jupiter.api.Assertions.assertEquals; @Log4j2 -public class EntitiesUnitTest extends AbstractUnitTest { +public class EntitiesUnitTest extends BaseTest { @Test public void uuidVersion_succeeds() { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/BrokerServiceGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/BrokerServiceGatewayUnitTest.java similarity index 94% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/BrokerServiceGatewayUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/BrokerServiceGatewayUnitTest.java index 32a8c8b1907c816d4000e544b2ec0e9d7e8a01fc..e8d2b0192303cf32a428759de306c5f437e87ebd 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/BrokerServiceGatewayUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/BrokerServiceGatewayUnitTest.java @@ -1,8 +1,9 @@ -package at.tuwien.gateway; +package at.ac.tuwien.ifs.dbrepo.gateway; -import at.tuwien.api.amqp.GrantExchangePermissionsDto; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.api.amqp.GrantExchangePermissionsDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.BrokerServiceConnectionException; +import at.ac.tuwien.ifs.dbrepo.core.exception.BrokerServiceException; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -25,7 +26,7 @@ import static org.mockito.Mockito.*; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class BrokerServiceGatewayUnitTest extends AbstractUnitTest { +public class BrokerServiceGatewayUnitTest extends BaseTest { @MockBean @Qualifier("brokerRestTemplate") @@ -36,8 +37,8 @@ public class BrokerServiceGatewayUnitTest extends AbstractUnitTest { private final GrantExchangePermissionsDto WRITE_ALL_PERMISSIONS = GrantExchangePermissionsDto.builder() .exchange("dbrepo") - .read("^(dbrepo\\.1\\..*)$") /* WRITE_ALL */ - .write("^(dbrepo\\.1\\..*)$") + .read("^(dbrepo\\." + DATABASE_1_ID + "\\..*)$") /* WRITE_ALL */ + .write("^(dbrepo\\." + DATABASE_1_ID + "\\..*)$") .build(); @Test diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/CrossrefGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/CrossRefGatewayUnitTest.java similarity index 70% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/CrossrefGatewayUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/CrossRefGatewayUnitTest.java index 881f29ed04b9559884fa26ace511a0627984c963..7513622f37a0dc8f50f13611715097bf0b8c2787 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/CrossrefGatewayUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/CrossRefGatewayUnitTest.java @@ -1,8 +1,8 @@ -package at.tuwien.gateway; +package at.ac.tuwien.ifs.dbrepo.gateway; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.api.crossref.CrossrefDto; -import at.tuwien.exception.DoiNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.api.crossref.CrossRefDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.DoiNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -16,7 +16,6 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.web.client.HttpServerErrorException; -import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.RestTemplate; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -25,24 +24,25 @@ import static org.mockito.Mockito.*; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class CrossrefGatewayUnitTest extends AbstractUnitTest { +public class CrossRefGatewayUnitTest extends BaseTest { @MockBean + @Qualifier("crossRefServiceRestTemplate") private RestTemplate restTemplate; @Autowired - private CrossrefGateway crossrefGateway; + private CrossRefGateway crossRefGateway; @Test public void findById_succeeds() throws DoiNotFoundException { /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(CrossrefDto.class))) + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(CrossRefDto.class))) .thenReturn(ResponseEntity.status(HttpStatus.OK) .build()); /* test */ - crossrefGateway.findById("501100004729"); + crossRefGateway.findById("501100004729"); } @Test @@ -51,11 +51,11 @@ public class CrossrefGatewayUnitTest extends AbstractUnitTest { /* mock */ doThrow(HttpServerErrorException.class) .when(restTemplate) - .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(CrossrefDto.class)); + .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(CrossRefDto.class)); /* test */ assertThrows(DoiNotFoundException.class, () -> { - crossrefGateway.findById("501100004729"); + crossRefGateway.findById("501100004729"); }); } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/DashboardServiceGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/DashboardServiceGatewayUnitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c1a60d0115d5c02e81ff49d13bcb6a486cccd12a --- /dev/null +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/DashboardServiceGatewayUnitTest.java @@ -0,0 +1,286 @@ +package at.ac.tuwien.ifs.dbrepo.gateway; + +import at.ac.tuwien.ifs.dbrepo.core.api.grafana.CreateDashboardResponseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.grafana.PermissionTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.DashboardServiceConnectionException; +import at.ac.tuwien.ifs.dbrepo.core.exception.DashboardServiceException; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; +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.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.RestTemplate; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; + +@Log4j2 +@SpringBootTest +@ExtendWith(SpringExtension.class) +public class DashboardServiceGatewayUnitTest extends BaseTest { + + @MockBean + @Qualifier("dashboardServiceRestTemplate") + private RestTemplate restTemplate; + + @Autowired + private DashboardServiceGateway dashboardServiceGateway; + + @Test + public void update_succeeds() throws DashboardServiceException, DashboardServiceConnectionException { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class))) + .thenReturn(ResponseEntity.status(HttpStatus.ACCEPTED) + .build()); + + /* test */ + dashboardServiceGateway.update(DATABASE_2_DTO); + } + + @Test + public void update_wrongStatus_failed() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class))) + .thenReturn(ResponseEntity.status(HttpStatus.OK) + .build()); + + /* test */ + assertThrows(DashboardServiceException.class, () -> { + dashboardServiceGateway.update(DATABASE_1_DTO); + }); + } + + @Test + public void update_connection_failed() { + + /* mock */ + doThrow(HttpServerErrorException.ServiceUnavailable.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class)); + + /* test */ + assertThrows(DashboardServiceConnectionException.class, () -> { + dashboardServiceGateway.update(DATABASE_1_DTO); + }); + } + + @Test + public void update_unauthorized_failed() { + + /* mock */ + doThrow(HttpClientErrorException.Unauthorized.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class)); + + /* test */ + assertThrows(DashboardServiceException.class, () -> { + dashboardServiceGateway.update(DATABASE_1_DTO); + }); + } + + @Test + public void create_succeeds() throws DashboardServiceException, DashboardServiceConnectionException { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(CreateDashboardResponseDto.class))) + .thenReturn(ResponseEntity.status(HttpStatus.CREATED) + .body(DATABASE_2_CREATE_DASHBOARD_RESPONSE_DTO)); + + /* test */ + final CreateDashboardResponseDto response = dashboardServiceGateway.create(DATABASE_2_CREATE_DASHBOARD_DTO); + assertEquals(DATABASE_2_DASHBOARD_UID, response.getUid()); + } + + @Test + public void create_emptyBody_fails() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(CreateDashboardResponseDto.class))) + .thenReturn(ResponseEntity.status(HttpStatus.CREATED) + .body(null)); // <<< + + /* test */ + assertThrows(DashboardServiceException.class, () -> { + dashboardServiceGateway.create(DATABASE_2_CREATE_DASHBOARD_DTO); + }); + } + + @Test + public void create_wrongStatus_failed() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(CreateDashboardResponseDto.class))) + .thenReturn(ResponseEntity.status(HttpStatus.OK) + .build()); + + /* test */ + assertThrows(DashboardServiceException.class, () -> { + dashboardServiceGateway.create(DATABASE_2_CREATE_DASHBOARD_DTO); + }); + } + + @Test + public void create_connection_failed() { + + /* mock */ + doThrow(HttpServerErrorException.ServiceUnavailable.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(CreateDashboardResponseDto.class)); + + /* test */ + assertThrows(DashboardServiceConnectionException.class, () -> { + dashboardServiceGateway.create(DATABASE_2_CREATE_DASHBOARD_DTO); + }); + } + + @Test + public void create_unauthorized_failed() { + + /* mock */ + doThrow(HttpClientErrorException.Unauthorized.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(CreateDashboardResponseDto.class)); + + /* test */ + assertThrows(DashboardServiceException.class, () -> { + dashboardServiceGateway.create(DATABASE_2_CREATE_DASHBOARD_DTO); + }); + } + + @Test + public void create_exists_failed() { + + /* mock */ + doThrow(HttpClientErrorException.Conflict.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(CreateDashboardResponseDto.class)); + + /* test */ + assertThrows(DashboardServiceException.class, () -> { + dashboardServiceGateway.create(DATABASE_2_CREATE_DASHBOARD_DTO); + }); + } + + @Test + public void updateAccess_succeeds() throws DashboardServiceException, DashboardServiceConnectionException { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class))) + .thenReturn(ResponseEntity.status(HttpStatus.ACCEPTED) + .build()); + + /* test */ + dashboardServiceGateway.updateAccess(DATABASE_2_DASHBOARD_UID, USER_2_USERNAME, PermissionTypeDto.VIEW); + } + + @Test + public void updateAccess_wrongStatus_failed() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class))) + .thenReturn(ResponseEntity.status(HttpStatus.OK) + .build()); + + /* test */ + assertThrows(DashboardServiceException.class, () -> { + dashboardServiceGateway.updateAccess(DATABASE_2_DASHBOARD_UID, USER_2_USERNAME, PermissionTypeDto.VIEW); + }); + } + + @Test + public void updateAccess_connection_failed() { + + /* mock */ + doThrow(HttpServerErrorException.ServiceUnavailable.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class)); + + /* test */ + assertThrows(DashboardServiceConnectionException.class, () -> { + dashboardServiceGateway.updateAccess(DATABASE_2_DASHBOARD_UID, USER_2_USERNAME, PermissionTypeDto.VIEW); + }); + } + + @Test + public void updateAccess_unauthorized_failed() { + + /* mock */ + doThrow(HttpClientErrorException.Unauthorized.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class)); + + /* test */ + assertThrows(DashboardServiceException.class, () -> { + dashboardServiceGateway.updateAccess(DATABASE_2_DASHBOARD_UID, USER_2_USERNAME, PermissionTypeDto.VIEW); + }); + } + + @Test + public void updateAnonymousAccess_succeeds() throws DashboardServiceException, DashboardServiceConnectionException { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class))) + .thenReturn(ResponseEntity.status(HttpStatus.ACCEPTED) + .build()); + + /* test */ + dashboardServiceGateway.updateAnonymousAccess(DATABASE_2_DASHBOARD_UID, DATABASE_2_BRIEF_DTO); + } + + @Test + public void updateAnonymousAccess_wrongStatus_failed() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class))) + .thenReturn(ResponseEntity.status(HttpStatus.OK) + .build()); + + /* test */ + assertThrows(DashboardServiceException.class, () -> { + dashboardServiceGateway.updateAnonymousAccess(DATABASE_2_DASHBOARD_UID, DATABASE_2_BRIEF_DTO); + }); + } + + @Test + public void updateAnonymousAccess_connection_failed() { + + /* mock */ + doThrow(HttpServerErrorException.ServiceUnavailable.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class)); + + /* test */ + assertThrows(DashboardServiceConnectionException.class, () -> { + dashboardServiceGateway.updateAnonymousAccess(DATABASE_2_DASHBOARD_UID, DATABASE_2_BRIEF_DTO); + }); + } + + @Test + public void updateAnonymousAccess_unauthorized_failed() { + + /* mock */ + doThrow(HttpClientErrorException.Unauthorized.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class)); + + /* test */ + assertThrows(DashboardServiceException.class, () -> { + dashboardServiceGateway.updateAnonymousAccess(DATABASE_2_DASHBOARD_UID, DATABASE_2_BRIEF_DTO); + }); + } +} \ No newline at end of file diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/DataServiceGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/DataServiceGatewayUnitTest.java similarity index 97% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/DataServiceGatewayUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/DataServiceGatewayUnitTest.java index af1ecc9f1c69b6f2acaf3176575045bf14ad8322..14df28608a18d6bddd5519abb67b8bcb20a09113 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/DataServiceGatewayUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/DataServiceGatewayUnitTest.java @@ -1,13 +1,13 @@ -package at.tuwien.gateway; - -import at.tuwien.api.database.AccessTypeDto; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.ViewDto; -import at.tuwien.api.database.query.QueryDto; -import at.tuwien.api.database.table.TableDto; -import at.tuwien.api.database.table.TableStatisticDto; -import at.tuwien.exception.*; -import at.tuwien.test.AbstractUnitTest; +package at.ac.tuwien.ifs.dbrepo.gateway; + +import at.ac.tuwien.ifs.dbrepo.core.api.database.AccessTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.QueryDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableStatisticDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -32,7 +32,7 @@ import static org.mockito.Mockito.when; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class DataServiceGatewayUnitTest extends AbstractUnitTest { +public class DataServiceGatewayUnitTest extends BaseTest { @MockBean @Qualifier("dataServiceRestTemplate") @@ -1045,20 +1045,6 @@ public class DataServiceGatewayUnitTest extends AbstractUnitTest { }); } - @Test - public void getTableStatistics_emptyBody_fails() { - - /* mock */ - when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableStatisticDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .build()); - - /* test */ - assertThrows(DataServiceException.class, () -> { - dataServiceGateway.getTableStatistics(DATABASE_3_ID, TABLE_8_ID); - }); - } - @Test public void updateTable_succeeds() throws DataServiceException, DataServiceConnectionException, DatabaseNotFoundException { 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/ac/tuwien/ifs/dbrepo/gateway/KeycloakGatewayIntegrationTest.java similarity index 87% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayIntegrationTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/KeycloakGatewayIntegrationTest.java index 583fa4c44025dc035c4d300b3a9e24f0bb7b1790..40d8eab970de1ae48e0fa39005cba88b7c9ae2bd 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayIntegrationTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/KeycloakGatewayIntegrationTest.java @@ -1,10 +1,10 @@ -package at.tuwien.gateway; +package at.ac.tuwien.ifs.dbrepo.gateway; -import at.tuwien.exception.AuthServiceException; -import at.tuwien.exception.UserNotFoundException; -import at.tuwien.gateway.impl.KeycloakGatewayImpl; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.utils.KeycloakUtils; +import at.ac.tuwien.ifs.dbrepo.core.exception.AuthServiceException; +import at.ac.tuwien.ifs.dbrepo.core.exception.UserNotFoundException; +import at.ac.tuwien.ifs.dbrepo.gateway.impl.KeycloakGatewayImpl; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; +import at.ac.tuwien.ifs.dbrepo.utils.KeycloakUtils; import dasniko.testcontainers.keycloak.KeycloakContainer; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; @@ -20,15 +20,13 @@ import org.testcontainers.images.PullPolicy; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; -import java.util.UUID; - import static org.junit.jupiter.api.Assertions.*; @Log4j2 @SpringBootTest @Testcontainers @ExtendWith(SpringExtension.class) -public class KeycloakGatewayIntegrationTest extends AbstractUnitTest { +public class KeycloakGatewayIntegrationTest extends BaseTest { @Autowired private KeycloakGatewayImpl keycloakGateway; @@ -38,13 +36,12 @@ public class KeycloakGatewayIntegrationTest extends AbstractUnitTest { @BeforeEach public void beforeEach() { - genesis(); /* auth service */ keycloakUtils.deleteUser(USER_1_USERNAME); } @Container - private static KeycloakContainer keycloakContainer = new KeycloakContainer(KEYCLOAK_IMAGE) + private static final KeycloakContainer keycloakContainer = new KeycloakContainer(KEYCLOAK_IMAGE) .withImagePullPolicy(PullPolicy.alwaysPull()) .withAdminUsername("admin") .withAdminPassword("admin") diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/OrcidGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/OrcidGatewayUnitTest.java similarity index 82% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/OrcidGatewayUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/OrcidGatewayUnitTest.java index bcd27107bc0189614b4086e0b333fa16cf16cb84..31d8baeab55a9122b1ea7b252a59446a31aa58eb 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/OrcidGatewayUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/OrcidGatewayUnitTest.java @@ -1,13 +1,12 @@ -package at.tuwien.gateway; +package at.ac.tuwien.ifs.dbrepo.gateway; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.api.orcid.OrcidDto; -import at.tuwien.exception.OrcidNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.OrcidDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.OrcidNotFoundException; 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.HttpEntity; @@ -16,16 +15,17 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.web.client.HttpServerErrorException; -import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.RestTemplate; +import java.io.IOException; + import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.*; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class OrcidGatewayUnitTest extends AbstractUnitTest { +public class OrcidGatewayUnitTest extends BaseTest { @MockBean private RestTemplate restTemplate; @@ -33,6 +33,9 @@ public class OrcidGatewayUnitTest extends AbstractUnitTest { @Autowired private OrcidGateway orcidGateway; + public OrcidGatewayUnitTest() throws IOException { + } + @Test public void findByUrl_succeeds() throws OrcidNotFoundException { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/RorGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/RorGatewayUnitTest.java similarity index 77% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/RorGatewayUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/RorGatewayUnitTest.java index ff9d4f741c18b2dfcd94dca91c344912fddd2167..b8b100c413761cbed6b57738146c1001345e70a6 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/RorGatewayUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/RorGatewayUnitTest.java @@ -1,15 +1,18 @@ -package at.tuwien.gateway; +package at.ac.tuwien.ifs.dbrepo.gateway; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.api.ror.RorDto; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.api.ror.RorDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.RorNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; 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.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.*; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.client.RestTemplate; @@ -20,7 +23,7 @@ import static org.mockito.Mockito.*; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class RorGatewayUnitTest extends AbstractUnitTest { +public class RorGatewayUnitTest extends BaseTest { @MockBean private RestTemplate restTemplate; 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/ac/tuwien/ifs/dbrepo/gateway/SearchServiceGatewayUnitTest.java similarity index 93% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/SearchServiceGatewayUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/gateway/SearchServiceGatewayUnitTest.java index b39dd06bac8cd722ccc6e464b1b97438f48b4850..3ff4a3a508b19a2c29f10df1b9bcabfaf2448980 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/ac/tuwien/ifs/dbrepo/gateway/SearchServiceGatewayUnitTest.java @@ -1,8 +1,10 @@ -package at.tuwien.gateway; +package at.ac.tuwien.ifs.dbrepo.gateway; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.api.database.DatabaseBriefDto; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.DatabaseNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.exception.SearchServiceConnectionException; +import at.ac.tuwien.ifs.dbrepo.core.exception.SearchServiceException; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -25,7 +27,7 @@ import static org.mockito.Mockito.*; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class SearchServiceGatewayUnitTest extends AbstractUnitTest { +public class SearchServiceGatewayUnitTest extends BaseTest { @MockBean @Qualifier("searchServiceRestTemplate") diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/handlers/ApiExceptionHandlerTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/handlers/ApiExceptionHandlerTest.java similarity index 95% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/handlers/ApiExceptionHandlerTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/handlers/ApiExceptionHandlerTest.java index 87d7d0185a6399c5b66340d892281053448e689a..7ab54f089c254c22b1f17af4622f6d65fe4a4044 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/handlers/ApiExceptionHandlerTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/handlers/ApiExceptionHandlerTest.java @@ -1,8 +1,8 @@ -package at.tuwien.handlers; +package at.ac.tuwien.ifs.dbrepo.handlers; -import at.tuwien.api.error.ApiErrorDto; -import at.tuwien.exception.*; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.api.error.ApiErrorDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import com.auth0.jwt.exceptions.TokenExpiredException; import jakarta.ws.rs.NotAuthorizedException; import lombok.extern.log4j.Log4j2; @@ -23,14 +23,14 @@ import java.util.Arrays; import java.util.List; import java.util.Optional; -import static at.tuwien.test.utils.EndpointUtils.getErrorCodes; -import static at.tuwien.test.utils.EndpointUtils.getExceptions; +import static at.ac.tuwien.ifs.dbrepo.core.test.utils.EndpointUtils.getErrorCodes; +import static at.ac.tuwien.ifs.dbrepo.core.test.utils.EndpointUtils.getExceptions; import static org.junit.jupiter.api.Assertions.*; @Log4j2 @ExtendWith(SpringExtension.class) @SpringBootTest -public class ApiExceptionHandlerTest extends AbstractUnitTest { +public class ApiExceptionHandlerTest extends BaseTest { @Autowired private ApiExceptionHandler apiExceptionHandler; @@ -49,7 +49,7 @@ public class ApiExceptionHandlerTest extends AbstractUnitTest { final Method method = optional.get(); /* exception */ Assertions.assertNotNull(exception.getDeclaredAnnotation(ResponseStatus.class).code()); - Assertions.assertNotEquals(exception.getDeclaredAnnotation(ResponseStatus.class).code(), HttpStatus.INTERNAL_SERVER_ERROR); + Assertions.assertNotEquals(HttpStatus.INTERNAL_SERVER_ERROR, exception.getDeclaredAnnotation(ResponseStatus.class).code()); Assertions.assertNotNull(exception.getDeclaredAnnotation(ResponseStatus.class).reason(), "Exception " + exception.getName() + " does not provide a reason code"); assertTrue(errorCodes.contains(exception.getDeclaredAnnotation(ResponseStatus.class).reason()), "Exception code " + exception.getDeclaredAnnotation(ResponseStatus.class).reason() + " does have a reason code mapped in localized ui error messages"); /* handler method */ @@ -239,6 +239,32 @@ public class ApiExceptionHandlerTest extends AbstractUnitTest { assertEquals("error.user.credentials", body.getCode()); } + @Test + public void handle_dashboardServiceConnectionException_succeeds() { + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(new DashboardServiceConnectionException("msg")); + assertEquals(HttpStatus.BAD_GATEWAY, response.getStatusCode()); + final ApiErrorDto body = response.getBody(); + assertNotNull(body); + assertEquals("msg", body.getMessage()); + assertEquals(HttpStatus.BAD_GATEWAY, body.getStatus()); + assertEquals("error.dashboard.connection", body.getCode()); + } + + @Test + public void handle_dashboardServiceException_succeeds() { + + /* test */ + final ResponseEntity<ApiErrorDto> response = apiExceptionHandler.handle(new DashboardServiceException("msg")); + assertEquals(HttpStatus.SERVICE_UNAVAILABLE, response.getStatusCode()); + final ApiErrorDto body = response.getBody(); + assertNotNull(body); + assertEquals("msg", body.getMessage()); + assertEquals(HttpStatus.SERVICE_UNAVAILABLE, body.getStatus()); + assertEquals("error.dashboard.invalid", body.getCode()); + } + @Test public void handle_dataServiceConnectionException_succeeds() { 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/ac/tuwien/ifs/dbrepo/mapper/MetadataMapperUnitTest.java similarity index 91% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/mapper/MetadataMapperUnitTest.java index ac1103d2e5ad0a4c9a12b781c575ddff9aa39bcf..0b3c5fdf68712c95cf1b72f5639bb75c235caaf1 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/ac/tuwien/ifs/dbrepo/mapper/MetadataMapperUnitTest.java @@ -1,14 +1,12 @@ -package at.tuwien.mapper; - -import at.tuwien.api.database.ViewDto; -import at.tuwien.api.identifier.IdentifierTypeDto; -import at.tuwien.api.user.UserBriefDto; -import at.tuwien.entities.database.View; -import at.tuwien.entities.identifier.Identifier; -import at.tuwien.entities.identifier.IdentifierType; -import at.tuwien.test.AbstractUnitTest; +package at.ac.tuwien.ifs.dbrepo.mapper; + +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.Identifier; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.IdentifierType; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -26,7 +24,7 @@ import static org.junit.jupiter.api.Assertions.*; @Log4j2 @SpringBootTest -public class MetadataMapperUnitTest extends AbstractUnitTest { +public class MetadataMapperUnitTest extends BaseTest { private final DateTimeFormatter mariaDbFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[.SSS]") .withZone(ZoneId.of("UTC")); @@ -34,11 +32,6 @@ public class MetadataMapperUnitTest extends AbstractUnitTest { @Autowired private MetadataMapper metadataMapper; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void mapMariaDbInstant_succeeds() { final String timestamp = "2023-01-08 08:49:29"; @@ -72,7 +65,7 @@ public class MetadataMapperUnitTest extends AbstractUnitTest { public void identifierCreateDtoToIdentifier_withDoi_succeeds() { /* test */ - final Identifier response = metadataMapper.identifierCreateDtoToIdentifier(IDENTIFIER_1_CREATE_WITH_DOI_DTO); + final Identifier response = metadataMapper.createIdentifierDtoToIdentifier(IDENTIFIER_1_CREATE_WITH_DOI_DTO); assertNull(response.getDatabase()); assertNull(response.getViewId()); assertNull(response.getQueryId()); @@ -85,7 +78,7 @@ public class MetadataMapperUnitTest extends AbstractUnitTest { public void identifierCreateDtoToIdentifier_subset_succeeds() { /* test */ - final Identifier response = metadataMapper.identifierCreateDtoToIdentifier(IDENTIFIER_2_CREATE_DTO); + final Identifier response = metadataMapper.createIdentifierDtoToIdentifier(IDENTIFIER_2_CREATE_DTO); assertNull(response.getDatabase()); assertNull(response.getViewId()); assertNull(response.getTableId()); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/ActuatorEndpointMvcTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/mvc/ActuatorEndpointMvcTest.java similarity index 90% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/ActuatorEndpointMvcTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/mvc/ActuatorEndpointMvcTest.java index a7a83a6184cab52aa4739df2005680a60eb7f81b..7d8c74437a1204dda49c7f18bdaba94ff668d01e 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/ActuatorEndpointMvcTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/mvc/ActuatorEndpointMvcTest.java @@ -1,6 +1,6 @@ -package at.tuwien.mvc; +package at.ac.tuwien.ifs.dbrepo.mvc; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -20,7 +20,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @AutoConfigureMockMvc @SpringBootTest @AutoConfigureObservability -public class ActuatorEndpointMvcTest extends AbstractUnitTest { +public class ActuatorEndpointMvcTest extends BaseTest { @Autowired private MockMvc mockMvc; 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/ac/tuwien/ifs/dbrepo/mvc/AuthenticationPrivilegedIntegrationMvcTest.java similarity index 87% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/AuthenticationPrivilegedIntegrationMvcTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/mvc/AuthenticationPrivilegedIntegrationMvcTest.java index e6535ccf19a5879f8bc581a6bb2e40fc0376be20..9a6354453b14b5248f0828769ea89e9334928ca5 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/ac/tuwien/ifs/dbrepo/mvc/AuthenticationPrivilegedIntegrationMvcTest.java @@ -1,16 +1,16 @@ -package at.tuwien.mvc; - -import at.tuwien.api.keycloak.TokenDto; -import at.tuwien.exception.AuthServiceConnectionException; -import at.tuwien.exception.AuthServiceException; -import at.tuwien.exception.CredentialsInvalidException; -import at.tuwien.gateway.KeycloakGateway; -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.utils.KeycloakUtils; +package at.ac.tuwien.ifs.dbrepo.mvc; + +import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.TokenDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.AuthServiceConnectionException; +import at.ac.tuwien.ifs.dbrepo.core.exception.AuthServiceException; +import at.ac.tuwien.ifs.dbrepo.core.exception.CredentialsInvalidException; +import at.ac.tuwien.ifs.dbrepo.gateway.KeycloakGateway; +import at.ac.tuwien.ifs.dbrepo.repository.ContainerRepository; +import at.ac.tuwien.ifs.dbrepo.repository.DatabaseRepository; +import at.ac.tuwien.ifs.dbrepo.repository.LicenseRepository; +import at.ac.tuwien.ifs.dbrepo.repository.UserRepository; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; +import at.ac.tuwien.ifs.dbrepo.utils.KeycloakUtils; import dasniko.testcontainers.keycloak.KeycloakContainer; import jakarta.transaction.Transactional; import lombok.extern.log4j.Log4j2; @@ -41,7 +41,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @AutoConfigureMockMvc @Testcontainers @SpringBootTest -public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest { +public class AuthenticationPrivilegedIntegrationMvcTest extends BaseTest { @Autowired private MockMvc mockMvc; @@ -65,7 +65,7 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest private KeycloakGateway keycloakGateway; @Container - private static KeycloakContainer keycloakContainer = new KeycloakContainer(KEYCLOAK_IMAGE) + private static final KeycloakContainer keycloakContainer = new KeycloakContainer(KEYCLOAK_IMAGE) .withImagePullPolicy(PullPolicy.alwaysPull()) .withAdminUsername("admin") .withAdminPassword("admin") @@ -79,7 +79,6 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest @BeforeEach public void beforeEach() throws AuthServiceException, AuthServiceConnectionException, CredentialsInvalidException { - genesis(); /* metadata database */ licenseRepository.save(LICENSE_1); userRepository.saveAll(List.of(USER_1, USER_2, USER_3, USER_4, USER_LOCAL)); @@ -115,7 +114,7 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest .andExpect(header().string("X-Port", "" + CONTAINER_1_PORT)) .andExpect(header().string("X-Username", CONTAINER_1_PRIVILEGED_USERNAME)) .andExpect(header().string("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD)) - .andExpect(header().string("X-Jdbc-Method", IMAGE_1_JDBC)) + .andExpect(header().string("X-Jdbc-Method", IMAGE_1_JDBC_METHOD)) .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password X-Jdbc-Method X-Host X-Port")) .andExpect(status().isOk()); } @@ -134,7 +133,7 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest .andExpect(header().string("X-Port", "" + CONTAINER_1_PORT)) .andExpect(header().string("X-Username", CONTAINER_1_PRIVILEGED_USERNAME)) .andExpect(header().string("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD)) - .andExpect(header().string("X-Jdbc-Method", IMAGE_1_JDBC)) + .andExpect(header().string("X-Jdbc-Method", IMAGE_1_JDBC_METHOD)) .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password X-Jdbc-Method X-Host X-Port")) .andExpect(status().isOk()); } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/IdentifierEndpointMvcTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/mvc/IdentifierEndpointMvcTest.java similarity index 86% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/IdentifierEndpointMvcTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/mvc/IdentifierEndpointMvcTest.java index 2594eb70b1240d7ba39c866e2ee8c900cf191ea7..b0cdca73e25243c1f59a8b3069bc6926a4e386cc 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/IdentifierEndpointMvcTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/mvc/IdentifierEndpointMvcTest.java @@ -1,7 +1,7 @@ -package at.tuwien.mvc; +package at.ac.tuwien.ifs.dbrepo.mvc; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.gateway.OrcidGateway; +import at.ac.tuwien.ifs.dbrepo.gateway.OrcidGateway; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import com.mchange.io.FileUtils; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.Test; @@ -16,7 +16,8 @@ import org.springframework.test.web.servlet.MockMvc; import java.io.File; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.when; 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.content; @@ -26,7 +27,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @ExtendWith(SpringExtension.class) @AutoConfigureMockMvc @SpringBootTest -public class IdentifierEndpointMvcTest extends AbstractUnitTest { +public class IdentifierEndpointMvcTest extends BaseTest { @MockBean private OrcidGateway orcidGateway; diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/MetadataEndpointMvcTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/mvc/MetadataEndpointMvcTest.java similarity index 93% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/MetadataEndpointMvcTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/mvc/MetadataEndpointMvcTest.java index 7f9ba9743d24f1d888f2a488bd8330755478d1e9..870251323e0af7913d07da4bf24872a94e7544bf 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/MetadataEndpointMvcTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/mvc/MetadataEndpointMvcTest.java @@ -1,10 +1,9 @@ -package at.tuwien.mvc; +package at.ac.tuwien.ifs.dbrepo.mvc; -import at.tuwien.repository.IdentifierRepository; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.config.MetadataConfig; +import at.ac.tuwien.ifs.dbrepo.config.MetadataConfig; +import at.ac.tuwien.ifs.dbrepo.repository.IdentifierRepository; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; 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; @@ -28,7 +27,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) @AutoConfigureMockMvc @SpringBootTest -public class MetadataEndpointMvcTest extends AbstractUnitTest { +public class MetadataEndpointMvcTest extends BaseTest { @MockBean private IdentifierRepository identifierRepository; @@ -39,11 +38,6 @@ public class MetadataEndpointMvcTest extends AbstractUnitTest { @Autowired private MockMvc mockMvc; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void identify_succeeds() throws Exception { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/OpenApiEndpointMvcTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/mvc/OpenApiEndpointMvcTest.java similarity index 91% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/OpenApiEndpointMvcTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/mvc/OpenApiEndpointMvcTest.java index d685ca65cd0478aa06ec8c9a2aa7bcfdcc61a804..0d37944ba9baa546d3e499efd002218e13360354 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/OpenApiEndpointMvcTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/mvc/OpenApiEndpointMvcTest.java @@ -1,8 +1,8 @@ -package at.tuwien.mvc; +package at.ac.tuwien.ifs.dbrepo.mvc; -import at.tuwien.api.error.ApiErrorDto; -import at.tuwien.endpoints.*; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.core.api.error.ApiErrorDto; +import at.ac.tuwien.ifs.dbrepo.endpoints.*; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.responses.ApiResponse; @@ -30,7 +30,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @ExtendWith(SpringExtension.class) @AutoConfigureMockMvc @SpringBootTest -public class OpenApiEndpointMvcTest extends AbstractUnitTest { +public class OpenApiEndpointMvcTest extends BaseTest { @Autowired private MockMvc mockMvc; @@ -113,6 +113,7 @@ public class OpenApiEndpointMvcTest extends AbstractUnitTest { } private void generic_openApiDocs(Class<?> endpoint) { + final String packageScope = "at.ac.tuwien.ifs.dbrepo"; final List<Method> methods = Arrays.stream(endpoint.getMethods()) .filter(m -> m.getDeclaringClass().equals(endpoint)) .toList(); @@ -120,9 +121,9 @@ public class OpenApiEndpointMvcTest extends AbstractUnitTest { final List<Class<?>> exceptions = Arrays.stream(m.getExceptionTypes()) .toList(); final List<Class<?>> invalidExceptions = exceptions.stream() - .filter(e -> !e.getName().startsWith("at.tuwien.")) + .filter(e -> !e.getName().startsWith(packageScope)) .toList(); - assertTrue(invalidExceptions.isEmpty(), "method '" + m.getName() + "' throws exception(s) outside package scope at.tuwien: " + invalidExceptions.stream().map(Class::getName).toList()); + assertTrue(invalidExceptions.isEmpty(), "method '" + m.getName() + "' throws exception(s) outside package scope " + packageScope + ": " + invalidExceptions.stream().map(Class::getName).toList()); exceptions.forEach(exception -> { assertNotNull(m.getDeclaredAnnotation(Operation.class).summary()); final int status = exception.getAnnotation(ResponseStatus.class) 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/ac/tuwien/ifs/dbrepo/mvc/PrometheusEndpointMvcTest.java similarity index 94% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/mvc/PrometheusEndpointMvcTest.java index 2adc2f0647150f47605cb4b0d70566c041cd81f7..f3a15c7f3f840530b7ca72f80277dab34b8b2ac1 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/ac/tuwien/ifs/dbrepo/mvc/PrometheusEndpointMvcTest.java @@ -1,14 +1,15 @@ -package at.tuwien.mvc; - -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; +package at.ac.tuwien.ifs.dbrepo.mvc; + +import at.ac.tuwien.ifs.dbrepo.core.api.container.CreateContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseModifyImageDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseModifyVisibilityDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseTransferDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.concepts.ColumnSemanticsUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierTypeDto; +import at.ac.tuwien.ifs.dbrepo.config.MetricsConfig; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.endpoints.*; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import io.micrometer.observation.tck.TestObservationRegistry; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.Test; @@ -38,7 +39,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @SpringBootTest @Import(MetricsConfig.class) @AutoConfigureObservability -public class PrometheusEndpointMvcTest extends AbstractUnitTest { +public class PrometheusEndpointMvcTest extends BaseTest { @Autowired private MockMvc mockMvc; @@ -150,7 +151,7 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest { /* ignore */ } try { - containerEndpoint.create(CreateContainerDto.builder().name(CONTAINER_1_NAME).imageId(IMAGE_1_ID).build()); + containerEndpoint.create(CreateContainerDto.builder().name(CONTAINER_1_NAME).imageId(CONTAINER_1_ID).build()); } catch (Exception e) { /* ignore */ } @@ -281,17 +282,17 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest { /* ignore */ } try { - imageEndpoint.findById(IMAGE_1_ID); + imageEndpoint.findById(CONTAINER_1_ID); } catch (Exception e) { /* ignore */ } try { - imageEndpoint.update(IMAGE_1_ID, IMAGE_1_CHANGE_DTO); + imageEndpoint.update(CONTAINER_1_ID, IMAGE_1_CHANGE_DTO); } catch (Exception e) { /* ignore */ } try { - imageEndpoint.delete(IMAGE_1_ID); + imageEndpoint.delete(CONTAINER_1_ID); } catch (Exception e) { /* ignore */ } 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/ac/tuwien/ifs/dbrepo/service/AccessServiceUnitTest.java similarity index 94% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AccessServiceUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/AccessServiceUnitTest.java index 1c96e6283d3d62bc5c31652f82a73312454e2035..17a7cb32f84e6b39ebead7f7ea81672604c5d259 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/ac/tuwien/ifs/dbrepo/service/AccessServiceUnitTest.java @@ -1,15 +1,14 @@ -package at.tuwien.service; - -import at.tuwien.exception.*; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.api.database.AccessTypeDto; -import at.tuwien.api.database.DatabaseBriefDto; -import at.tuwien.entities.database.AccessType; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.database.DatabaseAccess; -import at.tuwien.repository.DatabaseRepository; +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.api.database.AccessTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.AccessType; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.DatabaseAccess; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.repository.DatabaseRepository; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; 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; @@ -34,7 +33,7 @@ import static org.mockito.Mockito.*; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class AccessServiceUnitTest extends AbstractUnitTest { +public class AccessServiceUnitTest extends BaseTest { @MockBean private DatabaseRepository databaseRepository; @@ -50,11 +49,6 @@ public class AccessServiceUnitTest extends AbstractUnitTest { @Autowired private AccessService accessService; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void list_succeeds() { 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/ac/tuwien/ifs/dbrepo/service/AuthenticationServiceIntegrationTest.java similarity index 80% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AuthenticationServiceIntegrationTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/AuthenticationServiceIntegrationTest.java index d655a25cf1f599b2e92a9fd426cfa343747a3fe1..016e0f949b23d7db857c4944f015753e20defa34 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/ac/tuwien/ifs/dbrepo/service/AuthenticationServiceIntegrationTest.java @@ -1,13 +1,12 @@ -package at.tuwien.service; +package at.ac.tuwien.ifs.dbrepo.service; -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 at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.gateway.KeycloakGateway; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; +import at.ac.tuwien.ifs.dbrepo.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; @@ -27,7 +26,7 @@ import java.util.UUID; @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) @SpringBootTest @ExtendWith(SpringExtension.class) -public class AuthenticationServiceIntegrationTest extends AbstractUnitTest { +public class AuthenticationServiceIntegrationTest extends BaseTest { @Autowired private AuthenticationService authenticationService; @@ -38,13 +37,8 @@ public class AuthenticationServiceIntegrationTest extends AbstractUnitTest { @Autowired private KeycloakUtils keycloakUtils; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Container - private static KeycloakContainer keycloakContainer = new KeycloakContainer(KEYCLOAK_IMAGE) + private static final KeycloakContainer keycloakContainer = new KeycloakContainer(KEYCLOAK_IMAGE) .withImagePullPolicy(PullPolicy.alwaysPull()) .withAdminUsername("admin") .withAdminPassword("admin") diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/BrokerServiceIntegrationTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/BrokerServiceIntegrationTest.java similarity index 88% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/BrokerServiceIntegrationTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/BrokerServiceIntegrationTest.java index d04409c87b095cfcdc41a478df87a733cdf1bb82..ada49fbd9a165b8e8b303306b7306e4900895aba 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/BrokerServiceIntegrationTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/BrokerServiceIntegrationTest.java @@ -1,18 +1,17 @@ -package at.tuwien.service; - -import at.tuwien.api.amqp.GrantExchangePermissionsDto; -import at.tuwien.api.amqp.GrantVirtualHostPermissionsDto; -import at.tuwien.api.amqp.TopicPermissionDto; -import at.tuwien.api.amqp.VirtualHostPermissionDto; -import at.tuwien.config.RabbitConfig; -import at.tuwien.entities.database.DatabaseAccess; -import at.tuwien.entities.user.User; -import at.tuwien.exception.BrokerServiceConnectionException; -import at.tuwien.exception.BrokerServiceException; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.utils.AmqpUtils; +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.api.amqp.GrantExchangePermissionsDto; +import at.ac.tuwien.ifs.dbrepo.core.api.amqp.GrantVirtualHostPermissionsDto; +import at.ac.tuwien.ifs.dbrepo.core.api.amqp.TopicPermissionDto; +import at.ac.tuwien.ifs.dbrepo.core.api.amqp.VirtualHostPermissionDto; +import at.ac.tuwien.ifs.dbrepo.config.RabbitConfig; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.DatabaseAccess; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.BrokerServiceConnectionException; +import at.ac.tuwien.ifs.dbrepo.core.exception.BrokerServiceException; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; +import at.ac.tuwien.ifs.dbrepo.utils.AmqpUtils; 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; @@ -36,7 +35,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; @SpringBootTest @ExtendWith(SpringExtension.class) @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) -public class BrokerServiceIntegrationTest extends AbstractUnitTest { +public class BrokerServiceIntegrationTest extends BaseTest { @Autowired private RabbitConfig rabbitConfig; @@ -54,11 +53,6 @@ public class BrokerServiceIntegrationTest extends AbstractUnitTest { registry.add("dbrepo.endpoints.brokerService", rabbitContainer::getHttpUrl); } - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void updatePermissions_empty_succeeds() throws BrokerServiceException, BrokerServiceConnectionException { @@ -155,7 +149,7 @@ public class BrokerServiceIntegrationTest extends AbstractUnitTest { BrokerServiceConnectionException { /* test */ - final TopicPermissionDto permissions = setTopicExchangePermissions_generic(List.of(DATABASE_1_USER_1_READ_ACCESS)); + final TopicPermissionDto permissions = setTopicExchangePermissions_generic(List.of(DATABASE_1.getAccesses().get(0))); assertEquals(USER_1_USERNAME, permissions.getUser()); assertEquals(REALM_DBREPO_NAME, permissions.getVhost()); assertEquals(DATABASE_1_EXCHANGE, permissions.getExchange()); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ConceptServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/ConceptServiceUnitTest.java similarity index 80% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ConceptServiceUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/ConceptServiceUnitTest.java index 164f335eb73f68c986583da9881b743a32c44a06..67f14f3ebb6e9f236512cf06a8a86f9cc3d777ae 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ConceptServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/ConceptServiceUnitTest.java @@ -1,11 +1,10 @@ -package at.tuwien.service; +package at.ac.tuwien.ifs.dbrepo.service; -import at.tuwien.exception.ConceptNotFoundException; -import at.tuwien.repository.ConceptRepository; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.entities.database.table.columns.TableColumnConcept; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumnConcept; +import at.ac.tuwien.ifs.dbrepo.core.exception.ConceptNotFoundException; +import at.ac.tuwien.ifs.dbrepo.repository.ConceptRepository; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; 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; @@ -23,7 +22,7 @@ import static org.mockito.Mockito.when; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class ConceptServiceUnitTest extends AbstractUnitTest { +public class ConceptServiceUnitTest extends BaseTest { @MockBean private ConceptRepository conceptRepository; @@ -31,11 +30,6 @@ public class ConceptServiceUnitTest extends AbstractUnitTest { @Autowired private ConceptService conceptService; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void findAll_succeeds() { 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/ac/tuwien/ifs/dbrepo/service/ContainerServiceUnitTest.java similarity index 84% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/ContainerServiceUnitTest.java index a6fbbf759269d7f6b9331dc829ad2b83197be1ad..e8e17ea3ae3ec1f7d0438f9e06d53aa4dc837e33 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/ac/tuwien/ifs/dbrepo/service/ContainerServiceUnitTest.java @@ -1,15 +1,14 @@ -package at.tuwien.service; - -import at.tuwien.api.container.CreateContainerDto; -import at.tuwien.entities.container.Container; -import at.tuwien.exception.ContainerAlreadyExistsException; -import at.tuwien.exception.ContainerNotFoundException; -import at.tuwien.exception.ImageNotFoundException; -import at.tuwien.repository.ContainerRepository; -import at.tuwien.repository.ImageRepository; -import at.tuwien.test.AbstractUnitTest; +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.api.container.CreateContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.Container; +import at.ac.tuwien.ifs.dbrepo.core.exception.ContainerAlreadyExistsException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ContainerNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ImageNotFoundException; +import at.ac.tuwien.ifs.dbrepo.repository.ContainerRepository; +import at.ac.tuwien.ifs.dbrepo.repository.ImageRepository; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; 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; @@ -32,7 +31,7 @@ import static org.mockito.Mockito.when; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class ContainerServiceUnitTest extends AbstractUnitTest { +public class ContainerServiceUnitTest extends BaseTest { @MockBean private ContainerRepository containerRepository; @@ -43,22 +42,17 @@ public class ContainerServiceUnitTest extends AbstractUnitTest { @Autowired private ContainerService containerService; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void create_succeeds() throws ContainerAlreadyExistsException, ImageNotFoundException { final CreateContainerDto request = CreateContainerDto.builder() - .imageId(IMAGE_1_ID) + .imageId(CONTAINER_1_ID) .name(CONTAINER_1_NAME) .build(); /* mock */ when(containerRepository.findByInternalName(CONTAINER_1_NAME)) .thenReturn(Optional.empty()); - when(imageRepository.findById(IMAGE_1_ID)) + when(imageRepository.findById(CONTAINER_1_ID)) .thenReturn(Optional.of(IMAGE_1)); when(containerRepository.save(any(Container.class))) .thenReturn(CONTAINER_1); @@ -71,12 +65,12 @@ public class ContainerServiceUnitTest extends AbstractUnitTest { @Test public void create_containerExists_fails() { final CreateContainerDto request = CreateContainerDto.builder() - .imageId(IMAGE_1_ID) + .imageId(CONTAINER_1_ID) .name(CONTAINER_1_NAME) .build(); /* mock */ - when(containerRepository.findByInternalName(CONTAINER_1_INTERNALNAME)) + when(containerRepository.findByInternalName(CONTAINER_1_INTERNAL_NAME)) .thenReturn(Optional.of(CONTAINER_1)); /* test */ @@ -95,7 +89,7 @@ public class ContainerServiceUnitTest extends AbstractUnitTest { /* mock */ when(containerRepository.findByInternalName(CONTAINER_1_NAME)) .thenReturn(Optional.empty()); - when(imageRepository.findById(IMAGE_1_ID)) + when(imageRepository.findById(CONTAINER_1_ID)) .thenReturn(Optional.empty()); /* test */ 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/ac/tuwien/ifs/dbrepo/service/DataCiteIdentifierServicePersistenceTest.java similarity index 89% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DataCiteIdentifierServicePersistenceTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/DataCiteIdentifierServicePersistenceTest.java index 260aebe7be411cd1ac32c63160a8964d26c0f9a3..b96bc4bad2611d7a5ce87d44afa007e434c4796e 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/ac/tuwien/ifs/dbrepo/service/DataCiteIdentifierServicePersistenceTest.java @@ -1,20 +1,21 @@ -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; +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.api.datacite.DataCiteBody; +import at.ac.tuwien.ifs.dbrepo.core.api.datacite.doi.DataCiteDoi; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.BibliographyTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.Creator; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.Identifier; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.IdentifierStatusType; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.NameIdentifierSchemeType; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.gateway.SearchServiceGateway; +import at.ac.tuwien.ifs.dbrepo.repository.ContainerRepository; +import at.ac.tuwien.ifs.dbrepo.repository.DatabaseRepository; +import at.ac.tuwien.ifs.dbrepo.repository.LicenseRepository; +import at.ac.tuwien.ifs.dbrepo.repository.UserRepository; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -45,8 +46,8 @@ import static org.mockito.Mockito.when; @ExtendWith(SpringExtension.class) @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) -@SpringBootTest(properties = "spring.profiles.active:local,junit,doi") -public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest { +@SpringBootTest(properties = "spring.profiles.active=local,junit,doi") +public class DataCiteIdentifierServicePersistenceTest extends BaseTest { @MockBean private SearchServiceGateway searchServiceGateway; @@ -75,7 +76,6 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest { @BeforeEach public void beforeEach() { - genesis(); /* metadata database */ licenseRepository.save(LICENSE_1); userRepository.saveAll(List.of(USER_1, USER_2, USER_3, USER_4, USER_5)); @@ -89,7 +89,7 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest { /* test */ final List<Identifier> response = dataCiteIdentifierService.findAll(null, null, null, null, null); assertEquals(7, response.size()); - for (UUID id : List.of(IDENTIFIER_1_ID, IDENTIFIER_2_ID, IDENTIFIER_3_ID, IDENTIFIER_4_ID, IDENTIFIER_5_ID, IDENTIFIER_6_ID, IDENTIFIER_7_ID)) { + for (UUID id : List.of(IDENTIFIER_1_ID, IDENTIFIER_2_ID, IDENTIFIER_3_ID, IDENTIFIER_4_ID, IDENTIFIER_5_ID, IDENTIFIER_6_ID, IDENTIFIER_7.getId())) { assertTrue(response.stream().map(Identifier::getId).toList().contains(id)); } } @@ -202,7 +202,7 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest { @Test public void create_hasDoi_succeeds() throws SearchServiceException, MalformedException, DataServiceException, QueryNotFoundException, DataServiceConnectionException, DatabaseNotFoundException, - SearchServiceConnectionException, IdentifierNotFoundException, ViewNotFoundException, + SearchServiceConnectionException, ViewNotFoundException, ExternalServiceException { final ResponseEntity<DataCiteBody<DataCiteDoi>> mock = ResponseEntity.status(HttpStatus.CREATED) .body(IDENTIFIER_1_DATA_CITE); @@ -228,7 +228,7 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest { /* test */ final Identifier response = dataCiteIdentifierService.publish(IDENTIFIER_7); - assertEquals(IDENTIFIER_7_ID, response.getId()); + assertEquals(IDENTIFIER_7.getId(), response.getId()); assertEquals(IdentifierStatusType.PUBLISHED, response.getStatus()); } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/DatabaseServicePersistenceTest.java similarity index 66% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServicePersistenceTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/DatabaseServicePersistenceTest.java index b1886aa835f2cc0cb2aac9e53365d869ec30724c..2bb1d9e89d665f0bb0a389ad167faac38d09315a 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServicePersistenceTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/DatabaseServicePersistenceTest.java @@ -1,13 +1,12 @@ -package at.tuwien.service; - -import at.tuwien.entities.container.Container; -import at.tuwien.entities.database.Database; -import at.tuwien.exception.DatabaseNotFoundException; -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; +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.exception.DatabaseNotFoundException; +import at.ac.tuwien.ifs.dbrepo.repository.ContainerRepository; +import at.ac.tuwien.ifs.dbrepo.repository.DatabaseRepository; +import at.ac.tuwien.ifs.dbrepo.repository.LicenseRepository; +import at.ac.tuwien.ifs.dbrepo.repository.UserRepository; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -21,13 +20,12 @@ import org.springframework.transaction.annotation.Transactional; import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; @Log4j2 @SpringBootTest @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) @ExtendWith(SpringExtension.class) -public class DatabaseServicePersistenceTest extends AbstractUnitTest { +public class DatabaseServicePersistenceTest extends BaseTest { @Autowired private DatabaseService databaseService; @@ -46,7 +44,6 @@ public class DatabaseServicePersistenceTest extends AbstractUnitTest { @BeforeEach public void beforeEach() { - genesis(); /* metadata database */ licenseRepository.save(LICENSE_1); userRepository.saveAll(List.of(USER_1, USER_2, USER_3, USER_4, USER_5)); @@ -68,16 +65,7 @@ public class DatabaseServicePersistenceTest extends AbstractUnitTest { public void findAllPublicOrSchemaPublicByInternalName_privateEmpty_succeeds() { /* test */ - final List<Database> response = databaseService.findAllPublicOrSchemaPublicByInternalName(DATABASE_1_INTERNALNAME); - assertEquals(0, response.size()); - } - - @Test - @Transactional(readOnly = true) - public void findAllAtLestReadAccess_privateNoAccessEmpty_succeeds() { - - /* test */ - final List<Database> response = databaseService.findAllAtLestReadAccess(USER_4_ID); + final List<Database> response = databaseService.findAllPublicOrSchemaPublicByInternalName(DATABASE_1_INTERNAL_NAME); assertEquals(0, response.size()); } 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/ac/tuwien/ifs/dbrepo/service/DatabaseServiceUnitTest.java similarity index 88% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/DatabaseServiceUnitTest.java index 85829f6ae64809f594f19d512d0cd1dcfbe80de6..b2f42bd167d1814ed93f1f0cbdd1bbe5c0bf1030 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/ac/tuwien/ifs/dbrepo/service/DatabaseServiceUnitTest.java @@ -1,18 +1,17 @@ -package at.tuwien.service; - -import at.tuwien.api.database.DatabaseModifyVisibilityDto; -import at.tuwien.api.database.internal.CreateDatabaseDto; -import at.tuwien.api.user.internal.UpdateUserPasswordDto; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.database.table.Table; -import at.tuwien.entities.user.User; -import at.tuwien.exception.*; -import at.tuwien.gateway.DataServiceGateway; -import at.tuwien.gateway.SearchServiceGateway; -import at.tuwien.repository.DatabaseRepository; -import at.tuwien.test.AbstractUnitTest; +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseModifyVisibilityDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.internal.CreateDatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.internal.UpdateUserPasswordDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.Table; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.gateway.DataServiceGateway; +import at.ac.tuwien.ifs.dbrepo.gateway.SearchServiceGateway; +import at.ac.tuwien.ifs.dbrepo.repository.DatabaseRepository; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; 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; @@ -32,7 +31,7 @@ import static org.mockito.Mockito.*; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class DatabaseServiceUnitTest extends AbstractUnitTest { +public class DatabaseServiceUnitTest extends BaseTest { @MockBean private SearchServiceGateway searchServiceGateway; @@ -46,11 +45,6 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { @Autowired private DatabaseService databaseService; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void findAll_succeeds() { /* mock */ @@ -215,8 +209,8 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { @Test public void updateViewMetadata_oneMissing_succeeds() throws SearchServiceException, DataServiceException, - QueryNotFoundException, DatabaseNotFoundException, SearchServiceConnectionException, - DataServiceConnectionException, ViewNotFoundException { + DatabaseNotFoundException, SearchServiceConnectionException, DataServiceConnectionException, + ViewNotFoundException { /* mock */ when(dataServiceGateway.getViewSchemas(DATABASE_1_ID)) @@ -233,8 +227,8 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { @Test public void updateViewMetadata_allKnown_succeeds() throws SearchServiceException, DataServiceException, - QueryNotFoundException, DatabaseNotFoundException, SearchServiceConnectionException, - DataServiceConnectionException, ViewNotFoundException { + DatabaseNotFoundException, SearchServiceConnectionException, DataServiceConnectionException, + ViewNotFoundException { /* mock */ when(dataServiceGateway.getViewSchemas(DATABASE_1_ID)) @@ -251,8 +245,8 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { @Test public void updateTableMetadata_empty_succeeds() throws TableNotFoundException, SearchServiceException, - MalformedException, DataServiceException, QueryNotFoundException, DatabaseNotFoundException, - SearchServiceConnectionException, DataServiceConnectionException { + MalformedException, DataServiceException, DatabaseNotFoundException, SearchServiceConnectionException, + DataServiceConnectionException { /* mock */ when(dataServiceGateway.getTableSchemas(DATABASE_1_ID)) @@ -269,8 +263,8 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { @Test public void updateTableMetadata_allKnown_succeeds() throws TableNotFoundException, SearchServiceException, - MalformedException, DataServiceException, QueryNotFoundException, DatabaseNotFoundException, - SearchServiceConnectionException, DataServiceConnectionException { + MalformedException, DataServiceException, DatabaseNotFoundException, SearchServiceConnectionException, + DataServiceConnectionException { /* mock */ when(dataServiceGateway.getTableSchemas(DATABASE_1_ID)) @@ -287,8 +281,8 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { @Test public void updateTableMetadata_oneMissing_succeeds() throws TableNotFoundException, SearchServiceException, - MalformedException, DataServiceException, QueryNotFoundException, DatabaseNotFoundException, - SearchServiceConnectionException, DataServiceConnectionException { + MalformedException, DataServiceException, DatabaseNotFoundException, SearchServiceConnectionException, + DataServiceConnectionException { /* mock */ when(dataServiceGateway.getTableSchemas(DATABASE_1_ID)) @@ -303,7 +297,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { assertNotNull(response); final Optional<Table> optional = response.getTables() .stream() - .filter(t -> t.getInternalName().equals(TABLE_5_INTERNALNAME)) + .filter(t -> t.getInternalName().equals(TABLE_5_INTERNAL_NAME)) .findFirst(); assertTrue(optional.isPresent()); final Table table = optional.get(); @@ -513,9 +507,9 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { /* ## GENERIC TEST CASES ## */ /* ################################################################################################### */ - protected Database generic_create() throws DataServiceException, - DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, - ContainerNotFoundException, SearchServiceException, SearchServiceConnectionException { + protected Database generic_create() throws DataServiceException, DataServiceConnectionException, + UserNotFoundException, DatabaseNotFoundException, ContainerNotFoundException, SearchServiceException, + SearchServiceConnectionException, DashboardServiceException, DashboardServiceConnectionException { /* mock */ when(searchServiceGateway.update(any(Database.class))) @@ -525,7 +519,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { /* test */ final Database response = databaseService.create(CONTAINER_1, DATABASE_1_CREATE, USER_1, List.of(USER_LOCAL)); - assertTrue(response.getInternalName().startsWith(DATABASE_1_INTERNALNAME)); + assertTrue(response.getInternalName().startsWith(DATABASE_1_INTERNAL_NAME)); assertNotNull(response.getContainer()); assertNotNull(response.getTables()); assertNotNull(response.getViews()); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/EntityServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/EntityServiceUnitTest.java similarity index 86% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/EntityServiceUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/EntityServiceUnitTest.java index afe3b6e2b8b9c5e93c1afebed2eabb4a6fc9daa0..27987dd6b43c518a5f301241e762c4186e6b83c8 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/EntityServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/EntityServiceUnitTest.java @@ -1,11 +1,12 @@ -package at.tuwien.service; - -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.api.semantics.EntityDto; -import at.tuwien.api.semantics.TableColumnEntityDto; -import at.tuwien.exception.*; +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.api.semantics.EntityDto; +import at.ac.tuwien.ifs.dbrepo.core.api.semantics.TableColumnEntityDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.MalformedException; +import at.ac.tuwien.ifs.dbrepo.core.exception.OntologyNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.exception.SemanticEntityNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; -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; @@ -24,7 +25,7 @@ import static org.mockito.Mockito.when; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class EntityServiceUnitTest extends AbstractUnitTest { +public class EntityServiceUnitTest extends BaseTest { @MockBean private OntologyService ontologyService; @@ -32,11 +33,6 @@ public class EntityServiceUnitTest extends AbstractUnitTest { @Autowired private EntityService entityService; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void findByLabel_wikidataSparql_succeeds() throws MalformedException { @@ -49,7 +45,6 @@ public class EntityServiceUnitTest extends AbstractUnitTest { assertFalse(response.isEmpty()); final EntityDto entity0 = response.get(0); assertNotNull(entity0.getUri()); - log.trace("found concept {}", entity0); } @Test @@ -66,7 +61,6 @@ public class EntityServiceUnitTest extends AbstractUnitTest { assertEquals(1, response.size()); final EntityDto entity0 = response.get(0); assertNotNull(entity0.getUri()); - log.trace("found concept {}", entity0); } @Test @@ -82,7 +76,6 @@ public class EntityServiceUnitTest extends AbstractUnitTest { /* test */ final EntityDto response = entityService.findOneByUri(CONCEPT_1_URI); assertNotNull(response.getUri()); - log.trace("found concept {}", response); } @Test @@ -97,7 +90,6 @@ public class EntityServiceUnitTest extends AbstractUnitTest { assertFalse(response.isEmpty()); final EntityDto entity0 = response.get(0); assertNotNull(entity0.getUri()); - log.trace("found unit {}", entity0); } @Test @@ -114,7 +106,6 @@ public class EntityServiceUnitTest extends AbstractUnitTest { assertEquals(1, response.size()); final EntityDto entity0 = response.get(0); assertNotNull(entity0.getUri()); - log.trace("found unit {}", entity0); } @Test 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/ac/tuwien/ifs/dbrepo/service/IdentifierServicePersistenceTest.java similarity index 92% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/IdentifierServicePersistenceTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/IdentifierServicePersistenceTest.java index c053afa51d4de9404a69aa5eee8b81cb1e567384..259680ad1a23f95ef0d222ee19850f5876898c4a 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/ac/tuwien/ifs/dbrepo/service/IdentifierServicePersistenceTest.java @@ -1,18 +1,19 @@ -package at.tuwien.service; - -import at.tuwien.api.database.query.QueryDto; -import at.tuwien.api.identifier.BibliographyTypeDto; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.database.License; -import at.tuwien.entities.identifier.*; -import at.tuwien.exception.*; -import at.tuwien.gateway.DataServiceGateway; -import at.tuwien.gateway.SearchServiceGateway; -import at.tuwien.repository.ContainerRepository; -import at.tuwien.repository.DatabaseRepository; -import at.tuwien.repository.LicenseRepository; -import at.tuwien.repository.UserRepository; -import at.tuwien.test.AbstractUnitTest; +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.QueryDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.BibliographyTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.License; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.*; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; +import at.ac.tuwien.ifs.dbrepo.gateway.DataServiceGateway; +import at.ac.tuwien.ifs.dbrepo.gateway.SearchServiceGateway; +import at.ac.tuwien.ifs.dbrepo.repository.ContainerRepository; +import at.ac.tuwien.ifs.dbrepo.repository.DatabaseRepository; +import at.ac.tuwien.ifs.dbrepo.repository.LicenseRepository; +import at.ac.tuwien.ifs.dbrepo.repository.UserRepository; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -41,7 +42,7 @@ import static org.mockito.Mockito.when; @SpringBootTest @ExtendWith(SpringExtension.class) @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) -public class IdentifierServicePersistenceTest extends AbstractUnitTest { +public class IdentifierServicePersistenceTest extends BaseTest { @MockBean private DataServiceGateway dataServiceGateway; @@ -70,7 +71,6 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest { @BeforeEach public void beforeEach() { - genesis(); /* metadata database */ licenseRepository.save(LICENSE_1); userRepository.saveAll(List.of(USER_1, USER_2, USER_3, USER_4, USER_5)); @@ -84,7 +84,7 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest { /* test */ final List<Identifier> response = identifierService.findAll(null, null, null, null, null); assertEquals(7, response.size()); - for (UUID id : List.of(IDENTIFIER_1_ID, IDENTIFIER_2_ID, IDENTIFIER_3_ID, IDENTIFIER_4_ID, IDENTIFIER_5_ID, IDENTIFIER_6_ID, IDENTIFIER_7_ID)) { + for (UUID id : List.of(IDENTIFIER_1_ID, IDENTIFIER_2_ID, IDENTIFIER_3_ID, IDENTIFIER_4_ID, IDENTIFIER_5_ID, IDENTIFIER_6_ID, IDENTIFIER_7.getId())) { assertTrue(response.stream().map(Identifier::getId).toList().contains(id)); } } @@ -345,7 +345,7 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest { final List<IdentifierTitle> titles = response.getTitles(); assertEquals(2, titles.size()); final IdentifierTitle title0 = titles.get(0); - assertEquals(IDENTIFIER_1_TITLE_1_TITLE, title0.getTitle()); + assertEquals(IDENTIFIER_1.getTitles().get(0).getTitle(), title0.getTitle()); assertEquals(IDENTIFIER_1_TITLE_1_LANG, title0.getLanguage()); assertEquals(IDENTIFIER_1_TITLE_1_TYPE, title0.getTitleType()); final IdentifierTitle title1 = titles.get(1); @@ -357,7 +357,7 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest { final List<IdentifierDescription> descriptions = response.getDescriptions(); final IdentifierDescription description0 = descriptions.get(0); assertNotNull(description0.getId()); - assertEquals(IDENTIFIER_1_DESCRIPTION_1_DESCRIPTION, description0.getDescription()); + assertEquals(IDENTIFIER_1.getDescriptions().get(0).getDescription(), description0.getDescription()); assertEquals(IDENTIFIER_1_DESCRIPTION_1_LANG, description0.getLanguage()); assertEquals(IDENTIFIER_1_DESCRIPTION_1_TYPE, description0.getDescriptionType()); assertNotNull(response.getCreators()); @@ -391,7 +391,7 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest { final List<IdentifierTitle> titles = response.getTitles(); assertEquals(1, titles.size()); final IdentifierTitle title0 = titles.get(0); - assertEquals(IDENTIFIER_1_TITLE_1_TITLE, title0.getTitle()); + assertEquals(IDENTIFIER_1.getTitles().get(0).getTitle(), title0.getTitle()); assertEquals(IDENTIFIER_1_TITLE_1_LANG, title0.getLanguage()); assertEquals(IDENTIFIER_1_TITLE_1_TYPE, title0.getTitleType()); assertNotNull(response.getDescriptions()); @@ -476,8 +476,7 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest { @Test public void create_hasDoi_succeeds() throws SearchServiceException, MalformedException, DataServiceException, QueryNotFoundException, DataServiceConnectionException, DatabaseNotFoundException, - SearchServiceConnectionException, IdentifierNotFoundException, ViewNotFoundException, - ExternalServiceException { + SearchServiceConnectionException, ViewNotFoundException, ExternalServiceException { /* test */ final Identifier response = identifierService.create(DATABASE_1, USER_1, IDENTIFIER_1_CREATE_WITH_DOI_DTO); @@ -491,7 +490,7 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest { /* test */ final Identifier response = identifierService.publish(IDENTIFIER_7); - assertEquals(IDENTIFIER_7_ID, response.getId()); + assertEquals(IDENTIFIER_7.getId(), response.getId()); assertEquals(IdentifierStatusType.PUBLISHED, response.getStatus()); } } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/ImageServicePersistenceTest.java similarity index 65% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServicePersistenceTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/ImageServicePersistenceTest.java index fb501cb28179e895dfcf4340afb7dc0cfee547fb..8e597f5c6b8f9e3b048ba4ac8e85f2579e8c698c 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServicePersistenceTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/ImageServicePersistenceTest.java @@ -1,11 +1,11 @@ -package at.tuwien.service; - -import at.tuwien.exception.ImageInvalidException; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.api.container.image.ImageCreateDto; -import at.tuwien.exception.ImageAlreadyExistsException; -import at.tuwien.repository.ContainerRepository; -import at.tuwien.repository.ImageRepository; +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.ImageAlreadyExistsException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ImageInvalidException; +import at.ac.tuwien.ifs.dbrepo.repository.ContainerRepository; +import at.ac.tuwien.ifs.dbrepo.repository.ImageRepository; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -21,7 +21,7 @@ import static org.junit.jupiter.api.Assertions.*; @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) @ExtendWith(SpringExtension.class) @SpringBootTest -public class ImageServicePersistenceTest extends AbstractUnitTest { +public class ImageServicePersistenceTest extends BaseTest { @Autowired private ImageService imageService; @@ -34,7 +34,6 @@ public class ImageServicePersistenceTest extends AbstractUnitTest { @BeforeEach public void beforeEach() { - genesis(); /* metadata database */ imageRepository.save(IMAGE_1); } @@ -44,11 +43,11 @@ public class ImageServicePersistenceTest extends AbstractUnitTest { final ImageCreateDto request = ImageCreateDto.builder() .name(IMAGE_1_NAME) .version("11.1.4") // new tag - .registry(IMAGE_1_REGISTRY) - .jdbcMethod(IMAGE_1_JDBC) + .registry(IMAGE_1.getRegistry()) + .jdbcMethod(IMAGE_1_JDBC_METHOD) .dialect(IMAGE_1_DIALECT) - .driverClass(IMAGE_1_DRIVER) - .defaultPort(IMAGE_1_PORT) + .driverClass(IMAGE_1.getDriverClass()) + .defaultPort(IMAGE_1_DEFAULT_PORT) .isDefault(false) .build(); @@ -61,9 +60,9 @@ public class ImageServicePersistenceTest extends AbstractUnitTest { final ImageCreateDto request = ImageCreateDto.builder() .name(IMAGE_1_NAME) .version(IMAGE_1_VERSION) - .defaultPort(IMAGE_1_PORT) - .driverClass(IMAGE_1_DRIVER) - .jdbcMethod(IMAGE_1_JDBC) + .defaultPort(IMAGE_1_DEFAULT_PORT) + .driverClass(IMAGE_1.getDriverClass()) + .jdbcMethod(IMAGE_1_JDBC_METHOD) .dialect(IMAGE_1_DIALECT) .isDefault(IMAGE_1_IS_DEFAULT) .build(); @@ -79,10 +78,10 @@ public class ImageServicePersistenceTest extends AbstractUnitTest { final ImageCreateDto request = ImageCreateDto.builder() .name("mariadb") .version("10.5") - .registry(IMAGE_1_REGISTRY) - .defaultPort(IMAGE_1_PORT) - .driverClass(IMAGE_1_DRIVER) - .jdbcMethod(IMAGE_1_JDBC) + .registry(IMAGE_1.getRegistry()) + .defaultPort(IMAGE_1_DEFAULT_PORT) + .driverClass(IMAGE_1.getDriverClass()) + .jdbcMethod(IMAGE_1_JDBC_METHOD) .dialect(IMAGE_1_DIALECT) .isDefault(true) // <<<< .build(); @@ -94,11 +93,11 @@ public class ImageServicePersistenceTest extends AbstractUnitTest { } @Test - public void delete_hasNoContainer_succeeds() { + public void delete_hasNoContainer_succeeds() { /* test */ imageService.delete(IMAGE_1); - assertTrue(imageRepository.findById(IMAGE_1_ID).isEmpty()); + assertTrue(imageRepository.findById(CONTAINER_1_ID).isEmpty()); assertFalse(containerRepository.findById(CONTAINER_1_ID).isPresent()); /* container should NEVER be deletable in the metadata db */ } @@ -107,7 +106,7 @@ public class ImageServicePersistenceTest extends AbstractUnitTest { /* test */ imageService.delete(IMAGE_1); - assertTrue(imageRepository.findById(IMAGE_1_ID).isEmpty()); + assertTrue(imageRepository.findById(CONTAINER_1_ID).isEmpty()); } } 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/ac/tuwien/ifs/dbrepo/service/ImageServiceUnitTest.java similarity index 76% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServiceUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/ImageServiceUnitTest.java index dc77ff263b37406845afb93e80a5afc27f59f380..4ad64bfabef33a4c77abf504e6b5c80239e3de23 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/ac/tuwien/ifs/dbrepo/service/ImageServiceUnitTest.java @@ -1,16 +1,14 @@ -package at.tuwien.service; - -import at.tuwien.exception.ImageInvalidException; -import at.tuwien.exception.ImageNotFoundException; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.api.container.image.ImageChangeDto; -import at.tuwien.api.container.image.ImageCreateDto; -import at.tuwien.entities.container.image.ContainerImage; -import at.tuwien.exception.ImageAlreadyExistsException; -import at.tuwien.repository.ImageRepository; -import at.tuwien.service.impl.ImageServiceImpl; -import jakarta.validation.ConstraintViolationException; -import org.junit.jupiter.api.BeforeEach; +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageChangeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.image.ContainerImage; +import at.ac.tuwien.ifs.dbrepo.core.exception.ImageAlreadyExistsException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ImageInvalidException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ImageNotFoundException; +import at.ac.tuwien.ifs.dbrepo.repository.ImageRepository; +import at.ac.tuwien.ifs.dbrepo.service.impl.ImageServiceImpl; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -23,11 +21,12 @@ import java.util.Optional; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; @ExtendWith(SpringExtension.class) @SpringBootTest -public class ImageServiceUnitTest extends AbstractUnitTest { +public class ImageServiceUnitTest extends BaseTest { @MockBean private ImageRepository imageRepository; @@ -35,11 +34,6 @@ public class ImageServiceUnitTest extends AbstractUnitTest { @Autowired private ImageService imageService; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void getAll_succeeds() { @@ -58,11 +52,11 @@ public class ImageServiceUnitTest extends AbstractUnitTest { public void getById_succeeds() throws ImageNotFoundException { /* mock */ - when(imageRepository.findById(IMAGE_1_ID)) + when(imageRepository.findById(CONTAINER_1_ID)) .thenReturn(Optional.of(IMAGE_1)); /* test */ - final ContainerImage response = imageService.find(IMAGE_1_ID); + final ContainerImage response = imageService.find(CONTAINER_1_ID); assertEquals(IMAGE_1_NAME, response.getName()); assertEquals(IMAGE_1_VERSION, response.getVersion()); } @@ -71,12 +65,12 @@ public class ImageServiceUnitTest extends AbstractUnitTest { public void getById_notFound_fails() { /* mock */ - when(imageRepository.findById(IMAGE_1_ID)) + when(imageRepository.findById(CONTAINER_1_ID)) .thenReturn(Optional.empty()); /* test */ assertThrows(ImageNotFoundException.class, () -> { - imageService.find(IMAGE_1_ID); + imageService.find(CONTAINER_1_ID); }); } @@ -85,7 +79,7 @@ public class ImageServiceUnitTest extends AbstractUnitTest { final ImageCreateDto request = ImageCreateDto.builder() .name(IMAGE_1_NAME) .version(IMAGE_1_VERSION) - .defaultPort(IMAGE_1_PORT) + .defaultPort(IMAGE_1_DEFAULT_PORT) .build(); /* mock */ @@ -103,7 +97,7 @@ public class ImageServiceUnitTest extends AbstractUnitTest { final ImageCreateDto request = ImageCreateDto.builder() .name(IMAGE_1_NAME) .version("10.5") - .defaultPort(IMAGE_1_PORT) + .defaultPort(IMAGE_1_DEFAULT_PORT) .isDefault(true) .build(); @@ -123,11 +117,11 @@ public class ImageServiceUnitTest extends AbstractUnitTest { public void update_succeeds() { final ImageServiceImpl mockImageService = mock(ImageServiceImpl.class); final ImageChangeDto request = ImageChangeDto.builder() - .defaultPort(IMAGE_1_PORT) + .defaultPort(IMAGE_1_DEFAULT_PORT) .build(); /* mock */ - when(imageRepository.findById(IMAGE_1_ID)) + when(imageRepository.findById(CONTAINER_1_ID)) .thenReturn(Optional.of(IMAGE_1)); when(imageRepository.save(any())) .thenReturn(IMAGE_1); @@ -148,7 +142,7 @@ public class ImageServiceUnitTest extends AbstractUnitTest { .build(); /* mock */ - when(imageRepository.findById(IMAGE_1_ID)) + when(imageRepository.findById(CONTAINER_1_ID)) .thenReturn(Optional.of(IMAGE_1)); when(imageRepository.save(any())) .thenReturn(IMAGE_1); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/LicenseServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/LicenseServiceUnitTest.java similarity index 79% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/LicenseServiceUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/LicenseServiceUnitTest.java index a73ce8df2497dbdcedffa589f08f73ad2e174397..417c50424fb5280f6a22fc710782deb94d3839d8 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/LicenseServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/LicenseServiceUnitTest.java @@ -1,11 +1,10 @@ -package at.tuwien.service; +package at.ac.tuwien.ifs.dbrepo.service; -import at.tuwien.exception.LicenseNotFoundException; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.entities.database.License; -import at.tuwien.repository.LicenseRepository; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.License; +import at.ac.tuwien.ifs.dbrepo.core.exception.LicenseNotFoundException; +import at.ac.tuwien.ifs.dbrepo.repository.LicenseRepository; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; 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; @@ -24,7 +23,7 @@ import static org.mockito.Mockito.when; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class LicenseServiceUnitTest extends AbstractUnitTest { +public class LicenseServiceUnitTest extends BaseTest { @MockBean private LicenseRepository licenseRepository; @@ -32,11 +31,6 @@ public class LicenseServiceUnitTest extends AbstractUnitTest { @Autowired private LicenseService licenseService; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void findAll_succeeds() { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/MessageServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/MessageServiceUnitTest.java similarity index 85% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/MessageServiceUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/MessageServiceUnitTest.java index fb7806f454684e10e8dd819018a03283b90fb418..0fb606d6dfea57eb506fa10d1d9ce7f3a99b714c 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/MessageServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/MessageServiceUnitTest.java @@ -1,13 +1,12 @@ -package at.tuwien.service; - -import at.tuwien.exception.MessageNotFoundException; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.api.maintenance.BannerMessageCreateDto; -import at.tuwien.api.maintenance.BannerMessageUpdateDto; -import at.tuwien.entities.maintenance.BannerMessage; -import at.tuwien.repository.BannerMessageRepository; +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.maintenance.BannerMessage; +import at.ac.tuwien.ifs.dbrepo.core.exception.MessageNotFoundException; +import at.ac.tuwien.ifs.dbrepo.repository.BannerMessageRepository; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; 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; @@ -23,14 +22,13 @@ import java.util.UUID; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.when; @Log4j2 @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) @SpringBootTest @ExtendWith(SpringExtension.class) -public class MessageServiceUnitTest extends AbstractUnitTest { +public class MessageServiceUnitTest extends BaseTest { @MockBean private BannerMessageRepository bannerMessageRepository; @@ -38,11 +36,6 @@ public class MessageServiceUnitTest extends AbstractUnitTest { @Autowired private BannerMessageService bannerMessageService; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void findAll_succeeds() { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/MetadataServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/MetadataServiceUnitTest.java similarity index 86% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/MetadataServiceUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/MetadataServiceUnitTest.java index 2f4fd3a85aaca28de490b2953acde20804fb70cd..f96d6807f0071d9c3ee7b2a64c6846559022b80e 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/MetadataServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/MetadataServiceUnitTest.java @@ -1,22 +1,21 @@ -package at.tuwien.service; - -import at.tuwien.api.crossref.CrossrefDto; -import at.tuwien.api.orcid.OrcidDto; -import at.tuwien.api.ror.RorDto; -import at.tuwien.api.user.external.ExternalMetadataDto; -import at.tuwien.api.user.external.affiliation.ExternalAffiliationDto; -import at.tuwien.exception.*; -import at.tuwien.gateway.CrossrefGateway; -import at.tuwien.gateway.OrcidGateway; -import at.tuwien.gateway.RorGateway; -import at.tuwien.oaipmh.OaiErrorType; -import at.tuwien.oaipmh.OaiListIdentifiersParameters; -import at.tuwien.oaipmh.OaiRecordParameters; -import at.tuwien.test.AbstractUnitTest; +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.api.crossref.CrossRefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.OrcidDto; +import at.ac.tuwien.ifs.dbrepo.core.api.ror.RorDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.external.ExternalMetadataDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.external.affiliation.ExternalAffiliationDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; +import at.ac.tuwien.ifs.dbrepo.gateway.CrossRefGateway; +import at.ac.tuwien.ifs.dbrepo.gateway.OrcidGateway; +import at.ac.tuwien.ifs.dbrepo.gateway.RorGateway; +import at.ac.tuwien.ifs.dbrepo.oaipmh.OaiErrorType; +import at.ac.tuwien.ifs.dbrepo.oaipmh.OaiListIdentifiersParameters; +import at.ac.tuwien.ifs.dbrepo.oaipmh.OaiRecordParameters; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; 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; @@ -40,7 +39,7 @@ import static org.mockito.Mockito.when; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class MetadataServiceUnitTest extends AbstractUnitTest { +public class MetadataServiceUnitTest extends BaseTest { @MockBean private OrcidGateway orcidGateway; @@ -49,7 +48,7 @@ public class MetadataServiceUnitTest extends AbstractUnitTest { private RorGateway rorGateway; @MockBean - private CrossrefGateway crossrefGateway; + private CrossRefGateway crossRefGateway; @MockBean private IdentifierService identifierService; @@ -60,11 +59,6 @@ public class MetadataServiceUnitTest extends AbstractUnitTest { @Autowired private ObjectMapper objectMapper; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void identify_succeeds() { @@ -209,11 +203,11 @@ public class MetadataServiceUnitTest extends AbstractUnitTest { @Test public void findByUrl_doi_succeeds() throws OrcidNotFoundException, RorNotFoundException, IOException, DoiNotFoundException, IdentifierNotSupportedException { - final CrossrefDto doi = objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .readValue(new File("src/test/resources/json/doi_ec.json"), CrossrefDto.class); + final CrossRefDto doi = objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .readValue(new File("src/test/resources/json/doi_ec.json"), CrossRefDto.class); /* mock */ - when(crossrefGateway.findById(FUNDER_1_IDENTIFIER_ID_ONLY)) + when(crossRefGateway.findById(FUNDER_1_IDENTIFIER_ID_ONLY)) .thenReturn(doi); /* test */ @@ -229,7 +223,7 @@ public class MetadataServiceUnitTest extends AbstractUnitTest { /* mock */ doThrow(DoiNotFoundException.class) - .when(crossrefGateway) + .when(crossRefGateway) .findById(anyString()); /* test */ diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/StorageServiceIntegrationTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/StorageServiceIntegrationTest.java similarity index 89% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/StorageServiceIntegrationTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/StorageServiceIntegrationTest.java index 5ef5f9742bbfdcc8c5ab21360ca926fd61261244..21c2f6199a058fddc777e509fa144199510c21d4 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/StorageServiceIntegrationTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/StorageServiceIntegrationTest.java @@ -1,8 +1,9 @@ -package at.tuwien.service; +package at.ac.tuwien.ifs.dbrepo.service; -import at.tuwien.config.S3Config; -import at.tuwien.exception.*; -import at.tuwien.test.AbstractUnitTest; +import at.ac.tuwien.ifs.dbrepo.config.S3Config; +import at.ac.tuwien.ifs.dbrepo.core.exception.StorageNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.exception.StorageUnavailableException; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -33,7 +34,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) @SpringBootTest @ExtendWith(SpringExtension.class) -public class StorageServiceIntegrationTest extends AbstractUnitTest { +public class StorageServiceIntegrationTest extends BaseTest { @Autowired private StorageService storageService; @@ -45,7 +46,7 @@ public class StorageServiceIntegrationTest extends AbstractUnitTest { private S3Config s3Config; @Container - private static final MinIOContainer minIOContainer = new MinIOContainer("minio/minio:RELEASE.2024-06-06T09-36-42Z"); + private static final MinIOContainer minIOContainer = new MinIOContainer(MINIO_IMAGE); @DynamicPropertySource static void dynamicProperties(DynamicPropertyRegistry registry) { @@ -54,7 +55,6 @@ public class StorageServiceIntegrationTest extends AbstractUnitTest { @BeforeEach public void beforeEach() throws SQLException { - genesis(); /* s3 */ if (s3Client.listBuckets().buckets().stream().noneMatch(b -> b.name().equals(s3Config.getS3Bucket()))) { s3Client.createBucket(CreateBucketRequest.builder() 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/ac/tuwien/ifs/dbrepo/service/TableServicePersistenceTest.java similarity index 84% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/TableServicePersistenceTest.java index 459c3b6dbe9b96077c1c48d8aadd5955a03b1303..9cdacb06b3296ff87581f8f6e59c34f61828d8a5 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/ac/tuwien/ifs/dbrepo/service/TableServicePersistenceTest.java @@ -1,24 +1,24 @@ -package at.tuwien.service; - -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.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; -import at.tuwien.entities.database.table.columns.TableColumnType; -import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKey; -import at.tuwien.entities.database.table.constraints.primaryKey.PrimaryKey; -import at.tuwien.entities.database.table.constraints.unique.Unique; -import at.tuwien.exception.*; -import at.tuwien.gateway.DataServiceGateway; -import at.tuwien.gateway.SearchServiceGateway; -import at.tuwien.repository.ContainerRepository; -import at.tuwien.repository.DatabaseRepository; -import at.tuwien.repository.LicenseRepository; -import at.tuwien.repository.UserRepository; -import at.tuwien.test.AbstractUnitTest; +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.CreateTableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.CreateTableColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.CreateTableConstraintsDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.Table; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumn; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumnType; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.foreignKey.ForeignKey; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.primaryKey.PrimaryKey; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.unique.Unique; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.gateway.DataServiceGateway; +import at.ac.tuwien.ifs.dbrepo.gateway.SearchServiceGateway; +import at.ac.tuwien.ifs.dbrepo.repository.ContainerRepository; +import at.ac.tuwien.ifs.dbrepo.repository.DatabaseRepository; +import at.ac.tuwien.ifs.dbrepo.repository.LicenseRepository; +import at.ac.tuwien.ifs.dbrepo.repository.UserRepository; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -42,7 +42,7 @@ import static org.mockito.Mockito.*; @SpringBootTest @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) @ExtendWith(SpringExtension.class) -public class TableServicePersistenceTest extends AbstractUnitTest { +public class TableServicePersistenceTest extends BaseTest { @MockBean private SearchServiceGateway searchServiceGateway; @@ -70,7 +70,6 @@ public class TableServicePersistenceTest extends AbstractUnitTest { @BeforeEach public void beforeEach() { - genesis(); /* metadata database */ licenseRepository.save(LICENSE_1); userRepository.saveAll(List.of(USER_1, USER_2, USER_3)); @@ -81,7 +80,9 @@ public class TableServicePersistenceTest extends AbstractUnitTest { @Test @Transactional public void create_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException, - UserNotFoundException, TableNotFoundException, DatabaseNotFoundException, TableExistsException, SearchServiceException, SearchServiceConnectionException, OntologyNotFoundException, SemanticEntityNotFoundException { + UserNotFoundException, TableNotFoundException, DatabaseNotFoundException, TableExistsException, + SearchServiceException, SearchServiceConnectionException, OntologyNotFoundException, + SemanticEntityNotFoundException { final CreateTableDto request = CreateTableDto.builder() .name("New Table") .description("A wonderful table") diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/TableServiceUnitTest.java similarity index 89% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/TableServiceUnitTest.java index 9b0b7fcb1a241e20048fb70f85fb8b209db5f10d..0c260f3ed673d51f5c1e588978607cf7f15580a6 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/ac/tuwien/ifs/dbrepo/service/TableServiceUnitTest.java @@ -1,28 +1,27 @@ -package at.tuwien.service; - -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.ColumnStatisticDto; -import at.tuwien.api.database.table.columns.ColumnTypeDto; -import at.tuwien.api.database.table.columns.CreateTableColumnDto; -import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto; -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.ColumnEnum; -import at.tuwien.entities.database.table.columns.ColumnSet; -import at.tuwien.entities.database.table.columns.TableColumn; -import at.tuwien.entities.database.table.columns.TableColumnType; -import at.tuwien.entities.database.table.constraints.Constraints; -import at.tuwien.exception.*; -import at.tuwien.gateway.DataServiceGateway; -import at.tuwien.gateway.SearchServiceGateway; -import at.tuwien.repository.DatabaseRepository; -import at.tuwien.test.AbstractUnitTest; +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.CreateTableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableStatisticDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnStatisticDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.CreateTableColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.concepts.ColumnSemanticsUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.CreateTableConstraintsDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign.CreateForeignKeyDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.Table; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.ColumnEnum; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.ColumnSet; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumn; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumnType; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.Constraints; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.gateway.DataServiceGateway; +import at.ac.tuwien.ifs.dbrepo.gateway.SearchServiceGateway; +import at.ac.tuwien.ifs.dbrepo.repository.DatabaseRepository; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; 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; @@ -42,7 +41,7 @@ import static org.mockito.Mockito.*; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class TableServiceUnitTest extends AbstractUnitTest { +public class TableServiceUnitTest extends BaseTest { @MockBean private DatabaseRepository databaseRepository; @@ -68,11 +67,6 @@ public class TableServiceUnitTest extends AbstractUnitTest { @Autowired private TableService tableService; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void findById_succeeds() throws TableNotFoundException, DatabaseNotFoundException { @@ -188,15 +182,14 @@ public class TableServiceUnitTest extends AbstractUnitTest { public void updateStatistics_columnNotFound_fails() throws TableNotFoundException, DataServiceException, DataServiceConnectionException { final TableStatisticDto mock = TableStatisticDto.builder() - .columns(new HashMap<>() {{ - put("unknown_column", ColumnStatisticDto.builder() - .min(BigDecimal.valueOf(11.2)) - .max(BigDecimal.valueOf(23.1)) - .mean(BigDecimal.valueOf(13.5333)) - .median(BigDecimal.valueOf(11.4)) - .stdDev(BigDecimal.valueOf(4.2952)) - .build()); - }}) + .columns(new LinkedList<>(List.of(ColumnStatisticDto.builder() + .name("unknown_column") + .min(BigDecimal.valueOf(11.2)) + .max(BigDecimal.valueOf(23.1)) + .mean(BigDecimal.valueOf(13.5333)) + .median(BigDecimal.valueOf(11.4)) + .stdDev(BigDecimal.valueOf(4.2952)) + .build()))) .build(); /* mock */ @@ -286,7 +279,7 @@ public class TableServiceUnitTest extends AbstractUnitTest { /* test */ final Table response = tableService.createTable(DATABASE_1, TABLE_3_CREATE_DTO, USER_1_PRINCIPAL); - assertEquals(TABLE_3_INTERNALNAME, response.getInternalName()); + assertEquals(TABLE_3_INTERNAL_NAME, response.getInternalName()); } @Test diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UnitServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/UnitServiceUnitTest.java similarity index 80% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UnitServiceUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/UnitServiceUnitTest.java index 67b396c66015ca66f392fbd424c0c94daa717a69..e8e73fca32043680abfa0e473840daaf1acdad49 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UnitServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/UnitServiceUnitTest.java @@ -1,11 +1,10 @@ -package at.tuwien.service; +package at.ac.tuwien.ifs.dbrepo.service; -import at.tuwien.repository.UnitRepository; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.entities.database.table.columns.TableColumnUnit; -import at.tuwien.exception.UnitNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumnUnit; +import at.ac.tuwien.ifs.dbrepo.core.exception.UnitNotFoundException; +import at.ac.tuwien.ifs.dbrepo.repository.UnitRepository; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; 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; @@ -24,7 +23,7 @@ import static org.mockito.Mockito.when; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class UnitServiceUnitTest extends AbstractUnitTest { +public class UnitServiceUnitTest extends BaseTest { @MockBean private UnitRepository unitRepository; @@ -32,11 +31,6 @@ public class UnitServiceUnitTest extends AbstractUnitTest { @Autowired private UnitService unitService; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test @Transactional public void findAll_succeeds() { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceIntegrationTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/UserServiceIntegrationTest.java similarity index 75% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceIntegrationTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/UserServiceIntegrationTest.java index 39aed0d28ea800574177821a252dbbfbde647db9..9311d0dd3461b19b0a13c9e85224dc8ae63259b5 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceIntegrationTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/UserServiceIntegrationTest.java @@ -1,12 +1,11 @@ -package at.tuwien.service; +package at.ac.tuwien.ifs.dbrepo.service; -import at.tuwien.entities.user.User; -import at.tuwien.exception.AuthServiceException; -import at.tuwien.exception.UserNotFoundException; -import at.tuwien.gateway.KeycloakGateway; -import at.tuwien.repository.UserRepository; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.utils.KeycloakUtils; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.AuthServiceException; +import at.ac.tuwien.ifs.dbrepo.core.exception.UserNotFoundException; +import at.ac.tuwien.ifs.dbrepo.repository.UserRepository; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; +import at.ac.tuwien.ifs.dbrepo.utils.KeycloakUtils; import dasniko.testcontainers.keycloak.KeycloakContainer; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; @@ -14,7 +13,6 @@ 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; @@ -22,17 +20,14 @@ import org.testcontainers.images.PullPolicy; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; -import java.util.List; -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; @Log4j2 @Testcontainers @ExtendWith(SpringExtension.class) @SpringBootTest -public class UserServiceIntegrationTest extends AbstractUnitTest { +public class UserServiceIntegrationTest extends BaseTest { @Autowired private UserRepository userRepository; @@ -45,14 +40,13 @@ public class UserServiceIntegrationTest extends AbstractUnitTest { @BeforeEach public void beforeEach() { - genesis(); /* keycloak */ userRepository.deleteAll(); keycloakUtils.deleteUser(USER_1_USERNAME); } @Container - private static KeycloakContainer keycloakContainer = new KeycloakContainer(KEYCLOAK_IMAGE) + private static final KeycloakContainer keycloakContainer = new KeycloakContainer(KEYCLOAK_IMAGE) .withImagePullPolicy(PullPolicy.alwaysPull()) .withAdminUsername("admin") .withAdminPassword("admin") 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/ac/tuwien/ifs/dbrepo/service/UserServicePersistenceTest.java similarity index 84% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServicePersistenceTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/UserServicePersistenceTest.java index c224fa9a856e41e6c327fe6d05334fc953c91cea..cb4e873ac9d27ee9e74505a71053eecb144ba1d5 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/ac/tuwien/ifs/dbrepo/service/UserServicePersistenceTest.java @@ -1,12 +1,12 @@ -package at.tuwien.service; - -import at.tuwien.api.user.UserUpdateDto; -import at.tuwien.entities.user.User; -import at.tuwien.exception.AuthServiceException; -import at.tuwien.exception.UserNotFoundException; -import at.tuwien.gateway.KeycloakGateway; -import at.tuwien.repository.UserRepository; -import at.tuwien.test.AbstractUnitTest; +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.AuthServiceException; +import at.ac.tuwien.ifs.dbrepo.core.exception.UserNotFoundException; +import at.ac.tuwien.ifs.dbrepo.gateway.KeycloakGateway; +import at.ac.tuwien.ifs.dbrepo.repository.UserRepository; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -26,7 +26,7 @@ import static org.mockito.Mockito.doNothing; @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) @SpringBootTest @ExtendWith(SpringExtension.class) -public class UserServicePersistenceTest extends AbstractUnitTest { +public class UserServicePersistenceTest extends BaseTest { @Autowired private UserRepository userRepository; @@ -39,7 +39,6 @@ public class UserServicePersistenceTest extends AbstractUnitTest { @BeforeEach public void beforeEach() { - genesis(); /* metadata database */ userRepository.saveAll(List.of(USER_1, USER_LOCAL)); } 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/ac/tuwien/ifs/dbrepo/service/UserServiceUnitTest.java similarity index 82% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/UserServiceUnitTest.java index c610f3ee95d6d8e78cc11a4b6ac826b5a296c80b..8a6a29400b053029dfb7e5bc9557251a0caaa21f 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/ac/tuwien/ifs/dbrepo/service/UserServiceUnitTest.java @@ -1,13 +1,12 @@ -package at.tuwien.service; - -import at.tuwien.api.user.UserUpdateDto; -import at.tuwien.entities.user.User; -import at.tuwien.exception.AuthServiceException; -import at.tuwien.exception.UserNotFoundException; -import at.tuwien.gateway.KeycloakGateway; -import at.tuwien.repository.UserRepository; -import at.tuwien.test.AbstractUnitTest; -import org.junit.jupiter.api.BeforeEach; +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.AuthServiceException; +import at.ac.tuwien.ifs.dbrepo.core.exception.UserNotFoundException; +import at.ac.tuwien.ifs.dbrepo.gateway.KeycloakGateway; +import at.ac.tuwien.ifs.dbrepo.repository.UserRepository; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -25,7 +24,7 @@ import static org.mockito.Mockito.*; @ExtendWith(SpringExtension.class) @SpringBootTest -public class UserServiceUnitTest extends AbstractUnitTest { +public class UserServiceUnitTest extends BaseTest { @MockBean private UserRepository userRepository; @@ -36,11 +35,6 @@ public class UserServiceUnitTest extends AbstractUnitTest { @Autowired private UserService userService; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void findByUsername_succeeds() throws UserNotFoundException { 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/ac/tuwien/ifs/dbrepo/service/ViewServicePersistenceTest.java similarity index 78% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/ViewServicePersistenceTest.java index 57a84965dc81615613f201e6aee4e771582ac090..33cc7db8a441c46b32d419c7ad804262028b65e8 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/ac/tuwien/ifs/dbrepo/service/ViewServicePersistenceTest.java @@ -1,16 +1,15 @@ -package at.tuwien.service; - -import at.tuwien.entities.database.Database; -import at.tuwien.entities.database.View; -import at.tuwien.entities.database.ViewColumn; -import at.tuwien.exception.*; -import at.tuwien.gateway.DataServiceGateway; -import at.tuwien.gateway.SearchServiceGateway; -import at.tuwien.repository.ContainerRepository; -import at.tuwien.repository.DatabaseRepository; -import at.tuwien.repository.LicenseRepository; -import at.tuwien.repository.UserRepository; -import at.tuwien.test.AbstractUnitTest; +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.View; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.gateway.DataServiceGateway; +import at.ac.tuwien.ifs.dbrepo.gateway.SearchServiceGateway; +import at.ac.tuwien.ifs.dbrepo.repository.ContainerRepository; +import at.ac.tuwien.ifs.dbrepo.repository.DatabaseRepository; +import at.ac.tuwien.ifs.dbrepo.repository.LicenseRepository; +import at.ac.tuwien.ifs.dbrepo.repository.UserRepository; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; @@ -35,7 +34,7 @@ import static org.mockito.Mockito.when; @Disabled("CI/CD") @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) @ExtendWith(SpringExtension.class) -public class ViewServicePersistenceTest extends AbstractUnitTest { +public class ViewServicePersistenceTest extends BaseTest { @Autowired private UserRepository userRepository; @@ -60,7 +59,6 @@ public class ViewServicePersistenceTest extends AbstractUnitTest { @BeforeEach public void beforeEach() { - genesis(); /* metadata database */ licenseRepository.save(LICENSE_1); userRepository.saveAll(List.of(USER_1, USER_2, USER_3)); 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/ac/tuwien/ifs/dbrepo/service/ViewServiceUnitTest.java similarity index 86% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/service/ViewServiceUnitTest.java index e99fef1acc76dd0067b9b94233dea06c7c23b30b..a50b7ca3397d1738ab16c30b711576b3d89b3113 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/ac/tuwien/ifs/dbrepo/service/ViewServiceUnitTest.java @@ -1,15 +1,14 @@ -package at.tuwien.service; - -import at.tuwien.api.database.CreateViewDto; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.database.View; -import at.tuwien.exception.*; -import at.tuwien.gateway.DataServiceGateway; -import at.tuwien.gateway.SearchServiceGateway; -import at.tuwien.repository.DatabaseRepository; -import at.tuwien.test.AbstractUnitTest; +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.api.database.CreateViewDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.View; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.gateway.DataServiceGateway; +import at.ac.tuwien.ifs.dbrepo.gateway.SearchServiceGateway; +import at.ac.tuwien.ifs.dbrepo.repository.DatabaseRepository; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; 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; @@ -29,7 +28,7 @@ import static org.mockito.Mockito.*; @Testcontainers @SpringBootTest @ExtendWith(SpringExtension.class) -public class ViewServiceUnitTest extends AbstractUnitTest { +public class ViewServiceUnitTest extends BaseTest { @MockBean private DataServiceGateway dataServiceGateway; @@ -43,11 +42,6 @@ public class ViewServiceUnitTest extends AbstractUnitTest { @Autowired private ViewService viewService; - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void create_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException, TableNotFoundException, @@ -94,20 +88,6 @@ public class ViewServiceUnitTest extends AbstractUnitTest { }); } - @Test - public void findAll_public_succeeds() { - - /* test */ - viewService.findAll(DATABASE_1, null); - } - - @Test - public void findAll_publicAndPrivate_succeeds() { - - /* test */ - viewService.findAll(DATABASE_1, USER_1); - } - @Test public void delete_succeeds() throws DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, ViewNotFoundException, SearchServiceException, SearchServiceConnectionException { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/AmqpUtils.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/utils/AmqpUtils.java similarity index 98% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/AmqpUtils.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/utils/AmqpUtils.java index df86598714d65600e0dc79b5f6a3048fb3df16b5..09017252d8f539c8d3119751d68905edde2a1e5a 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/AmqpUtils.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/utils/AmqpUtils.java @@ -1,7 +1,7 @@ -package at.tuwien.utils; +package at.ac.tuwien.ifs.dbrepo.utils; -import at.tuwien.api.amqp.*; -import at.tuwien.test.BaseTest; +import at.ac.tuwien.ifs.dbrepo.core.api.amqp.*; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; import lombok.extern.log4j.Log4j2; import org.apache.commons.codec.binary.Base64; import org.springframework.beans.factory.annotation.Autowired; diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/H2Utils.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/utils/H2Utils.java similarity index 96% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/H2Utils.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/utils/H2Utils.java index 7c80d5274a386031276fdb48eab6eaa3e2989024..f10486047aabaec096dd2d98763f76f62c3a1e9b 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/H2Utils.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/utils/H2Utils.java @@ -1,4 +1,4 @@ -package at.tuwien.utils; +package at.ac.tuwien.ifs.dbrepo.utils; import jakarta.persistence.EntityManager; import lombok.extern.log4j.Log4j2; 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/ac/tuwien/ifs/dbrepo/utils/KeycloakUtils.java similarity index 90% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/KeycloakUtils.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/utils/KeycloakUtils.java index 100178a337fc142d9694c1ad5813d71b34c6423e..9a0ea26a733c6c92b3c3cbd04ca9dfdc86808db0 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/ac/tuwien/ifs/dbrepo/utils/KeycloakUtils.java @@ -1,9 +1,9 @@ -package at.tuwien.utils; +package at.ac.tuwien.ifs.dbrepo.utils; -import at.tuwien.api.keycloak.UserCreateDto; -import at.tuwien.config.KeycloakConfig; -import at.tuwien.exception.UserNotFoundException; -import at.tuwien.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.UserCreateDto; +import at.ac.tuwien.ifs.dbrepo.config.KeycloakConfig; +import at.ac.tuwien.ifs.dbrepo.core.exception.UserNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; import jakarta.ws.rs.core.Response; import lombok.extern.log4j.Log4j2; import org.keycloak.admin.client.Keycloak; diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/XmlUtils.java b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/utils/XmlUtils.java similarity index 96% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/XmlUtils.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/utils/XmlUtils.java index b351d2798eb2c441c228e38e46693c55e864464b..268d2c0be5c1de0d471d35cb40bc4317ec337a59 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/XmlUtils.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/utils/XmlUtils.java @@ -1,4 +1,4 @@ -package at.tuwien.utils; +package at.ac.tuwien.ifs.dbrepo.utils; import java.io.File; import java.io.IOException; 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/ac/tuwien/ifs/dbrepo/validator/EndpointValidatorUnitTest.java similarity index 94% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/validator/EndpointValidatorUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/ac/tuwien/ifs/dbrepo/validator/EndpointValidatorUnitTest.java index 1e7ce07afde0616c8915549cfa3e1bcc72bcb658..3d3675c28531b213fcbbaf0282809eb4855122f3 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/ac/tuwien/ifs/dbrepo/validator/EndpointValidatorUnitTest.java @@ -1,20 +1,19 @@ -package at.tuwien.validator; - -import at.tuwien.SortType; -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; -import at.tuwien.exception.*; -import at.tuwien.service.AccessService; -import at.tuwien.service.DatabaseService; -import at.tuwien.service.TableService; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.validation.EndpointValidator; +package at.ac.tuwien.ifs.dbrepo.validator; + +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.CreateTableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.SortType; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.CreateTableColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierSaveDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.service.AccessService; +import at.ac.tuwien.ifs.dbrepo.service.DatabaseService; +import at.ac.tuwien.ifs.dbrepo.service.TableService; +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; +import at.ac.tuwien.ifs.dbrepo.validation.EndpointValidator; 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; @@ -38,7 +37,7 @@ import static org.mockito.Mockito.when; @Log4j2 @SpringBootTest @ExtendWith(SpringExtension.class) -public class EndpointValidatorUnitTest extends AbstractUnitTest { +public class EndpointValidatorUnitTest extends BaseTest { @MockBean private DatabaseService databaseService; @@ -78,11 +77,6 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest { ); } - @BeforeEach - public void beforeEach() { - genesis(); - } - @Test public void validateDataParams_succeeds() throws PaginationException { @@ -216,7 +210,7 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest { when(databaseService.findById(DATABASE_1_ID)) .thenReturn(DATABASE_1); when(accessService.find(eq(DATABASE_1), any(User.class))) - .thenReturn(DATABASE_1_USER_1_READ_ACCESS); + .thenReturn(DATABASE_1.getAccesses().get(0)); /* test */ endpointValidator.validateOnlyAccessOrPublic(DATABASE_1, USER_1_PRINCIPAL); @@ -286,7 +280,7 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest { 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_READ_ACCESS); + .thenReturn(DATABASE_1.getAccesses().get(0)); /* test */ assertThrows(NotAllowedException.class, () -> { @@ -374,7 +368,7 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest { when(tableService.findById(DATABASE_1, TABLE_1_ID)) .thenReturn(TABLE_1); when(accessService.find(DATABASE_1, USER_1)) - .thenReturn(DATABASE_1_USER_1_READ_ACCESS); + .thenReturn(DATABASE_1.getAccesses().get(0)); /* test */ assertThrows(NotAllowedException.class, () -> { @@ -610,7 +604,7 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest { public void validateOnlyMineOrWriteAccessOrHasRole_readAccess_fails() { /* test */ - assertFalse(endpointValidator.validateOnlyMineOrWriteAccessOrHasRole(USER_1, USER_1_PRINCIPAL, DATABASE_1_USER_1_READ_ACCESS, "nobody-role")); + assertFalse(endpointValidator.validateOnlyMineOrWriteAccessOrHasRole(USER_1, USER_1_PRINCIPAL, DATABASE_1.getAccesses().get(0), "nobody-role")); } @Test diff --git a/dbrepo-metadata-service/rest-service/src/test/resources/application.properties b/dbrepo-metadata-service/rest-service/src/test/resources/application.properties index 0929175cf79929776a59fd6d27075ae6df998de6..d96b44310278aa87e9862990dcfb5f4c74269063 100644 --- a/dbrepo-metadata-service/rest-service/src/test/resources/application.properties +++ b/dbrepo-metadata-service/rest-service/src/test/resources/application.properties @@ -23,10 +23,10 @@ logging.level.com.github.dockerjava.=warn logging.level.com.github.dockerjava.zerodep.shaded.org.apache.hc.client5.http.wire.=off # datacite -dbrepo.datacite.url: https://api.test.datacite.org -dbrepo.datacite.prefix: 10.12345 -dbrepo.datacite.username: test-user -dbrepo.datacite.password: test-password +dbrepo.datacite.url= https://api.test.datacite.org +dbrepo.datacite.prefix= 10.12345 +dbrepo.datacite.username= test-user +dbrepo.datacite.password= test-password # s3 dbrepo.s3.accessKeyId=minioadmin diff --git a/dbrepo-metadata-service/rest-service/src/test/resources/doi/database.json b/dbrepo-metadata-service/rest-service/src/test/resources/doi/database.json new file mode 100644 index 0000000000000000000000000000000000000000..94508d61a528e8eb90e4330534160d3f69ff2709 --- /dev/null +++ b/dbrepo-metadata-service/rest-service/src/test/resources/doi/database.json @@ -0,0 +1,70 @@ +{ + "indexed": { + "date-parts": [ + [ + 2024, + 12, + 11 + ] + ], + "date-time": "2024-12-11T00:54:48Z", + "timestamp": 1733878488241, + "version": "3.30.1" + }, + "reference-count": 0, + "publisher": "International STM Association", + "content-domain": { + "domain": [], + "crossmark-restriction": false + }, + "DOI": "10.15223\/policy-037", + "type": "database", + "created": { + "date-parts": [ + [ + 2021, + 5, + 3 + ] + ], + "date-time": "2021-05-03T21:10:23Z", + "timestamp": 1620076223000 + }, + "source": "Crossref", + "is-referenced-by-count": 0, + "title": "Article Sharing Framework Policy #37", + "prefix": "10.15223", + "member": "5868", + "container-title": [], + "original-title": [], + "deposited": { + "date-parts": [ + [ + 2021, + 5, + 3 + ] + ], + "date-time": "2021-05-03T21:10:23Z", + "timestamp": 1620076223000 + }, + "score": 1, + "resource": { + "primary": { + "URL": "https:\/\/www.stm-assoc.org\/asf\/policy-037" + } + }, + "subtitle": [], + "short-title": [], + "issued": { + "date-parts": [ + [ + null + ] + ] + }, + "references-count": 0, + "URL": "http:\/\/dx.doi.org\/10.15223\/policy-037", + "relation": {}, + "subject": [] +} \ No newline at end of file diff --git a/dbrepo-metadata-service/rest-service/src/test/resources/doi/dataset.json b/dbrepo-metadata-service/rest-service/src/test/resources/doi/dataset.json new file mode 100644 index 0000000000000000000000000000000000000000..f23113868971703fcb08523b96e84e6774c5fa04 --- /dev/null +++ b/dbrepo-metadata-service/rest-service/src/test/resources/doi/dataset.json @@ -0,0 +1,25 @@ +{ + "type": "dataset", + "id": "https://doi.org/10.5281/zenodo.1404173", + "author": [ + { + "family": "Marshall", + "given": "Michael" + } + ], + "issued": { + "date-parts": [ + [ + 2018, + 8, + 27 + ] + ] + }, + "abstract": "<strong>Data Set Characteristics:</strong>\n\nNumber of Instances:\n150 (50 in each of three classes)\nNumber of Attributes:\n\n4 numeric, predictive attributes and the class\nAttribute Information:\n\n\n\tsepal length in cm\n\tsepal width in cm\n\tpetal length in cm\n\tpetal width in cm\n\t\n\tclass:\n\n\t\n\t\tIris-Setosa\n\t\tIris-Versicolour\n\t\tIris-Virginica", + "DOI": "10.5281/ZENODO.1404173", + "publisher": "Zenodo", + "title": "Scikit-Learn Iris", + "URL": "https://zenodo.org/record/1404173", + "copyright": "Creative Commons Attribution 4.0" +} \ No newline at end of file diff --git a/dbrepo-metadata-service/rest-service/src/test/resources/doi/journal-article.json b/dbrepo-metadata-service/rest-service/src/test/resources/doi/journal-article.json new file mode 100644 index 0000000000000000000000000000000000000000..627ca16767f318b4ab261299b9f5bc15b3962b7a --- /dev/null +++ b/dbrepo-metadata-service/rest-service/src/test/resources/doi/journal-article.json @@ -0,0 +1,403 @@ +{ + "indexed": { + "date-parts": [ + [ + 2024, + 7, + 1 + ] + ], + "date-time": "2024-07-01T09:15:12Z", + "timestamp": 1719825312147 + }, + "reference-count": 37, + "publisher": "Ubiquity Press, Ltd.", + "content-domain": { + "domain": [], + "crossmark-restriction": false + }, + "published-print": { + "date-parts": [ + [ + 2022, + 2, + 9 + ] + ] + }, + "DOI": "10.5334\/dsj-2022-004", + "type": "journal-article", + "created": { + "date-parts": [ + [ + 2022, + 2, + 9 + ] + ], + "date-time": "2022-02-09T11:11:20Z", + "timestamp": 1644405080000 + }, + "source": "Crossref", + "is-referenced-by-count": 5, + "title": "OSSDIP: Open Source Secure Data Infrastructure and Processes Supporting Data Visiting", + "prefix": "10.5334", + "volume": "21", + "author": [ + { + "ORCID": "http:\/\/orcid.org\/0000-0003-4216-302X", + "authenticated-orcid": false, + "given": "Martin", + "family": "Weise", + "sequence": "first", + "affiliation": [] + }, + { + "ORCID": "http:\/\/orcid.org\/0000-0002-2854-0434", + "authenticated-orcid": false, + "given": "Filip", + "family": "Kovacevic", + "sequence": "additional", + "affiliation": [] + }, + { + "ORCID": "http:\/\/orcid.org\/0000-0003-4615-2774", + "authenticated-orcid": false, + "given": "Nikolas", + "family": "Popper", + "sequence": "additional", + "affiliation": [] + }, + { + "ORCID": "http:\/\/orcid.org\/0000-0002-9272-6225", + "authenticated-orcid": false, + "given": "Andreas", + "family": "Rauber", + "sequence": "additional", + "affiliation": [] + } + ], + "member": "3285", + "reference": [ + { + "key": "key20220209060905_B1", + "volume-title": "Defenders\u2019 Guide to Container Infrastructure Security", + "year": "2019" + }, + { + "issue": "2", + "key": "key20220209060905_B2", + "first-page": "315", + "article-title": "20 remoteneps: Data Dissemination in a Collaborative Workspace", + "volume": "14", + "year": "2011", + "journal-title": "Zeitschrift f\u00fcr Erziehungswissenschaft" + }, + { + "issue": "1", + "key": "key20220209060905_B3", + "article-title": "Kadi4Mat: A Research Data Infrastructure for Materials Science", + "volume": "20", + "year": "2021", + "journal-title": "Data Science Journal" + }, + { + "issue": "1", + "key": "key20220209060905_B4", + "doi-asserted-by": "crossref", + "first-page": "195", + "DOI": "10.1055\/s-0039-1677917", + "article-title": "The French Health Data Hub and the German Medical Informatics Initiatives: Two National Projects to Promote Data Sharing in Healthcare", + "volume": "28", + "year": "2019", + "journal-title": "EN. Yearbook of Medical Informatics" + }, + { + "key": "key20220209060905_B5", + "article-title": "Five Safes: Designing data access for research [Online]", + "year": "2016", + "journal-title": "Economics Working Paper Series 1601" + }, + { + "key": "key20220209060905_B6", + "article-title": "Remote Access to Official Microdata", + "year": "2020" + }, + { + "key": "key20220209060905_B7", + "first-page": "554", + "article-title": "Role-Based Access Controls", + "year": "1992" + }, + { + "key": "key20220209060905_B8", + "article-title": "De-identification of personal information", + "year": "2015", + "journal-title": "National institute of standards and technology" + }, + { + "key": "key20220209060905_B9", + "first-page": "16", + "article-title": "Secure cloud computing with a virtualized network infrastructure", + "year": "2010" + }, + { + "key": "key20220209060905_B10", + "doi-asserted-by": "crossref", + "first-page": "196", + "DOI": "10.1016\/j.jbi.2014.01.003", + "article-title": "A case study of the Secure Anonymous Information Linkage (SAIL) Gateway: A privacy-protecting remote access system for health-related research and evaluation", + "volume": "50", + "year": "2014", + "journal-title": "Journal of Biomedical Informatics" + }, + { + "issue": "4", + "key": "key20220209060905_B11", + "doi-asserted-by": "crossref", + "first-page": "533", + "DOI": "10.1016\/j.giq.2010.10.008", + "article-title": "Key Issues in Data Center Security: An Investigation of Government Audit Reports", + "volume": "28", + "year": "2011", + "journal-title": "Government Information Quarterly" + }, + { + "issue": "5", + "key": "key20220209060905_B12", + "doi-asserted-by": "crossref", + "first-page": "38", + "DOI": "10.1109\/MSEC.2020.2990230", + "article-title": "Dedicated Security Chips in the Age of Secure Enclaves", + "volume": "18", + "year": "2020", + "journal-title": "IEEE Security & Privacy" + }, + { + "issue": "3", + "key": "key20220209060905_B13", + "first-page": "34", + "volume": "41", + "year": "2012", + "journal-title": "Temporal Features in SQL:2011" + }, + { + "issue": "4", + "key": "key20220209060905_B14", + "article-title": "Watermill: An Optimized Fingerprinting System for Databases under Constraints", + "volume": "20", + "year": "2008", + "journal-title": "IEEE Transactions on Knowledge and Data Engineering" + }, + { + "key": "key20220209060905_B15", + "article-title": "Keystone: An Open Framework for Architecting Trusted Execution Environments", + "year": "2020" + }, + { + "key": "key20220209060905_B16", + "first-page": "106", + "article-title": "T-closeness: privacy beyond k-anonymity and l-diversity", + "year": "2007" + }, + { + "issue": "1", + "key": "key20220209060905_B17", + "article-title": "Fingerprinting Relational Databases: Schemes and Specialties", + "volume": "2", + "year": "2005", + "journal-title": "Transactions on Dependable and Secure Computing" + }, + { + "issue": "1", + "key": "key20220209060905_B18", + "doi-asserted-by": "crossref", + "first-page": "3", + "DOI": "10.1145\/1217299.1217302", + "article-title": "L-diversity: privacy beyond k-anonymity", + "volume": "1", + "year": "2007", + "journal-title": "Acm transactions on knowledge discovery from data (tkdd)" + }, + { + "key": "key20220209060905_B19", + "first-page": "1", + "article-title": "Database security threats and challenges", + "year": "2020" + }, + { + "key": "key20220209060905_B20", + "article-title": "Data grid concepts for data security in distributed computing", + "year": "2013", + "journal-title": "Arxiv preprint arxiv:1308.6058" + }, + { + "key": "key20220209060905_B21", + "volume-title": "A vision of a Nordic secure digital infrastructure for health data: The Nordic Commons", + "year": "2019" + }, + { + "key": "key20220209060905_B22", + "unstructured": "Peisert, S. 2021. An Examination and Survey of Data Confidentiality Issues and Solutions in Academic Research Computing. https:\/\/escholarship.org\/uc\/item\/7cz7m1ws. Online; accessed 22 December 2021." + }, + { + "key": "key20220209060905_B23", + "first-page": "561", + "article-title": "Real-Time Screen Watermarking Using Overlaying Layer", + "year": "2014", + "journal-title": "2014 Ninth International Conference on Availability, Reliability and Security" + }, + { + "issue": "4", + "key": "key20220209060905_B24", + "doi-asserted-by": "crossref", + "first-page": "203", + "DOI": "10.11128\/sne.27.tn.10396", + "article-title": "Planning Future Health: Developing Big Data and System Modelling Pipelines for Health System Research", + "volume": "27", + "year": "2017", + "journal-title": "Simulation Notes Europe" + }, + { + "key": "key20220209060905_B25", + "first-page": "231", + "article-title": "Preventing Privilege Escalation", + "year": "2003" + }, + { + "key": "key20220209060905_B26", + "year": "2015", + "journal-title": "Data Citation of Evolving Data: Recommendations of the Working Group on Data Citation (WGDC)" + }, + { + "issue": "1", + "key": "key20220209060905_B27", + "article-title": "Identification of Reproducible Subsets for Data Citation, Sharing and Re-Use", + "volume": "12", + "year": "2016", + "journal-title": "Bulletin of the IEEE Technical Committe on Digital Libraries (TCDL)" + }, + { + "key": "key20220209060905_B28", + "first-page": "199", + "article-title": "Hey, you, get off of my cloud: exploring information leakage in third-party compute clouds", + "year": "2009" + }, + { + "key": "key20220209060905_B29", + "doi-asserted-by": "crossref", + "first-page": "221", + "DOI": "10.1109\/SERVICES.2015.40", + "volume-title": "2015 IEEE world congress on services", + "year": "2015" + }, + { + "key": "key20220209060905_B30", + "doi-asserted-by": "crossref", + "first-page": "611", + "DOI": "10.1007\/978-3-658-11994-2_34", + "volume-title": "Methodological Issues of Longitudinal Surveys: The Example of the National Educational Panel Study", + "year": "2016" + }, + { + "key": "key20220209060905_B31", + "first-page": "1", + "article-title": "A collective attestation scheme towards cloud system", + "year": "2020", + "journal-title": "Cluster computing" + }, + { + "issue": "5", + "key": "key20220209060905_B32", + "doi-asserted-by": "crossref", + "first-page": "557", + "DOI": "10.1142\/S0218488502001648", + "article-title": "K-anonymity: a model for protecting privacy", + "volume": "10", + "year": "2002", + "journal-title": "International journal of uncertainty, fuzziness and knowledge-based systems" + }, + { + "key": "key20220209060905_B33", + "unstructured": "United Kingdom Health Data Research Alliance. 2020. Trusted Research Environments [Online]. URL: https:\/\/ukhealthdata.org\/projects\/aligning-approach-to-trusted-research-environments\/. Accessed September 2020. Version 2.0." + }, + { + "key": "key20220209060905_B34", + "first-page": "34", + "article-title": "FDA-DBRepo: A Data Preservation Repository Supporting FAIR Principles, Data Versioning and Reproducible Queries", + "year": "2021" + }, + { + "key": "key20220209060905_B35", + "first-page": "51", + "article-title": "A Data-Visiting Infrastructure for Providing Access to Preserved Databases that Cannot be Shared or Made Publicly Accessible", + "year": "2021" + }, + { + "key": "key20220209060905_B36", + "article-title": "OpenSAFELY: factors associated with COVID-19-related hospital death in the linked electronic health records of 17 million adult NHS patients", + "year": "2020", + "journal-title": "Medrxiv" + }, + { + "key": "key20220209060905_B37", + "first-page": "305", + "article-title": "Cross-vm side channels and their use to extract private keys", + "year": "2012" + } + ], + "container-title": "Data Science Journal", + "original-title": [], + "language": "en", + "link": [ + { + "URL": "https:\/\/doi.org\/10.5334\/dsj-2022-004", + "content-type": "unspecified", + "content-version": "vor", + "intended-application": "similarity-checking" + } + ], + "deposited": { + "date-parts": [ + [ + 2022, + 7, + 11 + ] + ], + "date-time": "2022-07-11T09:21:08Z", + "timestamp": 1657531268000 + }, + "score": 1, + "resource": { + "primary": { + "URL": "http:\/\/datascience.codata.org\/articles\/10.5334\/dsj-2022-004\/" + } + }, + "subtitle": [], + "short-title": [], + "issued": { + "date-parts": [ + [ + 2022 + ] + ] + }, + "references-count": 37, + "alternative-id": [ + "10.5334\/dsj-2022-004" + ], + "URL": "http:\/\/dx.doi.org\/10.5334\/dsj-2022-004", + "relation": {}, + "ISSN": [ + "1683-1470" + ], + "subject": [], + "published": { + "date-parts": [ + [ + 2022 + ] + ] + } +} \ No newline at end of file diff --git a/dbrepo-metadata-service/rest-service/src/test/resources/doi/proceedings-article.json b/dbrepo-metadata-service/rest-service/src/test/resources/doi/proceedings-article.json new file mode 100644 index 0000000000000000000000000000000000000000..429179549a955721b9a23d98073d41b36ff6a657 --- /dev/null +++ b/dbrepo-metadata-service/rest-service/src/test/resources/doi/proceedings-article.json @@ -0,0 +1,320 @@ +{ + "indexed": { + "date-parts": [ + [ + 2025, + 1, + 18 + ] + ], + "date-time": "2025-01-18T05:07:56Z", + "timestamp": 1737176876420, + "version": "3.33.0" + }, + "reference-count": 28, + "publisher": "IEEE", + "license": [ + { + "start": { + "date-parts": [ + [ + 2024, + 12, + 15 + ] + ], + "date-time": "2024-12-15T00:00:00Z", + "timestamp": 1734220800000 + }, + "content-version": "stm-asf", + "delay-in-days": 0, + "URL": "https:\/\/doi.org\/10.15223\/policy-029" + }, + { + "start": { + "date-parts": [ + [ + 2024, + 12, + 15 + ] + ], + "date-time": "2024-12-15T00:00:00Z", + "timestamp": 1734220800000 + }, + "content-version": "stm-asf", + "delay-in-days": 0, + "URL": "https:\/\/doi.org\/10.15223\/policy-037" + } + ], + "funder": [ + { + "DOI": "10.13039\/100016234", + "name": "ASEAN-European Academic University Network", + "doi-asserted-by": "publisher", + "id": [ + { + "id": "10.13039\/100016234", + "id-type": "DOI", + "asserted-by": "publisher" + } + ] + } + ], + "content-domain": { + "domain": [], + "crossmark-restriction": false + }, + "published-print": { + "date-parts": [ + [ + 2024, + 12, + 15 + ] + ] + }, + "DOI": "10.1109\/bigdata62323.2024.10825401", + "type": "proceedings-article", + "created": { + "date-parts": [ + [ + 2025, + 1, + 16 + ] + ], + "date-time": "2025-01-16T18:31:23Z", + "timestamp": 1737052283000 + }, + "page": "322-331", + "source": "Crossref", + "is-referenced-by-count": 0, + "title": "DBRepo: A Data Repository System for Research Data in Databases", + "prefix": "10.1109", + "author": [ + { + "given": "Martin", + "family": "Weise", + "sequence": "first", + "affiliation": [ + { + "name": "ISE, TU Wien,Data Science Research Unit,Vienna,Austria" + } + ] + }, + { + "given": "Andreas", + "family": "Rauber", + "sequence": "additional", + "affiliation": [ + { + "name": "ISE, TU Wien,Data Science Research Unit,Vienna,Austria" + } + ] + } + ], + "member": "263", + "reference": [ + { + "key": "ref1", + "doi-asserted-by": "publisher", + "DOI": "10.1002\/0470867167.ch36" + }, + { + "key": "ref2", + "doi-asserted-by": "publisher", + "DOI": "10.2218\/ijdc.v17i1.825" + }, + { + "key": "ref3", + "doi-asserted-by": "publisher", + "DOI": "10.1145\/2380776.2380786" + }, + { + "key": "ref4", + "doi-asserted-by": "publisher", + "DOI": "10.1038\/sdata.2016.18" + }, + { + "year": "2024", + "key": "ref5", + "article-title": "DataCite Metadata Schema Documentation for the Publication and Citation of Research Data and Other Research Outputs v4.5" + }, + { + "article-title": "Digital Cartographic Standard for Geologic Map Symbolization", + "volume-title": "Tech. Rep.", + "year": "2006", + "key": "ref6" + }, + { + "article-title": "FAIR Digital Objects and FAIR Signposting", + "year": "2023", + "author": "Van de Sompel", + "key": "ref7" + }, + { + "key": "ref8", + "doi-asserted-by": "publisher", + "DOI": "10.1086\/666656" + }, + { + "key": "ref9", + "doi-asserted-by": "publisher", + "DOI": "10.1162\/99608f92.be565013" + }, + { + "key": "ref10", + "doi-asserted-by": "publisher", + "DOI": "10.1045\/january2003-smith" + }, + { + "key": "ref11", + "doi-asserted-by": "publisher", + "DOI": "10.1177\/0049124107306660" + }, + { + "key": "ref12", + "first-page": "157", + "article-title": "The Dryad Data Repository: a Singapore Framework metadata Architecture in a DSpace Environment", + "volume-title": "Proceedings of the 2008 International Conference on Dublin Core and Metadata Applications", + "author": "White" + }, + { + "key": "ref13", + "doi-asserted-by": "publisher", + "DOI": "10.5670\/oceanog.2014.50" + }, + { + "key": "ref14", + "doi-asserted-by": "publisher", + "DOI": "10.1109\/SOCA.2016.15" + }, + { + "key": "ref15", + "first-page": "83", + "article-title": "Introduction to Institutional Data Repositories Workshop", + "author": "Witt", + "year": "2008", + "journal-title": "Libraries Research Publications" + }, + { + "key": "ref16", + "doi-asserted-by": "publisher", + "DOI": "10.1109\/ICDE.2018.00098" + }, + { + "key": "ref17", + "doi-asserted-by": "publisher", + "DOI": "10.1145\/2737924.2737959" + }, + { + "key": "ref18", + "doi-asserted-by": "publisher", + "DOI": "10.1109\/ICoDSE56892.2022.9971958" + }, + { + "key": "ref19", + "doi-asserted-by": "publisher", + "DOI": "10.1016\/j.promfg.2019.03.032" + }, + { + "key": "ref20", + "doi-asserted-by": "publisher", + "DOI": "10.1016\/j.trpro.2023.11.866" + }, + { + "volume-title": "Emissionstrends 1990-2022", + "year": "2024", + "author": "Anderl", + "key": "ref21" + }, + { + "key": "ref22", + "doi-asserted-by": "publisher", + "DOI": "10.1109\/TVCG.2018.2864903" + }, + { + "key": "ref23", + "doi-asserted-by": "publisher", + "DOI": "10.1016\/j.scitotenv.2016.06.235" + }, + { + "key": "ref24", + "doi-asserted-by": "publisher", + "DOI": "10.1186\/s12302-024-00862-4" + }, + { + "key": "ref25", + "doi-asserted-by": "publisher", + "DOI": "10.1038\/533452a" + }, + { + "key": "ref26", + "doi-asserted-by": "publisher", + "DOI": "10.18653\/v1\/2024.findings-acl.137" + }, + { + "author": "Altug", + "key": "ref27", + "article-title": "Generating Semantic Context for Data Interoperability in Relational Databases using bge M3-Embeddings" + }, + { + "key": "ref28", + "doi-asserted-by": "publisher", + "DOI": "10.1186\/s13643-019-1250-y" + } + ], + "event": "2024 IEEE International Conference on Big Data (BigData)", + "container-title": "2024 IEEE International Conference on Big Data (BigData)", + "original-title": [], + "link": [ + { + "URL": "http:\/\/xplorestaging.ieee.org\/ielx8\/10824975\/10824942\/10825401.pdf?arnumber=10825401", + "content-type": "unspecified", + "content-version": "vor", + "intended-application": "similarity-checking" + } + ], + "deposited": { + "date-parts": [ + [ + 2025, + 1, + 17 + ] + ], + "date-time": "2025-01-17T07:55:27Z", + "timestamp": 1737100527000 + }, + "score": 1, + "resource": { + "primary": { + "URL": "https:\/\/ieeexplore.ieee.org\/document\/10825401\/" + } + }, + "subtitle": [], + "short-title": [], + "issued": { + "date-parts": [ + [ + 2024, + 12, + 15 + ] + ] + }, + "references-count": 28, + "URL": "http:\/\/dx.doi.org\/10.1109\/BigData62323.2024.10825401", + "relation": {}, + "subject": [], + "published": { + "date-parts": [ + [ + 2024, + 12, + 15 + ] + ] + } +} \ No newline at end of file diff --git a/dbrepo-metadata-service/services/pom.xml b/dbrepo-metadata-service/services/pom.xml index a0b354871b2884fd99c4b0fa54810ed519546d21..12d34b7e8f86b527853cee5cfad50ad98b6a9113 100644 --- a/dbrepo-metadata-service/services/pom.xml +++ b/dbrepo-metadata-service/services/pom.xml @@ -6,17 +6,17 @@ <parent> <artifactId>dbrepo-metadata-service</artifactId> <groupId>at.tuwien</groupId> - <version>1.7.3</version> + <version>1.8.0</version> </parent> <artifactId>dbrepo-metadata-service-services</artifactId> <name>dbrepo-metadata-service-services</name> - <version>1.7.3</version> + <version>1.8.0</version> <dependencies> <dependency> - <groupId>at.tuwien</groupId> - <artifactId>dbrepo-metadata-service-api</artifactId> + <groupId>at.ac.tuwien.ifs.dbrepo</groupId> + <artifactId>dbrepo-core</artifactId> <version>${project.version}</version> </dependency> <dependency> @@ -24,11 +24,6 @@ <artifactId>dbrepo-metadata-service-oai</artifactId> <version>${project.version}</version> </dependency> - <dependency> - <groupId>at.tuwien</groupId> - <artifactId>dbrepo-metadata-service-entities</artifactId> - <version>${project.version}</version> - </dependency> <dependency> <groupId>at.tuwien</groupId> <artifactId>dbrepo-metadata-service-repositories</artifactId> diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/auth/AuthTokenFilter.java similarity index 95% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/auth/AuthTokenFilter.java index b056eafe1749fe10d2e9e3a6fcfbbe80f2d27152..fc7d7bdaa2e433a1e2dc9132ddbb7a511c449fe7 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/auth/AuthTokenFilter.java @@ -1,7 +1,7 @@ -package at.tuwien.auth; +package at.ac.tuwien.ifs.dbrepo.auth; -import at.tuwien.api.auth.RealmAccessDto; -import at.tuwien.api.user.UserDetailsDto; +import at.ac.tuwien.ifs.dbrepo.core.api.auth.RealmAccessDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserDetailsDto; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; @@ -91,7 +91,7 @@ public class AuthTokenFilter extends OncePerRequestFilter { public String parseJwt(HttpServletRequest request) { String headerAuth = request.getHeader("Authorization"); if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) { - return headerAuth.substring(7, headerAuth.length()); + return headerAuth.substring(7); } return null; } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/auth/BasicAuthenticationProvider.java similarity index 84% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/auth/BasicAuthenticationProvider.java index 963249b393895781f38c1770ca5392e09fa47d66..5ab64107cd4dc80be7b16a8db0db4815372cc3fc 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/auth/BasicAuthenticationProvider.java @@ -1,7 +1,7 @@ -package at.tuwien.auth; +package at.ac.tuwien.ifs.dbrepo.auth; -import at.tuwien.api.keycloak.TokenDto; -import at.tuwien.service.CredentialService; +import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.TokenDto; +import at.ac.tuwien.ifs.dbrepo.service.CredentialService; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationManager; @@ -28,7 +28,7 @@ public class BasicAuthenticationProvider implements AuthenticationManager { public Authentication authenticate(Authentication auth) throws AuthenticationException { final TokenDto tokenDto = credentialService.getAccessToken(auth.getName(), auth.getCredentials().toString()); final UserDetails userDetails = authTokenFilter.verifyJwt(tokenDto.getAccessToken()); - log.debug("set basic auth principal: {}", userDetails); + log.debug("set basic auth principal username: {}", userDetails.getUsername()); return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); } } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/auth/InternalRequestInterceptor.java similarity index 87% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/auth/InternalRequestInterceptor.java index 6d7480ba8034a9108492ab0816005f4a92f8046c..272dfda2cf05e5ae8188492340632b1b2916aa70 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/auth/InternalRequestInterceptor.java @@ -1,8 +1,8 @@ -package at.tuwien.auth; +package at.ac.tuwien.ifs.dbrepo.auth; -import at.tuwien.api.keycloak.TokenDto; -import at.tuwien.config.GatewayConfig; -import at.tuwien.service.CredentialService; +import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.TokenDto; +import at.ac.tuwien.ifs.dbrepo.config.GatewayConfig; +import at.ac.tuwien.ifs.dbrepo.service.CredentialService; import lombok.extern.log4j.Log4j2; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpRequest; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/CacheConfig.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/CacheConfig.java similarity index 89% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/config/CacheConfig.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/CacheConfig.java index 9229927e83c19a8b73ca66f100a38091289750fb..4fd448efa2f3ab83761c2aa64a5a5af4b593d95d 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/CacheConfig.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/CacheConfig.java @@ -1,6 +1,6 @@ -package at.tuwien.config; +package at.ac.tuwien.ifs.dbrepo.config; -import at.tuwien.api.keycloak.TokenDto; +import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.TokenDto; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import org.springframework.beans.factory.annotation.Value; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/DataCiteConfig.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/DataCiteConfig.java similarity index 97% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/config/DataCiteConfig.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/DataCiteConfig.java index 9667553119f283b820ca1f0f98123181b10c76c9..1c00d625ddd4f0f01295088d33d5e8671b3fbcab 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/DataCiteConfig.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/DataCiteConfig.java @@ -1,4 +1,4 @@ -package at.tuwien.config; +package at.ac.tuwien.ifs.dbrepo.config; import lombok.Getter; import lombok.extern.log4j.Log4j2; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/EndpointConfig.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/EndpointConfig.java similarity index 86% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/config/EndpointConfig.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/EndpointConfig.java index 20e2805a035126a4fe70f244cdf03273f9de94a4..2512863082899183b6c3f89978a897b83198eb4b 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/EndpointConfig.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/EndpointConfig.java @@ -1,4 +1,4 @@ -package at.tuwien.config; +package at.ac.tuwien.ifs.dbrepo.config; import lombok.Getter; import org.springframework.beans.factory.annotation.Value; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/GatewayConfig.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/GatewayConfig.java similarity index 69% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/config/GatewayConfig.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/GatewayConfig.java index 34b0acbcb7dfc9164dda5b0408463a8c742b01d1..a7f99926509ddad057edabd5671eb4da0adfc0d7 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/GatewayConfig.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/GatewayConfig.java @@ -1,7 +1,7 @@ -package at.tuwien.config; +package at.ac.tuwien.ifs.dbrepo.config; -import at.tuwien.auth.InternalRequestInterceptor; -import at.tuwien.service.CredentialService; +import at.ac.tuwien.ifs.dbrepo.auth.InternalRequestInterceptor; +import at.ac.tuwien.ifs.dbrepo.service.CredentialService; import lombok.Getter; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; @@ -27,12 +27,18 @@ public class GatewayConfig { @Value("${dbrepo.endpoints.searchService}") private String searchEndpoint; + @Value("${dbrepo.endpoints.dashboardService}") + private String dashboardEndpoint; + @Value("${dbrepo.endpoints.rorService}") private String rorEndpoint; @Value("${dbrepo.endpoints.crossRefService}") private String crossRefEndpoint; + @Value("${dbrepo.endpoints.doiService}") + private String doiEndpoint; + @Value("${spring.rabbitmq.username}") private String brokerUsername; @@ -89,4 +95,27 @@ public class GatewayConfig { return restTemplate; } + @Bean("dashboardServiceRestTemplate") + public RestTemplate dashboardServiceRestTemplate() { + final RestTemplate restTemplate = new RestTemplate(); + restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(dashboardEndpoint)); + restTemplate.getInterceptors() + .add(new InternalRequestInterceptor(credentialService, this)); + return restTemplate; + } + + @Bean("doiServiceRestTemplate") + public RestTemplate doiServiceRestTemplate() { + final RestTemplate restTemplate = new RestTemplate(); + restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(doiEndpoint)); + return restTemplate; + } + + @Bean("crossRefServiceRestTemplate") + public RestTemplate crossRefServiceRestTemplate() { + final RestTemplate restTemplate = new RestTemplate(); + restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(crossRefEndpoint)); + return restTemplate; + } + } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/JacksonConfig.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/JacksonConfig.java similarity index 84% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/config/JacksonConfig.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/JacksonConfig.java index 61e7f2b180f15497b08c93ad8e474dc6a7722336..8ff2d5434e15532168491e1f5f466b041d475c9d 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/JacksonConfig.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/JacksonConfig.java @@ -1,6 +1,5 @@ -package at.tuwien.config; +package at.ac.tuwien.ifs.dbrepo.config; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.hibernate6.Hibernate6Module; @@ -10,7 +9,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.Date; import java.util.TimeZone; @Slf4j @@ -18,7 +16,7 @@ import java.util.TimeZone; public class JacksonConfig { @Bean - public ObjectMapper objectMapper() throws JsonProcessingException { + public ObjectMapper objectMapper() { final ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new Jdk8Module()); objectMapper.registerModule(new JavaTimeModule()); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/JenaConfig.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/JenaConfig.java similarity index 92% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/config/JenaConfig.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/JenaConfig.java index e9395e4470c034b0f98a5abd3e1d163c6c7fecea..4e1868e8b8c1b3fdb594525cf185e88448f74687 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/JenaConfig.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/JenaConfig.java @@ -1,4 +1,4 @@ -package at.tuwien.config; +package at.ac.tuwien.ifs.dbrepo.config; import lombok.Getter; import org.apache.jena.query.Dataset; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/KeycloakConfig.java similarity index 96% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/KeycloakConfig.java index 4b62b61dcba2e06f9847d9eb20042b1f535bbc8d..34596462e79465704c32683b9a15663bb9296f12 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/KeycloakConfig.java @@ -1,4 +1,4 @@ -package at.tuwien.config; +package at.ac.tuwien.ifs.dbrepo.config; import lombok.Getter; import org.keycloak.admin.client.Keycloak; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/MetadataConfig.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/MetadataConfig.java similarity index 93% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/config/MetadataConfig.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/MetadataConfig.java index d2484407ee7d640ef7f254ed95b119c15c5e7cf4..f79360781e6609a499a6c794275565d3f1e9180b 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/MetadataConfig.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/MetadataConfig.java @@ -1,4 +1,4 @@ -package at.tuwien.config; +package at.ac.tuwien.ifs.dbrepo.config; import lombok.Getter; import org.springframework.beans.factory.annotation.Value; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/MetricsConfig.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/MetricsConfig.java similarity index 90% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/config/MetricsConfig.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/MetricsConfig.java index b86a97a4dc66bf4e265dc82438d1083bed3c4ebd..8509d27c4407e66e1554d5bf9aeefd1623743b13 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/MetricsConfig.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/MetricsConfig.java @@ -1,10 +1,10 @@ -package at.tuwien.config; +package at.ac.tuwien.ifs.dbrepo.config; -import at.tuwien.entities.database.table.Table; -import at.tuwien.repository.DatabaseRepository; -import at.tuwien.repository.IdentifierRepository; -import at.tuwien.repository.TableRepository; -import at.tuwien.repository.ViewRepository; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.Table; +import at.ac.tuwien.ifs.dbrepo.repository.DatabaseRepository; +import at.ac.tuwien.ifs.dbrepo.repository.IdentifierRepository; +import at.ac.tuwien.ifs.dbrepo.repository.TableRepository; +import at.ac.tuwien.ifs.dbrepo.repository.ViewRepository; import io.micrometer.core.instrument.Gauge; import io.micrometer.core.instrument.Metrics; import io.micrometer.observation.ObservationRegistry; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/RabbitConfig.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/RabbitConfig.java similarity index 93% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/config/RabbitConfig.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/RabbitConfig.java index 0ed5001dd434d400a792bd3700b902d43b435de0..a727e972e253382a8a9bfa4fd25931e642e83dcf 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/RabbitConfig.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/RabbitConfig.java @@ -1,4 +1,4 @@ -package at.tuwien.config; +package at.ac.tuwien.ifs.dbrepo.config; import lombok.Getter; import lombok.extern.log4j.Log4j2; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/S3Config.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/S3Config.java similarity index 97% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/config/S3Config.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/S3Config.java index 6c82c29e25711de3e3a47ebcc9f86a359d31f6be..6202d2b2a85edf1a35b739fa45892fc364d2eb09 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/S3Config.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/S3Config.java @@ -1,4 +1,4 @@ -package at.tuwien.config; +package at.ac.tuwien.ifs.dbrepo.config; import lombok.Getter; import lombok.extern.slf4j.Slf4j; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/SecurityConfig.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/SecurityConfig.java similarity index 91% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/config/SecurityConfig.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/SecurityConfig.java index 03be90470ff1e54aef7a608f89490f45b9736f17..1d08f95630dc51c87c97c7d7f721c83adfaa16c6 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/SecurityConfig.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/SecurityConfig.java @@ -1,4 +1,4 @@ -package at.tuwien.config; +package at.ac.tuwien.ifs.dbrepo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/TemplateConfig.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/TemplateConfig.java similarity index 96% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/config/TemplateConfig.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/TemplateConfig.java index d38f17c6cb936e354b6b7362ccf8808476e24b47..28c5210e2947145ee3cd4cc98b59f0a209ce27ce 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/TemplateConfig.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/TemplateConfig.java @@ -1,4 +1,4 @@ -package at.tuwien.config; +package at.ac.tuwien.ifs.dbrepo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/WebSecurityConfig.java similarity index 95% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/WebSecurityConfig.java index 24133846961d340df4e04a3cf425470d68519a74..653c25c3378c30a710864b4a1f3ed5164262ed31 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/config/WebSecurityConfig.java @@ -1,8 +1,8 @@ -package at.tuwien.config; +package at.ac.tuwien.ifs.dbrepo.config; -import at.tuwien.auth.AuthTokenFilter; -import at.tuwien.auth.BasicAuthenticationProvider; -import at.tuwien.service.CredentialService; +import at.ac.tuwien.ifs.dbrepo.auth.AuthTokenFilter; +import at.ac.tuwien.ifs.dbrepo.auth.BasicAuthenticationProvider; +import at.ac.tuwien.ifs.dbrepo.service.CredentialService; import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; import io.swagger.v3.oas.annotations.security.SecurityScheme; import jakarta.servlet.http.HttpServletResponse; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/BrokerServiceGateway.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/BrokerServiceGateway.java similarity index 85% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/BrokerServiceGateway.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/BrokerServiceGateway.java index 42e8912d0c1c716309ead8d8ddfc3829f3206709..44e39389806b06f276bdd52fbe52dcff77c2ba5f 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/BrokerServiceGateway.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/BrokerServiceGateway.java @@ -1,8 +1,8 @@ -package at.tuwien.gateway; +package at.ac.tuwien.ifs.dbrepo.gateway; -import at.tuwien.api.amqp.*; -import at.tuwien.api.user.ExchangeUpdatePermissionsDto; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.api.amqp.*; +import at.ac.tuwien.ifs.dbrepo.core.api.user.ExchangeUpdatePermissionsDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; public interface BrokerServiceGateway { diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/CrossrefGateway.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/CrossRefGateway.java similarity index 53% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/CrossrefGateway.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/CrossRefGateway.java index 58e023ac9d32c3e1820969b1c73478a4d141de9d..83b04468279715a754f68a2d53a15c37dddd3d46 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/CrossrefGateway.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/CrossRefGateway.java @@ -1,9 +1,9 @@ -package at.tuwien.gateway; +package at.ac.tuwien.ifs.dbrepo.gateway; -import at.tuwien.api.crossref.CrossrefDto; -import at.tuwien.exception.DoiNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.api.crossref.CrossRefDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.DoiNotFoundException; -public interface CrossrefGateway { +public interface CrossRefGateway { /** * Retrieves metadata from the CrossRef funder database for a given CrossRef id. @@ -12,5 +12,5 @@ public interface CrossrefGateway { * @return The CrossRef metadata from the CrossRef funder database. * @throws DoiNotFoundException The metadata was not found in the CrossRef funder database. */ - CrossrefDto findById(String id) throws DoiNotFoundException; + CrossRefDto findById(String id) throws DoiNotFoundException; } diff --git a/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/DashboardServiceGateway.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/DashboardServiceGateway.java new file mode 100644 index 0000000000000000000000000000000000000000..95df0c65483d1693c331579f9d9a97e3dce88c32 --- /dev/null +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/DashboardServiceGateway.java @@ -0,0 +1,51 @@ +package at.ac.tuwien.ifs.dbrepo.gateway; + +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.grafana.CreateDashboardDto; +import at.ac.tuwien.ifs.dbrepo.core.api.grafana.CreateDashboardResponseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.grafana.PermissionTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.DashboardServiceConnectionException; +import at.ac.tuwien.ifs.dbrepo.core.exception.DashboardServiceException; + +public interface DashboardServiceGateway { + + /** + * Updates a dashboard configuration by given database. + * @param database The database. + * @throws DashboardServiceConnectionException The connection to the dashboard service failed. + * @throws DashboardServiceException The dashboard service failed to update the dashboard configuration. + */ + void update(DatabaseDto database) throws DashboardServiceConnectionException, DashboardServiceException; + + /** + * Creates a dashboard by given metadata. + * @param data The metadata. + * @return The dashboard response. + * @throws DashboardServiceConnectionException The connection to the dashboard service failed. + * @throws DashboardServiceException The dashboard service failed to create the dashboard. + */ + CreateDashboardResponseDto create(CreateDashboardDto data) throws DashboardServiceConnectionException, + DashboardServiceException; + + /** + * Updates the access on a dashboard for a given user by given dashboard uid and username. + * @param dashboardUid The dashboard uid. + * @param username The username. + * @param permission The access. + * @throws DashboardServiceConnectionException The connection to the dashboard service failed. + * @throws DashboardServiceException The dashboard service failed to update access to the dashboard. + */ + void updateAccess(String dashboardUid, String username, PermissionTypeDto permission) + throws DashboardServiceConnectionException, DashboardServiceException; + + /** + * Updates the access on a dashboard for anonymous users by given dashboard uid. + * @param dashboardUid The dashboard uid. + * @param database The database. + * @throws DashboardServiceConnectionException The connection to the dashboard service failed. + * @throws DashboardServiceException The dashboard service failed to update access to the dashboard. + */ + void updateAnonymousAccess(String dashboardUid, DatabaseBriefDto database) + throws DashboardServiceConnectionException, DashboardServiceException; +} diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/DataServiceGateway.java similarity index 90% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/DataServiceGateway.java index 3996448d212bed80364bdc2ac4d5ab62da3e1863..d7d54ca8e7e31ca982f7765da626c4895017f9d0 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/DataServiceGateway.java @@ -1,17 +1,17 @@ -package at.tuwien.gateway; - -import at.tuwien.api.database.AccessTypeDto; -import at.tuwien.api.database.CreateViewDto; -import at.tuwien.api.database.DatabaseDto; -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.CreateTableDto; -import at.tuwien.api.database.table.TableDto; -import at.tuwien.api.database.table.TableStatisticDto; -import at.tuwien.api.database.table.TableUpdateDto; -import at.tuwien.api.user.internal.UpdateUserPasswordDto; -import at.tuwien.exception.*; +package at.ac.tuwien.ifs.dbrepo.gateway; + +import at.ac.tuwien.ifs.dbrepo.core.api.database.AccessTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.CreateViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.internal.CreateDatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.QueryDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.CreateTableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableStatisticDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.internal.UpdateUserPasswordDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import java.util.List; import java.util.UUID; @@ -173,7 +173,7 @@ public interface DataServiceGateway { * * @param databaseId The database id. * @param tableId The table id. - * @return The statistic, if successful. + * @return The statistic, if successful. If no column can be analyzed, the response is null. * @throws DataServiceConnectionException The connection to the data service could not be established. * @throws DataServiceException The data service responded unexpectedly. * @throws TableNotFoundException The table was not found in the 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/ac/tuwien/ifs/dbrepo/gateway/KeycloakGateway.java similarity index 65% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/KeycloakGateway.java index 9436db80cb4ccde9c03cccc64482b9279b1d6d81..a829db05bf6d4b0b57895fd791b23de3e26da873 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/KeycloakGateway.java @@ -1,9 +1,9 @@ -package at.tuwien.gateway; +package at.ac.tuwien.ifs.dbrepo.gateway; -import at.tuwien.api.keycloak.TokenDto; -import at.tuwien.api.user.UserUpdateDto; -import at.tuwien.exception.AuthServiceException; -import at.tuwien.exception.UserNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.TokenDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.AuthServiceException; +import at.ac.tuwien.ifs.dbrepo.core.exception.UserNotFoundException; import org.keycloak.representations.idm.UserRepresentation; import java.util.UUID; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/OrcidGateway.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/OrcidGateway.java similarity index 69% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/OrcidGateway.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/OrcidGateway.java index 2cd5f142e6638f087265d6f605aa271fd518c51b..98336290b306d4c9b20996c59367fb4f4e68d6eb 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/OrcidGateway.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/OrcidGateway.java @@ -1,7 +1,7 @@ -package at.tuwien.gateway; +package at.ac.tuwien.ifs.dbrepo.gateway; -import at.tuwien.api.orcid.OrcidDto; -import at.tuwien.exception.OrcidNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.OrcidDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.OrcidNotFoundException; import org.springframework.stereotype.Service; @Service diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/RorGateway.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/RorGateway.java similarity index 69% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/RorGateway.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/RorGateway.java index 27603b99191708e22970c7452fc6a44337809128..8a49aa636b8595be2719a01ff83a989268396a05 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/RorGateway.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/RorGateway.java @@ -1,7 +1,7 @@ -package at.tuwien.gateway; +package at.ac.tuwien.ifs.dbrepo.gateway; -import at.tuwien.api.ror.RorDto; -import at.tuwien.exception.RorNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.api.ror.RorDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.RorNotFoundException; public interface RorGateway { diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/SearchServiceGateway.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/SearchServiceGateway.java similarity index 60% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/SearchServiceGateway.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/SearchServiceGateway.java index 1b3b20485f22d1f11ef92c6bc1698271923e9f0f..fdf4b430fea842e2214aecb30cf34763331f2126 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/SearchServiceGateway.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/SearchServiceGateway.java @@ -1,8 +1,8 @@ -package at.tuwien.gateway; +package at.ac.tuwien.ifs.dbrepo.gateway; -import at.tuwien.api.database.DatabaseBriefDto; -import at.tuwien.entities.database.Database; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import java.util.UUID; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/BrokerServiceGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/BrokerServiceGatewayImpl.java similarity index 94% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/BrokerServiceGatewayImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/BrokerServiceGatewayImpl.java index da1c28918576b0a0bf606b23c15e5d0a02a63820..9c35fa418223cbd33a2363649e1486c9bdd5e004 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/BrokerServiceGatewayImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/BrokerServiceGatewayImpl.java @@ -1,17 +1,16 @@ -package at.tuwien.gateway.impl; +package at.ac.tuwien.ifs.dbrepo.gateway.impl; -import at.tuwien.api.amqp.*; -import at.tuwien.api.user.ExchangeUpdatePermissionsDto; -import at.tuwien.config.RabbitConfig; -import at.tuwien.exception.*; -import at.tuwien.gateway.BrokerServiceGateway; +import at.ac.tuwien.ifs.dbrepo.core.api.amqp.*; +import at.ac.tuwien.ifs.dbrepo.core.api.user.ExchangeUpdatePermissionsDto; +import at.ac.tuwien.ifs.dbrepo.config.RabbitConfig; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.gateway.BrokerServiceGateway; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.*; import org.springframework.stereotype.Service; import org.springframework.web.client.HttpServerErrorException; -import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.RestTemplate; @Slf4j diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/CrossrefGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/CrossRefGatewayImpl.java similarity index 64% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/CrossrefGatewayImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/CrossRefGatewayImpl.java index 8fd957f330a947793f9bfc4e4fcbb08616bbf90f..559f3b7657efc8ce1a891d628034914e5dfa2632 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/CrossrefGatewayImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/CrossRefGatewayImpl.java @@ -1,40 +1,40 @@ -package at.tuwien.gateway.impl; +package at.ac.tuwien.ifs.dbrepo.gateway.impl; -import at.tuwien.api.crossref.CrossrefDto; -import at.tuwien.config.GatewayConfig; -import at.tuwien.exception.DoiNotFoundException; -import at.tuwien.gateway.CrossrefGateway; +import at.ac.tuwien.ifs.dbrepo.config.GatewayConfig; +import at.ac.tuwien.ifs.dbrepo.core.api.crossref.CrossRefDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.DoiNotFoundException; +import at.ac.tuwien.ifs.dbrepo.gateway.CrossRefGateway; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.web.client.HttpServerErrorException; -import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.RestTemplate; @Log4j2 @Service -public class CrossrefGatewayImpl implements CrossrefGateway { +public class CrossRefGatewayImpl implements CrossRefGateway { private final RestTemplate restTemplate; private final GatewayConfig gatewayConfig; @Autowired - public CrossrefGatewayImpl(RestTemplate restTemplate, GatewayConfig gatewayConfig) { + public CrossRefGatewayImpl(@Qualifier("crossRefServiceRestTemplate") RestTemplate restTemplate, + GatewayConfig gatewayConfig) { this.restTemplate = restTemplate; this.gatewayConfig = gatewayConfig; } @Override - public CrossrefDto findById(String id) throws DoiNotFoundException { + public CrossRefDto findById(String id) throws DoiNotFoundException { final String path = "/fundingdata/funder/" + id; log.trace("find crossref metadata by id from endpoint {} with path {}", gatewayConfig.getCrossRefEndpoint(), path); - final ResponseEntity<CrossrefDto> response; + final ResponseEntity<CrossRefDto> response; try { - response = restTemplate.exchange(gatewayConfig.getCrossRefEndpoint() + path, HttpMethod.GET, HttpEntity.EMPTY, CrossrefDto.class); + response = restTemplate.exchange(gatewayConfig.getCrossRefEndpoint() + path, HttpMethod.GET, HttpEntity.EMPTY, CrossRefDto.class); } catch (HttpServerErrorException e) { log.error("Failed to retrieve crossref metadata: {}", e.getMessage()); throw new DoiNotFoundException("Failed to retrieve crossref metadata: " + e.getMessage(), e); diff --git a/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/DashboardServiceGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/DashboardServiceGatewayImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..8f36db0f3b5814aa3ee3a0729c0248a7690e9451 --- /dev/null +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/DashboardServiceGatewayImpl.java @@ -0,0 +1,142 @@ +package at.ac.tuwien.ifs.dbrepo.gateway.impl; + +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.grafana.CreateDashboardDto; +import at.ac.tuwien.ifs.dbrepo.core.api.grafana.CreateDashboardResponseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.grafana.PermissionTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.grafana.UpdateDashboardAccessDto; +import at.ac.tuwien.ifs.dbrepo.config.GatewayConfig; +import at.ac.tuwien.ifs.dbrepo.core.exception.DashboardServiceConnectionException; +import at.ac.tuwien.ifs.dbrepo.core.exception.DashboardServiceException; +import at.ac.tuwien.ifs.dbrepo.gateway.DashboardServiceGateway; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.ResourceAccessException; +import org.springframework.web.client.RestTemplate; + +@Log4j2 +@Service +public class DashboardServiceGatewayImpl implements DashboardServiceGateway { + + private final RestTemplate restTemplate; + private final GatewayConfig gatewayConfig; + + @Autowired + public DashboardServiceGatewayImpl(@Qualifier("dashboardServiceRestTemplate") RestTemplate restTemplate, + GatewayConfig gatewayConfig) { + this.restTemplate = restTemplate; + this.gatewayConfig = gatewayConfig; + } + + @Override + public void update(DatabaseDto database) throws DashboardServiceConnectionException, DashboardServiceException { + final ResponseEntity<Void> response; + final String path = "/api/dashboard/" + database.getDashboardUid(); + log.trace("update dashboard at endpoint {} with path {}", gatewayConfig.getDashboardEndpoint(), path); + try { + response = restTemplate.exchange(path, HttpMethod.PUT, new HttpEntity<>(database), Void.class); + } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable | + HttpServerErrorException.InternalServerError e) { + log.error("Failed to update dashboard: {}", e.getMessage()); + throw new DashboardServiceConnectionException("Failed to update dashboard: " + e.getMessage(), e); + } catch (HttpClientErrorException.Unauthorized e) { + log.error("Failed to update dashboard: unauthorized: {}", e.getMessage()); + throw new DashboardServiceException("Failed to update dashboard: unauthorized: " + e.getMessage(), e); + } + if (!response.getStatusCode().equals(HttpStatus.ACCEPTED)) { + log.error("Failed to update dashboard: response code is not 202"); + throw new DashboardServiceException("Failed to update dashboard: response code is not 202"); + } + log.info("Updated dashboard with uid: {}", database.getDashboardUid()); + } + + @Override + public CreateDashboardResponseDto create(CreateDashboardDto data) throws DashboardServiceConnectionException, + DashboardServiceException { + final ResponseEntity<CreateDashboardResponseDto> response; + final String path = "/api/dashboard"; + log.trace("create dashboard at endpoint {} with path {}", gatewayConfig.getDashboardEndpoint(), path); + try { + response = restTemplate.exchange(path, HttpMethod.POST, new HttpEntity<>(data), CreateDashboardResponseDto.class); + } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable | + HttpServerErrorException.InternalServerError e) { + log.error("Failed to create dashboard: {}", e.getMessage()); + throw new DashboardServiceConnectionException("Failed to create dashboard: " + e.getMessage(), e); + } catch (HttpClientErrorException.BadRequest | HttpClientErrorException.Unauthorized e) { + log.error("Failed to create dashboard: malformed payload: {}", e.getMessage()); + throw new DashboardServiceException("Failed to create dashboard: malformed payload: " + e.getMessage(), e); + } catch (HttpClientErrorException.Conflict e) { + log.error("Failed to create dashboard: exists: {}", e.getMessage()); + throw new DashboardServiceException("Failed to create dashboard: exists: " + e.getMessage(), e); + } + if (!response.getStatusCode().equals(HttpStatus.CREATED)) { + log.error("Failed to create dashboard: response code is not 201"); + throw new DashboardServiceException("Failed to create dashboard: response code is not 201"); + } + final CreateDashboardResponseDto body = response.getBody(); + if (body == null) { + log.error("Failed to create dashboard: body is empty"); + throw new DashboardServiceException("Failed to create dashboard: body is empty"); + } + log.info("Created dashboard with uid: {}", body.getUid()); + return body; + } + + @Override + public void updateAccess(String dashboardUid, String username, PermissionTypeDto permission) + throws DashboardServiceConnectionException, DashboardServiceException { + final ResponseEntity<Void> response; + final String path = "/api/dashboard/" + dashboardUid + "/access/" + username; + log.trace("update dashboard access at endpoint {} with path {}", gatewayConfig.getDashboardEndpoint(), path); + try { + response = restTemplate.exchange(path, HttpMethod.PUT, new HttpEntity<>(UpdateDashboardAccessDto.builder() + .permission(permission) + .build()), Void.class); + } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable | + HttpServerErrorException.InternalServerError e) { + log.error("Failed to update dashboard access: {}", e.getMessage()); + throw new DashboardServiceConnectionException("Failed to update dashboard access: " + e.getMessage(), e); + } catch (HttpClientErrorException.BadRequest | HttpClientErrorException.Unauthorized e) { + log.error("Failed to update dashboard access: malformed payload: {}", e.getMessage()); + throw new DashboardServiceException("Failed to update dashboard access: malformed payload: " + e.getMessage(), e); + } + if (!response.getStatusCode().equals(HttpStatus.ACCEPTED)) { + log.error("Failed to update dashboard access: response code is not 202"); + throw new DashboardServiceException("Failed to update dashboard access: response code is not 202"); + } + log.info("Updated dashboard access for user with username: {}", username); + } + + @Override + public void updateAnonymousAccess(String dashboardUid, DatabaseBriefDto database) + throws DashboardServiceConnectionException, DashboardServiceException { + final ResponseEntity<Void> response; + final String path = "/api/dashboard/" + dashboardUid + "/access"; + log.trace("update dashboard anonymous access at endpoint {} with path {}", gatewayConfig.getDashboardEndpoint(), + path); + try { + response = restTemplate.exchange(path, HttpMethod.PUT, new HttpEntity<>(database), Void.class); + } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable | + HttpServerErrorException.InternalServerError e) { + log.error("Failed to update dashboard anonymous access: {}", e.getMessage()); + throw new DashboardServiceConnectionException("Failed to update dashboard anonymous access: " + e.getMessage(), e); + } catch (HttpClientErrorException.BadRequest | HttpClientErrorException.Unauthorized e) { + log.error("Failed to update dashboard anonymous access: malformed payload: {}", e.getMessage()); + throw new DashboardServiceException("Failed to update dashboard anonymous access: malformed payload: " + e.getMessage(), e); + } + if (!response.getStatusCode().equals(HttpStatus.ACCEPTED)) { + log.error("Failed to update dashboard access: response code is not 202"); + throw new DashboardServiceException("Failed to update dashboard access: response code is not 202"); + } + log.info("Updated dashboard anonymous access"); + } +} 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/ac/tuwien/ifs/dbrepo/gateway/impl/DataServiceGatewayImpl.java similarity index 96% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DataServiceGatewayImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/DataServiceGatewayImpl.java index ba855feda32000f1c4f0265c2b194c7e9e4e8237..41ab74b9cc1e97a755669ea431ca2907c1e52c98 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DataServiceGatewayImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/DataServiceGatewayImpl.java @@ -1,16 +1,16 @@ -package at.tuwien.gateway.impl; +package at.ac.tuwien.ifs.dbrepo.gateway.impl; -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.CreateTableDto; -import at.tuwien.api.database.table.TableDto; -import at.tuwien.api.database.table.TableStatisticDto; -import at.tuwien.api.database.table.TableUpdateDto; -import at.tuwien.api.user.internal.UpdateUserPasswordDto; -import at.tuwien.config.GatewayConfig; -import at.tuwien.exception.*; -import at.tuwien.gateway.DataServiceGateway; +import at.ac.tuwien.ifs.dbrepo.core.api.database.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.internal.CreateDatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.QueryDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.CreateTableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableStatisticDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.internal.UpdateUserPasswordDto; +import at.ac.tuwien.ifs.dbrepo.config.GatewayConfig; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.gateway.DataServiceGateway; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpEntity; @@ -398,12 +398,7 @@ public class DataServiceGatewayImpl implements DataServiceGateway { log.error("Failed to analyse table statistic: wrong http code: {}", response.getStatusCode()); throw new DataServiceException("Failed to analyse table statistic: wrong http code: " + response.getStatusCode()); } - final TableStatisticDto body = response.getBody(); - if (body == null) { - log.error("Failed to analyse table statistic: empty body: {}", response.getStatusCode()); - throw new DataServiceException("Failed to analyse table statistic: empty body"); - } - return body; + return response.getBody(); } } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/KeycloakGatewayImpl.java similarity index 90% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/KeycloakGatewayImpl.java index 4eb96aeee5b025b996d2bbbaf783a625f25372e2..f3f5c4ad09823b7ff6e9223892ca437a55e170fc 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/KeycloakGatewayImpl.java @@ -1,12 +1,12 @@ -package at.tuwien.gateway.impl; +package at.ac.tuwien.ifs.dbrepo.gateway.impl; -import at.tuwien.api.keycloak.TokenDto; -import at.tuwien.api.user.UserUpdateDto; -import at.tuwien.config.KeycloakConfig; -import at.tuwien.exception.AuthServiceException; -import at.tuwien.exception.UserNotFoundException; -import at.tuwien.gateway.KeycloakGateway; -import at.tuwien.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.TokenDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserUpdateDto; +import at.ac.tuwien.ifs.dbrepo.config.KeycloakConfig; +import at.ac.tuwien.ifs.dbrepo.core.exception.AuthServiceException; +import at.ac.tuwien.ifs.dbrepo.core.exception.UserNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.gateway.KeycloakGateway; import jakarta.ws.rs.ForbiddenException; import jakarta.ws.rs.NotAuthorizedException; import jakarta.ws.rs.NotFoundException; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/OrcidGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/OrcidGatewayImpl.java similarity index 82% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/OrcidGatewayImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/OrcidGatewayImpl.java index 7634e421fe2cda96ebaaa13d029282d682c5d240..78751b72be9bb69819290d6577aa27686d14cb9d 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/OrcidGatewayImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/OrcidGatewayImpl.java @@ -1,17 +1,15 @@ -package at.tuwien.gateway.impl; +package at.ac.tuwien.ifs.dbrepo.gateway.impl; -import at.tuwien.api.orcid.OrcidDto; -import at.tuwien.exception.OrcidNotFoundException; -import at.tuwien.gateway.OrcidGateway; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.OrcidDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.OrcidNotFoundException; +import at.ac.tuwien.ifs.dbrepo.gateway.OrcidGateway; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.web.client.HttpServerErrorException; -import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.RestTemplate; @Log4j2 diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/RorGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/RorGatewayImpl.java similarity index 83% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/RorGatewayImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/RorGatewayImpl.java index 37ed982f9e4489431e9e86b7fb5c5ec61fed57ec..b8af43362d2c029e97f2853572ca94fa6359598e 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/RorGatewayImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/RorGatewayImpl.java @@ -1,18 +1,16 @@ -package at.tuwien.gateway.impl; +package at.ac.tuwien.ifs.dbrepo.gateway.impl; -import at.tuwien.api.ror.RorDto; -import at.tuwien.config.GatewayConfig; -import at.tuwien.exception.RorNotFoundException; -import at.tuwien.gateway.RorGateway; +import at.ac.tuwien.ifs.dbrepo.core.api.ror.RorDto; +import at.ac.tuwien.ifs.dbrepo.config.GatewayConfig; +import at.ac.tuwien.ifs.dbrepo.core.exception.RorNotFoundException; +import at.ac.tuwien.ifs.dbrepo.gateway.RorGateway; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.web.client.HttpServerErrorException; -import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.RestTemplate; @Log4j2 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/ac/tuwien/ifs/dbrepo/gateway/impl/SearchServiceGatewayImpl.java similarity index 87% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/SearchServiceGatewayImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/SearchServiceGatewayImpl.java index 89b4dff5c71eb3f58b2fe1e9ac0616ab743cd5f6..97977fbb433963676996118ae1f5796124445a06 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/SearchServiceGatewayImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/gateway/impl/SearchServiceGatewayImpl.java @@ -1,13 +1,13 @@ -package at.tuwien.gateway.impl; +package at.ac.tuwien.ifs.dbrepo.gateway.impl; -import at.tuwien.api.database.DatabaseBriefDto; -import at.tuwien.config.GatewayConfig; -import at.tuwien.entities.database.Database; -import at.tuwien.exception.DatabaseNotFoundException; -import at.tuwien.exception.SearchServiceConnectionException; -import at.tuwien.exception.SearchServiceException; -import at.tuwien.gateway.SearchServiceGateway; -import at.tuwien.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseBriefDto; +import at.ac.tuwien.ifs.dbrepo.config.GatewayConfig; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.exception.DatabaseNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.exception.SearchServiceConnectionException; +import at.ac.tuwien.ifs.dbrepo.core.exception.SearchServiceException; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.gateway.SearchServiceGateway; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -37,7 +37,8 @@ public class SearchServiceGatewayImpl implements SearchServiceGateway { } @Override - public DatabaseBriefDto update(Database database) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException { + public DatabaseBriefDto update(Database database) throws SearchServiceConnectionException, SearchServiceException, + DatabaseNotFoundException { final ResponseEntity<DatabaseBriefDto> response; final HttpHeaders headers = new HttpHeaders(); headers.set("Accept", "application/json"); diff --git a/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/AccessService.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/AccessService.java new file mode 100644 index 0000000000000000000000000000000000000000..21f8f0444b39ba90de24e889d802bec4ddd12b13 --- /dev/null +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/AccessService.java @@ -0,0 +1,81 @@ +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.api.database.AccessTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.DatabaseAccess; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; + +import java.security.Principal; +import java.util.List; + +public interface AccessService { + + /** + * Loads all database access definitions for a database with id. + * + * @param database The database. + * @return The list of database access definitions. + */ + List<DatabaseAccess> list(Database database); + + /** + * Finds database access by given database and user, where the access is determined by the username (needed since {@link Principal#getName()} embeds the username). + * + * @param database The database. + * @param user The user. + * @return The database access, if successful. + * @throws AccessNotFoundException The access was not found in the metadata database. + */ + DatabaseAccess find(Database database, User user) throws AccessNotFoundException; + + /** + * Give somebody access to a database of container. + * + * @param database The database. + * @param access The access. + * @param user The user. + * @return The database access, if successful. + * @throws DataServiceException The data service responded with an unexpected error code. + * @throws DataServiceConnectionException The connection with the data service could not be established. + * @throws DatabaseNotFoundException The database was not found in the metadata/search database. + * @throws SearchServiceException The search service responded with an unexpected error code. + * @throws SearchServiceConnectionException The connection with the search service could not be established. + */ + DatabaseAccess create(Database database, User user, AccessTypeDto access) throws DataServiceException, + DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, + SearchServiceConnectionException; + + /** + * Update access to a database. + * + * @param database The database. + * @param user The user. + * @param access The updated access. + * @throws DataServiceException The data service responded with unexpected behavior. + * @throws DataServiceConnectionException The connection with the data service could not be established. + * @throws AccessNotFoundException The access was not found. + * @throws DatabaseNotFoundException The database was not found in the metadata/search database. + * @throws SearchServiceException The search service responded with an unexpected error code. + * @throws SearchServiceConnectionException The connection with the search service could not be established. + */ + void update(Database database, User user, AccessTypeDto access) throws DataServiceException, + DataServiceConnectionException, AccessNotFoundException, DatabaseNotFoundException, SearchServiceException, + SearchServiceConnectionException; + + /** + * Revokes access to a database of container. + * + * @param database The database. + * @param user The user. + * @throws AccessNotFoundException The access was not found. + * @throws DataServiceException The data service responded with unexpected behavior. + * @throws DataServiceConnectionException The connection with the data service could not be established. + * @throws DatabaseNotFoundException The database was not found in the metadata/search database. + * @throws SearchServiceException The search service responded with an unexpected error code. + * @throws SearchServiceConnectionException The connection with the search service could not be established. + */ + void delete(Database database, User user) throws AccessNotFoundException, DataServiceException, + DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, + SearchServiceConnectionException; +} diff --git a/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/AuthenticationService.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/AuthenticationService.java new file mode 100644 index 0000000000000000000000000000000000000000..808c774e23e69f2ee072ca1a2199a593993f9108 --- /dev/null +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/AuthenticationService.java @@ -0,0 +1,18 @@ +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.AuthServiceException; +import at.ac.tuwien.ifs.dbrepo.core.exception.UserNotFoundException; + +public interface AuthenticationService { + + /** + * Deletes a user at the Authentication Service with given user id. + * + * @param user The user. + * @throws AuthServiceException The auth service responded with unexpected behavior. + * @throws UserNotFoundException The user was not found after creation in the auth database. + */ + void delete(User user) throws AuthServiceException, UserNotFoundException; + +} diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/BannerMessageService.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/BannerMessageService.java similarity index 81% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/BannerMessageService.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/BannerMessageService.java index a7973b6171d8cf941a0cc24b264b69f76255628e..98c6b1267938cf8afa190729f001b4f3a00ff67e 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/BannerMessageService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/BannerMessageService.java @@ -1,9 +1,9 @@ -package at.tuwien.service; +package at.ac.tuwien.ifs.dbrepo.service; -import at.tuwien.api.maintenance.BannerMessageCreateDto; -import at.tuwien.api.maintenance.BannerMessageUpdateDto; -import at.tuwien.entities.maintenance.BannerMessage; -import at.tuwien.exception.MessageNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.maintenance.BannerMessage; +import at.ac.tuwien.ifs.dbrepo.core.exception.MessageNotFoundException; import java.util.List; import java.util.UUID; diff --git a/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/BrokerService.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/BrokerService.java new file mode 100644 index 0000000000000000000000000000000000000000..6f9109cbe0c72b0b1d059513d72a183c1b4ce329 --- /dev/null +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/BrokerService.java @@ -0,0 +1,25 @@ +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; + +public interface BrokerService { + + /** + * Updates the virtual host permissions in the Broker Service for a user with given principal. + * + * @param user The user. + * @throws BrokerServiceException The broker service responded with an unexpected response code. + * @throws BrokerServiceConnectionException The connection to the broker service could not be established. + */ + void setVirtualHostPermissions(User user) throws BrokerServiceException, BrokerServiceConnectionException; + + /** + * Sets topic exchange permissions for a user. + * + * @param user The user. + * @throws BrokerServiceException The broker service responded with an unexpected response code. + * @throws BrokerServiceConnectionException The connection to the broker service could not be established. + */ + void setTopicExchangePermissions(User user) throws BrokerServiceException, BrokerServiceConnectionException; +} diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ConceptService.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/ConceptService.java similarity index 75% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ConceptService.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/ConceptService.java index 94fa1e0c890637d62e3faa20382c0fb668d8904a..ec582b10d8d52d19db5ff887e2184c67906061af 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ConceptService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/ConceptService.java @@ -1,7 +1,7 @@ -package at.tuwien.service; +package at.ac.tuwien.ifs.dbrepo.service; -import at.tuwien.entities.database.table.columns.TableColumnConcept; -import at.tuwien.exception.ConceptNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumnConcept; +import at.ac.tuwien.ifs.dbrepo.core.exception.ConceptNotFoundException; import java.util.List; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ContainerService.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/ContainerService.java similarity index 75% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ContainerService.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/ContainerService.java index d559b5134d6b34b3d5855debb30ece42115caff5..fcda5ef460c7f3fd2650f7fbeec5ac3c48fa9ea4 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ContainerService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/ContainerService.java @@ -1,10 +1,10 @@ -package at.tuwien.service; +package at.ac.tuwien.ifs.dbrepo.service; -import at.tuwien.api.container.CreateContainerDto; -import at.tuwien.entities.container.Container; -import at.tuwien.exception.ContainerAlreadyExistsException; -import at.tuwien.exception.ContainerNotFoundException; -import at.tuwien.exception.ImageNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.api.container.CreateContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.Container; +import at.ac.tuwien.ifs.dbrepo.core.exception.ContainerAlreadyExistsException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ContainerNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ImageNotFoundException; import java.util.List; import java.util.UUID; @@ -19,8 +19,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(CreateContainerDto createDto) throws ImageNotFoundException, - ContainerAlreadyExistsException; + Container create(CreateContainerDto createDto) throws ImageNotFoundException, ContainerAlreadyExistsException; /** * Removes a container by given id from the metadata database. diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/CredentialService.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/CredentialService.java similarity index 80% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/CredentialService.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/CredentialService.java index b1c28cf1701772eb16f3c79a8f155faf6e8261a9..4a54849006fa031872af1b1aa43938036e3ac243 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/CredentialService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/CredentialService.java @@ -1,6 +1,6 @@ -package at.tuwien.service; +package at.ac.tuwien.ifs.dbrepo.service; -import at.tuwien.api.keycloak.TokenDto; +import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.TokenDto; public interface CredentialService { diff --git a/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/DashboardService.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/DashboardService.java new file mode 100644 index 0000000000000000000000000000000000000000..77be6e24477aa72cc3070602d882916fc05313ab --- /dev/null +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/DashboardService.java @@ -0,0 +1,44 @@ +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.api.database.AccessTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.grafana.CreateDashboardResponseDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.DashboardServiceConnectionException; +import at.ac.tuwien.ifs.dbrepo.core.exception.DashboardServiceException; + +public interface DashboardService { + + /** + * Updates the panels in the dashboard in the dashboard service for a given database. Only updates the dashboard if + * (and only if) the {@link Database#isDashboardEnabled} is set to true. + * + * @param database The database. + * @throws DashboardServiceException The dashboard service responded with an unexpected error code. + * @throws DashboardServiceConnectionException The connection to the dashboard service could not be established. + */ + void update(Database database) throws DashboardServiceException, DashboardServiceConnectionException; + + /** + * Creates the dashboard in the dashboard service for a given database. Does not create panels. + * + * @param database The database. + * @return The response containing the UID of the created dashboard. + * @throws DashboardServiceException The dashboard service responded with an unexpected error code. + * @throws DashboardServiceConnectionException The connection to the dashboard service could not be established. + */ + CreateDashboardResponseDto create(Database database) throws DashboardServiceException, + DashboardServiceConnectionException; + + /** + * Updates the access on the dashboard in the dashboard service. + * + * @param database The database. + * @param user The user whose access is updated. + * @param access The access type. + * @throws DashboardServiceException The dashboard service responded with an unexpected error code. + * @throws DashboardServiceConnectionException The connection to the dashboard service could not be established. + */ + void updateAccess(Database database, User user, AccessTypeDto access) throws DashboardServiceException, + DashboardServiceConnectionException; +} diff --git a/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/DatabaseService.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/DatabaseService.java new file mode 100644 index 0000000000000000000000000000000000000000..351e383b05ed01cbffbf4e3685f79b2b279b2eb2 --- /dev/null +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/DatabaseService.java @@ -0,0 +1,193 @@ +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.api.database.CreateDatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseModifyVisibilityDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.Container; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.UUID; + +@Service +public interface DatabaseService { + + /** + * Finds all databases stored in the metadata database. + * + * @return List of databases. + */ + List<Database> findAll(); + + /** + * Filters all databases where {@link Database#isPublic} or {@link Database#isSchemaPublic} evaluates to true. + * + * @return List of databases. + */ + List<Database> findAllPublicOrSchemaPublic(); + + /** + * Filters all databases whose internal name matches the given internal name. + * + * @param internalName The internal name. + * @return List of databases. + */ + List<Database> findByInternalName(String internalName); + + /** + * Filters all databases where {@link Database#isPublic} or {@link Database#isSchemaPublic} and the user by given id + * has at least read access and whose internal name matches the given internal name evaluates to true. + * @param userId The user id. + * @param internalName The internal name. + * @return List of databases. + */ + List<Database> findAllPublicOrSchemaPublicOrReadAccessByInternalName(UUID userId, String internalName); + + /** + * Filters all databases where {@link Database#isPublic} or {@link Database#isSchemaPublic} or the user by given id + * has at least read access evaluate to true. + * + * @param userId The user id. + * @return List of databases. + */ + List<Database> findAllPublicOrSchemaPublicOrReadAccess(UUID userId); + + /** + * Filters all databases where {@link Database#isPublic} or {@link Database#isSchemaPublic} or the internal name + * matches the given internal name evaluate to true. + * + * @param internalName The internal name. + * @return List of databases. + */ + List<Database> findAllPublicOrSchemaPublicByInternalName(String internalName); + + /** + * Find a database by given id. + * + * @param databaseId The id. + * @return The database, if successful. + * @throws DatabaseNotFoundException The database was not found in the metadata database. + */ + Database findById(UUID databaseId) throws DatabaseNotFoundException; + + /** + * Creates a new database with minimal metadata in the metadata database and creates a new database on the + * container. + * + * @param container The container. + * @param createDto The metadata. + * @param user The user. + * @param internalUsers The list of internal users. + * @return The database, if successful. + * @throws DataServiceException The data service responded with unexpected behavior. + * @throws DataServiceConnectionException The connection with the data service could not be established. + * @throws DatabaseNotFoundException The created database was not found in the metadata database. + * @throws SearchServiceException The search service responded with an unexpected error code. + * @throws SearchServiceConnectionException The connection with the search service could not be established. + * @throws DashboardServiceException The dashboard service responded with an unexpected error code. + * @throws DashboardServiceConnectionException The connection to the dashboard service could not be established. + */ + Database create(Container container, CreateDatabaseDto createDto, User user, List<User> internalUsers) + throws DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, + SearchServiceException, SearchServiceConnectionException, DashboardServiceException, + DashboardServiceConnectionException; + + /** + * Updates the user's password. + * + * @param database The database. + * @param user The user. + * @throws DataServiceException The data service responded with unexpected behavior. + * @throws DataServiceConnectionException The connection with the data service could not be established. + * @throws DatabaseNotFoundException The created database was not found in the metadata database. + */ + void updatePassword(Database database, User user) throws DataServiceException, DataServiceConnectionException, + DatabaseNotFoundException; + + /** + * Updates the visibility of the database. + * + * @param database The database. + * @param data The visibility + * @return The database, if successful. + * @throws DatabaseNotFoundException The created database was not found in the metadata database. + * @throws SearchServiceException The search service responded with an unexpected error code. + * @throws SearchServiceConnectionException The connection with the search service could not be established. + */ + Database modifyVisibility(Database database, DatabaseModifyVisibilityDto data) throws DatabaseNotFoundException, + SearchServiceException, SearchServiceConnectionException; + + /** + * Transfer ownership of a database + * + * @param database The database. + * @param user The payload with the new owner. + * @return The database, if successful. + * @throws DatabaseNotFoundException The created database was not found in the metadata database. + * @throws SearchServiceException The search service responded with an unexpected error code. + * @throws SearchServiceConnectionException The connection with the search service could not be established. + */ + Database modifyOwner(Database database, User user) throws DatabaseNotFoundException, SearchServiceException, + SearchServiceConnectionException; + + /** + * Modify image of database with given id. + * + * @param database The database. + * @param image The image. + * @return The database, if successful. + * @throws DatabaseNotFoundException The created database was not found in the metadata database. + * @throws SearchServiceException The search service responded with an unexpected error code. + * @throws SearchServiceConnectionException The connection with the search service could not be established. + */ + Database modifyImage(Database database, byte[] image) throws DatabaseNotFoundException, SearchServiceException, + SearchServiceConnectionException; + + /** + * Modify dashboard uid of database with given id. + * + * @param database The database. + * @param uid The dashboard uid. + * @return The database, if successful. + * @throws DatabaseNotFoundException The created database was not found in the metadata database. + * @throws SearchServiceException The search service responded with an unexpected error code. + * @throws SearchServiceConnectionException The connection with the search service could not be established. + */ + Database modifyDashboard(Database database, String uid) throws DatabaseNotFoundException, SearchServiceException, + SearchServiceConnectionException; + + /** + * Updates the table metadata of a given database. + * + * @param database The database. + * @return The updated database, if successful. + * @throws DatabaseNotFoundException The created database was not found in the metadata database. + * @throws DataServiceException The data service responded with unexpected behavior. + * @throws SearchServiceException The search service responded with an unexpected error code. + * @throws SearchServiceConnectionException The connection with the search service could not be established. + * @throws DataServiceConnectionException The connection with the data service could not be established. + * @throws MalformedException The table is malformed, e.g. a column of a primary key constraint could not be found. + * @throws TableNotFoundException The table was not found in the metadata database. + */ + Database updateTableMetadata(Database database) throws DatabaseNotFoundException, DataServiceException, + SearchServiceException, SearchServiceConnectionException, DataServiceConnectionException, + MalformedException, TableNotFoundException; + + /** + * Updates the view metadata of a given database. + * + * @param database The database. + * @return The updated database, if successful. + * @throws DatabaseNotFoundException The created database was not found in the metadata database. + * @throws DataServiceException The data service responded with unexpected behavior. + * @throws SearchServiceException The search service responded with an unexpected error code. + * @throws SearchServiceConnectionException The connection with the search service could not be established. + * @throws DataServiceConnectionException The connection with the data service could not be established. + * @throws ViewNotFoundException The view was not found in the metadata database. + */ + Database updateViewMetadata(Database database) throws DatabaseNotFoundException, DataServiceException, + SearchServiceException, SearchServiceConnectionException, DataServiceConnectionException, + ViewNotFoundException; +} diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/EntityService.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/EntityService.java similarity index 54% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/EntityService.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/EntityService.java index 69a801cf5c2ad27f6819d44b10a43516fa85c649..c767ad3a7b21b5d01a7e31f90a27f054f95ee1cc 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/EntityService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/EntityService.java @@ -1,11 +1,13 @@ -package at.tuwien.service; +package at.ac.tuwien.ifs.dbrepo.service; -import at.tuwien.api.semantics.EntityDto; -import at.tuwien.api.semantics.TableColumnEntityDto; -import at.tuwien.entities.database.table.Table; -import at.tuwien.entities.database.table.columns.TableColumn; -import at.tuwien.entities.semantics.Ontology; -import at.tuwien.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.api.semantics.EntityDto; +import at.ac.tuwien.ifs.dbrepo.core.api.semantics.TableColumnEntityDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.Table; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumn; +import at.ac.tuwien.ifs.dbrepo.core.entity.semantics.Ontology; +import at.ac.tuwien.ifs.dbrepo.core.exception.MalformedException; +import at.ac.tuwien.ifs.dbrepo.core.exception.OntologyNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.exception.SemanticEntityNotFoundException; import java.util.List; @@ -16,7 +18,8 @@ public interface EntityService { * * @param ontology The ontology. * @param label The label. - * @return The list of entities that match. + * @return List of entities. + * @throws MalformedException The query is malformed. */ List<EntityDto> findByLabel(Ontology ontology, String label) throws MalformedException; @@ -26,7 +29,8 @@ public interface EntityService { * @param ontology The ontology. * @param label The label. * @param limit The maximum number of entities to return. - * @return The list of entities that match. + * @return List of entities. + * @throws MalformedException The query is malformed. */ List<EntityDto> findByLabel(Ontology ontology, String label, Integer limit) throws MalformedException; @@ -34,7 +38,9 @@ public interface EntityService { * Finds entities in the ontology whose uri match the given uri. * * @param uri The uri. - * @return The list of entities that match. + * @return List of entities. + * @throws MalformedException The query is malformed. + * @throws OntologyNotFoundException The ontology was not found in the metadata database. */ List<EntityDto> findByUri(String uri) throws MalformedException, OntologyNotFoundException; @@ -43,14 +49,19 @@ public interface EntityService { * * @param uri The uri. * @return The entity, if successful. + * @throws MalformedException The query is malformed. + * @throws SemanticEntityNotFoundException The semantic entity was not found in the metadata database. + * @throws OntologyNotFoundException The ontology was not found in the metadata database. */ - EntityDto findOneByUri(String uri) throws MalformedException, SemanticEntityNotFoundException, OntologyNotFoundException; + EntityDto findOneByUri(String uri) throws MalformedException, SemanticEntityNotFoundException, + OntologyNotFoundException; /** * Attempts to suggest table semantics for a table with given id in database with given id. * * @param table The table. * @return The list of entities that were suggested. + * @throws MalformedException The query is malformed. */ List<EntityDto> suggestByTable(Table table) throws MalformedException; @@ -59,6 +70,7 @@ public interface EntityService { * * @param column The table column. * @return The list of entities that were suggested. + * @throws MalformedException The query is malformed. */ List<TableColumnEntityDto> suggestByColumn(TableColumn column) throws MalformedException; } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/IdentifierService.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/IdentifierService.java similarity index 54% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/IdentifierService.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/IdentifierService.java index 8c9a3088fe96844df0628ba95d71c0356ebc2b33..ac23dc1b4f9e425307e057722fdbc31b18e0a660 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/IdentifierService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/IdentifierService.java @@ -1,13 +1,13 @@ -package at.tuwien.service; - -import at.tuwien.api.identifier.BibliographyTypeDto; -import at.tuwien.api.identifier.CreateIdentifierDto; -import at.tuwien.api.identifier.IdentifierSaveDto; -import at.tuwien.api.identifier.IdentifierTypeDto; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.identifier.Identifier; -import at.tuwien.entities.user.User; -import at.tuwien.exception.*; +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.BibliographyTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.CreateIdentifierDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierSaveDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.Identifier; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; import org.springframework.core.io.InputStreamResource; import org.springframework.stereotype.Service; @@ -91,11 +91,12 @@ public interface IdentifierService { * * @param identifier The identifier. * @return The resulting identifier. - * @throws SearchServiceException - * @throws DatabaseNotFoundException - * @throws SearchServiceConnectionException - * @throws MalformedException - * @throws DataServiceConnectionException + * @throws SearchServiceException The search service responded with an unexpected error code. + * @throws DatabaseNotFoundException The created database was not found in the metadata database. + * @throws SearchServiceConnectionException The connection with the search service could not be established. + * @throws MalformedException The table is malformed, e.g. a column of a primary key constraint could not be found. + * @throws DataServiceConnectionException The connection with the data service could not be established. + * @throws ExternalServiceException The DataCite system rejected the publish-request. */ Identifier publish(Identifier identifier) throws SearchServiceException, DatabaseNotFoundException, SearchServiceConnectionException, MalformedException, DataServiceConnectionException, @@ -108,19 +109,20 @@ public interface IdentifierService { * @param user The user. * @param data The data. * @return The created identifier from the metadata database if successful. - * @throws DataServiceException - * @throws DataServiceConnectionException - * @throws IdentifierNotFoundException - * @throws MalformedException - * @throws ViewNotFoundException - * @throws DatabaseNotFoundException - * @throws QueryNotFoundException - * @throws SearchServiceException - * @throws SearchServiceConnectionException + * @throws DataServiceException The data service responded with unexpected behavior. + * @throws DataServiceConnectionException The connection with the data service could not be established. + * @throws IdentifierNotFoundException The identifier was not found in the metadata service. + * @throws MalformedException The table is malformed, e.g. a column of a primary key constraint could not be found. + * @throws ViewNotFoundException The view was not found in the metadata service. + * @throws DatabaseNotFoundException The created database was not found in the metadata database. + * @throws QueryNotFoundException The subset was not found in the data service. + * @throws SearchServiceException The search service responded with an unexpected error code. + * @throws SearchServiceConnectionException The connection with the search service could not be established. */ Identifier save(Database database, User user, IdentifierSaveDto data) throws DataServiceException, DataServiceConnectionException, IdentifierNotFoundException, MalformedException, ViewNotFoundException, - DatabaseNotFoundException, QueryNotFoundException, SearchServiceException, SearchServiceConnectionException, ExternalServiceException; + DatabaseNotFoundException, QueryNotFoundException, SearchServiceException, SearchServiceConnectionException, + ExternalServiceException; /** * Creates a new identifier in the metadata database for a query or database. @@ -129,19 +131,18 @@ public interface IdentifierService { * @param user The user. * @param data The data. * @return The created identifier from the metadata database if successful. - * @throws DataServiceException - * @throws DataServiceConnectionException - * @throws IdentifierNotFoundException - * @throws MalformedException - * @throws ViewNotFoundException - * @throws DatabaseNotFoundException - * @throws QueryNotFoundException - * @throws SearchServiceException - * @throws SearchServiceConnectionException + * @throws DataServiceException The data service responded with unexpected behavior. + * @throws DataServiceConnectionException The connection with the data service could not be established. + * @throws MalformedException The table is malformed, e.g. a column of a primary key constraint could not be found. + * @throws ViewNotFoundException The view was not found in the metadata service. + * @throws DatabaseNotFoundException The created database was not found in the metadata database. + * @throws QueryNotFoundException The subset was not found in the data service. + * @throws SearchServiceException The search service responded with an unexpected error code. + * @throws SearchServiceConnectionException The connection with the search service could not be established. */ Identifier create(Database database, User user, CreateIdentifierDto data) throws DataServiceException, - DataServiceConnectionException, IdentifierNotFoundException, MalformedException, ViewNotFoundException, - DatabaseNotFoundException, QueryNotFoundException, SearchServiceException, SearchServiceConnectionException, ExternalServiceException; + DataServiceConnectionException, MalformedException, ViewNotFoundException, DatabaseNotFoundException, + QueryNotFoundException, SearchServiceException, SearchServiceConnectionException, ExternalServiceException; /** * Export metadata for a identifier @@ -166,13 +167,10 @@ public interface IdentifierService { * database, but sets it as deleted. * * @param identifier The identifier. - * @throws DataServiceException - * @throws DataServiceConnectionException - * @throws IdentifierNotFoundException - * @throws DatabaseNotFoundException - * @throws SearchServiceException - * @throws SearchServiceConnectionException + * @throws DatabaseNotFoundException The created database was not found in the metadata database. + * @throws SearchServiceException The search service responded with an unexpected error code. + * @throws SearchServiceConnectionException The connection with the search service could not be established. */ - void delete(Identifier identifier) throws DataServiceException, DataServiceConnectionException, IdentifierNotFoundException, - DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException; + void delete(Identifier identifier) throws DatabaseNotFoundException, SearchServiceException, + SearchServiceConnectionException; } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ImageService.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/ImageService.java similarity index 73% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ImageService.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/ImageService.java index c5f353c7a18a5cb5e6eecd6819b7923e4b49d08e..09afe61aae70764e76e00da69d77dfae06bff640 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ImageService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/ImageService.java @@ -1,11 +1,11 @@ -package at.tuwien.service; +package at.ac.tuwien.ifs.dbrepo.service; -import at.tuwien.api.container.image.ImageChangeDto; -import at.tuwien.api.container.image.ImageCreateDto; -import at.tuwien.entities.container.image.ContainerImage; -import at.tuwien.exception.ImageAlreadyExistsException; -import at.tuwien.exception.ImageInvalidException; -import at.tuwien.exception.ImageNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageChangeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.image.ContainerImage; +import at.ac.tuwien.ifs.dbrepo.core.exception.ImageAlreadyExistsException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ImageInvalidException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ImageNotFoundException; import java.security.Principal; import java.util.List; @@ -25,6 +25,7 @@ public interface ImageService { * * @param imageId The image id. * @return The image, if successful. + * @throws ImageNotFoundException The image was not found in the metadata service. */ ContainerImage find(UUID imageId) throws ImageNotFoundException; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/LicenseService.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/LicenseService.java similarity index 74% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/LicenseService.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/LicenseService.java index 4bea3499465405333a26551591bdfe508da1ff7e..a0854ab3740ea45ee46d1f20b33003cbe588ad75 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/LicenseService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/LicenseService.java @@ -1,7 +1,7 @@ -package at.tuwien.service; +package at.ac.tuwien.ifs.dbrepo.service; -import at.tuwien.entities.database.License; -import at.tuwien.exception.LicenseNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.License; +import at.ac.tuwien.ifs.dbrepo.core.exception.LicenseNotFoundException; import java.util.List; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/MetadataService.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/MetadataService.java similarity index 62% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/MetadataService.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/MetadataService.java index 95c2b299e4b0e76be7f148f0f86b6cd5b04b3f3e..bbc2d2d494784d55a6b77bd50898b3bac2ef96a2 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/MetadataService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/MetadataService.java @@ -1,10 +1,10 @@ -package at.tuwien.service; +package at.ac.tuwien.ifs.dbrepo.service; -import at.tuwien.api.user.external.ExternalMetadataDto; -import at.tuwien.exception.*; -import at.tuwien.oaipmh.OaiErrorType; -import at.tuwien.oaipmh.OaiListIdentifiersParameters; -import at.tuwien.oaipmh.OaiRecordParameters; +import at.ac.tuwien.ifs.dbrepo.core.api.user.external.ExternalMetadataDto; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.oaipmh.OaiErrorType; +import at.ac.tuwien.ifs.dbrepo.oaipmh.OaiListIdentifiersParameters; +import at.ac.tuwien.ifs.dbrepo.oaipmh.OaiRecordParameters; public interface MetadataService { @@ -28,6 +28,7 @@ public interface MetadataService { * * @param parameters The parameters. * @return The xml record. + * @throws IdentifierNotFoundException The identifier was not found. */ String getRecord(OaiRecordParameters parameters) throws IdentifierNotFoundException; @@ -51,9 +52,10 @@ public interface MetadataService { * * @param url The user identifier. * @return The user metadata. - * @throws OrcidNotFoundException The provided identifier is of ORCID type and does not exist. - * @throws RorNotFoundException The provided identifier is of ROR type and does not exist. - * @throws DoiNotFoundException The doi was not found. + * @throws OrcidNotFoundException The provided identifier is of ORCID type and does not exist. + * @throws RorNotFoundException The provided identifier is of ROR type and does not exist. + * @throws DoiNotFoundException The doi was not found. + * @throws IdentifierNotSupportedException The identifier is not supported. */ ExternalMetadataDto findByUrl(String url) throws OrcidNotFoundException, RorNotFoundException, DoiNotFoundException, IdentifierNotSupportedException; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/OntologyService.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/OntologyService.java similarity index 72% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/OntologyService.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/OntologyService.java index c8e4c7067642ca1b948a321dba5d004d0f9eb2d2..584ab4178cd6cba9ea22d610b11d98eedec5c963 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/OntologyService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/OntologyService.java @@ -1,9 +1,9 @@ -package at.tuwien.service; +package at.ac.tuwien.ifs.dbrepo.service; -import at.tuwien.api.semantics.OntologyCreateDto; -import at.tuwien.api.semantics.OntologyModifyDto; -import at.tuwien.entities.semantics.Ontology; -import at.tuwien.exception.OntologyNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.api.semantics.OntologyCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.semantics.OntologyModifyDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.semantics.Ontology; +import at.ac.tuwien.ifs.dbrepo.core.exception.OntologyNotFoundException; import java.security.Principal; import java.util.List; @@ -34,6 +34,13 @@ public interface OntologyService { */ Ontology find(UUID ontologyId) throws OntologyNotFoundException; + /** + * Finds an ontology in the metadata database with given entity uri. + * + * @param entityUri The entity uri. + * @return The ontology, if successful. + * @throws OntologyNotFoundException The ontology was not found in the metadata database. + */ Ontology find(String entityUri) throws OntologyNotFoundException; /** diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/StorageService.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/StorageService.java similarity index 73% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/StorageService.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/StorageService.java index 7cb195ce4ee59c919ff0377ece7636be2d091827..33a96b1296d29598b7df653e3dc5ba67e6b976ad 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/StorageService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/StorageService.java @@ -1,7 +1,7 @@ -package at.tuwien.service; +package at.ac.tuwien.ifs.dbrepo.service; -import at.tuwien.exception.StorageNotFoundException; -import at.tuwien.exception.StorageUnavailableException; +import at.ac.tuwien.ifs.dbrepo.core.exception.StorageNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.exception.StorageUnavailableException; import java.io.InputStream; @@ -13,8 +13,8 @@ public interface StorageService { * @param bucket The bucket name. * @param key The object key. * @return The input stream, if successful. + * @throws StorageNotFoundException The object could not be found in the Storage Service. * @throws StorageUnavailableException The object failed to be loaded from the Storage Service. - * @throws StorageNotFoundException The object could not be found in the Storage Service. */ InputStream getObject(String bucket, String key) throws StorageNotFoundException, StorageUnavailableException; @@ -25,7 +25,7 @@ public interface StorageService { * @param key The object key. * @return The byte array. * @throws StorageUnavailableException The object failed to be loaded from the Storage Service. - * @throws StorageNotFoundException The object could not be found in the Storage Service. + * @throws StorageNotFoundException The object could not be found in the Storage Service. */ byte[] getBytes(String key) throws StorageUnavailableException, StorageNotFoundException; @@ -35,8 +35,8 @@ public interface StorageService { * @param bucket The bucket name. * @param key The object key. * @return The byte array. + * @throws StorageNotFoundException The object could not be found in the Storage Service. * @throws StorageUnavailableException The object failed to be loaded from the Storage Service. - * @throws StorageNotFoundException The object could not be found in the Storage Service. */ byte[] getBytes(String bucket, String key) throws StorageNotFoundException, StorageUnavailableException; } diff --git a/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/TableService.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/TableService.java new file mode 100644 index 0000000000000000000000000000000000000000..b024698362dba56e45083d8f24f017f483e972ae --- /dev/null +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/TableService.java @@ -0,0 +1,140 @@ +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.CreateTableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.concepts.ColumnSemanticsUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.Table; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumn; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; + +import java.security.Principal; +import java.util.UUID; + +public interface TableService { + + /** + * Find a table in the metadata database by database and table id. + * + * @param database The database. + * @param tableId The table id. + * @return The table, if successful. + * @throws TableNotFoundException The table was not found in the metadata service. + * @throws DatabaseNotFoundException The database was not found in the metadata service. + */ + Table findById(Database database, UUID tableId) throws TableNotFoundException, DatabaseNotFoundException; + + /** + * Find a table in the metadata database by database id and table name. + * + * @param database The database. + * @param internalName The table name. + * @return The table, if successful. + * @throws TableNotFoundException The table was not found in the metadata service. + * @throws DatabaseNotFoundException The database was not found in the metadata service. + */ + Table findByName(Database database, String internalName) throws TableNotFoundException, DatabaseNotFoundException; + + + /** + * + * Creates a table for a database id with given schema as data + * + * @param database The database. + * @param createDto The schema (as data). + * @param principal The principal. + * @return The created table. + * @throws TableNotFoundException The table was not found in the metadata service. + * @throws DataServiceException The data service responded with unexpected behavior. + * @throws DataServiceConnectionException The connection with the data service could not be established. + * @throws UserNotFoundException The user with this username was not found in the metadata database. + * @throws DatabaseNotFoundException The database was not found in the metadata service. + * @throws TableExistsException The table with this name exists in the target database. + * @throws SearchServiceException The search service responded with an unexpected error code. + * @throws SearchServiceConnectionException The connection with the search service could not be established. + * @throws MalformedException The table is malformed, e.g. a column of a primary key constraint could not be found. + * @throws OntologyNotFoundException The ontology was not found in the metadata database. + * @throws SemanticEntityNotFoundException The semantic entity was not found in the metadata database. + */ + Table createTable(Database database, CreateTableDto createDto, Principal principal) throws TableNotFoundException, + DataServiceException, DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, + TableExistsException, SearchServiceException, SearchServiceConnectionException, MalformedException, + OntologyNotFoundException, SemanticEntityNotFoundException; + + /** + * Deletes a given table from the database in the metadata database and data database. + * + * @param table The table. + * @throws DataServiceException The data service responded with unexpected behavior. + * @throws DataServiceConnectionException The connection with the data service could not be established. + * @throws DatabaseNotFoundException The database was not found in the metadata service. + * @throws TableNotFoundException The table was not found in the metadata service. + * @throws SearchServiceException The search service responded with an unexpected error code. + * @throws SearchServiceConnectionException The connection with the search service could not be established. + */ + void deleteTable(Table table) throws DataServiceException, DataServiceConnectionException, + DatabaseNotFoundException, TableNotFoundException, SearchServiceException, SearchServiceConnectionException; + + /** + * Updates a given table from the database in the metadata database. + * + * @param table The table. + * @param data The update data. + * @return The updated table, if successful. + * @throws DataServiceException The data service responded with unexpected behavior. + * @throws DataServiceConnectionException The connection with the data service could not be established. + * @throws DatabaseNotFoundException The database was not found in the metadata service. + * @throws TableNotFoundException The table was not found in the metadata service. + * @throws SearchServiceException The search service responded with an unexpected error code. + * @throws SearchServiceConnectionException The connection with the search service could not be established. + */ + Table updateTable(Table table, TableUpdateDto data) throws DataServiceException, + DataServiceConnectionException, DatabaseNotFoundException, TableNotFoundException, SearchServiceException, + SearchServiceConnectionException; + + /** + * Updates a given table column in the metadata database. + * + * @param column The table column. + * @param updateDto The update data. + * @return The updated table column, if successful. + * @throws DataServiceException The data service responded with unexpected behavior. + * @throws DataServiceConnectionException The connection with the data service could not be established. + * @throws DatabaseNotFoundException The database was not found in the metadata service. + * @throws SearchServiceException The search service responded with an unexpected error code. + * @throws SearchServiceConnectionException The connection with the search service could not be established. + * @throws MalformedException The table is malformed, e.g. a column of a primary key constraint could not be found. + * @throws OntologyNotFoundException The ontology was not found in the metadata database. + * @throws SemanticEntityNotFoundException The semantic entity was not found in the metadata database. + */ + TableColumn update(TableColumn column, ColumnSemanticsUpdateDto updateDto) throws DataServiceException, + DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, + SearchServiceConnectionException, MalformedException, OntologyNotFoundException, + SemanticEntityNotFoundException; + + /** + * Find a table column by given table and column id. + * + * @param table The table. + * @param columnId The column id. + * @return The column, if found. + * @throws MalformedException The table column was not found. + */ + TableColumn findColumnById(Table table, UUID columnId) throws MalformedException; + + /** + * Updates the table statistics by given table. + * + * @param table The table. + * @throws SearchServiceException The search service responded with an unexpected error code. + * @throws DatabaseNotFoundException The database was not found in the metadata service. + * @throws SearchServiceConnectionException The connection with the search service could not be established. + * @throws MalformedException The table is malformed, e.g. a column of a primary key constraint could not be found. + * @throws TableNotFoundException The table was not found in the metadata service. + * @throws DataServiceException The data service responded with unexpected behavior. + * @throws DataServiceConnectionException The connection with the data service could not be established. + */ + void updateStatistics(Table table) throws SearchServiceException, DatabaseNotFoundException, + SearchServiceConnectionException, MalformedException, TableNotFoundException, DataServiceException, + DataServiceConnectionException; +} diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UnitService.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/UnitService.java similarity index 63% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UnitService.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/UnitService.java index 93824eeb62b94ca5191526b5cb8c576acc9ed433..fcf37fbe5a3effca02da7bab976e748225bff834 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UnitService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/UnitService.java @@ -1,13 +1,19 @@ -package at.tuwien.service; +package at.ac.tuwien.ifs.dbrepo.service; -import at.tuwien.entities.database.table.columns.TableColumnUnit; -import at.tuwien.exception.UnitNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumnUnit; +import at.ac.tuwien.ifs.dbrepo.core.exception.UnitNotFoundException; import org.springframework.transaction.annotation.Transactional; import java.util.List; public interface UnitService { + /** + * Creates a table column unit in the metadata database. + * + * @param unit The table column unit. + * @return The saved table column unit, if successful. + */ TableColumnUnit create(TableColumnUnit unit); /** diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UserService.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/UserService.java similarity index 68% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UserService.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/UserService.java index f38268c000aa85a663bacbb51511aeae8ef197d1..3e244e8e8b954f9b08e363376ca78649c60ea0e5 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UserService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/UserService.java @@ -1,12 +1,10 @@ -package at.tuwien.service; +package at.ac.tuwien.ifs.dbrepo.service; -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.AuthServiceException; -import at.tuwien.exception.UserExistsException; -import at.tuwien.exception.UserNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.api.auth.CreateUserDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.AuthServiceException; +import at.ac.tuwien.ifs.dbrepo.core.exception.UserNotFoundException; import java.util.List; import java.util.UUID; @@ -29,6 +27,11 @@ public interface UserService { */ User findByUsername(String username) throws UserNotFoundException; + /** + * Filters all users where they are marked as service account ({@link User#isInternal}). + * + * @return List of users. + */ List<User> findAllInternalUsers(); /** @@ -54,8 +57,8 @@ public interface UserService { * @param user The user. * @param data The user information. * @return The user if successful. False otherwise. + * @throws UserNotFoundException The user was not found. + * @throws AuthServiceException The auth service responded with an unexpected error code. */ User modify(User user, UserUpdateDto data) throws UserNotFoundException, AuthServiceException; - - String getMariaDbPassword(String password); } diff --git a/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/ViewService.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/ViewService.java new file mode 100644 index 0000000000000000000000000000000000000000..eda8cdd4430c591f64306f613c7b82209cff8aa6 --- /dev/null +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/ViewService.java @@ -0,0 +1,69 @@ +package at.ac.tuwien.ifs.dbrepo.service; + +import at.ac.tuwien.ifs.dbrepo.core.api.database.CreateViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.View; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; + +import java.util.UUID; + +public interface ViewService { + + /** + * Find a view of a database with id. + * + * @param database The database. + * @param viewId The view id. + * @return The view, if successful. + * @throws ViewNotFoundException The view with given id was not found in the metadata database. + */ + View findById(Database database, UUID viewId) throws ViewNotFoundException; + + /** + * Delete view in the container with the given id and database with id and the given view id. + * + * @param view The view. + * @throws DataServiceException The data service responded with unexpected behavior. + * @throws DataServiceConnectionException The connection with the data service could not be established. + * @throws DatabaseNotFoundException The database was not found in the metadata service. + * @throws ViewNotFoundException The view was not found in the metadata database. + * @throws SearchServiceException The search service responded with an unexpected error code. + * @throws SearchServiceConnectionException The connection with the search service could not be established. + */ + void delete(View view) throws DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, + ViewNotFoundException, SearchServiceException, SearchServiceConnectionException; + + /** + * Creates a view in the container with given id and database with id with the given query. + * + * @param database The database. + * @param user The user. + * @param data The given query. + * @return The view that was created. + * @throws MalformedException The query was malformed in the data service. + * @throws DataServiceException The data service responded with unexpected behavior. + * @throws DataServiceConnectionException The connection with the data service could not be established. + * @throws DatabaseNotFoundException The database was not found in the metadata service. + * @throws SearchServiceException The search service responded with an unexpected error code. + * @throws SearchServiceConnectionException The connection with the search service could not be established. + */ + View create(Database database, User user, CreateViewDto data) throws MalformedException, DataServiceException, + DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, + SearchServiceConnectionException; + + /** + * Updates the view in the metadata database and search service. + * + * @param view The view. + * @param data The update data. + * @return The view, if successful. + * @throws DataServiceConnectionException The connection with the data service could not be established. + * @throws DatabaseNotFoundException The database was not found in the metadata service. + * @throws SearchServiceException The search service responded with an unexpected error code. + * @throws SearchServiceConnectionException The connection with the search service could not be established. + */ + View update(View view, ViewUpdateDto data) throws DataServiceConnectionException, DatabaseNotFoundException, + SearchServiceException, SearchServiceConnectionException; +} diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/AccessServiceImpl.java similarity index 87% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/AccessServiceImpl.java index e5b59ebda8accad54421a1ed9834c7114b9ab911..7d3120bba2d2eccf643045658b8e7ecc8753bfc2 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/AccessServiceImpl.java @@ -1,16 +1,16 @@ -package at.tuwien.service.impl; +package at.ac.tuwien.ifs.dbrepo.service.impl; -import at.tuwien.api.database.AccessTypeDto; -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.gateway.DataServiceGateway; -import at.tuwien.gateway.SearchServiceGateway; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.repository.DatabaseRepository; -import at.tuwien.service.AccessService; -import at.tuwien.service.DatabaseService; +import at.ac.tuwien.ifs.dbrepo.core.api.database.AccessTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.DatabaseAccess; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.gateway.DataServiceGateway; +import at.ac.tuwien.ifs.dbrepo.gateway.SearchServiceGateway; +import at.ac.tuwien.ifs.dbrepo.repository.DatabaseRepository; +import at.ac.tuwien.ifs.dbrepo.service.AccessService; +import at.ac.tuwien.ifs.dbrepo.service.DatabaseService; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; 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/ac/tuwien/ifs/dbrepo/service/impl/AuthenticationServiceImpl.java similarity index 62% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/AuthenticationServiceImpl.java index e6bb056bfe31f23563acad6fe801021a830f9528..b2b485327120efc855a0ac13c3407ca06eec1355 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/AuthenticationServiceImpl.java @@ -1,10 +1,10 @@ -package at.tuwien.service.impl; +package at.ac.tuwien.ifs.dbrepo.service.impl; -import at.tuwien.entities.user.User; -import at.tuwien.exception.AuthServiceException; -import at.tuwien.exception.UserNotFoundException; -import at.tuwien.gateway.KeycloakGateway; -import at.tuwien.service.AuthenticationService; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.AuthServiceException; +import at.ac.tuwien.ifs.dbrepo.core.exception.UserNotFoundException; +import at.ac.tuwien.ifs.dbrepo.gateway.KeycloakGateway; +import at.ac.tuwien.ifs.dbrepo.service.AuthenticationService; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/BannerMessageServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/BannerMessageServiceImpl.java similarity index 82% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/BannerMessageServiceImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/BannerMessageServiceImpl.java index d75d384b3c293e68d00eba2da092ae85214617d5..8b8766401a3c482d202f3a64400abe0194b2fdb5 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/BannerMessageServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/BannerMessageServiceImpl.java @@ -1,12 +1,12 @@ -package at.tuwien.service.impl; +package at.ac.tuwien.ifs.dbrepo.service.impl; -import at.tuwien.api.maintenance.BannerMessageCreateDto; -import at.tuwien.api.maintenance.BannerMessageUpdateDto; -import at.tuwien.entities.maintenance.BannerMessage; -import at.tuwien.exception.MessageNotFoundException; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.repository.BannerMessageRepository; -import at.tuwien.service.BannerMessageService; +import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.maintenance.BannerMessage; +import at.ac.tuwien.ifs.dbrepo.core.exception.MessageNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.repository.BannerMessageRepository; +import at.ac.tuwien.ifs.dbrepo.service.BannerMessageService; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/BrokerServiceRabbitMqImpl.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/BrokerServiceRabbitMqImpl.java similarity index 88% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/BrokerServiceRabbitMqImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/BrokerServiceRabbitMqImpl.java index 2800c96bc9d376e14cb990edb4d8fe5f9cc5d3a3..709e7cebde2bcd054f8c59d4643866cb20a1563d 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/BrokerServiceRabbitMqImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/BrokerServiceRabbitMqImpl.java @@ -1,13 +1,13 @@ -package at.tuwien.service.impl; +package at.ac.tuwien.ifs.dbrepo.service.impl; -import at.tuwien.api.amqp.GrantExchangePermissionsDto; -import at.tuwien.api.amqp.GrantVirtualHostPermissionsDto; -import at.tuwien.config.RabbitConfig; -import at.tuwien.entities.database.AccessType; -import at.tuwien.entities.user.User; -import at.tuwien.exception.*; -import at.tuwien.gateway.BrokerServiceGateway; -import at.tuwien.service.BrokerService; +import at.ac.tuwien.ifs.dbrepo.core.api.amqp.GrantExchangePermissionsDto; +import at.ac.tuwien.ifs.dbrepo.core.api.amqp.GrantVirtualHostPermissionsDto; +import at.ac.tuwien.ifs.dbrepo.config.RabbitConfig; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.AccessType; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.gateway.BrokerServiceGateway; +import at.ac.tuwien.ifs.dbrepo.service.BrokerService; import lombok.extern.log4j.Log4j2; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ConceptServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/ConceptServiceImpl.java similarity index 80% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ConceptServiceImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/ConceptServiceImpl.java index 647d4fe198abc4b4ab4caf3836ab552bb521ce2c..93f64a16ea13efa86934f089ce5f8a9d778fc47e 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ConceptServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/ConceptServiceImpl.java @@ -1,9 +1,9 @@ -package at.tuwien.service.impl; +package at.ac.tuwien.ifs.dbrepo.service.impl; -import at.tuwien.entities.database.table.columns.TableColumnConcept; -import at.tuwien.exception.ConceptNotFoundException; -import at.tuwien.repository.ConceptRepository; -import at.tuwien.service.ConceptService; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumnConcept; +import at.ac.tuwien.ifs.dbrepo.core.exception.ConceptNotFoundException; +import at.ac.tuwien.ifs.dbrepo.repository.ConceptRepository; +import at.ac.tuwien.ifs.dbrepo.service.ConceptService; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; 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/ac/tuwien/ifs/dbrepo/service/impl/ContainerServiceImpl.java similarity index 84% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/ContainerServiceImpl.java index d92b6c17dc052728af0eb2e861baecdcda150995..27daf634877cd316a51aa9677a82bda7f3145865 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/ContainerServiceImpl.java @@ -1,15 +1,15 @@ -package at.tuwien.service.impl; +package at.ac.tuwien.ifs.dbrepo.service.impl; -import at.tuwien.api.container.CreateContainerDto; -import at.tuwien.entities.container.Container; -import at.tuwien.entities.container.image.ContainerImage; -import at.tuwien.exception.ContainerAlreadyExistsException; -import at.tuwien.exception.ContainerNotFoundException; -import at.tuwien.exception.ImageNotFoundException; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.repository.ContainerRepository; -import at.tuwien.repository.ImageRepository; -import at.tuwien.service.ContainerService; +import at.ac.tuwien.ifs.dbrepo.core.api.container.CreateContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.Container; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.image.ContainerImage; +import at.ac.tuwien.ifs.dbrepo.core.exception.ContainerAlreadyExistsException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ContainerNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ImageNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.repository.ContainerRepository; +import at.ac.tuwien.ifs.dbrepo.repository.ImageRepository; +import at.ac.tuwien.ifs.dbrepo.service.ContainerService; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/CredentialServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/CredentialServiceImpl.java similarity index 85% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/CredentialServiceImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/CredentialServiceImpl.java index 7cf7d1eff4394ae174b0e724fa8e34455b363578..65597ec056b7f03cc4bd9f88db11f2e15c212485 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/CredentialServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/CredentialServiceImpl.java @@ -1,8 +1,8 @@ -package at.tuwien.service.impl; +package at.ac.tuwien.ifs.dbrepo.service.impl; -import at.tuwien.api.keycloak.TokenDto; -import at.tuwien.gateway.KeycloakGateway; -import at.tuwien.service.CredentialService; +import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.TokenDto; +import at.ac.tuwien.ifs.dbrepo.gateway.KeycloakGateway; +import at.ac.tuwien.ifs.dbrepo.service.CredentialService; import com.github.benmanes.caffeine.cache.Cache; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; diff --git a/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/DashboardServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/DashboardServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..af76ee2d4fb13a966d10ba5999725f58589f3ea2 --- /dev/null +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/DashboardServiceImpl.java @@ -0,0 +1,51 @@ +package at.ac.tuwien.ifs.dbrepo.service.impl; + +import at.ac.tuwien.ifs.dbrepo.core.api.database.AccessTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.grafana.CreateDashboardResponseDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.DashboardServiceConnectionException; +import at.ac.tuwien.ifs.dbrepo.core.exception.DashboardServiceException; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.gateway.DashboardServiceGateway; +import at.ac.tuwien.ifs.dbrepo.service.DashboardService; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Log4j2 +@Service +public class DashboardServiceImpl implements DashboardService { + + private final MetadataMapper metadataMapper; + private final DashboardServiceGateway dashboardServiceGateway; + + @Autowired + public DashboardServiceImpl(MetadataMapper metadataMapper, DashboardServiceGateway dashboardServiceGateway) { + this.metadataMapper = metadataMapper; + this.dashboardServiceGateway = dashboardServiceGateway; + } + + @Override + public void update(Database database) throws DashboardServiceException, DashboardServiceConnectionException { + if (!database.getIsDashboardEnabled()) { + log.trace("database does not manage their dashboard, skip"); + return; + } + dashboardServiceGateway.update(metadataMapper.databaseToDatabaseDto(database)); + } + + @Override + public CreateDashboardResponseDto create(Database database) throws DashboardServiceException, + DashboardServiceConnectionException { + return dashboardServiceGateway.create(metadataMapper.databaseToCreateDashboardDto(database)); + } + + @Override + public void updateAccess(Database database, User user, AccessTypeDto access) throws DashboardServiceException, + DashboardServiceConnectionException { + dashboardServiceGateway.updateAccess(database.getDashboardUid(), user.getUsername(), + metadataMapper.accessTypeDtoToPermissionTypeDto(access)); + } + +} 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/ac/tuwien/ifs/dbrepo/service/impl/DataCiteIdentifierServiceImpl.java similarity index 83% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/DataCiteIdentifierServiceImpl.java index 5ab9cc26a226374d817966e880a684393c36cf08..5c109633183eb1d62f4a560e878140d15d75a6cd 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/DataCiteIdentifierServiceImpl.java @@ -1,24 +1,24 @@ -package at.tuwien.service.impl; - -import at.tuwien.api.datacite.DataCiteBody; -import at.tuwien.api.datacite.DataCiteData; -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.CreateIdentifierDto; -import at.tuwien.api.identifier.IdentifierSaveDto; -import at.tuwien.api.identifier.IdentifierTypeDto; -import at.tuwien.config.DataCiteConfig; -import at.tuwien.config.EndpointConfig; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.identifier.Identifier; -import at.tuwien.entities.identifier.IdentifierStatusType; -import at.tuwien.entities.user.User; -import at.tuwien.exception.*; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.repository.IdentifierRepository; -import at.tuwien.service.IdentifierService; +package at.ac.tuwien.ifs.dbrepo.service.impl; + +import at.ac.tuwien.ifs.dbrepo.core.api.datacite.DataCiteBody; +import at.ac.tuwien.ifs.dbrepo.core.api.datacite.DataCiteData; +import at.ac.tuwien.ifs.dbrepo.core.api.datacite.doi.DataCiteCreateDoi; +import at.ac.tuwien.ifs.dbrepo.core.api.datacite.doi.DataCiteDoi; +import at.ac.tuwien.ifs.dbrepo.core.api.datacite.doi.DataCiteDoiEvent; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.BibliographyTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.CreateIdentifierDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierSaveDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierTypeDto; +import at.ac.tuwien.ifs.dbrepo.config.DataCiteConfig; +import at.ac.tuwien.ifs.dbrepo.config.EndpointConfig; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.Identifier; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.IdentifierStatusType; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.repository.IdentifierRepository; +import at.ac.tuwien.ifs.dbrepo.service.IdentifierService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Primary; @@ -107,9 +107,8 @@ public class DataCiteIdentifierServiceImpl implements IdentifierService { @Override @Transactional(rollbackFor = {Exception.class}) public Identifier create(Database database, User user, CreateIdentifierDto data) throws DataServiceException, - DataServiceConnectionException, IdentifierNotFoundException, MalformedException, ViewNotFoundException, - DatabaseNotFoundException, QueryNotFoundException, SearchServiceException, - SearchServiceConnectionException, ExternalServiceException { + DataServiceConnectionException, MalformedException, ViewNotFoundException, DatabaseNotFoundException, + QueryNotFoundException, SearchServiceException, SearchServiceConnectionException, ExternalServiceException { data.setDoi(remoteSave(identifierService.create(database, user, data), DataCiteDoiEvent.REGISTER)); return identifierService.create(database, user, data); } @@ -198,8 +197,7 @@ public class DataCiteIdentifierServiceImpl implements IdentifierService { @Override @Transactional - public void delete(Identifier identifier) throws DataServiceException, DataServiceConnectionException, - DatabaseNotFoundException, IdentifierNotFoundException, SearchServiceException, + public void delete(Identifier identifier) throws DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException { identifierService.delete(identifier); } 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/ac/tuwien/ifs/dbrepo/service/impl/DatabaseServiceImpl.java similarity index 85% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/DatabaseServiceImpl.java index d01e5c0b6e1470362916a45dae689b155d1c92f2..6cfa0180a8891c97e49fdcebd1c2923da8088adf 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/DatabaseServiceImpl.java @@ -1,28 +1,28 @@ -package at.tuwien.service.impl; +package at.ac.tuwien.ifs.dbrepo.service.impl; -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.table.TableDto; -import at.tuwien.api.user.internal.UpdateUserPasswordDto; -import at.tuwien.entities.container.Container; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.database.View; -import at.tuwien.entities.database.ViewColumn; -import at.tuwien.entities.database.table.Table; -import at.tuwien.entities.database.table.columns.TableColumn; -import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKey; -import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKeyReference; -import at.tuwien.entities.database.table.constraints.primaryKey.PrimaryKey; -import at.tuwien.entities.database.table.constraints.unique.Unique; -import at.tuwien.entities.user.User; -import at.tuwien.exception.*; -import at.tuwien.gateway.DataServiceGateway; -import at.tuwien.gateway.SearchServiceGateway; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.repository.DatabaseRepository; -import at.tuwien.service.DatabaseService; +import at.ac.tuwien.ifs.dbrepo.core.api.database.CreateDatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.DatabaseModifyVisibilityDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.internal.UpdateUserPasswordDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.Container; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.View; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.ViewColumn; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.Table; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumn; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.foreignKey.ForeignKey; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.foreignKey.ForeignKeyReference; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.primaryKey.PrimaryKey; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.unique.Unique; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.gateway.DataServiceGateway; +import at.ac.tuwien.ifs.dbrepo.gateway.SearchServiceGateway; +import at.ac.tuwien.ifs.dbrepo.repository.DatabaseRepository; +import at.ac.tuwien.ifs.dbrepo.service.DatabaseService; import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.RandomStringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -72,11 +72,6 @@ public class DatabaseServiceImpl implements DatabaseService { return databaseRepository.findAllPublicOrSchemaPublicOrReadAccessByInternalNameDesc(userId, internalName); } - @Override - public List<Database> findAllAtLestReadAccess(UUID userId) { - return databaseRepository.findAllAtLestReadAccessDesc(userId); - } - @Override public List<Database> findAllPublicOrSchemaPublicOrReadAccess(UUID userId) { return databaseRepository.findAllPublicOrSchemaPublicOrReadAccessDesc(userId); @@ -101,11 +96,13 @@ public class DatabaseServiceImpl implements DatabaseService { @Override @Transactional public Database create(Container container, CreateDatabaseDto data, User user, List<User> internalUsers) - throws UserNotFoundException, ContainerNotFoundException, DataServiceException, SearchServiceException, - DataServiceConnectionException, DatabaseNotFoundException, SearchServiceConnectionException { + throws DataServiceException, SearchServiceException, DataServiceConnectionException, + DatabaseNotFoundException, SearchServiceConnectionException, DashboardServiceException, + DashboardServiceConnectionException { final Database entity = Database.builder() .isPublic(data.getIsPublic()) .isSchemaPublic(data.getIsSchemaPublic()) + .isDashboardEnabled(true) .name(data.getName()) .internalName(metadataMapper.nameToInternalName(data.getName()) + "_" + RandomStringUtils.randomAlphabetic(4).toLowerCase()) .cid(data.getCid()) @@ -120,13 +117,15 @@ public class DatabaseServiceImpl implements DatabaseService { .identifiers(new LinkedList<>()) .build(); /* create in data database */ - final at.tuwien.api.database.internal.CreateDatabaseDto payload = at.tuwien.api.database.internal.CreateDatabaseDto.builder() + final at.ac.tuwien.ifs.dbrepo.core.api.database.internal.CreateDatabaseDto payload = at.ac.tuwien.ifs.dbrepo.core.api.database.internal.CreateDatabaseDto.builder() .containerId(data.getCid()) .userId(user.getId()) .username(user.getUsername()) .password(user.getMariadbPassword()) .privilegedUsername(container.getPrivilegedUsername()) .privilegedPassword(container.getPrivilegedPassword()) + .readonlyUsername(container.getReadonlyUsername()) + .readonlyPassword(container.getReadonlyPassword()) .internalName(entity.getInternalName()) .build(); final DatabaseDto dto = dataServiceGateway.createDatabase(payload); @@ -135,10 +134,6 @@ public class DatabaseServiceImpl implements DatabaseService { final Database entity1 = databaseRepository.save(entity); entity1.getAccesses() .add(metadataMapper.userToWriteAllAccess(entity1, user)); -// entity1.getAccesses() -// .addAll(internalUsers.stream() -// .map(internalUser -> metadataMapper.userToWriteAllAccess(entity1, internalUser)) -// .toList()); final Database database = databaseRepository.save(entity1); /* create in search service */ searchServiceGateway.update(database); @@ -170,6 +165,7 @@ public class DatabaseServiceImpl implements DatabaseService { /* update in metadata database */ database.setIsPublic(data.getIsPublic()); database.setIsSchemaPublic(data.getIsSchemaPublic()); + database.setIsDashboardEnabled(data.getIsDashboardEnabled()); log.debug("visibility change affects {} table(s)", database.getTables().stream().filter(t -> !t.getIsSchemaPublic().equals(data.getIsSchemaPublic())).count()); database.getTables() .forEach(table -> table.setIsSchemaPublic(data.getIsSchemaPublic())); @@ -209,6 +205,19 @@ public class DatabaseServiceImpl implements DatabaseService { return database; } + @Override + @Transactional + public Database modifyDashboard(Database database, String uid) throws DatabaseNotFoundException, + SearchServiceException, SearchServiceConnectionException { + /* update in metadata database */ + database.setDashboardUid(uid); + database = databaseRepository.save(database); + /* save in search service */ + searchServiceGateway.update(database); + log.info("Updated database dashboard uid of database with id {} & search database", database.getId()); + return database; + } + @Override @Transactional(rollbackFor = {Exception.class}) public Database updateTableMetadata(Database database) throws DatabaseNotFoundException, DataServiceException, diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/EntityServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/EntityServiceImpl.java similarity index 91% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/EntityServiceImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/EntityServiceImpl.java index dba30481f5c3884ddea7da87930e295df91be37d..60001b92ac0685e424b468caeea10a1c367fdfe2 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/EntityServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/EntityServiceImpl.java @@ -1,15 +1,15 @@ -package at.tuwien.service.impl; +package at.ac.tuwien.ifs.dbrepo.service.impl; -import at.tuwien.api.semantics.EntityDto; -import at.tuwien.api.semantics.TableColumnEntityDto; -import at.tuwien.config.JenaConfig; -import at.tuwien.entities.database.table.Table; -import at.tuwien.entities.database.table.columns.TableColumn; -import at.tuwien.entities.semantics.Ontology; -import at.tuwien.exception.*; -import at.tuwien.mapper.SparqlMapper; -import at.tuwien.service.EntityService; -import at.tuwien.service.OntologyService; +import at.ac.tuwien.ifs.dbrepo.core.api.semantics.EntityDto; +import at.ac.tuwien.ifs.dbrepo.core.api.semantics.TableColumnEntityDto; +import at.ac.tuwien.ifs.dbrepo.config.JenaConfig; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.Table; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumn; +import at.ac.tuwien.ifs.dbrepo.core.entity.semantics.Ontology; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.mapper.SparqlMapper; +import at.ac.tuwien.ifs.dbrepo.service.EntityService; +import at.ac.tuwien.ifs.dbrepo.service.OntologyService; import lombok.extern.log4j.Log4j2; import org.apache.jena.query.*; import org.apache.jena.rdf.model.RDFNode; 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/ac/tuwien/ifs/dbrepo/service/impl/IdentifierServiceImpl.java similarity index 90% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/IdentifierServiceImpl.java index 8af7023c8cb48b64078457c409b8e14ece6187b7..f8b2c273e8c9032a103b327f84892528aad7826f 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/IdentifierServiceImpl.java @@ -1,25 +1,25 @@ -package at.tuwien.service.impl; +package at.ac.tuwien.ifs.dbrepo.service.impl; -import at.tuwien.api.database.query.QueryDto; -import at.tuwien.api.identifier.BibliographyTypeDto; -import at.tuwien.api.identifier.CreateIdentifierDto; -import at.tuwien.api.identifier.IdentifierSaveDto; -import at.tuwien.api.identifier.IdentifierTypeDto; -import at.tuwien.config.MetadataConfig; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.database.LanguageType; -import at.tuwien.entities.database.View; -import at.tuwien.entities.identifier.Identifier; -import at.tuwien.entities.identifier.IdentifierStatusType; -import at.tuwien.entities.identifier.IdentifierTitle; -import at.tuwien.entities.user.User; -import at.tuwien.exception.*; -import at.tuwien.gateway.DataServiceGateway; -import at.tuwien.gateway.SearchServiceGateway; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.repository.IdentifierRepository; -import at.tuwien.service.IdentifierService; -import at.tuwien.service.ViewService; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.QueryDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.BibliographyTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.CreateIdentifierDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierSaveDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierTypeDto; +import at.ac.tuwien.ifs.dbrepo.config.MetadataConfig; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.LanguageType; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.View; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.Identifier; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.IdentifierStatusType; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.IdentifierTitle; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.gateway.DataServiceGateway; +import at.ac.tuwien.ifs.dbrepo.gateway.SearchServiceGateway; +import at.ac.tuwien.ifs.dbrepo.repository.IdentifierRepository; +import at.ac.tuwien.ifs.dbrepo.service.IdentifierService; +import at.ac.tuwien.ifs.dbrepo.service.ViewService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; import org.springframework.core.io.InputStreamResource; @@ -226,8 +226,8 @@ public class IdentifierServiceImpl implements IdentifierService { @Transactional public Identifier create(Database database, User user, CreateIdentifierDto data) throws SearchServiceException, DataServiceException, QueryNotFoundException, DataServiceConnectionException, DatabaseNotFoundException, - SearchServiceConnectionException, IdentifierNotFoundException, ViewNotFoundException { - final Identifier identifier = metadataMapper.identifierCreateDtoToIdentifier(data); + SearchServiceConnectionException, ViewNotFoundException { + final Identifier identifier = metadataMapper.createIdentifierDtoToIdentifier(data); identifier.setDatabase(database); identifier.setOwnedBy(user.getId()); identifier.setOwner(user); @@ -278,8 +278,8 @@ public class IdentifierServiceImpl implements IdentifierService { @Transactional public Identifier save(Identifier identifier) throws DataServiceException, DataServiceConnectionException, - IdentifierNotFoundException, ViewNotFoundException, DatabaseNotFoundException, QueryNotFoundException, - SearchServiceException, SearchServiceConnectionException { + ViewNotFoundException, DatabaseNotFoundException, QueryNotFoundException, SearchServiceException, + SearchServiceConnectionException { /* save identifier */ switch (identifier.getType()) { case SUBSET -> { @@ -357,8 +357,7 @@ public class IdentifierServiceImpl implements IdentifierService { @Override @Transactional - public void delete(Identifier identifier) throws DataServiceException, DataServiceConnectionException, - IdentifierNotFoundException, DatabaseNotFoundException, SearchServiceException, + public void delete(Identifier identifier) throws DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException { /* delete in metadata database */ identifierRepository.deleteById(identifier.getId()); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ImageServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/ImageServiceImpl.java similarity index 85% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ImageServiceImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/ImageServiceImpl.java index b82c8ca38290d5bc24dff6f60a14c5051ecf4697..470fd9c3a85e254c05e6637df394483482db2a20 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ImageServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/ImageServiceImpl.java @@ -1,14 +1,14 @@ -package at.tuwien.service.impl; +package at.ac.tuwien.ifs.dbrepo.service.impl; -import at.tuwien.api.container.image.ImageChangeDto; -import at.tuwien.api.container.image.ImageCreateDto; -import at.tuwien.entities.container.image.ContainerImage; -import at.tuwien.exception.ImageAlreadyExistsException; -import at.tuwien.exception.ImageInvalidException; -import at.tuwien.exception.ImageNotFoundException; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.repository.ImageRepository; -import at.tuwien.service.ImageService; +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageChangeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.image.ContainerImage; +import at.ac.tuwien.ifs.dbrepo.core.exception.ImageAlreadyExistsException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ImageInvalidException; +import at.ac.tuwien.ifs.dbrepo.core.exception.ImageNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.repository.ImageRepository; +import at.ac.tuwien.ifs.dbrepo.service.ImageService; import jakarta.validation.ConstraintViolationException; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/LicenseServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/LicenseServiceImpl.java similarity index 76% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/LicenseServiceImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/LicenseServiceImpl.java index de5018f8c7e6c99fe301e1ba734dd0da3450e1dd..41765fb36a51ce192bd8b28867f78751293b5e0b 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/LicenseServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/LicenseServiceImpl.java @@ -1,9 +1,9 @@ -package at.tuwien.service.impl; +package at.ac.tuwien.ifs.dbrepo.service.impl; -import at.tuwien.entities.database.License; -import at.tuwien.exception.LicenseNotFoundException; -import at.tuwien.repository.LicenseRepository; -import at.tuwien.service.LicenseService; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.License; +import at.ac.tuwien.ifs.dbrepo.core.exception.LicenseNotFoundException; +import at.ac.tuwien.ifs.dbrepo.repository.LicenseRepository; +import at.ac.tuwien.ifs.dbrepo.service.LicenseService; import lombok.extern.log4j.Log4j2; import org.springframework.stereotype.Service; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/MetadataServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/MetadataServiceImpl.java similarity index 84% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/MetadataServiceImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/MetadataServiceImpl.java index 1b6051f5437ba8a07ee10eef0ebe1c5ef5e67587..1c4376184a2a12f034440d5de46030c5abd4dd14 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/MetadataServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/MetadataServiceImpl.java @@ -1,22 +1,22 @@ -package at.tuwien.service.impl; +package at.ac.tuwien.ifs.dbrepo.service.impl; -import at.tuwien.api.crossref.CrossrefDto; -import at.tuwien.api.orcid.OrcidDto; -import at.tuwien.api.ror.RorDto; -import at.tuwien.api.user.external.ExternalMetadataDto; -import at.tuwien.config.MetadataConfig; -import at.tuwien.entities.identifier.Identifier; -import at.tuwien.exception.*; -import at.tuwien.gateway.CrossrefGateway; -import at.tuwien.gateway.OrcidGateway; -import at.tuwien.gateway.RorGateway; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.oaipmh.OaiErrorType; -import at.tuwien.oaipmh.OaiListIdentifiersParameters; -import at.tuwien.oaipmh.OaiRecordParameters; -import at.tuwien.repository.IdentifierRepository; -import at.tuwien.service.IdentifierService; -import at.tuwien.service.MetadataService; +import at.ac.tuwien.ifs.dbrepo.config.MetadataConfig; +import at.ac.tuwien.ifs.dbrepo.core.api.crossref.CrossRefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.OrcidDto; +import at.ac.tuwien.ifs.dbrepo.core.api.ror.RorDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.external.ExternalMetadataDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.Identifier; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.gateway.CrossRefGateway; +import at.ac.tuwien.ifs.dbrepo.gateway.OrcidGateway; +import at.ac.tuwien.ifs.dbrepo.gateway.RorGateway; +import at.ac.tuwien.ifs.dbrepo.oaipmh.OaiErrorType; +import at.ac.tuwien.ifs.dbrepo.oaipmh.OaiListIdentifiersParameters; +import at.ac.tuwien.ifs.dbrepo.oaipmh.OaiRecordParameters; +import at.ac.tuwien.ifs.dbrepo.repository.IdentifierRepository; +import at.ac.tuwien.ifs.dbrepo.service.IdentifierService; +import at.ac.tuwien.ifs.dbrepo.service.MetadataService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -39,21 +39,21 @@ public class MetadataServiceImpl implements MetadataService { private final MetadataConfig metadataConfig; private final MetadataMapper metadataMapper; private final TemplateEngine templateEngine; - private final CrossrefGateway crossrefGateway; + private final CrossRefGateway crossRefGateway; private final IdentifierService identifierService; private final IdentifierRepository identifierRepository; @Autowired public MetadataServiceImpl(RorGateway rorGateway, OrcidGateway orcidGateway, MetadataConfig metadataConfig, MetadataMapper metadataMapper, TemplateEngine templateEngine, - CrossrefGateway crossrefGateway, IdentifierService identifierService, + CrossRefGateway crossRefGateway, IdentifierService identifierService, IdentifierRepository identifierRepository) { this.rorGateway = rorGateway; this.orcidGateway = orcidGateway; this.metadataConfig = metadataConfig; this.metadataMapper = metadataMapper; this.templateEngine = templateEngine; - this.crossrefGateway = crossrefGateway; + this.crossRefGateway = crossRefGateway; this.identifierService = identifierService; this.identifierRepository = identifierRepository; } @@ -117,10 +117,9 @@ public class MetadataServiceImpl implements MetadataService { @Override public String listMetadataFormats() { - final StringBuilder builder = new StringBuilder("<ListMetadataFormats>"); - builder.append(templateEngine.process("metadata-format.xml", new Context())); - builder.append("</ListMetadataFormats>"); - return parseResponse("verb=\"ListMetadataFormats\"", builder.toString()); + String builder = "<ListMetadataFormats>" + templateEngine.process("metadata-format.xml", new Context()) + + "</ListMetadataFormats>"; + return parseResponse("verb=\"ListMetadataFormats\"", builder); } @Override @@ -178,7 +177,7 @@ public class MetadataServiceImpl implements MetadataService { throw new RorNotFoundException("Failed to find metadata from CrossRef URL: too short"); } final String id = url.substring(idx + 8); - final CrossrefDto crossrefDto = crossrefGateway.findById(id); + final CrossRefDto crossrefDto = crossRefGateway.findById(id); return metadataMapper.crossrefDtoToExternalMetadataDto(crossrefDto); } log.error("Failed to find metadata: unsupported identifier {}", url); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/OntologyServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/OntologyServiceImpl.java similarity index 84% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/OntologyServiceImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/OntologyServiceImpl.java index d40239a06eb560272aea8acdf35a0f3bdc39fe4f..182f1eb5c9f354c17b782834a7eb95d6f51419d5 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/OntologyServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/OntologyServiceImpl.java @@ -1,13 +1,12 @@ -package at.tuwien.service.impl; +package at.ac.tuwien.ifs.dbrepo.service.impl; -import at.tuwien.api.semantics.OntologyCreateDto; -import at.tuwien.api.semantics.OntologyModifyDto; -import at.tuwien.entities.semantics.Ontology; -import at.tuwien.exception.OntologyNotFoundException; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.mapper.SparqlMapper; -import at.tuwien.repository.OntologyRepository; -import at.tuwien.service.OntologyService; +import at.ac.tuwien.ifs.dbrepo.core.api.semantics.OntologyCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.semantics.OntologyModifyDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.semantics.Ontology; +import at.ac.tuwien.ifs.dbrepo.core.exception.OntologyNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.repository.OntologyRepository; +import at.ac.tuwien.ifs.dbrepo.service.OntologyService; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -23,14 +22,12 @@ import java.util.UUID; @Service public class OntologyServiceImpl implements OntologyService { - private final SparqlMapper sparqlMapper; private final MetadataMapper metadataMapper; private final OntologyRepository ontologyRepository; @Autowired - public OntologyServiceImpl(SparqlMapper ontologyMapper, MetadataMapper metadataMapper, + public OntologyServiceImpl(MetadataMapper metadataMapper, OntologyRepository ontologyRepository) { - this.sparqlMapper = ontologyMapper; this.metadataMapper = metadataMapper; this.ontologyRepository = ontologyRepository; } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/StorageServiceS3Impl.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/StorageServiceS3Impl.java similarity index 82% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/StorageServiceS3Impl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/StorageServiceS3Impl.java index aef3213ccf2cac81ef70ad4a053c803cde16002d..345529486aaee6b1af596dc89da29298b060baff 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/StorageServiceS3Impl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/StorageServiceS3Impl.java @@ -1,14 +1,16 @@ -package at.tuwien.service.impl; +package at.ac.tuwien.ifs.dbrepo.service.impl; -import at.tuwien.config.S3Config; -import at.tuwien.exception.StorageNotFoundException; -import at.tuwien.exception.StorageUnavailableException; -import at.tuwien.service.StorageService; +import at.ac.tuwien.ifs.dbrepo.config.S3Config; +import at.ac.tuwien.ifs.dbrepo.core.exception.StorageNotFoundException; +import at.ac.tuwien.ifs.dbrepo.core.exception.StorageUnavailableException; +import at.ac.tuwien.ifs.dbrepo.service.StorageService; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import software.amazon.awssdk.services.s3.S3Client; -import software.amazon.awssdk.services.s3.model.*; +import software.amazon.awssdk.services.s3.model.GetObjectRequest; +import software.amazon.awssdk.services.s3.model.NoSuchKeyException; +import software.amazon.awssdk.services.s3.model.S3Exception; import java.io.IOException; import java.io.InputStream; 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/ac/tuwien/ifs/dbrepo/service/impl/TableServiceImpl.java similarity index 89% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/TableServiceImpl.java index 3b0a530e52ea65ad79b118f309353d14c0141dd1..520f84b401be428c7f877e7456abdc49cc2461b8 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/TableServiceImpl.java @@ -1,29 +1,32 @@ -package at.tuwien.service.impl; +package at.ac.tuwien.ifs.dbrepo.service.impl; -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.ColumnStatisticDto; -import at.tuwien.api.database.table.columns.CreateTableColumnDto; -import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto; -import at.tuwien.config.RabbitConfig; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.database.table.Table; -import at.tuwien.entities.database.table.columns.*; -import at.tuwien.entities.user.User; -import at.tuwien.exception.*; -import at.tuwien.gateway.DataServiceGateway; -import at.tuwien.gateway.SearchServiceGateway; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.repository.DatabaseRepository; -import at.tuwien.service.*; +import at.ac.tuwien.ifs.dbrepo.config.RabbitConfig; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.CreateTableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableStatisticDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnStatisticDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.CreateTableColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.concepts.ColumnSemanticsUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.Table; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.*; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.gateway.DataServiceGateway; +import at.ac.tuwien.ifs.dbrepo.gateway.SearchServiceGateway; +import at.ac.tuwien.ifs.dbrepo.repository.DatabaseRepository; +import at.ac.tuwien.ifs.dbrepo.service.*; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.security.Principal; -import java.util.*; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; @Log4j2 @Service @@ -296,18 +299,21 @@ public class TableServiceImpl implements TableService { DatabaseNotFoundException, SearchServiceConnectionException, MalformedException, TableNotFoundException, DataServiceException, DataServiceConnectionException { final TableStatisticDto statistic = dataServiceGateway.getTableStatistics(table.getTdbid(), table.getId()); - table.setNumRows(statistic.getRows()); + if (statistic == null) { + log.warn("Table statistic is empty (no column can be analysed), skip."); + return; + } + table.setNumRows(statistic.getTotalRows()); table.setDataLength(statistic.getDataLength()); table.setAvgRowLength(statistic.getAvgRowLength()); table.setMaxDataLength(statistic.getMaxDataLength()); - for (Map.Entry<String, ColumnStatisticDto> entry : statistic.getColumns().entrySet()) { - final Optional<TableColumn> optional = table.getColumns().stream().filter(c -> c.getInternalName().equals(entry.getKey())).findFirst(); + for (ColumnStatisticDto columnStatistic : statistic.getColumns()) { + final Optional<TableColumn> optional = table.getColumns().stream().filter(c -> c.getInternalName().equals(columnStatistic.getName())).findFirst(); if (optional.isEmpty()) { - log.error("Failed to assign table column statistic: column {} does not exist in table {}.{}", entry.getKey(), table.getDatabase().getInternalName(), table.getInternalName()); + log.error("Failed to assign table column statistic: column {} does not exist in table {}.{}", columnStatistic.getName(), table.getDatabase().getInternalName(), table.getInternalName()); throw new MalformedException("Failed to assign table column statistic: column does not exist"); } final TableColumn column = optional.get(); - final ColumnStatisticDto columnStatistic = statistic.getColumns().get(entry.getKey()); column.setMean(columnStatistic.getMean()); column.setMedian(columnStatistic.getMedian()); column.setMin(columnStatistic.getMin()); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UnitServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/UnitServiceImpl.java similarity index 80% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UnitServiceImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/UnitServiceImpl.java index 03270abcd597683a39e106a1bb12325719a9dde0..ae24d0342fb47ba0bc3363190dce2bd11274bd31 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UnitServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/UnitServiceImpl.java @@ -1,9 +1,9 @@ -package at.tuwien.service.impl; +package at.ac.tuwien.ifs.dbrepo.service.impl; -import at.tuwien.entities.database.table.columns.TableColumnUnit; -import at.tuwien.exception.UnitNotFoundException; -import at.tuwien.repository.UnitRepository; -import at.tuwien.service.UnitService; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumnUnit; +import at.ac.tuwien.ifs.dbrepo.core.exception.UnitNotFoundException; +import at.ac.tuwien.ifs.dbrepo.repository.UnitRepository; +import at.ac.tuwien.ifs.dbrepo.service.UnitService; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; 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/ac/tuwien/ifs/dbrepo/service/impl/UserServiceImpl.java similarity index 79% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/UserServiceImpl.java index ad05c4fd469a381aca7b8f11bfd6d0e5b017b2ff..f93dacc21c112d9bdbd1be6f511c0d89829ea836 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/UserServiceImpl.java @@ -1,13 +1,13 @@ -package at.tuwien.service.impl; +package at.ac.tuwien.ifs.dbrepo.service.impl; -import at.tuwien.api.auth.CreateUserDto; -import at.tuwien.api.user.UserUpdateDto; -import at.tuwien.entities.user.User; -import at.tuwien.exception.AuthServiceException; -import at.tuwien.exception.UserNotFoundException; -import at.tuwien.gateway.KeycloakGateway; -import at.tuwien.repository.UserRepository; -import at.tuwien.service.UserService; +import at.ac.tuwien.ifs.dbrepo.core.api.auth.CreateUserDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.AuthServiceException; +import at.ac.tuwien.ifs.dbrepo.core.exception.UserNotFoundException; +import at.ac.tuwien.ifs.dbrepo.gateway.KeycloakGateway; +import at.ac.tuwien.ifs.dbrepo.repository.UserRepository; +import at.ac.tuwien.ifs.dbrepo.service.UserService; import lombok.extern.log4j.Log4j2; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang3.RandomStringUtils; @@ -65,12 +65,15 @@ public class UserServiceImpl implements UserService { @Override public User create(CreateUserDto data) { /* create at authentication service */ + final String passwordHash = "*" + DigestUtils.sha1Hex(DigestUtils.sha1(RandomStringUtils.randomAlphabetic(40) + .getBytes(StandardCharsets.UTF_8))) + .toUpperCase(); final User entity = User.builder() .id(data.getLdapId()) .keycloakId(data.getId()) .username(data.getUsername()) .theme("light") - .mariadbPassword(getMariaDbPassword(RandomStringUtils.randomAlphabetic(10))) + .mariadbPassword(passwordHash) .language("en") .firstname(data.getGivenName()) .lastname(data.getFamilyName()) @@ -97,10 +100,4 @@ public class UserServiceImpl implements UserService { log.info("Modified user with id: {}", user.getId()); return user; } - - @Override - public String getMariaDbPassword(String password) { - final byte[] utf8 = password.getBytes(StandardCharsets.UTF_8); - return "*" + DigestUtils.sha1Hex(DigestUtils.sha1(utf8)).toUpperCase(); - } } 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/ac/tuwien/ifs/dbrepo/service/impl/ViewServiceImpl.java similarity index 67% rename from dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java rename to dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/ViewServiceImpl.java index 51c9832e267aac53cb02e09802839ebbdc6b151c..e952e25e4233d383f3eb38cff9a0b233881d8954 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/ac/tuwien/ifs/dbrepo/service/impl/ViewServiceImpl.java @@ -1,17 +1,17 @@ -package at.tuwien.service.impl; +package at.ac.tuwien.ifs.dbrepo.service.impl; -import at.tuwien.api.database.CreateViewDto; -import at.tuwien.api.database.ViewDto; -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 at.tuwien.gateway.DataServiceGateway; -import at.tuwien.gateway.SearchServiceGateway; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.repository.DatabaseRepository; -import at.tuwien.service.ViewService; +import at.ac.tuwien.ifs.dbrepo.core.api.database.CreateViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.ViewUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.View; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.exception.*; +import at.ac.tuwien.ifs.dbrepo.core.mapper.MetadataMapper; +import at.ac.tuwien.ifs.dbrepo.gateway.DataServiceGateway; +import at.ac.tuwien.ifs.dbrepo.gateway.SearchServiceGateway; +import at.ac.tuwien.ifs.dbrepo.repository.DatabaseRepository; +import at.ac.tuwien.ifs.dbrepo.service.ViewService; import com.google.common.hash.Hashing; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; @@ -20,7 +20,6 @@ import org.springframework.transaction.annotation.Transactional; import java.nio.charset.StandardCharsets; import java.util.LinkedList; -import java.util.List; import java.util.Optional; import java.util.UUID; @@ -55,25 +54,10 @@ public class ViewServiceImpl implements ViewService { return optional.get(); } - @Override - @Transactional(readOnly = true) - public List<View> findAll(Database database, User user) { - if (user == null) { - return database.getViews() - .stream() - .filter(View::getIsPublic) - .toList(); - } - return database.getViews() - .stream() - .filter(v -> v.getIsPublic() || v.getOwnedBy().equals(user.getId())) - .toList(); - } - @Override @Transactional - public void delete(View view) throws DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, - ViewNotFoundException, SearchServiceException, SearchServiceConnectionException { + public void delete(View view) throws DataServiceException, DataServiceConnectionException, + DatabaseNotFoundException, ViewNotFoundException, SearchServiceException, SearchServiceConnectionException { /* delete in data service */ dataServiceGateway.deleteView(view.getDatabase().getId(), view.getId()); /* delete in metadata database */ @@ -90,7 +74,7 @@ public class ViewServiceImpl implements ViewService { @Transactional public View create(Database database, User creator, CreateViewDto data) throws MalformedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, - SearchServiceConnectionException, TableNotFoundException, ImageNotFoundException { + SearchServiceConnectionException { /* create in metadata database */ final View view = View.builder() .database(database) @@ -136,24 +120,15 @@ public class ViewServiceImpl implements ViewService { @Override @Transactional - public View update(Database database, View view, ViewUpdateDto data) throws DataServiceConnectionException, - DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException, ViewNotFoundException { - final Optional<View> optional = database.getViews() - .stream() - .filter(v -> v.getInternalName().equals(view.getInternalName())) - .findFirst(); - if (optional.isEmpty()) { - log.error("Failed to find view"); - throw new ViewNotFoundException("Failed to find view"); - } - final View tmpView = optional.get(); - tmpView.setIsPublic(data.getIsPublic()); - tmpView.setIsSchemaPublic(data.getIsSchemaPublic()); - database = databaseRepository.save(database); + public View update(View view, ViewUpdateDto data) throws DataServiceConnectionException, DatabaseNotFoundException, + SearchServiceException, SearchServiceConnectionException { + view.setIsPublic(data.getIsPublic()); + view.setIsSchemaPublic(data.getIsSchemaPublic()); + final Database database = databaseRepository.save(view.getDatabase()); /* update in search service */ searchServiceGateway.update(database); - log.info("Updated view with id {}", tmpView.getId()); - return optional.get(); + log.info("Updated view with id {}", view.getId()); + return view; } } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/AccessService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/AccessService.java deleted file mode 100644 index 2642574f2720e0e6f565e0b83669c6398ccf453f..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/AccessService.java +++ /dev/null @@ -1,70 +0,0 @@ -package at.tuwien.service; - -import at.tuwien.api.database.AccessTypeDto; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.database.DatabaseAccess; -import at.tuwien.entities.user.User; -import at.tuwien.exception.*; - -import java.security.Principal; -import java.util.List; - -public interface AccessService { - - /** - * Loads all database access definitions for a database with id. - * - * @param database The database. - * @return The list of database access definitions. - */ - List<DatabaseAccess> list(Database database); - - /** - * Finds database access by given database and user, where the access is determined by the username (needed since {@link Principal#getName()} embeds the username). - * - * @param database The database. - * @param user The user. - * @return The database access, if successful. - * @throws AccessNotFoundException The access was not found in the metadata database. - */ - DatabaseAccess find(Database database, User user) throws AccessNotFoundException; - - /** - * Give somebody access to a database of container. - * - * @param database The database. - * @param access The access. - * @param user The user. - * @return The database access, if successful. - * @throws DataServiceException The data service responded with unexpected behavior. - * @throws DataServiceConnectionException The connection with the data service could not be established. - * @throws DatabaseNotFoundException The database was not found in the metadata/search database. - */ - DatabaseAccess create(Database database, User user, AccessTypeDto access) throws DataServiceException, DataServiceConnectionException, - DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException; - - /** - * Update access to a database. - * - * @param database The database. - * @param user The user. - * @param access The updated access. - * @throws DataServiceException The data service responded with unexpected behavior. - * @throws DataServiceConnectionException The connection with the data service could not be established. - * @throws DatabaseNotFoundException The database was not found in the metadata/search database. - */ - void update(Database database, User user, AccessTypeDto access) throws at.tuwien.exception.DataServiceException, DataServiceConnectionException, - AccessNotFoundException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException; - - /** - * Revokes access to a database of container. - * - * @param database The database. - * @param user The user. - * @throws DataServiceException The data service responded with unexpected behavior. - * @throws DataServiceConnectionException The connection with the data service could not be established. - * @throws DatabaseNotFoundException The database was not found in the search database. - */ - void delete(Database database, User user) throws AccessNotFoundException, DataServiceException, - DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException; -} 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 deleted file mode 100644 index f93e81b69f650f88167ec9fb886ba10520b4c6a6..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/AuthenticationService.java +++ /dev/null @@ -1,22 +0,0 @@ -package at.tuwien.service; - -import at.tuwien.entities.user.User; -import at.tuwien.exception.AuthServiceConnectionException; -import at.tuwien.exception.AuthServiceException; -import at.tuwien.exception.CredentialsInvalidException; -import at.tuwien.exception.UserNotFoundException; - -public interface AuthenticationService { - - /** - * Deletes a user at the Authentication Service with given user id. - * - * @param user The user. - * @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 delete(User user) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException, - CredentialsInvalidException; - -} diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/BrokerService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/BrokerService.java deleted file mode 100644 index f249f7a2cf128ffd09f4fcbeee4add401609436b..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/BrokerService.java +++ /dev/null @@ -1,21 +0,0 @@ -package at.tuwien.service; - -import at.tuwien.entities.user.User; -import at.tuwien.exception.*; - -public interface BrokerService { - - /** - * Updates the virtual host permissions in the Broker Service for a user with given principal. - * - * @param user The user. - */ - void setVirtualHostPermissions(User user) throws BrokerServiceException, BrokerServiceConnectionException; - - /** - * Sets topic exchange permissions for a user. - * - * @param user The user. - */ - void setTopicExchangePermissions(User user) throws BrokerServiceException, BrokerServiceConnectionException; -} 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 deleted file mode 100644 index 2f6aa6f3726627d7965c5466fa7db662cf88ddc4..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/DatabaseService.java +++ /dev/null @@ -1,124 +0,0 @@ -package at.tuwien.service; - -import at.tuwien.api.database.CreateDatabaseDto; -import at.tuwien.api.database.DatabaseModifyVisibilityDto; -import at.tuwien.entities.container.Container; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.user.User; -import at.tuwien.exception.*; -import org.springframework.stereotype.Service; - -import java.util.List; -import java.util.UUID; - -@Service -public interface DatabaseService { - - /** - * Finds all databases stored in the metadata database. - * - * @return List of databases. - */ - List<Database> findAll(); - - List<Database> findAllPublicOrSchemaPublic(); - - List<Database> findByInternalName(String internalName); - - List<Database> findAllPublicOrSchemaPublicOrReadAccessByInternalName(UUID userId, String internalName); - - /** - * Finds all databases stored in the metadata database. - * - * @param userId The user id. - * @return List of databases. - */ - List<Database> findAllAtLestReadAccess(UUID userId); - - /** - * Finds all databases stored in the metadata database. - * - * @param userId The user id. - * @return List of databases. - */ - List<Database> findAllPublicOrSchemaPublicOrReadAccess(UUID userId); - - /** - * @param internalName The database internal name. - * @return The databases if found. - */ - List<Database> findAllPublicOrSchemaPublicByInternalName(String internalName); - - /** - * Find a database by id, only used in the authentication service - * - * @param databaseId the database id. - * @return The database, if successful. - * @throws DatabaseNotFoundException The database was not found in the metadata database. - */ - Database findById(UUID databaseId) throws DatabaseNotFoundException; - - /** - * Creates a new database with minimal metadata in the metadata database and creates a new database on the container. - * - * @param container The container. - * @param createDto The metadata. - * @param user The user. - * @param internalUsers The list of internal users. - * @return The database, if successful. - * @throws UserNotFoundException If the container/user was not found in the metadata database. - * @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, CreateDatabaseDto createDto, User user, List<User> internalUsers) throws UserNotFoundException, - ContainerNotFoundException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, - SearchServiceException, SearchServiceConnectionException; - - /** - * Updates the user's password. - * - * @param database The database. - * @param user The user. - * @throws DataServiceException If the data service returned non-successfully. - * @throws DataServiceConnectionException If failing to connect to the data service. - */ - void updatePassword(Database database, User user) throws DataServiceException, DataServiceConnectionException, DatabaseNotFoundException; - - /** - * Updates the visibility of the database. - * - * @param database The database. - * @param data The visibility - * @return The database, if successful. - * @throws NotFoundException The database was not found in the metadata database. - * @throws DataServiceConnectionException If failing to connect to the search service. - */ - Database modifyVisibility(Database database, DatabaseModifyVisibilityDto data) throws DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException; - - /** - * Transfer ownership of a database - * - * @param database The database. - * @param user The payload with the new owner. - * @return The database, if successful. - * @throws DatabaseNotFoundException The database was not found in the metadata database. - */ - Database modifyOwner(Database database, User user) throws DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException; - - /** - * Modify image of database with given id. - * - * @param database The database. - * @param image The image. - * @return The database, if successful. - */ - Database modifyImage(Database database, byte[] image) throws DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException; - - Database updateTableMetadata(Database database) throws DatabaseNotFoundException, DataServiceException, - SearchServiceException, SearchServiceConnectionException, QueryNotFoundException, - DataServiceConnectionException, MalformedException, TableNotFoundException; - - Database updateViewMetadata(Database database) throws DatabaseNotFoundException, DataServiceException, - SearchServiceException, SearchServiceConnectionException, QueryNotFoundException, - DataServiceConnectionException, ViewNotFoundException; -} 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 deleted file mode 100644 index 2edea6ebeb2a61a80e4891a59afe4fd018e42109..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/TableService.java +++ /dev/null @@ -1,64 +0,0 @@ -package at.tuwien.service; - -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; -import at.tuwien.entities.database.table.Table; -import at.tuwien.entities.database.table.columns.TableColumn; -import at.tuwien.exception.*; - -import java.security.Principal; -import java.util.UUID; - -public interface TableService { - - /** - * Find a table in the metadata database by database and table id. - * - * @param database The database. - * @param tableId The table id. - * @return The table, if successful. - */ - Table findById(Database database, UUID tableId) throws TableNotFoundException, DatabaseNotFoundException; - - /** - * Find a table in the metadata database by database id and table name. - * - * @param database The database. - * @param internalName The table name. - * @return The table, if successful. - */ - Table findByName(Database database, String internalName) throws TableNotFoundException, DatabaseNotFoundException; - - - /** - * Creates a table for a database id with given schema as data - * - * @param database The database. - * @param createDto The schema (as data). - * @param principal The principal. - * @return The created table. - */ - Table createTable(Database database, CreateTableDto createDto, Principal principal) - throws TableNotFoundException, DataServiceException, DataServiceConnectionException, UserNotFoundException, - DatabaseNotFoundException, TableExistsException, SearchServiceException, SearchServiceConnectionException, MalformedException, OntologyNotFoundException, SemanticEntityNotFoundException; - - /** - * Deletes a table from the database in the metadata database and data database. - * - * @param table The table. - */ - void deleteTable(Table table) throws DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, TableNotFoundException, SearchServiceException, SearchServiceConnectionException; - - Table updateTable(Table table, TableUpdateDto data) throws DataServiceException, - DataServiceConnectionException, DatabaseNotFoundException, TableNotFoundException, SearchServiceException, - SearchServiceConnectionException; - - TableColumn update(TableColumn column, ColumnSemanticsUpdateDto updateDto) throws DataServiceException, - DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException, MalformedException, OntologyNotFoundException, SemanticEntityNotFoundException; - - TableColumn findColumnById(Table table, UUID columnId) throws MalformedException; - - void updateStatistics(Table table) throws SearchServiceException, DatabaseNotFoundException, SearchServiceConnectionException, MalformedException, TableNotFoundException, DataServiceException, DataServiceConnectionException; -} 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 deleted file mode 100644 index 54c9dd80bf7ed56040a55f019ca2e6b127a20cf9..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ViewService.java +++ /dev/null @@ -1,72 +0,0 @@ -package at.tuwien.service; - -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 java.util.List; -import java.util.UUID; - -public interface ViewService { - - /** - * Find a view of a database with id. - * - * @param database The database. - * @param viewId The view id. - * @return The view, if successful. - */ - View findById(Database database, UUID viewId) throws ViewNotFoundException; - - /** - * Find all views by database id. - * - * @param database The database. - * @param user The user. - * @return A list of views. - */ - List<View> findAll(Database database, User user); - - /** - * Delete view in the container with the given id and database with id and the given view id. - * - * @param view The view. - */ - void delete(View view) throws DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, - ViewNotFoundException, SearchServiceException, SearchServiceConnectionException; - - /** - * Creates a view in the container with given id and database with id with the given query. - * - * @param database The database. - * @param user The user. - * @param data The given query. - * @return The view that was created. - * @throws MalformedException - * @throws DataServiceException - * @throws DataServiceConnectionException - * @throws DatabaseNotFoundException - * @throws SearchServiceException - * @throws SearchServiceConnectionException - */ - View create(Database database, User user, CreateViewDto data) throws MalformedException, DataServiceException, - DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, - SearchServiceConnectionException, TableNotFoundException, ImageNotFoundException; - - /** - * @param database - * @param view - * @param data - * @return - * @throws DataServiceConnectionException - * @throws DatabaseNotFoundException - * @throws SearchServiceException - * @throws SearchServiceConnectionException - * @throws ViewNotFoundException - */ - View update(Database database, View view, ViewUpdateDto data) throws DataServiceConnectionException, - DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException, ViewNotFoundException; -} 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 deleted file mode 100644 index 230aada37a32157fbf17cb999edb1cf00cd9a0cd..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java +++ /dev/null @@ -1,160 +0,0 @@ -package at.tuwien.test; - -import at.tuwien.entities.database.AccessType; -import at.tuwien.entities.identifier.IdentifierStatusType; -import org.springframework.test.context.TestPropertySource; - -import java.util.LinkedList; -import java.util.List; - -@TestPropertySource(locations = "classpath:application.properties") -public abstract class AbstractUnitTest extends BaseTest { - - public void genesis() { - IMAGE_1_DTO.setOperators(IMAGE_1_OPERATORS_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))); - /* USER_1 */ - USER_1.setAccesses(new LinkedList<>()); - USER_1.setTheme(USER_1_THEME); - /* USER_2 */ - USER_2.setAccesses(new LinkedList<>()); - /* USER_3 */ - USER_3.setAccesses(new LinkedList<>()); - /* USER_4 */ - USER_4.setAccesses(new LinkedList<>()); - /* USER_4 */ - USER_5.setAccesses(new LinkedList<>()); - /* DATABASE 1 */ - TABLE_1_COLUMNS.get(0).setUnit(null); - TABLE_1_COLUMNS.get(0).setConcept(null); - DATABASE_1.setOwner(USER_1); - DATABASE_1.setSubsets(new LinkedList<>()); - DATABASE_1.setIsPublic(DATABASE_1_PUBLIC); - 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))); - 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); - 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); - IDENTIFIER_2.setDatabase(DATABASE_1); - IDENTIFIER_3.setDatabase(DATABASE_1); - 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_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_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_DTO.setColumns(new LinkedList<>(TABLE_2_COLUMNS_DTO)); - TABLE_2_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); - TABLE_3_DTO.setColumns(new LinkedList<>(TABLE_3_COLUMNS_DTO)); - TABLE_3_DTO.setConstraints(TABLE_3_CONSTRAINTS_DTO); - TABLE_4.setDatabase(DATABASE_1); - TABLE_4.setColumns(new LinkedList<>(TABLE_4_COLUMNS)); - TABLE_4.setConstraints(TABLE_4_CONSTRAINTS); - TABLE_4_DTO.setColumns(TABLE_4_COLUMNS_DTO); - TABLE_4_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))); - VIEW_2.setDatabase(DATABASE_1); - VIEW_2.setColumns(new LinkedList<>(VIEW_2_COLUMNS)); - VIEW_3.setDatabase(DATABASE_1); - VIEW_3.setColumns(new LinkedList<>(VIEW_3_COLUMNS)); - IDENTIFIER_1.setDatabase(DATABASE_1); - IDENTIFIER_2.setDatabase(DATABASE_1); - IDENTIFIER_3.setDatabase(DATABASE_1); - IDENTIFIER_4.setDatabase(DATABASE_1); - /* DATABASE 2 */ - DATABASE_2.setSubsets(new LinkedList<>()); - DATABASE_2.setAccesses(new LinkedList<>(List.of(DATABASE_2_USER_2_WRITE_ALL_ACCESS, DATABASE_2_USER_3_READ_ACCESS))); - DATABASE_2.setTables(new LinkedList<>(List.of(TABLE_5, TABLE_6, TABLE_7))); - 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_DTO.setAccesses(new LinkedList<>(List.of(DATABASE_2_USER_2_WRITE_ALL_ACCESS_DTO, DATABASE_2_USER_3_READ_ACCESS_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))); - 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_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))); - TABLE_5.setDatabase(DATABASE_2); - TABLE_5.setColumns(new LinkedList<>(TABLE_5_COLUMNS)); - TABLE_5.setConstraints(TABLE_5_CONSTRAINTS); - TABLE_5_DTO.setColumns(new LinkedList<>(TABLE_5_COLUMNS_DTO)); - TABLE_5_DTO.setConstraints(TABLE_5_CONSTRAINTS_DTO); - TABLE_6.setDatabase(DATABASE_2); - TABLE_6.setColumns(new LinkedList<>(TABLE_6_COLUMNS)); - TABLE_6.setConstraints(TABLE_6_CONSTRAINTS); - TABLE_7.setDatabase(DATABASE_2); - TABLE_7.setColumns(new LinkedList<>(TABLE_7_COLUMNS)); - TABLE_7.setConstraints(TABLE_7_CONSTRAINTS); - TABLE_7_CONSTRAINTS.getForeignKeys().get(0).getReferences().get(0).setForeignKey(TABLE_7_CONSTRAINTS.getForeignKeys().get(0)); - TABLE_7_CONSTRAINTS.getForeignKeys().get(1).getReferences().get(0).setForeignKey(TABLE_7_CONSTRAINTS.getForeignKeys().get(1)); - TABLE_7_DTO.setColumns(TABLE_7_COLUMNS_DTO); - TABLE_7_DTO.setConstraints(TABLE_7_CONSTRAINTS_DTO); - TABLE_7_CONSTRAINTS_DTO.getForeignKeys().get(0).getReferences().get(0).setForeignKey(TABLE_7_CONSTRAINTS_FOREIGN_KEY_BRIEF_0_DTO); - TABLE_7_CONSTRAINTS_DTO.getForeignKeys().get(1).getReferences().get(0).setForeignKey(TABLE_7_CONSTRAINTS_FOREIGN_KEY_BRIEF_1_DTO); - VIEW_4.setDatabase(DATABASE_2); - IDENTIFIER_5.setDatabase(DATABASE_2); - /* DATABASE 3 */ - DATABASE_3.setSubsets(new LinkedList<>()); - DATABASE_3.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))); - DATABASE_3_PRIVILEGED_DTO.setTables(new LinkedList<>(List.of(TABLE_8_DTO))); - DATABASE_3_PRIVILEGED_DTO.setViews(new LinkedList<>(List.of(VIEW_5_DTO))); - DATABASE_3_PRIVILEGED_DTO.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_6_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); - 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))); - DATABASE_4_PRIVILEGED_DTO.setTables(new LinkedList<>(List.of(TABLE_9_DTO))); - DATABASE_4_PRIVILEGED_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); - IDENTIFIER_7.setStatus(IdentifierStatusType.DRAFT); - IDENTIFIER_7.setDatabase(DATABASE_4); - } - -} diff --git a/dbrepo-metric-db/prometheus.yml b/dbrepo-metric-db/prometheus.yml index ce0a6eb43ca2e1a0987bb1a4e953e3ca43d85751..333420ee559caa20e420b86bec5f2d08a881ef43 100644 --- a/dbrepo-metric-db/prometheus.yml +++ b/dbrepo-metric-db/prometheus.yml @@ -16,4 +16,4 @@ scrape_configs: - job_name: 'metrics scrape' metrics_path: '/metrics' static_configs: - - targets: ['ui:3000', 'auth-service:9000', 'analyse-service:8080', 'search-service:8080', 'storage-service:9090', 'upload-service:8080', 'dashboard-service:3000', 'broker-service:15692'] + - targets: ['ui:3000', 'auth-service:9000', 'analyse-service:8080', 'search-service:8080', 'storage-service:9090', 'dashboard-service:8080', 'dashboard-ui:3000', 'broker-service:15692'] diff --git a/dbrepo-search-db/Dockerfile b/dbrepo-search-db/Dockerfile deleted file mode 100644 index 022dc438a31cd41b50ef5c931c894bb53bee4b79..0000000000000000000000000000000000000000 --- a/dbrepo-search-db/Dockerfile +++ /dev/null @@ -1,30 +0,0 @@ -FROM opensearchproject/opensearch:2.10.0 AS runtime - -USER root - -RUN yum install -y jq - -COPY ./limits.conf /etc/security/limits.conf - -WORKDIR /usr/share/opensearch - -RUN chmod 0700 ./config -COPY --chown=opensearch:opensearch ./opensearch.yml ./config/opensearch.yml -COPY --chown=opensearch:opensearch ./config.yml ./config/opensearch-security/config.yml - -RUN chmod 0600 ./config/opensearch.yml -RUN chmod 0600 ./config/opensearch-security/config.yml - -COPY --chown=opensearch:opensearch ./pem/admin.pem ./config/admin.pem -COPY --chown=opensearch:opensearch ./pem/admin-key.pem ./config/admin-key.pem -RUN chmod 0600 ./config/admin*.pem -COPY --chown=opensearch:opensearch ./pem/node1.pem ./config/node1.pem -COPY --chown=opensearch:opensearch ./pem/node1-key.pem ./config/node1-key.pem -RUN chmod 0600 ./config/node1*.pem -COPY --chown=opensearch:opensearch ./pem/root-ca.pem ./config/root-ca.pem -COPY --chown=opensearch:opensearch ./pem/root-ca-key.pem ./config/root-ca-key.pem -RUN chmod 0600 ./config/root-ca*.pem - -USER opensearch - -ENV DISABLE_INSTALL_DEMO_CONFIG=true diff --git a/dbrepo-search-db/README.md b/dbrepo-search-db/README.md deleted file mode 100644 index 5b7e1d92f22f36515a9a8de5126fc88f2fff8861..0000000000000000000000000000000000000000 --- a/dbrepo-search-db/README.md +++ /dev/null @@ -1,16 +0,0 @@ - -# Search Database - -## REST - -### Indices - -* View all [http://localhost:9200/_cat/indices](http://localhost:9200/_cat/indices) - -### Nodes - -* View all [http://localhost:9200/_cat/nodes](http://localhost:9200/_cat/nodes) - -### Health - -* View all [http://localhost:9200/_plugins/_security/health](http://localhost:9200/_plugins/_security/health) \ No newline at end of file diff --git a/dbrepo-search-db/config.yml b/dbrepo-search-db/config.yml deleted file mode 100644 index 37ddd7317618870917d18d7605de299f74cb2972..0000000000000000000000000000000000000000 --- a/dbrepo-search-db/config.yml +++ /dev/null @@ -1,41 +0,0 @@ ---- - -_meta: - type: "config" - config_version: 2 - -config: - dynamic: - http: - # Either enables or disables anonymous authentication. When true, HTTP authenticators try to find user credentials in - # the HTTP request. If credentials are found, the user is authenticated. If none are found, the user is authenticated - # as an “anonymous” user. This user then has the username “anonymous” and one role named “anonymous_backendrole”. - # When you enable anonymous authentication, all defined HTTP authenticators are non-challenging. Also see The - # challenge setting. - anonymous_auth_enabled: true - xff: - enabled: false - authc: - basic_internal_auth_domain: - description: "Authenticate via HTTP Basic against internal users database" - http_enabled: true - transport_enabled: true - order: 0 - http_authenticator: - type: basic - challenge: true - authentication_backend: - type: intern - openid_auth_domain: - http_enabled: true - transport_enabled: true - order: 1 - http_authenticator: - type: openid - challenge: false - config: - subject_key: client_id - roles_key: roles - openid_connect_url: http://auth-service:8080/api/auth/realms/dbrepo/.well-known/openid-configuration - authentication_backend: - type: noop diff --git a/dbrepo-search-db/generate-pki.sh b/dbrepo-search-db/generate-pki.sh deleted file mode 100644 index 6aff5a819eda145fbdc88995b713b90fbe23af00..0000000000000000000000000000000000000000 --- a/dbrepo-search-db/generate-pki.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -# Generate the private key of the root CA -openssl genrsa -out ./pem/root-ca-key.pem 4096 -# Generate the self-signed root CA certificate -openssl req -x509 -sha256 -new -nodes -key ./pem/root-ca-key.pem -days 3650 -out ./pem/root-ca.pem -subj "/C=AT/O=Technische Universität Wien/CN=test.dbrepo.tuwien.ac.at" - -# Create the certificate key -openssl genrsa -out ./pem/admin-key.pem 4096 -# Create the signing (csr) -openssl req -new -sha256 -key ./pem/admin-key.pem -subj "/C=AT/O=Technische Universität Wien/CN=test.dbrepo.tuwien.ac.at" -out ./pem/admin.csr -# Generate the certificate using the csr and key along with the CA Root key -openssl x509 -req -in ./pem/admin.csr -CA ./pem/root-ca.pem -CAkey ./pem/root-ca-key.pem -CAcreateserial -out ./pem/admin.pem -days 365 -sha256 - -# Create the certificate key -openssl genrsa -out ./pem/node1-key.pem 4096 -# Create the signing (csr) -openssl req -new -sha256 -key ./pem/node1-key.pem -subj "/C=AT/O=Technische Universität Wien/CN=test.dbrepo.tuwien.ac.at" -out ./pem/node1.csr -# Generate the certificate using the csr and key along with the CA Root key -openssl x509 -req -in ./pem/node1.csr -CA ./pem/root-ca.pem -CAkey ./pem/root-ca-key.pem -CAcreateserial -out ./pem/node1.pem -days 365 -sha256 \ No newline at end of file diff --git a/dbrepo-search-db/limits.conf b/dbrepo-search-db/limits.conf deleted file mode 100644 index 80050ed3983f22e4ce355a5b9b8d2f43c260813f..0000000000000000000000000000000000000000 --- a/dbrepo-search-db/limits.conf +++ /dev/null @@ -1,3 +0,0 @@ -# allow user 'opensearch' mlockall -opensearch soft memlock unlimited -opensearch hard memlock unlimited diff --git a/dbrepo-search-db/opensearch.yml b/dbrepo-search-db/opensearch.yml deleted file mode 100644 index b64bacde53f7a534cfed30cb277aecee53115d28..0000000000000000000000000000000000000000 --- a/dbrepo-search-db/opensearch.yml +++ /dev/null @@ -1,21 +0,0 @@ ---- -cluster.name: search-db - -# Bind to all interfaces because we don't know what IP address Docker will assign to us. -network.host: 0.0.0.0 - -# Setting network.host to a non-loopback address enables the annoying bootstrap checks. "Single-node" mode disables them again. -discovery.type: single-node - -plugins.security.ssl.transport.pemcert_filepath: /usr/share/opensearch/config/node1.pem -plugins.security.ssl.transport.pemkey_filepath: /usr/share/opensearch/config/node1-key.pem -plugins.security.ssl.transport.pemtrustedcas_filepath: /usr/share/opensearch/config/root-ca.pem -plugins.security.ssl.http.pemcert_filepath: /usr/share/opensearch/config/node1.pem -plugins.security.ssl.http.pemkey_filepath: /usr/share/opensearch/config/node1-key.pem -plugins.security.ssl.http.pemtrustedcas_filepath: r/usr/share/opensearch/config/root-ca.pem -plugins.security.allow_default_init_securityindex: true -plugins.security.audit.type: internal_opensearch -plugins.security.enable_snapshot_restore_privilege: true -plugins.security.check_snapshot_restore_write_privileges: true -plugins.security.restapi.roles_enabled: ["all_access", "security_rest_api_access"] -cluster.routing.allocation.disk.threshold_enabled: false diff --git a/dbrepo-search-db/opensearch_dashboards.yml b/dbrepo-search-db/opensearch_dashboards.yml deleted file mode 100644 index e6e255a48c6c2702d83d50e5d41f241483814142..0000000000000000000000000000000000000000 --- a/dbrepo-search-db/opensearch_dashboards.yml +++ /dev/null @@ -1,5 +0,0 @@ -server.name: log-dashboard -server.host: "0.0.0.0" -opensearch.hosts: http://search-db:9200 -opensearch.username: admin -opensearch.password: admin diff --git a/dbrepo-search-db/pem/admin-key.pem b/dbrepo-search-db/pem/admin-key.pem deleted file mode 100644 index e7310ac797494910c7dc68681b019c3bbed8af2d..0000000000000000000000000000000000000000 --- a/dbrepo-search-db/pem/admin-key.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -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 ------END RSA PRIVATE KEY----- diff --git a/dbrepo-search-db/pem/admin.csr b/dbrepo-search-db/pem/admin.csr deleted file mode 100644 index 65320f68643213b508f568732e668aa6cd14267c..0000000000000000000000000000000000000000 --- a/dbrepo-search-db/pem/admin.csr +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIIEnjCCAoYCAQAwWTELMAkGA1UEBhMCQVQxJzAlBgNVBAoMHlRlY2huaXNjaGUg -VW5pdmVyc2l0w4PCpHQgV2llbjEhMB8GA1UEAwwYdGVzdC5kYnJlcG8udHV3aWVu -LmFjLmF0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2IAI4L2wvxlV -S/StlmCQVQLMz+Oif7R2ydDsy1io/W5Tf+68N6Ybn3b6GUjeVMNT49gCctYoDBOb -uu9ZdKYsYzF1gr8j0LoNoXIUg0wo5vTz2jQoB747q6ttTI6s6VgMknZx62FQ0tlY -QwyXSTAq4JT/Rr2fO1wkPzafmdQ56n3DPkznHjikgx7bXmez8DpxvwN4YJpdT1cG -CE4OYQipPpHfqSOnzJG4E6C/78juErX7vH2HY3t2TGXdvXnSMZym9Ie7MNNZln9p -y0KjJykXnbuh3dLZfCtkEcjyxZTQzaQgIKsNG0g8ViHx7jJE0Dn4MpcWI9cQ4BfS -Lg4Gg+ToK3EFa0VtOWiFgLZqA3bro5i2zSLKXhdls2sTe0ftKdkoRckswB4IffsU -+zc7WtQw+MHjrZEfVd38lShydmQx+HoARb4tIniSUujEz6FX9+EbCGvWgPC2TRgq -XtQAuILlkykvkXMk5bP+YqeL+Ul1TPw/t/R7KLp/7XJhGvkuZrbZnd1jGN5WpD1D -vrliV3apJbfbcGb/DgxUHwBkx+dNYrPKyVXq+gtHM0q1NNHFMl7NHn1gCaXghnNy -7lWDPx8Rt5xlnu7xtIoub/Ou4USx55FdIP5uX165FpelBlrdAqt2HqFABj36jt8y -IbvPL+r+VQrjjOyFKCFyJPzcpciPWCkCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IC -AQCLRTDst5KQB/tEKxxYGKsoykZzHzEME+UsjWwu3EFvKWeN96H4ZzcDoFA106R5 -ernGiy7VPr6AjJ5osYZM6LooBZ7RGMBoBufYCuy4rHbj2+5V/+B8Nyhlcse15d6j -6YKKGsz6sTpxdOb26+RR5WDiOlF4uSinGVeLBLKIhDiWK/U7lNeZofqrVZhEhKHN -O8jYOW5igmMF7ydqX1qCmKyQR1UHLyGqbX1LrOK38UQux3hXpW/5QbwcokhxJnIV -YlLbrDrJoQ7TvtQA4JiAJ1SQ2WTYGbTWaFsv3qyFezJgpiLzqtqatn94yJ9B5fGb -W2OO8/NUtg1UXPlUxNOQMJbI7iLoEBZPBEEhusuMyp9jvshKaK0N7Vv3cbPZj/qm -EnBjLYEBEa5pcHo+q0n9F4IYFvDuks6dv8tu2VnBOYcGsYJHFoo3Ubv1JoCH1wXl -ApFWK55GuZqOLcsptqUVVkK5XvXlCuhBieThJcpR4qD5nA1yL0qZ8Jlt7sSufBHd -hOUkqQrHKXE5i14dKru3IWo5MjgmSBe3yv9Jxp6+GkWqcada9eMjHDaGfzHeSNmW -HVF1fvgEJUsjEgYk6rOB38i4aSQNSuJ/3z7Dtu3FFugPEpE8IcryUWZJjE8LFq9P -VOwcOSaWhve/oiWxZuARAm1B0NamHuRgT0DBooYhd4rAmA== ------END CERTIFICATE REQUEST----- diff --git a/dbrepo-search-db/pem/admin.pem b/dbrepo-search-db/pem/admin.pem deleted file mode 100644 index 43ae3e3fe594027a8f7ce1f4839eefe23155ae5e..0000000000000000000000000000000000000000 --- a/dbrepo-search-db/pem/admin.pem +++ /dev/null @@ -1,30 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFOTCCAyECFA8pGpUGVSN3/rXMBf0WWMvA90juMA0GCSqGSIb3DQEBCwUAMFkx -CzAJBgNVBAYTAkFUMScwJQYDVQQKDB5UZWNobmlzY2hlIFVuaXZlcnNpdMODwqR0 -IFdpZW4xITAfBgNVBAMMGHRlc3QuZGJyZXBvLnR1d2llbi5hYy5hdDAeFw0yMzEw -MjAxOTQwNThaFw0yNDEwMTkxOTQwNThaMFkxCzAJBgNVBAYTAkFUMScwJQYDVQQK -DB5UZWNobmlzY2hlIFVuaXZlcnNpdMODwqR0IFdpZW4xITAfBgNVBAMMGHRlc3Qu -ZGJyZXBvLnR1d2llbi5hYy5hdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC -ggIBANiACOC9sL8ZVUv0rZZgkFUCzM/jon+0dsnQ7MtYqP1uU3/uvDemG592+hlI -3lTDU+PYAnLWKAwTm7rvWXSmLGMxdYK/I9C6DaFyFINMKOb089o0KAe+O6urbUyO -rOlYDJJ2cethUNLZWEMMl0kwKuCU/0a9nztcJD82n5nUOep9wz5M5x44pIMe215n -s/A6cb8DeGCaXU9XBghODmEIqT6R36kjp8yRuBOgv+/I7hK1+7x9h2N7dkxl3b15 -0jGcpvSHuzDTWZZ/actCoycpF527od3S2XwrZBHI8sWU0M2kICCrDRtIPFYh8e4y -RNA5+DKXFiPXEOAX0i4OBoPk6CtxBWtFbTlohYC2agN266OYts0iyl4XZbNrE3tH -7SnZKEXJLMAeCH37FPs3O1rUMPjB462RH1Xd/JUocnZkMfh6AEW+LSJ4klLoxM+h -V/fhGwhr1oDwtk0YKl7UALiC5ZMpL5FzJOWz/mKni/lJdUz8P7f0eyi6f+1yYRr5 -Lma22Z3dYxjeVqQ9Q765Yld2qSW323Bm/w4MVB8AZMfnTWKzyslV6voLRzNKtTTR -xTJezR59YAml4IZzcu5Vgz8fEbecZZ7u8bSKLm/zruFEseeRXSD+bl9euRaXpQZa -3QKrdh6hQAY9+o7fMiG7zy/q/lUK44zshSghciT83KXIj1gpAgMBAAEwDQYJKoZI -hvcNAQELBQADggIBAHc2ACMWyQuSZeah9zAaPGeKS0OmBUF3dI35ApE33lz266oh -e/EeOaWocul8I9aqW8yoBfGJ/MazTUx4zrOIXSHX5s5Owt7OksRnvlwLbRBHMQ/X -GLqb2HFuGtmVANVkkw4AkSGoDxc+BUqgetbqMczf6HQKQk4OKPN4HWc3ak22UaKb -lIgIFvU0c1UjbczXTSZR1qr/6nH2Kn7qlN3qmRw7MT45uvKn+/J961b5cwvWNpf+ -mi5V4vC7j5+d5SFAgwuFH09aPUaShA5E58VvAO8FqJYTqigobcqvKZkZ0s1udfW6 -2zOoLCwF48u8UuHjIpJUe/IkQv2D/RMrA21XFQJp5BbVcDqX99/ZSA92ha2iLxqZ -Ngte9QSbliDGETyPY251hPwHVWRrn0POJB6xGn3n0XLmgj5+LDWBHo776GtehsNS -hWbG4Uqh33WkOboqb8nSQARckdxv3jUDI8rVj5w/nuEXqk+/uZ8Nqgw9GUSKJ5lM -17va57Vvo+p8p4m0XvqkcTpEqKfD+vfLGm5z3Fz1IrXQB+cCa8lM2DzAWua4NEwt -xazm5eQenU69OhFrPwVstmL0CLLd3yHKv8Yr+LXTiKBBInWGmQZ7qwyEkUDK46lS -LL0LplajHeGJ7VnpwPFoVcwVQt9+WPLFDUNQK1l3kVsiPfoUyD7aUeElrS6h ------END CERTIFICATE----- diff --git a/dbrepo-search-db/pem/node1-key.pem b/dbrepo-search-db/pem/node1-key.pem deleted file mode 100644 index 359df25e2e8cde488a8326d9e7db5f20a3f6ab0b..0000000000000000000000000000000000000000 --- a/dbrepo-search-db/pem/node1-key.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -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 ------END RSA PRIVATE KEY----- diff --git a/dbrepo-search-db/pem/node1.csr b/dbrepo-search-db/pem/node1.csr deleted file mode 100644 index d0a4464a50f7ab7f25fa881bb04fdc92a0fa68ac..0000000000000000000000000000000000000000 --- a/dbrepo-search-db/pem/node1.csr +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIIEnjCCAoYCAQAwWTELMAkGA1UEBhMCQVQxJzAlBgNVBAoMHlRlY2huaXNjaGUg -VW5pdmVyc2l0w4PCpHQgV2llbjEhMB8GA1UEAwwYdGVzdC5kYnJlcG8udHV3aWVu -LmFjLmF0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuwKkBUg/6Sqa -W1zaqCWP8FfIWP/FzoG63h5/tZXS2wFGmOfQh3pRy+BCebN1R5lJGhc6zzOTnyvt -OK6u7EA/oVv2uLIgirE4OSU1qUoaY7FlPSFygUzF6GiSraIFMIz7VFcY7hWA9KXj -XE8eSvqpij6iOrXuB7iFrR4SoT2mM+LduSl+S1EfM56IwlA4LQZ1JbAWexLIr6w4 -vZ8KjSaeLku8XqNjHaGE3Qj8BgUNwMqHA4eUHlh28dW8y8mo/Un1CCP4kOFyhsKB -2AYXy/FNgUgyRi9NKQX1FuxzCaJ7K/lAgeR/zNUhpr8XBInoXMkXZkjzPQfH/26v -B2rIvtW5sKemwNdUmA4Y+BSD/v+9SH7nxml151eGxEeU8Jjo51MRH7xIMWAri7Ae -2Ch9Bc3rYAjvtmH2TkzPPYw9ZE80fqSRIW5gJntyxlUB3kuRv/pp7OnPPpLjOGa9 -6r+CaMHkrI0YzsAgd9VOasi4LiJqDtxQgw/SXYitPJXktnB3Z+hhV2QpSxpkXpqe -azus7MarzRk6nHDfABhyZhYc75KBN/WGfCRjs/3DviBiRlmnksSmBu8WsT1tegHC -XJvCxzyQ7l67dSKGbzi2wnbedvkd+sUt9ZpsYRJiUu1/9zWHKfX4+szPBecFBT9a -0jxR1+wvLLb5iBS0uhRuz4JW21srRsMCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IC -AQA6QDgWK0UlMpshwMrkoHsw0FN5r6/Rq1d11QpN0828qwE47K38xreBWRQGlxHT -TDdFQih9RMGz7CV7AncQ6rPueBE8zG3l1R3TZZkbdLwYlWnLTjlHzrmdx5qHbuYC -EB05XukVI7mWZ6WagQZMDuf6qct3I9VSgQ62F/XygNsMoHHIbFtnLVWx3slon6oF -aAx8/8AROyZeSDCTMSoGVdk1i9TUSU6vwxdrlY+mXviHhq236Dvdx9zrQdUT0ohd -UG3oeRZjNa9NoPUJQ7VMXuj77jAFwzhytZKdg04MuD6wxiQ651TLQ9S9yyYq/77/ -sW5uVMKnGUfUS8WeX5U3HG2FnQCPZ2gT5VLo2f9td/elieGVuUiyNThpPJsNHW/j -/dEli8Qqvcrh8TVp8MZKS9FFX5tW7yaRllakrHikwiIuqWQG8ZSX/AzSNkNPvEnA -yc2GtBvd7ICKV2LjReUsizzQv46dviIAUh2DznQg9Y90/jBUZFtFAj9vY3hNaWy+ -iYPDWZPmWGGg5oj90PJPeGaEdZN4pZ0QyOsuInkHNDGh3/PjcIxXZKr8wHPpsvB/ -vJc/AzLvgLsxejaTKIjYnJvlp0U7bhN1rpQYk66PLLG+teaW6eX4ZbJM3KHBwMhb -V1CqYFHgZE2L40j78FUFgZCWGHZ7BqdWKiC7t5plxgQ1Hw== ------END CERTIFICATE REQUEST----- diff --git a/dbrepo-search-db/pem/node1.pem b/dbrepo-search-db/pem/node1.pem deleted file mode 100644 index 5704f25dbc1c9dd21f1c0bfa665c40015196e805..0000000000000000000000000000000000000000 --- a/dbrepo-search-db/pem/node1.pem +++ /dev/null @@ -1,30 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFOTCCAyECFA8pGpUGVSN3/rXMBf0WWMvA90jvMA0GCSqGSIb3DQEBCwUAMFkx -CzAJBgNVBAYTAkFUMScwJQYDVQQKDB5UZWNobmlzY2hlIFVuaXZlcnNpdMODwqR0 -IFdpZW4xITAfBgNVBAMMGHRlc3QuZGJyZXBvLnR1d2llbi5hYy5hdDAeFw0yMzEw -MjAxOTQxMDBaFw0yNDEwMTkxOTQxMDBaMFkxCzAJBgNVBAYTAkFUMScwJQYDVQQK -DB5UZWNobmlzY2hlIFVuaXZlcnNpdMODwqR0IFdpZW4xITAfBgNVBAMMGHRlc3Qu -ZGJyZXBvLnR1d2llbi5hYy5hdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC -ggIBALsCpAVIP+kqmltc2qglj/BXyFj/xc6But4ef7WV0tsBRpjn0Id6UcvgQnmz -dUeZSRoXOs8zk58r7TiuruxAP6Fb9riyIIqxODklNalKGmOxZT0hcoFMxehokq2i -BTCM+1RXGO4VgPSl41xPHkr6qYo+ojq17ge4ha0eEqE9pjPi3bkpfktRHzOeiMJQ -OC0GdSWwFnsSyK+sOL2fCo0mni5LvF6jYx2hhN0I/AYFDcDKhwOHlB5YdvHVvMvJ -qP1J9Qgj+JDhcobCgdgGF8vxTYFIMkYvTSkF9Rbscwmieyv5QIHkf8zVIaa/FwSJ -6FzJF2ZI8z0Hx/9urwdqyL7VubCnpsDXVJgOGPgUg/7/vUh+58ZpdedXhsRHlPCY -6OdTER+8SDFgK4uwHtgofQXN62AI77Zh9k5Mzz2MPWRPNH6kkSFuYCZ7csZVAd5L -kb/6aezpzz6S4zhmveq/gmjB5KyNGM7AIHfVTmrIuC4iag7cUIMP0l2IrTyV5LZw -d2foYVdkKUsaZF6anms7rOzGq80ZOpxw3wAYcmYWHO+SgTf1hnwkY7P9w74gYkZZ -p5LEpgbvFrE9bXoBwlybwsc8kO5eu3Uihm84tsJ23nb5HfrFLfWabGESYlLtf/c1 -hyn1+PrMzwXnBQU/WtI8UdfsLyy2+YgUtLoUbs+CVttbK0bDAgMBAAEwDQYJKoZI -hvcNAQELBQADggIBANPQq2mJZ+UwgihSuo2iHJRljm4csiKUsf5Q9SvtmyeXYZVp -41T04DPucrgMVXlVSAIyclBWzoloSiiBsv28iM6ZWvEt8TdNjzWEMioihWVkjI+X -eNCumk8h/+OUfjRE50LJh94Is/7vCMNfKBL0r8SBWO5kJuhrlV7TWopygR8zPQ4p -xcjN0v/nMWS5EZCvP5cl4pmooyhGMJjwvfujUgeUi+jK5EJtSlccXjPpq9//e4/u -x5D+cS0BPSp7/NYVjUVG31qK6SJ2XBjBg2IInVuLCbfyF2QHK0TQafWbtirzxtQi -PJDrisqPAqrTol38Ov3r/+U97pSbOTfMwtA58bJfFr+jIXxhRMlvGflbdrU2SZOp -GyENHBR0yb06qCGuyhZ9PYap4yLNxq95ENw/pzRii70cehaOlix6iVkN/Cdh9xnx -h8WfY73eIfsDB8JNHYEBg2UREu5RLMpqXUIoJ++5yIIhZp7VOy+COQv8Ovewt/Vz -wVoTYovMPOBJpAOqy91RFJuyr/ewPbw/H2nq1ak8jSr0bWqAgBCFWVFMbRjWQ9T6 -LXrN4poIHlU6NbAVUtKqs7Uksj5ZAd90v20QUJHFLclpjTbRo/JcpChHSmhI1L0j -JMPc90BgcRDQWx8pFd+kklpgW5o0Cx+ZkW1dY62c0sY0wLlJxoxPshr+ZR2N ------END CERTIFICATE----- diff --git a/dbrepo-search-db/pem/root-ca-key.pem b/dbrepo-search-db/pem/root-ca-key.pem deleted file mode 100644 index 06192a8cebdc8ca0bcb5e4cb948d310290c1fd54..0000000000000000000000000000000000000000 --- a/dbrepo-search-db/pem/root-ca-key.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -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 ------END RSA PRIVATE KEY----- diff --git a/dbrepo-search-db/pem/root-ca.pem b/dbrepo-search-db/pem/root-ca.pem deleted file mode 100644 index 47b1af9d1eb8e279830642c6849dae06e2d4c45b..0000000000000000000000000000000000000000 --- a/dbrepo-search-db/pem/root-ca.pem +++ /dev/null @@ -1,32 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFkzCCA3ugAwIBAgIUIlyZZ6AC0dvI9/szfx2KotOqhpAwDQYJKoZIhvcNAQEL -BQAwWTELMAkGA1UEBhMCQVQxJzAlBgNVBAoMHlRlY2huaXNjaGUgVW5pdmVyc2l0 -w4PCpHQgV2llbjEhMB8GA1UEAwwYdGVzdC5kYnJlcG8udHV3aWVuLmFjLmF0MB4X -DTIzMTAyMDE5NDA1N1oXDTMzMTAxNzE5NDA1N1owWTELMAkGA1UEBhMCQVQxJzAl -BgNVBAoMHlRlY2huaXNjaGUgVW5pdmVyc2l0w4PCpHQgV2llbjEhMB8GA1UEAwwY -dGVzdC5kYnJlcG8udHV3aWVuLmFjLmF0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A -MIICCgKCAgEA5zjphoEVAZzg5au4dvdejXuk6R151mt5hTxZgAcI1ahitR+UDTJy -av7y3CRbRKFLYGYc4Au0AI7j/z2OgT2dcAegTTcsv+hU4FL53Y/DHrv7NAd74kHp -AAgNT/S7C3+JdFtD3/34up8NvrtYieZkyNrApAEB8RluxG6VlgSU0samMHHeIoP1 -Np8BJC3nXEm6deIGkEBAmwT9mTSUnwGfCAtrYiCDQHKTd+zwyZjmMthCA7DhkIeU -K5+eaGXjxg+Oyiv2mY8cKT0q/xavGGewcujQwaTQq1jnOtZ2MaOS7tI9Gl9P1IsU -eum5lNQ8IRNr5/KamKaDRjXE83gBFKx5tyP0Sy4JQKQq1iLNXCxRbPcdkVRY8RGy -szbB9jqE2+JANjrkfx9hFfDh+5cBUJpXNO+RO+GWs6ctS3w2zfMWICUDLXsyhFXY -xmLFZZjVp6tiXGVDvPSs3X49r6FZ/Q8c2JAKyBfDzEbI8kaCdUw3/IqIfeF2pn3d -Py4IaH/oAXAADLaGmvWMXVJV4OEMAYq1tQ3OYcVNRN4pDcc/wwW6A+r/UE6AcNOZ -83HvUNJgPk4wUAvshqg2ZrDxk2ZDE7z8lesNEenAXt7g3cNdAYmOwr5MgTtrqS9/ -r02gFDrOmcg/hZ9UO9yUZKo0ChkK5PehelH2blGRO5X2BwDvKJqnCzkCAwEAAaNT -MFEwHQYDVR0OBBYEFBTLcdE8I6tQvEEdD1COQLmHQiofMB8GA1UdIwQYMBaAFBTL -cdE8I6tQvEEdD1COQLmHQiofMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL -BQADggIBAF2TN5VdkoULWy4bVHrkGfkdO6vTDx6qqp4m6rqqcf7XwglScn86fFzD -TmZM+klXOl1HUVKU6NiFb+ZH79HL8O+63XzaBzH588InuF+uW7Zmh7qmZGU/J58w -ZXbl0aaBZmM3mEjz7uqrlb/gjlwhXKYWTLeqBFSNxteOLhkYBSc4XBxoU4yyjmlN -3GX1NgKLnUzdIspnmH6wGQ1pFXwePso6SnKctUJ79ROicwhDCsbBJ5BfZ8Ura7Eh -DFO68Y2eDfIjWEiJ5qTtXG1Q8VHzisxtTarPaa9DcZTFIdGWndafGe2+wOqneOtE -YZ76In7iXBdTxJRuMBnUwZStmBp38+/GryTT1Zmvtj6zJNJP9FNf+zUqaC7dAscJ -rscTc7dxhRB26AHPEkyb3sOnfi5RDQskkR4KS0n4MlfTm3cnDXc6Vf8T2BZORXA7 -xuRjjAYNzEOBog47LNKXSn2eof0eJN1WIszdbSuHIeLbpT4j6ASI91oEeSyH+hiY -WX4pn+GaOmETlJtLKATSScvzCKXhM2H+hfGpF9zCtWy748pQXAtqsM7itx80JDY+ -3q8Lw2Y3A9NdeelBdJuRYr+7khNosLVhJlPZOSApnbJG/6FkH1ZlOvJ4zdZq75IE -hQ4WWtstrjTwE1W/fV0dOg/9idfU9FViQ5y3fEKfcOoZjGLQxgQO ------END CERTIFICATE----- diff --git a/dbrepo-search-db/pem/root-ca.srl b/dbrepo-search-db/pem/root-ca.srl deleted file mode 100644 index 6f3548578c06917791aafc7a182ce570158e1cca..0000000000000000000000000000000000000000 --- a/dbrepo-search-db/pem/root-ca.srl +++ /dev/null @@ -1 +0,0 @@ -0F291A9506552377FEB5CC05FD1658CBC0F748EF diff --git a/dbrepo-search-service/.gitignore b/dbrepo-search-service/.gitignore index 726e588cd1b2f59f2f847d48bf8a48549202d1b4..e4a1bfbd16200450d72d68d3c880e8f7aae5bae2 100644 --- a/dbrepo-search-service/.gitignore +++ b/dbrepo-search-service/.gitignore @@ -38,12 +38,6 @@ MANIFEST *.manifest *.spec -# generate -/friendly_names_overrides.json -/test/rsa -/test/test_keycloak_client.py -/test/test_opensearch_client.py - # Installer logs pip-log.txt pip-delete-this-directory.txt diff --git a/dbrepo-search-service/.testpickle b/dbrepo-search-service/.testpickle deleted file mode 100644 index 8588dbe4ae53420fa89daf9e6c52728afad63086..0000000000000000000000000000000000000000 Binary files a/dbrepo-search-service/.testpickle and /dev/null differ diff --git a/dbrepo-search-service/Dockerfile b/dbrepo-search-service/Dockerfile index 3e46d8fc90475c9dff854f1e6a6bbe8cf221a416..8b7356470d7127cb606744826d7006834aed8c2b 100644 --- a/dbrepo-search-service/Dockerfile +++ b/dbrepo-search-service/Dockerfile @@ -13,12 +13,12 @@ RUN pip install pipenv && \ pipenv install gunicorn && \ pipenv install --system --deploy -USER 1001 +RUN adduser -D dbrepo --uid 1001 WORKDIR /app -COPY --chown=1001 ./init/clients ./clients -COPY --chown=1001 ./init/omlib ./omlib +USER 1001 + COPY --chown=1001 ./init/friendly_names_overrides.json ./friendly_names_overrides.json COPY --chown=1001 ./os-yml ./os-yml COPY --chown=1001 ./app.py ./app.py diff --git a/dbrepo-search-service/Pipfile b/dbrepo-search-service/Pipfile index 2c5f2a319a42dbf1fadde04ac981d1408af4f2de..f3a2c53320c8b2468b9605f145b0944413e704ef 100644 --- a/dbrepo-search-service/Pipfile +++ b/dbrepo-search-service/Pipfile @@ -18,7 +18,8 @@ jwt = "~=1.3" testcontainers-opensearch = "*" pytest = "*" rdflib = "*" -dbrepo = {path = "./lib/dbrepo-1.7.3.tar.gz"} +grafana-client = "*" +dbrepo = {path = "./lib/dbrepo-1.8.0.tar.gz"} gunicorn = "*" [dev-packages] diff --git a/dbrepo-search-service/Pipfile.lock b/dbrepo-search-service/Pipfile.lock index 23c64796a6118eea2aca33df6ef606a593cffe73..5f07119f32c85c883a041a523ded4cb78cda68dc 100644 --- a/dbrepo-search-service/Pipfile.lock +++ b/dbrepo-search-service/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "7996ac8acc7350e2485cccbdc5226347f8590634130778a023c0efb67932f296" + "sha256": "fb499e12b1aebca72d5bf49fe952273163696c251b5b6440361db361baa21131" }, "pipfile-spec": 6, "requires": { @@ -26,90 +26,90 @@ }, "aiohttp": { "hashes": [ - "sha256:04eb541ce1e03edc1e3be1917a0f45ac703e913c21a940111df73a2c2db11d73", - "sha256:05582cb2d156ac7506e68b5eac83179faedad74522ed88f88e5861b78740dc0e", - "sha256:0a29be28e60e5610d2437b5b2fed61d6f3dcde898b57fb048aa5079271e7f6f3", - "sha256:0b2501f1b981e70932b4a552fc9b3c942991c7ae429ea117e8fba57718cdeed0", - "sha256:0df3788187559c262922846087e36228b75987f3ae31dd0a1e5ee1034090d42f", - "sha256:12c5869e7ddf6b4b1f2109702b3cd7515667b437da90a5a4a50ba1354fe41881", - "sha256:14fc03508359334edc76d35b2821832f092c8f092e4b356e74e38419dfe7b6de", - "sha256:1a7169ded15505f55a87f8f0812c94c9412623c744227b9e51083a72a48b68a5", - "sha256:1c68e41c4d576cd6aa6c6d2eddfb32b2acfb07ebfbb4f9da991da26633a3db1a", - "sha256:20412c7cc3720e47a47e63c0005f78c0c2370020f9f4770d7fc0075f397a9fb0", - "sha256:22a8107896877212130c58f74e64b77f7007cb03cea8698be317272643602d45", - "sha256:28a3d083819741592685762d51d789e6155411277050d08066537c5edc4066e6", - "sha256:2b86efe23684b58a88e530c4ab5b20145f102916bbb2d82942cafec7bd36a647", - "sha256:2d0b46abee5b5737cb479cc9139b29f010a37b1875ee56d142aefc10686a390b", - "sha256:321238a42ed463848f06e291c4bbfb3d15ba5a79221a82c502da3e23d7525d06", - "sha256:3a8a0d127c10b8d89e69bbd3430da0f73946d839e65fec00ae48ca7916a31948", - "sha256:3a8b0321e40a833e381d127be993b7349d1564b756910b28b5f6588a159afef3", - "sha256:3b420d076a46f41ea48e5fcccb996f517af0d406267e31e6716f480a3d50d65c", - "sha256:3b512f1de1c688f88dbe1b8bb1283f7fbeb7a2b2b26e743bb2193cbadfa6f307", - "sha256:413fe39fd929329f697f41ad67936f379cba06fcd4c462b62e5b0f8061ee4a77", - "sha256:41cf0cefd9e7b5c646c2ef529c8335e7eafd326f444cc1cdb0c47b6bc836f9be", - "sha256:4848ae31ad44330b30f16c71e4f586cd5402a846b11264c412de99fa768f00f3", - "sha256:4b0a200e85da5c966277a402736a96457b882360aa15416bf104ca81e6f5807b", - "sha256:4e2e8ef37d4bc110917d038807ee3af82700a93ab2ba5687afae5271b8bc50ff", - "sha256:4edcbe34e6dba0136e4cabf7568f5a434d89cc9de5d5155371acda275353d228", - "sha256:51ba80d473eb780a329d73ac8afa44aa71dfb521693ccea1dea8b9b5c4df45ce", - "sha256:5409a59d5057f2386bb8b8f8bbcfb6e15505cedd8b2445db510563b5d7ea1186", - "sha256:572def4aad0a4775af66d5a2b5923c7de0820ecaeeb7987dcbccda2a735a993f", - "sha256:599b66582f7276ebefbaa38adf37585e636b6a7a73382eb412f7bc0fc55fb73d", - "sha256:59a05cdc636431f7ce843c7c2f04772437dd816a5289f16440b19441be6511f1", - "sha256:602d4db80daf4497de93cb1ce00b8fc79969c0a7cf5b67bec96fa939268d806a", - "sha256:65c75b14ee74e8eeff2886321e76188cbe938d18c85cff349d948430179ad02c", - "sha256:69bb252bfdca385ccabfd55f4cd740d421dd8c8ad438ded9637d81c228d0da49", - "sha256:6d3986112e34eaa36e280dc8286b9dd4cc1a5bcf328a7f147453e188f6fe148f", - "sha256:6dd9766da617855f7e85f27d2bf9a565ace04ba7c387323cd3e651ac4329db91", - "sha256:70ab0f61c1a73d3e0342cedd9a7321425c27a7067bebeeacd509f96695b875fc", - "sha256:749f1eb10e51dbbcdba9df2ef457ec060554842eea4d23874a3e26495f9e87b1", - "sha256:781c8bd423dcc4641298c8c5a2a125c8b1c31e11f828e8d35c1d3a722af4c15a", - "sha256:7e7abe865504f41b10777ac162c727af14e9f4db9262e3ed8254179053f63e6d", - "sha256:7f2dadece8b85596ac3ab1ec04b00694bdd62abc31e5618f524648d18d9dd7fa", - "sha256:86135c32d06927339c8c5e64f96e4eee8825d928374b9b71a3c42379d7437058", - "sha256:8778620396e554b758b59773ab29c03b55047841d8894c5e335f12bfc45ebd28", - "sha256:87f0e003fb4dd5810c7fbf47a1239eaa34cd929ef160e0a54c570883125c4831", - "sha256:8aa5c68e1e68fff7cd3142288101deb4316b51f03d50c92de6ea5ce646e6c71f", - "sha256:8d14e274828561db91e4178f0057a915f3af1757b94c2ca283cb34cbb6e00b50", - "sha256:8d1dd75aa4d855c7debaf1ef830ff2dfcc33f893c7db0af2423ee761ebffd22b", - "sha256:92007c89a8cb7be35befa2732b0b32bf3a394c1b22ef2dff0ef12537d98a7bda", - "sha256:92868f6512714efd4a6d6cb2bfc4903b997b36b97baea85f744229f18d12755e", - "sha256:948abc8952aff63de7b2c83bfe3f211c727da3a33c3a5866a0e2cf1ee1aa950f", - "sha256:95d7787f2bcbf7cb46823036a8d64ccfbc2ffc7d52016b4044d901abceeba3db", - "sha256:997b57e38aa7dc6caab843c5e042ab557bc83a2f91b7bd302e3c3aebbb9042a1", - "sha256:99b8bbfc8111826aa8363442c0fc1f5751456b008737ff053570f06a151650b3", - "sha256:9e73fa341d8b308bb799cf0ab6f55fc0461d27a9fa3e4582755a3d81a6af8c09", - "sha256:a0d2c04a623ab83963576548ce098baf711a18e2c32c542b62322a0b4584b990", - "sha256:a40087b82f83bd671cbeb5f582c233d196e9653220404a798798bfc0ee189fff", - "sha256:ad1f2fb9fe9b585ea4b436d6e998e71b50d2b087b694ab277b30e060c434e5db", - "sha256:b05774864c87210c531b48dfeb2f7659407c2dda8643104fb4ae5e2c311d12d9", - "sha256:b41693b7388324b80f9acfabd479bd1c84f0bc7e8f17bab4ecd9675e9ff9c734", - "sha256:b42dbd097abb44b3f1156b4bf978ec5853840802d6eee2784857be11ee82c6a0", - "sha256:b4e7c7ec4146a94a307ca4f112802a8e26d969018fabed526efc340d21d3e7d0", - "sha256:b59d096b5537ec7c85954cb97d821aae35cfccce3357a2cafe85660cc6295628", - "sha256:b9c60d1de973ca94af02053d9b5111c4fbf97158e139b14f1be68337be267be6", - "sha256:bccd2cb7aa5a3bfada72681bdb91637094d81639e116eac368f8b3874620a654", - "sha256:c32593ead1a8c6aabd58f9d7ee706e48beac796bb0cb71d6b60f2c1056f0a65f", - "sha256:c7571f99525c76a6280f5fe8e194eeb8cb4da55586c3c61c59c33a33f10cfce7", - "sha256:c8b2df9feac55043759aa89f722a967d977d80f8b5865a4153fc41c93b957efc", - "sha256:ca9f835cdfedcb3f5947304e85b8ca3ace31eef6346d8027a97f4de5fb687534", - "sha256:cc9253069158d57e27d47a8453d8a2c5a370dc461374111b5184cf2f147a3cc3", - "sha256:ced66c5c6ad5bcaf9be54560398654779ec1c3695f1a9cf0ae5e3606694a000a", - "sha256:d173c0ac508a2175f7c9a115a50db5fd3e35190d96fdd1a17f9cb10a6ab09aa1", - "sha256:d6edc538c7480fa0a3b2bdd705f8010062d74700198da55d16498e1b49549b9c", - "sha256:daf20d9c3b12ae0fdf15ed92235e190f8284945563c4b8ad95b2d7a31f331cd3", - "sha256:dc311634f6f28661a76cbc1c28ecf3b3a70a8edd67b69288ab7ca91058eb5a33", - "sha256:e2bc827c01f75803de77b134afdbf74fa74b62970eafdf190f3244931d7a5c0d", - "sha256:e365034c5cf6cf74f57420b57682ea79e19eb29033399dd3f40de4d0171998fa", - "sha256:e906da0f2bcbf9b26cc2b144929e88cb3bf943dd1942b4e5af066056875c7618", - "sha256:e9faafa74dbb906b2b6f3eb9942352e9e9db8d583ffed4be618a89bd71a4e914", - "sha256:ec6cd1954ca2bbf0970f531a628da1b1338f594bf5da7e361e19ba163ecc4f3b", - "sha256:f296d637a50bb15fb6a229fbb0eb053080e703b53dbfe55b1e4bb1c5ed25d325", - "sha256:f30fc72daf85486cdcdfc3f5e0aea9255493ef499e31582b34abadbfaafb0965", - "sha256:fe846f0a98aa9913c2852b630cd39b4098f296e0907dd05f6c7b30d911afa4c3" + "sha256:004511d3413737700835e949433536a2fe95a7d0297edd911a1e9705c5b5ea43", + "sha256:0902e887b0e1d50424112f200eb9ae3dfed6c0d0a19fc60f633ae5a57c809656", + "sha256:09b00dd520d88eac9d1768439a59ab3d145065c91a8fab97f900d1b5f802895e", + "sha256:0a2f451849e6b39e5c226803dcacfa9c7133e9825dcefd2f4e837a2ec5a3bb98", + "sha256:0a950c2eb8ff17361abd8c85987fd6076d9f47d040ebffce67dce4993285e973", + "sha256:0ad1fb47da60ae1ddfb316f0ff16d1f3b8e844d1a1e154641928ea0583d486ed", + "sha256:13ceac2c5cdcc3f64b9015710221ddf81c900c5febc505dbd8f810e770011540", + "sha256:14461157d8426bcb40bd94deb0450a6fa16f05129f7da546090cebf8f3123b0f", + "sha256:16f8a2c9538c14a557b4d309ed4d0a7c60f0253e8ed7b6c9a2859a7582f8b1b8", + "sha256:17ae4664031aadfbcb34fd40ffd90976671fa0c0286e6c4113989f78bebab37a", + "sha256:1ce63ae04719513dd2651202352a2beb9f67f55cb8490c40f056cea3c5c355ce", + "sha256:23a15727fbfccab973343b6d1b7181bfb0b4aa7ae280f36fd2f90f5476805682", + "sha256:2540ddc83cc724b13d1838026f6a5ad178510953302a49e6d647f6e1de82bc34", + "sha256:37dcee4906454ae377be5937ab2a66a9a88377b11dd7c072df7a7c142b63c37c", + "sha256:38bea84ee4fe24ebcc8edeb7b54bf20f06fd53ce4d2cc8b74344c5b9620597fd", + "sha256:3ab3367bb7f61ad18793fea2ef71f2d181c528c87948638366bf1de26e239183", + "sha256:3ad1d59fd7114e6a08c4814983bb498f391c699f3c78712770077518cae63ff7", + "sha256:3b4e6db8dc4879015b9955778cfb9881897339c8fab7b3676f8433f849425913", + "sha256:3e061b09f6fa42997cf627307f220315e313ece74907d35776ec4373ed718b86", + "sha256:42864e70a248f5f6a49fdaf417d9bc62d6e4d8ee9695b24c5916cb4bb666c802", + "sha256:493910ceb2764f792db4dc6e8e4b375dae1b08f72e18e8f10f18b34ca17d0979", + "sha256:4d0c970c0d602b1017e2067ff3b7dac41c98fef4f7472ec2ea26fd8a4e8c2149", + "sha256:54eb3aead72a5c19fad07219acd882c1643a1027fbcdefac9b502c267242f955", + "sha256:56a3443aca82abda0e07be2e1ecb76a050714faf2be84256dae291182ba59049", + "sha256:576f5ca28d1b3276026f7df3ec841ae460e0fc3aac2a47cbf72eabcfc0f102e1", + "sha256:58ede86453a6cf2d6ce40ef0ca15481677a66950e73b0a788917916f7e35a0bb", + "sha256:61c721764e41af907c9d16b6daa05a458f066015abd35923051be8705108ed17", + "sha256:634d96869be6c4dc232fc503e03e40c42d32cfaa51712aee181e922e61d74814", + "sha256:696ef00e8a1f0cec5e30640e64eca75d8e777933d1438f4facc9c0cdf288a810", + "sha256:69a2cbd61788d26f8f1e626e188044834f37f6ae3f937bd9f08b65fc9d7e514e", + "sha256:6a792ce34b999fbe04a7a71a90c74f10c57ae4c51f65461a411faa70e154154e", + "sha256:6ac13b71761e49d5f9e4d05d33683bbafef753e876e8e5a7ef26e937dd766713", + "sha256:6fdec0213244c39973674ca2a7f5435bf74369e7d4e104d6c7473c81c9bcc8c4", + "sha256:72b1b03fb4655c1960403c131740755ec19c5898c82abd3961c364c2afd59fe7", + "sha256:745f1ed5e2c687baefc3c5e7b4304e91bf3e2f32834d07baaee243e349624b24", + "sha256:776c8e959a01e5e8321f1dec77964cb6101020a69d5a94cd3d34db6d555e01f7", + "sha256:780df0d837276276226a1ff803f8d0fa5f8996c479aeef52eb040179f3156cbd", + "sha256:78e6e23b954644737e385befa0deb20233e2dfddf95dd11e9db752bdd2a294d3", + "sha256:7951decace76a9271a1ef181b04aa77d3cc309a02a51d73826039003210bdc86", + "sha256:7ba92a2d9ace559a0a14b03d87f47e021e4fa7681dc6970ebbc7b447c7d4b7cd", + "sha256:7f6428fee52d2bcf96a8aa7b62095b190ee341ab0e6b1bcf50c615d7966fd45b", + "sha256:87944bd16b7fe6160607f6a17808abd25f17f61ae1e26c47a491b970fb66d8cb", + "sha256:87a6e922b2b2401e0b0cf6b976b97f11ec7f136bfed445e16384fbf6fd5e8602", + "sha256:8cb0688a8d81c63d716e867d59a9ccc389e97ac7037ebef904c2b89334407180", + "sha256:8df6612df74409080575dca38a5237282865408016e65636a76a2eb9348c2567", + "sha256:911a6e91d08bb2c72938bc17f0a2d97864c531536b7832abee6429d5296e5b27", + "sha256:92b7ee222e2b903e0a4b329a9943d432b3767f2d5029dbe4ca59fb75223bbe2e", + "sha256:938f756c2b9374bbcc262a37eea521d8a0e6458162f2a9c26329cc87fdf06534", + "sha256:9756d9b9d4547e091f99d554fbba0d2a920aab98caa82a8fb3d3d9bee3c9ae85", + "sha256:98b88a2bf26965f2015a771381624dd4b0839034b70d406dc74fd8be4cc053e3", + "sha256:9b751a6306f330801665ae69270a8a3993654a85569b3469662efaad6cf5cc50", + "sha256:a2a450bcce4931b295fc0848f384834c3f9b00edfc2150baafb4488c27953de6", + "sha256:a3814760a1a700f3cfd2f977249f1032301d0a12c92aba74605cfa6ce9f78489", + "sha256:a5abcbba9f4b463a45c8ca8b7720891200658f6f46894f79517e6cd11f3405ca", + "sha256:a6db7458ab89c7d80bc1f4e930cc9df6edee2200127cfa6f6e080cf619eddfbd", + "sha256:ad497f38a0d6c329cb621774788583ee12321863cd4bd9feee1effd60f2ad133", + "sha256:ad9509ffb2396483ceacb1eee9134724443ee45b92141105a4645857244aecc8", + "sha256:bbcba75fe879ad6fd2e0d6a8d937f34a571f116a0e4db37df8079e738ea95c71", + "sha256:c10d85e81d0b9ef87970ecbdbfaeec14a361a7fa947118817fcea8e45335fa46", + "sha256:c15b2271c44da77ee9d822552201180779e5e942f3a71fb74e026bf6172ff287", + "sha256:ca37057625693d097543bd88076ceebeb248291df9d6ca8481349efc0b05dcd0", + "sha256:cc3a145479a76ad0ed646434d09216d33d08eef0d8c9a11f5ae5cdc37caa3540", + "sha256:ccf10f16ab498d20e28bc2b5c1306e9c1512f2840f7b6a67000a517a4b37d5ee", + "sha256:cd464ba806e27ee24a91362ba3621bfc39dbbb8b79f2e1340201615197370f7c", + "sha256:d007aa39a52d62373bd23428ba4a2546eed0e7643d7bf2e41ddcefd54519842c", + "sha256:d0666afbe984f6933fe72cd1f1c3560d8c55880a0bdd728ad774006eb4241ecd", + "sha256:d07502cc14ecd64f52b2a74ebbc106893d9a9717120057ea9ea1fd6568a747e7", + "sha256:d489d9778522fbd0f8d6a5c6e48e3514f11be81cb0a5954bdda06f7e1594b321", + "sha256:df7db76400bf46ec6a0a73192b14c8295bdb9812053f4fe53f4e789f3ea66bbb", + "sha256:e3538bc9fe1b902bef51372462e3d7c96fce2b566642512138a480b7adc9d508", + "sha256:e87fd812899aa78252866ae03a048e77bd11b80fb4878ce27c23cade239b42b2", + "sha256:ecdb8173e6c7aa09eee342ac62e193e6904923bd232e76b4157ac0bfa670609f", + "sha256:f244b8e541f414664889e2c87cac11a07b918cb4b540c36f7ada7bfa76571ea2", + "sha256:f4065145bf69de124accdd17ea5f4dc770da0a6a6e440c53f6e0a8c27b3e635c", + "sha256:f420bfe862fb357a6d76f2065447ef6f484bc489292ac91e29bc65d2d7a2c84d", + "sha256:f6ddd90d9fb4b501c97a4458f1c1720e42432c26cb76d28177c5b5ad4e332601", + "sha256:fa73e8c2656a3653ae6c307b3f4e878a21f87859a9afab228280ddccd7369d71", + "sha256:fadbb8f1d4140825069db3fedbbb843290fd5f5bc0a5dbd7eaf81d91bf1b003b", + "sha256:fb3d0cc5cdb926090748ea60172fa8a213cec728bd6c54eae18b96040fcd6227", + "sha256:fb46bb0f24813e6cede6cc07b1961d4b04f331f7112a23b5e21f567da4ee50aa", + "sha256:fd36c119c5d6551bce374fcb5c19269638f8d09862445f85a5a48596fd59f4bb" ], "markers": "python_version >= '3.9'", - "version": "==3.11.14" + "version": "==3.11.16" }, "aiosignal": { "hashes": [ @@ -373,9 +373,9 @@ }, "dbrepo": { "hashes": [ - "sha256:ad01d6dc5d99f3c0c9caf3fb11b51502bec5390c72ff28b6b725e2755f5a2f7c" + "sha256:55de6a4934010e14a574032b5a5179bf3dac9895ef74e5cd4a221a625a75674b" ], - "path": "./lib/dbrepo-1.7.3.tar.gz" + "path": "./lib/dbrepo-1.8.0.tar.gz" }, "docker": { "hashes": [ @@ -539,6 +539,15 @@ "markers": "python_version >= '3.8'", "version": "==1.5.0" }, + "grafana-client": { + "hashes": [ + "sha256:2477a47b923fd0637947e620b0b777c641af18a3025464fa4505783dbf05dfcc", + "sha256:8cb61bb2a87ec07bca10974df276b9a1a95bfdb63f3a696f065692ffc9b8c389" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==4.3.2" + }, "greenlet": { "hashes": [ "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e", @@ -627,6 +636,14 @@ "markers": "python_version >= '3.7'", "version": "==23.0.0" }, + "h11": { + "hashes": [ + "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", + "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761" + ], + "markers": "python_version >= '3.7'", + "version": "==0.14.0" + }, "idna": { "hashes": [ "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", @@ -637,11 +654,11 @@ }, "iniconfig": { "hashes": [ - "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", - "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" + "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", + "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760" ], - "markers": "python_version >= '3.7'", - "version": "==2.0.0" + "markers": "python_version >= '3.8'", + "version": "==2.1.0" }, "itsdangerous": { "hashes": [ @@ -651,6 +668,108 @@ "markers": "python_version >= '3.8'", "version": "==2.2.0" }, + "jh2": { + "hashes": [ + "sha256:038091480cd1544e9389b0adbb1b1645a797689dcb68ceae7e45eec96ed24497", + "sha256:0c8e336df8ed1687590695f4469f480eeb4159bf13bb6193791c6530fe114b49", + "sha256:0c9bf2d5e4ef45c1686c6f76935e7ca263f5eae4de92bf5d1873a0e737e4eb7d", + "sha256:0faf6e96f74d27b8ca816b40217904891f91b664ed1c0388737949ceb50ac15d", + "sha256:10ea7f497e6226372e1d4fdbf42c8381f4887819a643ab930bff4072ad298d84", + "sha256:11650f7ed77ee1df30f25d6b3b74b2fa1c94124e074fd455abafea3cbc913d53", + "sha256:12ead3ee3e9c7caa00356b528a5cc7fe210fbe2060628af6e19ed76b8416572e", + "sha256:136b3c5b08883681fcb58f12393a5bbfa422d6e2d5ba887e263e776874276bc6", + "sha256:17d6e1691154ea9f726e43dcb717df48e56c66b5a01c90ad675c6494c36e5be1", + "sha256:19cb987915cc0d321746a12f2a693d087ffb721c37ac9a153cc088c57d4d90eb", + "sha256:1cdf15de698c4026e64fd914fead3180e52bf2a7bcbe44a3392404582dbf2d22", + "sha256:1e81e1c64e33506b8508ba5e3c7c139b2577e78b079c2c16a8e7a02a161f1080", + "sha256:2226c76e4ff2149c5d9f94bed22bf9c4f3411d38cc53d4a7ddfbe0899c8b558c", + "sha256:2837412fb7b684c6ce7392c8bc57440c6dbadaf1bde7a53144381f7df7083c1c", + "sha256:293f0f3da3c391e997e0d55fdb85540e98a8b0406622bb4ba57fb7617697f31e", + "sha256:2b9cc6c0239215a349d28c192fa4c4e7a7348eee7980531525c01bffe39eea80", + "sha256:2f3ad679f84ff236a0d7b71ddc4b3c09fe467abee2f1a86671f0cd417be5352b", + "sha256:358cad2f328c52c15756cf32b0ad17afb0d617e7cdfe93d59aa2616966d825b7", + "sha256:3663712305b509f79c002c8c0ca9994f716cadba576f5a59632dda1aec1ca8c6", + "sha256:41794820ccca039ca2ead6245f30b34601dd1456eee5b5dde620672bb989e79d", + "sha256:44b7e64aff542471c474c24f771eae5efd9152da02a12556f7cb7607020e1420", + "sha256:45770eb0990166026538d3c2fd7d92f17cfde13ca6567570c4baec3ce9162936", + "sha256:498060078a4d1b458e9381fefb027d85329397b50d65287712b3d48233e20836", + "sha256:4c2f18f337c2393f84e45e5011c8b02697b81638b1cec49da60a01b9ed067695", + "sha256:5162d6e475d2762035fb8ea25982bcbec6c58715e33bd0951499f743cd90b110", + "sha256:51e8c890bb59008c95b3a552cefd8bd9ce50a7466a6c920a78cf586e885d7449", + "sha256:56ad3839ac6ac5fd3d023cf59d4b04264b74bb4cb44c0780faf51d6b5ff38fbc", + "sha256:5821638ef0d7c973071810a6786f59b305172197f7e7e469a2ce169e7f4978e3", + "sha256:5ac1b2d379f4d40c13dcce537e69704452943cddbe991fd54a84fdb2da9026d5", + "sha256:5b465d4311b0429fe6fa85df8e2cfcb038c9fface95396dd14e838ecabaaadf2", + "sha256:5d8656b98057329bd03d968aac8d5198389cf51517511295cfc4cb827a507e39", + "sha256:5dcfb3e823ef4b91b70b92848570d1d8cfd584304bd2bd54272dc100c9494def", + "sha256:5e40d23ea43f683f3a7c032dde391104f609b05c21b6d284101120b51dbd50c1", + "sha256:63a01522bde161c713f7fa5ee5d850fee6386fc386073490ebcd438f14579cf2", + "sha256:6b2a3d7756035dde13571f4ad232629b78b7f35c2cd5fda7b464079fc697db3a", + "sha256:6b3be1a6bf6c965aea3b4e3a40df9d2c134c516d89c76cf2b6c81f67e6c5c6ed", + "sha256:6c7bea3357f2dc653756e6da55f66cd21c73d3875c8f3dc4e8d196a876252de0", + "sha256:6e6c8e229507cf29333a2f491cbaa7dff5b8a4a3e613af8090ccce9ce3e4f7a0", + "sha256:6fad27f2a63884ee45d491aebec4b1f38752cd6aaccc625038c21e7f43c02c49", + "sha256:71bfef52547c2b8b145897fa8d1b5142bc52313cfa38c0742e0ef755f0d09c60", + "sha256:72370d312323282b1bf74426e53fae861a310d7ae519b419da46673c38e7d147", + "sha256:76c7d36043a9c478b0c846fcec7da5cb095983722473e503e0122ccd170182b5", + "sha256:78d8a81ef51edb9a2f278a6fb278789b49e304b12bb21bccf2fe7e344f71a9fb", + "sha256:798a6b159ce32181a5e7ab7611c17d1080e74a5541fec47f961b728dab25a76f", + "sha256:7e370567f66a57e2c0e3ae2afcc6f126e1d6babd36831cfd0caad279b05c1c88", + "sha256:8004b845f606b95a8b17efa112aa10b327e46e95dcda604a257b4633d4ed45c8", + "sha256:80b20bf9ea4e709b3b9ae364ac298dfa872b084c186e5c1d60b0b79c79a7ee7e", + "sha256:87303f4bb1b493997f911a4f126123ccd2827d3a2e7dd2390cc6143fbc75805b", + "sha256:8d423f4631395b92dceda39f481a463498131ac02a58581124a44495491f715b", + "sha256:94ee262192db50fb9c069a0be7bb1a426fb1b43af26ce12bf4c6c30e13f46b56", + "sha256:960e4be2e7de340300ab4bcc2b45bed46be1d62330575b8265e6602dbcb9a14c", + "sha256:99397d5e1da6b345cec3e6125e2902b0e6864eb8eaa4be43a2013f059c502c93", + "sha256:9abbb8c1bad08817bad62ae1ea76c01bdbd0ee8c827d05f3ba038c9f6d6f14bb", + "sha256:9c0b8fadf80bc70d341032f92702bda1b0ed78c01e9c495f0df701938c99bcf5", + "sha256:9f977da9abae170eebdcf02bda33727c342fad5dcdbc08498bfdfb6cc6c65489", + "sha256:a6be712ca39d5e9c89b705bc9800be36739436fefb8d0b52b2d332f7d6d22a01", + "sha256:aa434418d6ee44b0ba3a5a407bc9e1543cf496328f43f149e9b58f74a63d5c21", + "sha256:ac4f778e32f7de0ba63346893a4af87c2280ffc1783f594a117be51d908a10da", + "sha256:ac85d65ee369c09b2904b55078ad589961e2e2e03c810963d35a26e6a3931425", + "sha256:ad5d78c664d39960435d4162db31117c8945ba74fb0c414e79ba85a8bdeafdec", + "sha256:ad91f57c3485d87a8edee558dafab0f08c716857d748731c0998dcefe9d3fd5f", + "sha256:afd255d42b340036883ca95bded553b29065b064e2fe5db64ad5988517db9694", + "sha256:b1c2c74f100a0c2110a8e30445554ae331860d32f145c60a2a1e1c27702022a2", + "sha256:b49a8c71378d40d43c6a56eaa536d7823baa43c27c93e082aeb60a9717be0c10", + "sha256:b5f52611323e8e35705e6750a760f32165b41c052d22da154ae343871e7cd50d", + "sha256:b6bf99ae529ac359263269710356d3ddb173c15d8f8dc8849ae794ab811e5cd0", + "sha256:ba361bf87c4701f11241be92c99ef5cf916865dd225955cccb2376bf76717b3c", + "sha256:bc351aa2158575e68943d8e1d5531719ad86bf6607776627ed5a1a60657664af", + "sha256:bd6eb7b1e12e4dd0b75cab1b023272f1333494add5ad61deedac738af1ffeede", + "sha256:bf8852595f5e2d2b072e24c29394b5aca7fba96ecc8656d56660535f9e9872c9", + "sha256:c1dd66541569a2bdbe92589cc96a89f470b20d168f2238fd463e1b59ee3e2d49", + "sha256:c36a7a004cba4e370d0675826eeefe4e42a256638b6b1432263ddb4af317bc02", + "sha256:c886cda61da4d39010be84802bed11bc75f03e8a6094cc18016957a2c80254d4", + "sha256:cc7aa83946f80c66a5d2dea7e165f15aa3eb21e7b74b24d8f850afc0d44bb00e", + "sha256:cea9c4bef70d1358bafec6019164abce362f4de15d79d1ecd64ae31c1749d77a", + "sha256:cfe1951e80869695857986be104a40a1e7fa8ec7de05f86bcbd7bd20854be764", + "sha256:d36cf6f139da3279644794fcfda18af425c8bb122ef9c2e7c762a937bbf7b0f4", + "sha256:d81308faaa9393b7e6ed20718d465c4c2b73c24d5e4826024961acf4b87b1524", + "sha256:db51ea1f9c5ac790848bc271fcdf4108ad1b77a77c6949a96320477962cf7ba5", + "sha256:dd05c18c920a15e00d7a52df37bffd3930fe2c004c690f9422b20e12077e6dbd", + "sha256:df05918a11e1db0198d00486e36673b4b4a89390e4458ff9479b4908dde357ac", + "sha256:e4c31dccf6be131709e545d0258eb5b75c5fac304857ad3976331c6740e8b9d6", + "sha256:e60954d673040430802b29fe5bba698e262182b5ba5f302ff4458e39f8101881", + "sha256:e60e2d2c88a0552e61c37172fe377f6a8abf479130a445314886de4a360ba940", + "sha256:e786f773ddc153846b2ebdb854011cfd1f7c874b8ee79cced3706801341c9f5d", + "sha256:e7cd91548fb95b69edd376f5204e27115ac7d093ec7d80066123a5bdb31c71d9", + "sha256:eaef2ea4f5602aefaaf3d6e8235f3b9ffde35aff15aac1c16cc802f6bbf0a3b5", + "sha256:ec8c5ea93a03775fbadd08462200cf34ce617ec75a032abfa44fd6d3a00e5424", + "sha256:eddeb8574bc9d9abb8491d4a46b60e553c2cea235b80373756acb06568101175", + "sha256:eeb300b0e4b428aab2f70d785cad4306529262af6de8c8c5fe6a4b41a674a434", + "sha256:f39d71ece8e97cf069e4154868eaac1256b133fe23e0459829432e4bb6406472", + "sha256:f4840ddad2b9d53710e92361391944da89e3576641a290066a1719520059247c", + "sha256:f70723a00bcbce0f9a216853139955be45da35741335eb3afead304e77662560", + "sha256:f829cf2ba5b553e6529d6238928c07096f1feb47f4ad536b7f06bca6cc77173f", + "sha256:f96386910467725895f7972939a6faabd6e96b1de0cc2c092e4bd2c40e956e25", + "sha256:fe259a9d6f555bc79aed9bb4b9a7fff73db443b4c483e4a81a428c8a2860428b" + ], + "markers": "python_version >= '3.7'", + "version": "==5.0.8" + }, "jinja2": { "hashes": [ "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", @@ -752,109 +871,117 @@ }, "mistune": { "hashes": [ - "sha256:4b47731332315cdca99e0ded46fc0004001c1299ff773dfb48fbe1fd226de319", - "sha256:733bf018ba007e8b5f2d3a9eb624034f6ee26c4ea769a98ec533ee111d504dff" + "sha256:1a32314113cff28aa6432e99e522677c8587fd83e3d51c29b82a52409c842bd9", + "sha256:a7035c21782b2becb6be62f8f25d3df81ccb4d6fa477a6525b15af06539f02a0" ], "markers": "python_version >= '3.8'", - "version": "==3.1.2" + "version": "==3.1.3" }, "multidict": { "hashes": [ - "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f", - "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056", - "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761", - "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3", - "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b", - "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6", - "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748", - "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966", - "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f", - "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1", - "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6", - "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada", - "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305", - "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2", - "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d", - "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a", - "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef", - "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c", - "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb", - "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60", - "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6", - "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4", - "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478", - "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81", - "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7", - "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56", - "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3", - "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6", - "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30", - "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb", - "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", - "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0", - "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925", - "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c", - "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6", - "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e", - "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95", - "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2", - "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133", - "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2", - "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa", - "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3", - "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3", - "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436", - "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657", - "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581", - "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492", - "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43", - "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2", - "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2", - "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926", - "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057", - "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc", - "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80", - "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255", - "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1", - "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972", - "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53", - "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1", - "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423", - "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a", - "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160", - "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c", - "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd", - "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa", - "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5", - "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b", - "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa", - "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef", - "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44", - "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4", - "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156", - "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753", - "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28", - "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d", - "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a", - "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304", - "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008", - "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429", - "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72", - "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399", - "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3", - "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392", - "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167", - "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c", - "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774", - "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351", - "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76", - "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875", - "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd", - "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28", - "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db" + "sha256:0085b0afb2446e57050140240a8595846ed64d1cbd26cef936bfab3192c673b8", + "sha256:042028348dc5a1f2be6c666437042a98a5d24cee50380f4c0902215e5ec41844", + "sha256:05fefbc3cddc4e36da209a5e49f1094bbece9a581faa7f3589201fd95df40e5d", + "sha256:063be88bd684782a0715641de853e1e58a2f25b76388538bd62d974777ce9bc2", + "sha256:07bfa8bc649783e703263f783f73e27fef8cd37baaad4389816cf6a133141331", + "sha256:08549895e6a799bd551cf276f6e59820aa084f0f90665c0f03dd3a50db5d3c48", + "sha256:095a2eabe8c43041d3e6c2cb8287a257b5f1801c2d6ebd1dd877424f1e89cf29", + "sha256:0b183a959fb88ad1be201de2c4bdf52fa8e46e6c185d76201286a97b6f5ee65c", + "sha256:0c383d28857f66f5aebe3e91d6cf498da73af75fbd51cedbe1adfb85e90c0460", + "sha256:0d57a01a2a9fa00234aace434d8c131f0ac6e0ac6ef131eda5962d7e79edfb5b", + "sha256:0dc25a3293c50744796e87048de5e68996104d86d940bb24bc3ec31df281b191", + "sha256:0e5a644e50ef9fb87878d4d57907f03a12410d2aa3b93b3acdf90a741df52c49", + "sha256:0f249badb360b0b4d694307ad40f811f83df4da8cef7b68e429e4eea939e49dd", + "sha256:0f74f2fc51555f4b037ef278efc29a870d327053aba5cb7d86ae572426c7cccc", + "sha256:125dd82b40f8c06d08d87b3510beaccb88afac94e9ed4a6f6c71362dc7dbb04b", + "sha256:13551d0e2d7201f0959725a6a769b6f7b9019a168ed96006479c9ac33fe4096b", + "sha256:14ed9ed1bfedd72a877807c71113deac292bf485159a29025dfdc524c326f3e1", + "sha256:163f4604e76639f728d127293d24c3e208b445b463168af3d031b92b0998bb90", + "sha256:19e2819b0b468174de25c0ceed766606a07cedeab132383f1e83b9a4e96ccb4f", + "sha256:1e2a2193d3aa5cbf5758f6d5680a52aa848e0cf611da324f71e5e48a9695cc86", + "sha256:1f3c099d3899b14e1ce52262eb82a5f5cb92157bb5106bf627b618c090a0eadc", + "sha256:214207dcc7a6221d9942f23797fe89144128a71c03632bf713d918db99bd36de", + "sha256:2325105e16d434749e1be8022f942876a936f9bece4ec41ae244e3d7fae42aaf", + "sha256:2529ddbdaa424b2c6c2eb668ea684dd6b75b839d0ad4b21aad60c168269478d7", + "sha256:256d431fe4583c5f1e0f2e9c4d9c22f3a04ae96009b8cfa096da3a8723db0a16", + "sha256:25bb96338512e2f46f615a2bb7c6012fe92a4a5ebd353e5020836a7e33120349", + "sha256:2e87f1926e91855ae61769ba3e3f7315120788c099677e0842e697b0bfb659f2", + "sha256:2fc6af8e39f7496047c7876314f4317736eac82bf85b54c7c76cf1a6f8e35d98", + "sha256:3157126b028c074951839233647bd0e30df77ef1fedd801b48bdcad242a60f4e", + "sha256:32c9b4878f48be3e75808ea7e499d6223b1eea6d54c487a66bc10a1871e3dc6a", + "sha256:32ed748ff9ac682eae7859790d3044b50e3076c7d80e17a44239683769ff485e", + "sha256:3501621d5e86f1a88521ea65d5cad0a0834c77b26f193747615b7c911e5422d2", + "sha256:437c33561edb6eb504b5a30203daf81d4a9b727e167e78b0854d9a4e18e8950b", + "sha256:48d39b1824b8d6ea7de878ef6226efbe0773f9c64333e1125e0efcfdd18a24c7", + "sha256:4ac3fcf9a2d369bd075b2c2965544036a27ccd277fc3c04f708338cc57533081", + "sha256:4ccfd74957ef53fa7380aaa1c961f523d582cd5e85a620880ffabd407f8202c0", + "sha256:52b05e21ff05729fbea9bc20b3a791c3c11da61649ff64cce8257c82a020466d", + "sha256:5389445f0173c197f4a3613713b5fb3f3879df1ded2a1a2e4bc4b5b9c5441b7e", + "sha256:5c5e7d2e300d5cb3b2693b6d60d3e8c8e7dd4ebe27cd17c9cb57020cac0acb80", + "sha256:5d26547423e5e71dcc562c4acdc134b900640a39abd9066d7326a7cc2324c530", + "sha256:5dd7106d064d05896ce28c97da3f46caa442fe5a43bc26dfb258e90853b39b44", + "sha256:5f8cb1329f42fadfb40d6211e5ff568d71ab49be36e759345f91c69d1033d633", + "sha256:61d5541f27533f803a941d3a3f8a3d10ed48c12cf918f557efcbf3cd04ef265c", + "sha256:639556758c36093b35e2e368ca485dada6afc2bd6a1b1207d85ea6dfc3deab27", + "sha256:641cf2e3447c9ecff2f7aa6e9eee9eaa286ea65d57b014543a4911ff2799d08a", + "sha256:6aed763b6a1b28c46c055692836879328f0b334a6d61572ee4113a5d0c859872", + "sha256:6e2a2d6749e1ff2c9c76a72c6530d5baa601205b14e441e6d98011000f47a7ac", + "sha256:7243c5a6523c5cfeca76e063efa5f6a656d1d74c8b1fc64b2cd1e84e507f7e2a", + "sha256:76b34c12b013d813e6cb325e6bd4f9c984db27758b16085926bbe7ceeaace626", + "sha256:781b5dd1db18c9e9eacc419027b0acb5073bdec9de1675c0be25ceb10e2ad133", + "sha256:7c611345bbe7cb44aabb877cb94b63e86f2d0db03e382667dbd037866d44b4f8", + "sha256:83b78c680d4b15d33042d330c2fa31813ca3974197bddb3836a5c635a5fd013f", + "sha256:84e87a7d75fa36839a3a432286d719975362d230c70ebfa0948549cc38bd5b46", + "sha256:89b3857652183b8206a891168af47bac10b970d275bba1f6ee46565a758c078d", + "sha256:8cd1a0644ccaf27e9d2f6d9c9474faabee21f0578fe85225cc5af9a61e1653df", + "sha256:8de4d42dffd5ced9117af2ce66ba8722402541a3aa98ffdf78dde92badb68932", + "sha256:94a7bb972178a8bfc4055db80c51efd24baefaced5e51c59b0d598a004e8305d", + "sha256:98aa8325c7f47183b45588af9c434533196e241be0a4e4ae2190b06d17675c02", + "sha256:9e658d1373c424457ddf6d55ec1db93c280b8579276bebd1f72f113072df8a5d", + "sha256:9f49585f4abadd2283034fc605961f40c638635bc60f5162276fec075f2e37a4", + "sha256:9f6cad071960ba1914fa231677d21b1b4a3acdcce463cee41ea30bc82e6040cf", + "sha256:a0cc398350ef31167e03f3ca7c19313d4e40a662adcb98a88755e4e861170bdd", + "sha256:a1133414b771619aa3c3000701c11b2e4624a7f492f12f256aedde97c28331a2", + "sha256:a33273a541f1e1a8219b2a4ed2de355848ecc0254264915b9290c8d2de1c74e1", + "sha256:a3c0ff89fe40a152e77b191b83282c9664357dce3004032d42e68c514ceff27e", + "sha256:a49994481b99cd7dedde07f2e7e93b1d86c01c0fca1c32aded18f10695ae17eb", + "sha256:abf5b17bc0cf626a8a497d89ac691308dbd825d2ac372aa990b1ca114e470151", + "sha256:ac380cacdd3b183338ba63a144a34e9044520a6fb30c58aa14077157a033c13e", + "sha256:ad81012b24b88aad4c70b2cbc2dad84018783221b7f923e926f4690ff8569da3", + "sha256:b2c00ad31fbc2cbac85d7d0fcf90853b2ca2e69d825a2d3f3edb842ef1544a2c", + "sha256:b4c153863dd6569f6511845922c53e39c8d61f6e81f228ad5443e690fca403de", + "sha256:b4f3d66dd0354b79761481fc15bdafaba0b9d9076f1f42cc9ce10d7fcbda205a", + "sha256:b99aac6bb2c37db336fa03a39b40ed4ef2818bf2dfb9441458165ebe88b793af", + "sha256:b9f6392d98c0bd70676ae41474e2eecf4c7150cb419237a41f8f96043fcb81d1", + "sha256:c537da54ce4ff7c15e78ab1292e5799d0d43a2108e006578a57f531866f64025", + "sha256:ca23db5fb195b5ef4fd1f77ce26cadefdf13dba71dab14dadd29b34d457d7c44", + "sha256:cc826b9a8176e686b67aa60fd6c6a7047b0461cae5591ea1dc73d28f72332a8a", + "sha256:cca83a629f77402cfadd58352e394d79a61c8015f1694b83ab72237ec3941f88", + "sha256:cf8d370b2fea27fb300825ec3984334f7dd54a581bde6456799ba3776915a656", + "sha256:d1175b0e0d6037fab207f05774a176d71210ebd40b1c51f480a04b65ec5c786d", + "sha256:d1996ee1330e245cd3aeda0887b4409e3930524c27642b046e4fae88ffa66c5e", + "sha256:d5a36953389f35f0a4e88dc796048829a2f467c9197265504593f0e420571547", + "sha256:da51d8928ad8b4244926fe862ba1795f0b6e68ed8c42cd2f822d435db9c2a8f4", + "sha256:e16e7297f29a544f49340012d6fc08cf14de0ab361c9eb7529f6a57a30cbfda1", + "sha256:e25b11a0417475f093d0f0809a149aff3943c2c56da50fdf2c3c88d57fe3dfbd", + "sha256:e4371591e621579cb6da8401e4ea405b33ff25a755874a3567c4075ca63d56e2", + "sha256:e653d36b1bf48fa78c7fcebb5fa679342e025121ace8c87ab05c1cefd33b34fc", + "sha256:e7d91a230c7f8af86c904a5a992b8c064b66330544693fd6759c3d6162382ecf", + "sha256:e851e6363d0dbe515d8de81fd544a2c956fdec6f8a049739562286727d4a00c3", + "sha256:ef7d48207926edbf8b16b336f779c557dd8f5a33035a85db9c4b0febb0706817", + "sha256:f7716f7e7138252d88607228ce40be22660d6608d20fd365d596e7ca0738e019", + "sha256:facaf11f21f3a4c51b62931feb13310e6fe3475f85e20d9c9fdce0d2ea561b87" ], - "markers": "python_version >= '3.8'", - "version": "==6.1.0" + "markers": "python_version >= '3.9'", + "version": "==6.2.0" + }, + "niquests": { + "hashes": [ + "sha256:68e0a7e9f338466b3606945fffd11f75e3c90af7498aa9336ef03812323b7e36", + "sha256:86e484c2c60444aa96069c15f6295af6e25a8bad50781e1326df1b5c7ab48339" + ], + "markers": "python_version >= '3.7'", + "version": "==3.14.0" }, "numpy": { "hashes": [ @@ -1016,107 +1143,107 @@ }, "propcache": { "hashes": [ - "sha256:02df07041e0820cacc8f739510078f2aadcfd3fc57eaeeb16d5ded85c872c89e", - "sha256:03acd9ff19021bd0567582ac88f821b66883e158274183b9e5586f678984f8fe", - "sha256:03c091bb752349402f23ee43bb2bff6bd80ccab7c9df6b88ad4322258d6960fc", - "sha256:07700939b2cbd67bfb3b76a12e1412405d71019df00ca5697ce75e5ef789d829", - "sha256:0c3e893c4464ebd751b44ae76c12c5f5c1e4f6cbd6fbf67e3783cd93ad221863", - "sha256:119e244ab40f70a98c91906d4c1f4c5f2e68bd0b14e7ab0a06922038fae8a20f", - "sha256:11ae6a8a01b8a4dc79093b5d3ca2c8a4436f5ee251a9840d7790dccbd96cb649", - "sha256:15010f29fbed80e711db272909a074dc79858c6d28e2915704cfc487a8ac89c6", - "sha256:19d36bb351ad5554ff20f2ae75f88ce205b0748c38b146c75628577020351e3c", - "sha256:1c8f7d896a16da9455f882870a507567d4f58c53504dc2d4b1e1d386dfe4588a", - "sha256:2383a17385d9800b6eb5855c2f05ee550f803878f344f58b6e194de08b96352c", - "sha256:24c04f8fbf60094c531667b8207acbae54146661657a1b1be6d3ca7773b7a545", - "sha256:2578541776769b500bada3f8a4eeaf944530516b6e90c089aa368266ed70c49e", - "sha256:26a67e5c04e3119594d8cfae517f4b9330c395df07ea65eab16f3d559b7068fe", - "sha256:2b975528998de037dfbc10144b8aed9b8dd5a99ec547f14d1cb7c5665a43f075", - "sha256:2d15bc27163cd4df433e75f546b9ac31c1ba7b0b128bfb1b90df19082466ff57", - "sha256:2d913d36bdaf368637b4f88d554fb9cb9d53d6920b9c5563846555938d5450bf", - "sha256:3302c5287e504d23bb0e64d2a921d1eb4a03fb93a0a0aa3b53de059f5a5d737d", - "sha256:36ca5e9a21822cc1746023e88f5c0af6fce3af3b85d4520efb1ce4221bed75cc", - "sha256:3b812b3cb6caacd072276ac0492d249f210006c57726b6484a1e1805b3cfeea0", - "sha256:3c6ec957025bf32b15cbc6b67afe233c65b30005e4c55fe5768e4bb518d712f1", - "sha256:41de3da5458edd5678b0f6ff66691507f9885f5fe6a0fb99a5d10d10c0fd2d64", - "sha256:42924dc0c9d73e49908e35bbdec87adedd651ea24c53c29cac103ede0ea1d340", - "sha256:4544699674faf66fb6b4473a1518ae4999c1b614f0b8297b1cef96bac25381db", - "sha256:46ed02532cb66612d42ae5c3929b5e98ae330ea0f3900bc66ec5f4862069519b", - "sha256:49ea05212a529c2caffe411e25a59308b07d6e10bf2505d77da72891f9a05641", - "sha256:4fa0e7c9c3cf7c276d4f6ab9af8adddc127d04e0fcabede315904d2ff76db626", - "sha256:507c5357a8d8b4593b97fb669c50598f4e6cccbbf77e22fa9598aba78292b4d7", - "sha256:549722908de62aa0b47a78b90531c022fa6e139f9166be634f667ff45632cc92", - "sha256:58e6d2a5a7cb3e5f166fd58e71e9a4ff504be9dc61b88167e75f835da5764d07", - "sha256:5a16167118677d94bb48bfcd91e420088854eb0737b76ec374b91498fb77a70e", - "sha256:5d62c4f6706bff5d8a52fd51fec6069bef69e7202ed481486c0bc3874912c787", - "sha256:5fa159dcee5dba00c1def3231c249cf261185189205073bde13797e57dd7540a", - "sha256:6032231d4a5abd67c7f71168fd64a47b6b451fbcb91c8397c2f7610e67683810", - "sha256:63f26258a163c34542c24808f03d734b338da66ba91f410a703e505c8485791d", - "sha256:65a37714b8ad9aba5780325228598a5b16c47ba0f8aeb3dc0514701e4413d7c0", - "sha256:67054e47c01b7b349b94ed0840ccae075449503cf1fdd0a1fdd98ab5ddc2667b", - "sha256:67dda3c7325691c2081510e92c561f465ba61b975f481735aefdfc845d2cd043", - "sha256:6985a593417cdbc94c7f9c3403747335e450c1599da1647a5af76539672464d3", - "sha256:6a1948df1bb1d56b5e7b0553c0fa04fd0e320997ae99689488201f19fa90d2e7", - "sha256:6b5b7fd6ee7b54e01759f2044f936dcf7dea6e7585f35490f7ca0420fe723c0d", - "sha256:6c929916cbdb540d3407c66f19f73387f43e7c12fa318a66f64ac99da601bcdf", - "sha256:6f4d7a7c0aff92e8354cceca6fe223973ddf08401047920df0fcb24be2bd5138", - "sha256:728af36011bb5d344c4fe4af79cfe186729efb649d2f8b395d1572fb088a996c", - "sha256:742840d1d0438eb7ea4280f3347598f507a199a35a08294afdcc560c3739989d", - "sha256:75e872573220d1ee2305b35c9813626e620768248425f58798413e9c39741f46", - "sha256:794c3dd744fad478b6232289c866c25406ecdfc47e294618bdf1697e69bd64a6", - "sha256:7c0fdbdf6983526e269e5a8d53b7ae3622dd6998468821d660d0daf72779aefa", - "sha256:7c5f5290799a3f6539cc5e6f474c3e5c5fbeba74a5e1e5be75587746a940d51e", - "sha256:7c6e7e4f9167fddc438cd653d826f2222222564daed4116a02a184b464d3ef05", - "sha256:7cedd25e5f678f7738da38037435b340694ab34d424938041aa630d8bac42663", - "sha256:7e2e068a83552ddf7a39a99488bcba05ac13454fb205c847674da0352602082f", - "sha256:8319293e85feadbbfe2150a5659dbc2ebc4afdeaf7d98936fb9a2f2ba0d4c35c", - "sha256:8526b0941ec5a40220fc4dfde76aed58808e2b309c03e9fa8e2260083ef7157f", - "sha256:8884ba1a0fe7210b775106b25850f5e5a9dc3c840d1ae9924ee6ea2eb3acbfe7", - "sha256:8cb625bcb5add899cb8ba7bf716ec1d3e8f7cdea9b0713fa99eadf73b6d4986f", - "sha256:8d663fd71491dde7dfdfc899d13a067a94198e90695b4321084c6e450743b8c7", - "sha256:8ee1983728964d6070ab443399c476de93d5d741f71e8f6e7880a065f878e0b9", - "sha256:997e7b8f173a391987df40f3b52c423e5850be6f6df0dcfb5376365440b56667", - "sha256:9be90eebc9842a93ef8335291f57b3b7488ac24f70df96a6034a13cb58e6ff86", - "sha256:9ddd49258610499aab83b4f5b61b32e11fce873586282a0e972e5ab3bcadee51", - "sha256:9ecde3671e62eeb99e977f5221abcf40c208f69b5eb986b061ccec317c82ebd0", - "sha256:9ff4e9ecb6e4b363430edf2c6e50173a63e0820e549918adef70515f87ced19a", - "sha256:a254537b9b696ede293bfdbc0a65200e8e4507bc9f37831e2a0318a9b333c85c", - "sha256:a2b9bf8c79b660d0ca1ad95e587818c30ccdb11f787657458d6f26a1ea18c568", - "sha256:a61a68d630e812b67b5bf097ab84e2cd79b48c792857dc10ba8a223f5b06a2af", - "sha256:a7080b0159ce05f179cfac592cda1a82898ca9cd097dacf8ea20ae33474fbb25", - "sha256:a8fd93de4e1d278046345f49e2238cdb298589325849b2645d4a94c53faeffc5", - "sha256:a94ffc66738da99232ddffcf7910e0f69e2bbe3a0802e54426dbf0714e1c2ffe", - "sha256:aa806bbc13eac1ab6291ed21ecd2dd426063ca5417dd507e6be58de20e58dfcf", - "sha256:b0c1a133d42c6fc1f5fbcf5c91331657a1ff822e87989bf4a6e2e39b818d0ee9", - "sha256:b58229a844931bca61b3a20efd2be2a2acb4ad1622fc026504309a6883686fbf", - "sha256:bb2f144c6d98bb5cbc94adeb0447cfd4c0f991341baa68eee3f3b0c9c0e83767", - "sha256:be90c94570840939fecedf99fa72839aed70b0ced449b415c85e01ae67422c90", - "sha256:bf0d9a171908f32d54f651648c7290397b8792f4303821c42a74e7805bfb813c", - "sha256:bf15fc0b45914d9d1b706f7c9c4f66f2b7b053e9517e40123e137e8ca8958b3d", - "sha256:bf4298f366ca7e1ad1d21bbb58300a6985015909964077afd37559084590c929", - "sha256:c441c841e82c5ba7a85ad25986014be8d7849c3cfbdb6004541873505929a74e", - "sha256:cacea77ef7a2195f04f9279297684955e3d1ae4241092ff0cfcef532bb7a1c32", - "sha256:cd54895e4ae7d32f1e3dd91261df46ee7483a735017dc6f987904f194aa5fd14", - "sha256:d1323cd04d6e92150bcc79d0174ce347ed4b349d748b9358fd2e497b121e03c8", - "sha256:d383bf5e045d7f9d239b38e6acadd7b7fdf6c0087259a84ae3475d18e9a2ae8b", - "sha256:d3e7420211f5a65a54675fd860ea04173cde60a7cc20ccfbafcccd155225f8bc", - "sha256:d8074c5dd61c8a3e915fa8fc04754fa55cfa5978200d2daa1e2d4294c1f136aa", - "sha256:df03cd88f95b1b99052b52b1bb92173229d7a674df0ab06d2b25765ee8404bce", - "sha256:e45377d5d6fefe1677da2a2c07b024a6dac782088e37c0b1efea4cfe2b1be19b", - "sha256:e53d19c2bf7d0d1e6998a7e693c7e87300dd971808e6618964621ccd0e01fe4e", - "sha256:e560fd75aaf3e5693b91bcaddd8b314f4d57e99aef8a6c6dc692f935cc1e6bbf", - "sha256:ec5060592d83454e8063e487696ac3783cc48c9a329498bafae0d972bc7816c9", - "sha256:ecc2920630283e0783c22e2ac94427f8cca29a04cfdf331467d4f661f4072dac", - "sha256:ed7161bccab7696a473fe7ddb619c1d75963732b37da4618ba12e60899fefe4f", - "sha256:ee0bd3a7b2e184e88d25c9baa6a9dc609ba25b76daae942edfb14499ac7ec374", - "sha256:ee25f1ac091def37c4b59d192bbe3a206298feeb89132a470325bf76ad122a1e", - "sha256:efa44f64c37cc30c9f05932c740a8b40ce359f51882c70883cc95feac842da4d", - "sha256:f47d52fd9b2ac418c4890aad2f6d21a6b96183c98021f0a48497a904199f006e", - "sha256:f857034dc68d5ceb30fb60afb6ff2103087aea10a01b613985610e007053a121", - "sha256:fb91d20fa2d3b13deea98a690534697742029f4fb83673a3501ae6e3746508b5", - "sha256:fddb8870bdb83456a489ab67c6b3040a8d5a55069aa6f72f9d872235fbc52f54" + "sha256:050b571b2e96ec942898f8eb46ea4bfbb19bd5502424747e83badc2d4a99a44e", + "sha256:05543250deac8e61084234d5fc54f8ebd254e8f2b39a16b1dce48904f45b744b", + "sha256:069e7212890b0bcf9b2be0a03afb0c2d5161d91e1bf51569a64f629acc7defbf", + "sha256:09400e98545c998d57d10035ff623266927cb784d13dd2b31fd33b8a5316b85b", + "sha256:0c3c3a203c375b08fd06a20da3cf7aac293b834b6f4f4db71190e8422750cca5", + "sha256:0c86e7ceea56376216eba345aa1fc6a8a6b27ac236181f840d1d7e6a1ea9ba5c", + "sha256:0fbe94666e62ebe36cd652f5fc012abfbc2342de99b523f8267a678e4dfdee3c", + "sha256:17d1c688a443355234f3c031349da69444be052613483f3e4158eef751abcd8a", + "sha256:19a06db789a4bd896ee91ebc50d059e23b3639c25d58eb35be3ca1cbe967c3bf", + "sha256:1c5c7ab7f2bb3f573d1cb921993006ba2d39e8621019dffb1c5bc94cdbae81e8", + "sha256:1eb34d90aac9bfbced9a58b266f8946cb5935869ff01b164573a7634d39fbcb5", + "sha256:1f6cc0ad7b4560e5637eb2c994e97b4fa41ba8226069c9277eb5ea7101845b42", + "sha256:27c6ac6aa9fc7bc662f594ef380707494cb42c22786a558d95fcdedb9aa5d035", + "sha256:2d219b0dbabe75e15e581fc1ae796109b07c8ba7d25b9ae8d650da582bed01b0", + "sha256:2fce1df66915909ff6c824bbb5eb403d2d15f98f1518e583074671a30fe0c21e", + "sha256:319fa8765bfd6a265e5fa661547556da381e53274bc05094fc9ea50da51bfd46", + "sha256:359e81a949a7619802eb601d66d37072b79b79c2505e6d3fd8b945538411400d", + "sha256:3a02a28095b5e63128bcae98eb59025924f121f048a62393db682f049bf4ac24", + "sha256:3e19ea4ea0bf46179f8a3652ac1426e6dcbaf577ce4b4f65be581e237340420d", + "sha256:3e584b6d388aeb0001d6d5c2bd86b26304adde6d9bb9bfa9c4889805021b96de", + "sha256:40d980c33765359098837527e18eddefc9a24cea5b45e078a7f3bb5b032c6ecf", + "sha256:4114c4ada8f3181af20808bedb250da6bae56660e4b8dfd9cd95d4549c0962f7", + "sha256:43593c6772aa12abc3af7784bff4a41ffa921608dd38b77cf1dfd7f5c4e71371", + "sha256:47ef24aa6511e388e9894ec16f0fbf3313a53ee68402bc428744a367ec55b833", + "sha256:4cf9e93a81979f1424f1a3d155213dc928f1069d697e4353edb8a5eba67c6259", + "sha256:4d0dfdd9a2ebc77b869a0b04423591ea8823f791293b527dc1bb896c1d6f1136", + "sha256:563f9d8c03ad645597b8d010ef4e9eab359faeb11a0a2ac9f7b4bc8c28ebef25", + "sha256:58aa11f4ca8b60113d4b8e32d37e7e78bd8af4d1a5b5cb4979ed856a45e62005", + "sha256:5a0a9898fdb99bf11786265468571e628ba60af80dc3f6eb89a3545540c6b0ef", + "sha256:5aed8d8308215089c0734a2af4f2e95eeb360660184ad3912686c181e500b2e7", + "sha256:5b9145c35cc87313b5fd480144f8078716007656093d23059e8993d3a8fa730f", + "sha256:5cb5918253912e088edbf023788de539219718d3b10aef334476b62d2b53de53", + "sha256:5cdb0f3e1eb6dfc9965d19734d8f9c481b294b5274337a8cb5cb01b462dcb7e0", + "sha256:5ced33d827625d0a589e831126ccb4f5c29dfdf6766cac441d23995a65825dcb", + "sha256:603f1fe4144420374f1a69b907494c3acbc867a581c2d49d4175b0de7cc64566", + "sha256:61014615c1274df8da5991a1e5da85a3ccb00c2d4701ac6f3383afd3ca47ab0a", + "sha256:64a956dff37080b352c1c40b2966b09defb014347043e740d420ca1eb7c9b908", + "sha256:668ddddc9f3075af019f784456267eb504cb77c2c4bd46cc8402d723b4d200bf", + "sha256:6d8e309ff9a0503ef70dc9a0ebd3e69cf7b3894c9ae2ae81fc10943c37762458", + "sha256:6f173bbfe976105aaa890b712d1759de339d8a7cef2fc0a1714cc1a1e1c47f64", + "sha256:71ebe3fe42656a2328ab08933d420df5f3ab121772eef78f2dc63624157f0ed9", + "sha256:730178f476ef03d3d4d255f0c9fa186cb1d13fd33ffe89d39f2cda4da90ceb71", + "sha256:7d2d5a0028d920738372630870e7d9644ce437142197f8c827194fca404bf03b", + "sha256:7f30241577d2fef2602113b70ef7231bf4c69a97e04693bde08ddab913ba0ce5", + "sha256:813fbb8b6aea2fc9659815e585e548fe706d6f663fa73dff59a1677d4595a037", + "sha256:82de5da8c8893056603ac2d6a89eb8b4df49abf1a7c19d536984c8dd63f481d5", + "sha256:83be47aa4e35b87c106fc0c84c0fc069d3f9b9b06d3c494cd404ec6747544894", + "sha256:8638f99dca15b9dff328fb6273e09f03d1c50d9b6512f3b65a4154588a7595fe", + "sha256:87380fb1f3089d2a0b8b00f006ed12bd41bd858fabfa7330c954c70f50ed8757", + "sha256:88c423efef9d7a59dae0614eaed718449c09a5ac79a5f224a8b9664d603f04a3", + "sha256:89498dd49c2f9a026ee057965cdf8192e5ae070ce7d7a7bd4b66a8e257d0c976", + "sha256:8a17583515a04358b034e241f952f1715243482fc2c2945fd99a1b03a0bd77d6", + "sha256:916cd229b0150129d645ec51614d38129ee74c03293a9f3f17537be0029a9641", + "sha256:9532ea0b26a401264b1365146c440a6d78269ed41f83f23818d4b79497aeabe7", + "sha256:967a8eec513dbe08330f10137eacb427b2ca52118769e82ebcfcab0fba92a649", + "sha256:975af16f406ce48f1333ec5e912fe11064605d5c5b3f6746969077cc3adeb120", + "sha256:9979643ffc69b799d50d3a7b72b5164a2e97e117009d7af6dfdd2ab906cb72cd", + "sha256:9a8ecf38de50a7f518c21568c80f985e776397b902f1ce0b01f799aba1608b40", + "sha256:9cec3239c85ed15bfaded997773fdad9fb5662b0a7cbc854a43f291eb183179e", + "sha256:9e64e948ab41411958670f1093c0a57acfdc3bee5cf5b935671bbd5313bcf229", + "sha256:9f64d91b751df77931336b5ff7bafbe8845c5770b06630e27acd5dbb71e1931c", + "sha256:a0ab8cf8cdd2194f8ff979a43ab43049b1df0b37aa64ab7eca04ac14429baeb7", + "sha256:a110205022d077da24e60b3df8bcee73971be9575dec5573dd17ae5d81751111", + "sha256:a34aa3a1abc50740be6ac0ab9d594e274f59960d3ad253cd318af76b996dd654", + "sha256:a444192f20f5ce8a5e52761a031b90f5ea6288b1eef42ad4c7e64fef33540b8f", + "sha256:a461959ead5b38e2581998700b26346b78cd98540b5524796c175722f18b0294", + "sha256:a75801768bbe65499495660b777e018cbe90c7980f07f8aa57d6be79ea6f71da", + "sha256:aa8efd8c5adc5a2c9d3b952815ff8f7710cefdcaf5f2c36d26aff51aeca2f12f", + "sha256:aca63103895c7d960a5b9b044a83f544b233c95e0dcff114389d64d762017af7", + "sha256:b0313e8b923b3814d1c4a524c93dfecea5f39fa95601f6a9b1ac96cd66f89ea0", + "sha256:b23c11c2c9e6d4e7300c92e022046ad09b91fd00e36e83c44483df4afa990073", + "sha256:b303b194c2e6f171cfddf8b8ba30baefccf03d36a4d9cab7fd0bb68ba476a3d7", + "sha256:b655032b202028a582d27aeedc2e813299f82cb232f969f87a4fde491a233f11", + "sha256:bd39c92e4c8f6cbf5f08257d6360123af72af9f4da75a690bef50da77362d25f", + "sha256:bef100c88d8692864651b5f98e871fb090bd65c8a41a1cb0ff2322db39c96c27", + "sha256:c2fe5c910f6007e716a06d269608d307b4f36e7babee5f36533722660e8c4a70", + "sha256:c66d8ccbc902ad548312b96ed8d5d266d0d2c6d006fd0f66323e9d8f2dd49be7", + "sha256:cd6a55f65241c551eb53f8cf4d2f4af33512c39da5d9777694e9d9c60872f519", + "sha256:d249609e547c04d190e820d0d4c8ca03ed4582bcf8e4e160a6969ddfb57b62e5", + "sha256:d4e89cde74154c7b5957f87a355bb9c8ec929c167b59c83d90654ea36aeb6180", + "sha256:dc1915ec523b3b494933b5424980831b636fe483d7d543f7afb7b3bf00f0c10f", + "sha256:e1c4d24b804b3a87e9350f79e2371a705a188d292fd310e663483af6ee6718ee", + "sha256:e474fc718e73ba5ec5180358aa07f6aded0ff5f2abe700e3115c37d75c947e18", + "sha256:e4fe2a6d5ce975c117a6bb1e8ccda772d1e7029c1cca1acd209f91d30fa72815", + "sha256:e7fb9a84c9abbf2b2683fa3e7b0d7da4d8ecf139a1c635732a8bda29c5214b0e", + "sha256:e861ad82892408487be144906a368ddbe2dc6297074ade2d892341b35c59844a", + "sha256:ec314cde7314d2dd0510c6787326bbffcbdc317ecee6b7401ce218b3099075a7", + "sha256:ed5f6d2edbf349bd8d630e81f474d33d6ae5d07760c44d33cd808e2f5c8f4ae6", + "sha256:ef2e4e91fb3945769e14ce82ed53007195e616a63aa43b40fb7ebaaf907c8d4c", + "sha256:f011f104db880f4e2166bcdcf7f58250f7a465bc6b068dc84c824a3d4a5c94dc", + "sha256:f1528ec4374617a7a753f90f20e2f551121bb558fcb35926f99e3c42367164b8", + "sha256:f27785888d2fdd918bc36de8b8739f2d6c791399552333721b58193f68ea3e98", + "sha256:f35c7070eeec2cdaac6fd3fe245226ed2a6292d3ee8c938e5bb645b434c5f256", + "sha256:f3bbecd2f34d0e6d3c543fdb3b15d6b60dd69970c2b4c822379e5ec8f6f621d5", + "sha256:f6f1324db48f001c2ca26a25fa25af60711e09b9aaf4b28488602776f4f9a744", + "sha256:f78eb8422acc93d7b69964012ad7048764bb45a54ba7a39bb9e146c72ea29723", + "sha256:fb6e0faf8cb6b4beea5d6ed7b5a578254c6d7df54c36ccd3d8b3eb00d6770277", + "sha256:feccd282de1f6322f56f6845bf1207a537227812f0a9bf5571df52bb418d79d5" ], "markers": "python_version >= '3.9'", - "version": "==0.3.0" + "version": "==0.3.1" }, "pycparser": { "hashes": [ @@ -1128,117 +1255,116 @@ }, "pydantic": { "hashes": [ - "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584", - "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236" + "sha256:442557d2910e75c991c39f4b4ab18963d57b9b55122c8b2a9cd176d8c29ce968", + "sha256:5b6c415eee9f8123a14d859be0c84363fec6b1feb6b688d6435801230b56e0b8" ], - "markers": "python_version >= '3.8'", - "version": "==2.10.6" + "markers": "python_version >= '3.9'", + "version": "==2.11.1" }, "pydantic-core": { "hashes": [ - "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278", - "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50", - "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9", - "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f", - "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", - "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", - "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54", - "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630", - "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9", - "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236", - "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", - "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", - "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", - "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", - "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", - "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", - "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", - "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd", - "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", - "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", - "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7", - "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", - "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e", - "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa", - "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", - "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962", - "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", - "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f", - "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", - "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5", - "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", - "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf", - "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a", - "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c", - "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76", - "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362", - "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4", - "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", - "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320", - "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118", - "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96", - "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", - "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046", - "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3", - "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", - "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af", - "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", - "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67", - "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a", - "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", - "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35", - "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", - "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151", - "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b", - "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", - "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133", - "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", - "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145", - "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", - "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", - "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", - "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", - "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", - "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", - "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5", - "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", - "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", - "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8", - "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", - "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da", - "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", - "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc", - "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993", - "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656", - "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4", - "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", - "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb", - "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d", - "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", - "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e", - "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", - "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc", - "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a", - "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9", - "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506", - "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b", - "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1", - "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", - "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", - "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", - "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31", - "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c", - "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", - "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", - "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308", - "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2", - "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228", - "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b", - "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", - "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad" + "sha256:024d136ae44d233e6322027bbf356712b3940bee816e6c948ce4b90f18471b3d", + "sha256:0310524c833d91403c960b8a3cf9f46c282eadd6afd276c8c5edc617bd705dc9", + "sha256:07b4ced28fccae3f00626eaa0c4001aa9ec140a29501770a88dbbb0966019a86", + "sha256:085d8985b1c1e48ef271e98a658f562f29d89bda98bf120502283efbc87313eb", + "sha256:0a98257451164666afafc7cbf5fb00d613e33f7e7ebb322fbcd99345695a9a61", + "sha256:0bcf0bab28995d483f6c8d7db25e0d05c3efa5cebfd7f56474359e7137f39856", + "sha256:138d31e3f90087f42aa6286fb640f3c7a8eb7bdae829418265e7e7474bd2574b", + "sha256:14229c1504287533dbf6b1fc56f752ce2b4e9694022ae7509631ce346158de11", + "sha256:1583539533160186ac546b49f5cde9ffc928062c96920f58bd95de32ffd7bffd", + "sha256:175ab598fb457a9aee63206a1993874badf3ed9a456e0654273e56f00747bbd6", + "sha256:1a69b7596c6603afd049ce7f3835bcf57dd3892fc7279f0ddf987bebed8caa5a", + "sha256:1a73be93ecef45786d7d95b0c5e9b294faf35629d03d5b145b09b81258c7cd6d", + "sha256:1b1262b912435a501fa04cd213720609e2cefa723a07c92017d18693e69bf00b", + "sha256:1b2ea72dea0825949a045fa4071f6d5b3d7620d2a208335207793cf29c5a182d", + "sha256:20d4275f3c4659d92048c70797e5fdc396c6e4446caf517ba5cad2db60cd39d3", + "sha256:23c3e77bf8a7317612e5c26a3b084c7edeb9552d645742a54a5867635b4f2453", + "sha256:26a4ea04195638dcd8c53dadb545d70badba51735b1594810e9768c2c0b4a5da", + "sha256:26bc7367c0961dec292244ef2549afa396e72e28cc24706210bd44d947582c59", + "sha256:2a0147c0bef783fd9abc9f016d66edb6cac466dc54a17ec5f5ada08ff65caf5d", + "sha256:2c0afd34f928383e3fd25740f2050dbac9d077e7ba5adbaa2227f4d4f3c8da5c", + "sha256:30369e54d6d0113d2aa5aee7a90d17f225c13d87902ace8fcd7bbf99b19124db", + "sha256:31860fbda80d8f6828e84b4a4d129fd9c4535996b8249cfb8c720dc2a1a00bb8", + "sha256:34e7fb3abe375b5c4e64fab75733d605dda0f59827752debc99c17cb2d5f3276", + "sha256:40eb8af662ba409c3cbf4a8150ad32ae73514cd7cb1f1a2113af39763dd616b3", + "sha256:41d698dcbe12b60661f0632b543dbb119e6ba088103b364ff65e951610cb7ce0", + "sha256:4726f1f3f42d6a25678c67da3f0b10f148f5655813c5aca54b0d1742ba821b8f", + "sha256:4927564be53239a87770a5f86bdc272b8d1fbb87ab7783ad70255b4ab01aa25b", + "sha256:4b6d77c75a57f041c5ee915ff0b0bb58eabb78728b69ed967bc5b780e8f701b8", + "sha256:4d9149e7528af8bbd76cc055967e6e04617dcb2a2afdaa3dea899406c5521faa", + "sha256:4deac83a8cc1d09e40683be0bc6d1fa4cde8df0a9bf0cda5693f9b0569ac01b6", + "sha256:4f1ab031feb8676f6bd7c85abec86e2935850bf19b84432c64e3e239bffeb1ec", + "sha256:502ed542e0d958bd12e7c3e9a015bce57deaf50eaa8c2e1c439b512cb9db1e3a", + "sha256:5461934e895968655225dfa8b3be79e7e927e95d4bd6c2d40edd2fa7052e71b6", + "sha256:58c1151827eef98b83d49b6ca6065575876a02d2211f259fb1a6b7757bd24dd8", + "sha256:5bdd36b362f419c78d09630cbaebc64913f66f62bda6d42d5fbb08da8cc4f181", + "sha256:5bf637300ff35d4f59c006fff201c510b2b5e745b07125458a5389af3c0dff8c", + "sha256:5bf68bb859799e9cec3d9dd8323c40c00a254aabb56fe08f907e437005932f2b", + "sha256:5d8dc9f63a26f7259b57f46a7aab5af86b2ad6fbe48487500bb1f4b27e051e4c", + "sha256:5f36afd0d56a6c42cf4e8465b6441cf546ed69d3a4ec92724cc9c8c61bd6ecf4", + "sha256:5f72914cfd1d0176e58ddc05c7a47674ef4222c8253bf70322923e73e14a4ac3", + "sha256:6291797cad239285275558e0a27872da735b05c75d5237bbade8736f80e4c225", + "sha256:62c151ce3d59ed56ebd7ce9ce5986a409a85db697d25fc232f8e81f195aa39a1", + "sha256:635702b2fed997e0ac256b2cfbdb4dd0bf7c56b5d8fba8ef03489c03b3eb40e2", + "sha256:64672fa888595a959cfeff957a654e947e65bbe1d7d82f550417cbd6898a1d6b", + "sha256:68504959253303d3ae9406b634997a2123a0b0c1da86459abbd0ffc921695eac", + "sha256:69297418ad644d521ea3e1aa2e14a2a422726167e9ad22b89e8f1130d68e1e9a", + "sha256:6c32a40712e3662bebe524abe8abb757f2fa2000028d64cc5a1006016c06af43", + "sha256:715c62af74c236bf386825c0fdfa08d092ab0f191eb5b4580d11c3189af9d330", + "sha256:71dffba8fe9ddff628c68f3abd845e91b028361d43c5f8e7b3f8b91d7d85413e", + "sha256:7419241e17c7fbe5074ba79143d5523270e04f86f1b3a0dff8df490f84c8273a", + "sha256:759871f00e26ad3709efc773ac37b4d571de065f9dfb1778012908bcc36b3a73", + "sha256:7a25493320203005d2a4dac76d1b7d953cb49bce6d459d9ae38e30dd9f29bc9c", + "sha256:7b79af799630af263eca9ec87db519426d8c9b3be35016eddad1832bac812d87", + "sha256:7c9c84749f5787781c1c45bb99f433402e484e515b40675a5d121ea14711cf61", + "sha256:7da333f21cd9df51d5731513a6d39319892947604924ddf2e24a4612975fb936", + "sha256:82a4eba92b7ca8af1b7d5ef5f3d9647eee94d1f74d21ca7c21e3a2b92e008358", + "sha256:89670d7a0045acb52be0566df5bc8b114ac967c662c06cf5e0c606e4aadc964b", + "sha256:8a1d581e8cdbb857b0e0e81df98603376c1a5c34dc5e54039dcc00f043df81e7", + "sha256:8ec86b5baa36f0a0bfb37db86c7d52652f8e8aa076ab745ef7725784183c3fdd", + "sha256:91301a0980a1d4530d4ba7e6a739ca1a6b31341252cb709948e0aca0860ce0ae", + "sha256:918f2013d7eadea1d88d1a35fd4a1e16aaf90343eb446f91cb091ce7f9b431a2", + "sha256:9cb2390355ba084c1ad49485d18449b4242da344dea3e0fe10babd1f0db7dcfc", + "sha256:9ee65f0cc652261744fd07f2c6e6901c914aa6c5ff4dcfaf1136bc394d0dd26b", + "sha256:a608a75846804271cf9c83e40bbb4dab2ac614d33c6fd5b0c6187f53f5c593ef", + "sha256:a66d931ea2c1464b738ace44b7334ab32a2fd50be023d863935eb00f42be1778", + "sha256:a7a7f2a3f628d2f7ef11cb6188bcf0b9e1558151d511b974dfea10a49afe192b", + "sha256:abaeec1be6ed535a5d7ffc2e6c390083c425832b20efd621562fbb5bff6dc518", + "sha256:abfa44cf2f7f7d7a199be6c6ec141c9024063205545aa09304349781b9a125e6", + "sha256:ade5dbcf8d9ef8f4b28e682d0b29f3008df9842bb5ac48ac2c17bc55771cc976", + "sha256:ae62032ef513fe6281ef0009e30838a01057b832dc265da32c10469622613885", + "sha256:aec79acc183865bad120b0190afac467c20b15289050648b876b07777e67ea48", + "sha256:b716294e721d8060908dbebe32639b01bfe61b15f9f57bcc18ca9a0e00d9520b", + "sha256:b9ec80eb5a5f45a2211793f1c4aeddff0c3761d1c70d684965c1807e923a588b", + "sha256:ba95691cf25f63df53c1d342413b41bd7762d9acb425df8858d7efa616c0870e", + "sha256:bccc06fa0372151f37f6b69834181aa9eb57cf8665ed36405fb45fbf6cac3bae", + "sha256:c860773a0f205926172c6644c394e02c25421dc9a456deff16f64c0e299487d3", + "sha256:ca1103d70306489e3d006b0f79db8ca5dd3c977f6f13b2c59ff745249431a606", + "sha256:ce72d46eb201ca43994303025bd54d8a35a3fc2a3495fac653d6eb7205ce04f4", + "sha256:d20cbb9d3e95114325780f3cfe990f3ecae24de7a2d75f978783878cce2ad585", + "sha256:dcfebee69cd5e1c0b76a17e17e347c84b00acebb8dd8edb22d4a03e88e82a207", + "sha256:e1c69aa459f5609dec2fa0652d495353accf3eda5bdb18782bc5a2ae45c9273a", + "sha256:e2762c568596332fdab56b07060c8ab8362c56cf2a339ee54e491cd503612c50", + "sha256:e37f10f6d4bc67c58fbd727108ae1d8b92b397355e68519f1e4a7babb1473442", + "sha256:e790954b5093dff1e3a9a2523fddc4e79722d6f07993b4cd5547825c3cbf97b5", + "sha256:e81a295adccf73477220e15ff79235ca9dcbcee4be459eb9d4ce9a2763b8386c", + "sha256:e925819a98318d17251776bd3d6aa9f3ff77b965762155bdad15d1a9265c4cfd", + "sha256:ea30239c148b6ef41364c6f51d103c2988965b643d62e10b233b5efdca8c0099", + "sha256:eabf946a4739b5237f4f56d77fa6668263bc466d06a8036c055587c130a46f7b", + "sha256:ecb158fb9b9091b515213bed3061eb7deb1d3b4e02327c27a0ea714ff46b0760", + "sha256:ecc6d02d69b54a2eb83ebcc6f29df04957f734bcf309d346b4f83354d8376862", + "sha256:eddb18a00bbb855325db27b4c2a89a4ba491cd6a0bd6d852b225172a1f54b36c", + "sha256:f00e8b59e1fc8f09d05594aa7d2b726f1b277ca6155fc84c0396db1b373c4555", + "sha256:f1fb026c575e16f673c61c7b86144517705865173f3d0907040ac30c4f9f5915", + "sha256:f200b2f20856b5a6c3a35f0d4e344019f805e363416e609e9b47c552d35fd5ea", + "sha256:f225f3a3995dbbc26affc191d0443c6c4aa71b83358fd4c2b7d63e2f6f0336f9", + "sha256:f22dab23cdbce2005f26a8f0c71698457861f97fc6318c75814a50c75e87d025", + "sha256:f3eb479354c62067afa62f53bb387827bee2f75c9c79ef25eef6ab84d4b1ae3b", + "sha256:fc53e05c16697ff0c1c7c2b98e45e131d4bfb78068fffff92a82d169cbb4c7b7", + "sha256:ff48a55be9da6930254565ff5238d71d5e9cd8c5487a191cb85df3bdb8c77365" ], - "markers": "python_version >= '3.8'", - "version": "==2.27.2" + "markers": "python_version >= '3.9'", + "version": "==2.33.0" }, "pyjwt": { "hashes": [ @@ -1250,11 +1376,11 @@ }, "pyparsing": { "hashes": [ - "sha256:506ff4f4386c4cec0590ec19e6302d3aedb992fdc02c761e90416f158dacf8e1", - "sha256:61980854fd66de3a90028d679a954d5f2623e83144b5afe5ee86f43d762e5f0a" + "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf", + "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be" ], "markers": "python_version >= '3.9'", - "version": "==3.2.1" + "version": "==3.2.3" }, "pytest": { "hashes": [ @@ -1275,19 +1401,19 @@ }, "python-dotenv": { "hashes": [ - "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", - "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" + "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5", + "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d" ], "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==1.0.1" + "markers": "python_version >= '3.9'", + "version": "==1.1.0" }, "pytz": { "hashes": [ - "sha256:89dd22dca55b46eac6eda23b2d72721bf1bdfef212645d81513ef5d03038de57", - "sha256:c2db42be2a2518b28e65f9207c4d05e6ff547d1efa4086469ef855e4ab70178e" + "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", + "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00" ], - "version": "==2025.1" + "version": "==2025.2" }, "pyyaml": { "hashes": [ @@ -1348,14 +1474,115 @@ "markers": "python_version >= '3.8'", "version": "==6.0.2" }, + "qh3": { + "hashes": [ + "sha256:0107f576a0524421e1b0f9e0437d2881a1835b1b6105eadd7ea0c1c9bf2da917", + "sha256:06159707895c606a321ccb5630347a2d2a44ee584f22945e5b22b0ad34f21ec8", + "sha256:06255835f99ea1af9e5d358056011686fcccbafaba893454027daa62ab6f701f", + "sha256:09b2305a954e61a9ed8b46a7a45f54e8d95ef870a47d5fd1836e14c7600d3b92", + "sha256:0a51dcffae03a89ddbab1884860569e0d1dbbf95deee47457c1fd29b4ac8d220", + "sha256:0a5d1cd881b7d43481ad60262cf3390a555e0e51751bc2af70ba4a612487e797", + "sha256:0e1c273660f9b8511c22d0b082137556e46d6a7eccf132bd82f95d29f90488b2", + "sha256:0e540cc7e7da65da30381bdb73a789a8635c6aaef98688d904eee3bc587654a5", + "sha256:10ed818f47dc522350a12641e8f2bea19ff824f8ce373c23a8e594b3481fd7a4", + "sha256:195b4ad58cf5a8da218e2368d34f47628c14581f3cc9863fc0406b32e137f3a6", + "sha256:1a80d07249c7ccbaa57bb9015b5ead0ead7ac1940cd5483548dfe56db99ce7a4", + "sha256:1cf0b18823801078d2294a0356abc2be34b4a224bea863a87029c1c97d6c34e0", + "sha256:1fac2ab4b8a2e50894b54a19416cd363defe0fb33f52754686ea58999f98dfc5", + "sha256:205cdaea9da8881b31b76eb6da5b88c9558ba96bc16a3ecf11333098ac7f3859", + "sha256:2294e78bcc40728a3a772df0f8ecf8b8756616d06dd001029016876aa4e5c9de", + "sha256:235236ab195d34e7cd18d186e46b7a4f8aceafe246bf36b42913f72627ded414", + "sha256:25eef1f2be50d79d23e01a567c719e46e4892518a5ccc96685fcb4746357320b", + "sha256:2ae147b756c3adf59699756feb9e07d4a69674f57b4e13d6c25f9d1dc3c8707c", + "sha256:2c9cdd7ea49c79b671e7de35dad61d2aa91920e2498d0c6dfa932d5e05070a5e", + "sha256:2dc9f269d7316b0a44e61ae7a11ffd8daa800b3f5ba773de2e9d8c4ee636a896", + "sha256:2f94d69edb0070ef4ec414deabfc2369aa2100b11bf4a4f2f393f2c28c4bc7ba", + "sha256:311da331e31c55afc3f4f4f2ba9d07a1d700ffb7db5aa4f58300b9f56f2523dc", + "sha256:3578844a9ff4c342a409d010f909782afc52a31680876f7fab65bf133aa3f4db", + "sha256:4032c2898b4c0ff7a25cf7d68c3b1f2abdcaf4f25cc8b6802a941a842f9a95b6", + "sha256:40abd150eddfa0884c139bd281e87ff920d4cd52d685fc4ef25ddcc77ff7a220", + "sha256:43e32602651d07f8a0860ba0a45d8c8fe9ccd537030e7632d1258f7b84881416", + "sha256:45a21d25fe17168f4db09fcaabee5dd171763ad1bd8753c257297837f5ba9197", + "sha256:45bfbb126e31ecf63ef74c249d38d07e149c0663b4a191cf9e2e3445a80758d5", + "sha256:4745667c9956bcfd74ff677edd4c73d6cb578b6b47c5fb3d246aaa223dd6a004", + "sha256:4936a5d8915866b4f08ab18018f41ed93a2593788ad0a80796aada2e23d402e5", + "sha256:4a45a9698b3bcae05f91356f50df8dab3c3fdef3187548b9c4a396a6eb6760b5", + "sha256:4b84c1ca283278e2e22a3b9e2ce8ea55c0a1797d6e86255640a1b6293fe18b2a", + "sha256:4dc88397ed7f3b46f542f87e19050a7f82267225009ce65651ac44cb55b204b1", + "sha256:4e10a872077373c71d7938fb1a7ae0561f2e79aad2b1b5323dbb6325a389041a", + "sha256:4f1b5dcb4d9da5b441e0b14216b816be7b5b5d080c2ccb957adf84266411ff6b", + "sha256:50d25182d598312197f500a65acebf5430391764e6ffcdb73d96e80c5dd06fc7", + "sha256:529c5b9e27fced27befce26e2699eca3110c576f6427dfbd26e30b7666b2d6d1", + "sha256:571da625b22e953731307539b44b2177f6ab13b6142d7698c0f28b9379ae1be6", + "sha256:5a9de89e2480b385a99613798d375e69a0a53d4575bd74b133307c8e83a84751", + "sha256:5bcc46cf89cb1036c2d029c01f360c82180329997a75728b20dc205f34114327", + "sha256:5dfa6238a6236f2bb3ecaac9befd23cee0bcbb9e497003fb3aef875e19325c61", + "sha256:6342b961b18037e3df8692e8914c576816a966bf29f913ee2728e7e838bde9bd", + "sha256:65e112c175a0b0328822dd0d19ead9ef1d7925359d154fb52e46b080945eef38", + "sha256:6f8a2b15c4dd58133e92f95d4312efd09b87ec15b881885629dff70e89f1e751", + "sha256:726f749444d1cc73c1bf221343dc6fdbde2541ffe30860d2d5ef6e310a1f5478", + "sha256:742f39cd807df31c21e035aec63f6f61e139a60545cffb16e8e87f61609d7cba", + "sha256:7840c18ec27aa08ecdd8ff23df348c124378c6f3edf9a0e02b16a5a4ce504c89", + "sha256:79d1de24d3c7345719af8333b64f19a8777dd50a059851bfcfa583c7109eddf2", + "sha256:7ba9303c5334d64b547483be92c4bbacd37964ff3abd0b1e8c82c63ec6f7b3ec", + "sha256:85587d9dfbd2f7f8622cf57f3c1a19cee441b5607a982cdf4c08ef38d45d5a36", + "sha256:8711b86e447e689d1b693419708b6ad64bf0c57091b94a3f65c6d4bd7cfb7d9a", + "sha256:877edc4db25309d86af07d992926394936f491cce84fce439961729552e942fe", + "sha256:8bb17669e362d3456bebd5c69abb0c26e8ab29c10894f123c715b0217aece479", + "sha256:8bb17a1e50e35a8d07cab784caea68b33f739391ccb5e3161afb9db0bde8faf4", + "sha256:8d4640a6bb3aa29797bdcf0c5bae4e86da5f2fbf84b67a7fad549fa34c19aa98", + "sha256:90697f3d9e4b3ddccfb31b40637bac6d44b39288cd57f78e51ff13e70916eccc", + "sha256:90f127f57c00b111ea3ffd95f4c12ad83efebd10310fd718d66771dd64e568f1", + "sha256:95f8f70bca1e880da7559ef38b7f1778a3b39b586fc829b8a7e989e912aa988f", + "sha256:9a60c102a01dfa8c5d737499c9a5d5e7c2b6642009c9b80b27f228ec50ce6fb0", + "sha256:9c7f1821ec749ea29bd9d079e4f13a552371731d0b664962a60cbb2f31d571b5", + "sha256:9f81ee66fadedbfd4d5c49e64151db3b6f353b041ddf5ab0b151340a4467e038", + "sha256:9f8e530e29e1afe9231b1100645aa5cc240b823c0e4162f70046270a3559400c", + "sha256:a0c647db3f156e8c94a63c1fa0fc4f2ce8b70f0eb12f2726e6c19493198b1e99", + "sha256:a0cda60607ab4ffc14fa8425ea7c9ae78ad60923c3c8be94d19c14f83198b1cf", + "sha256:a5bff397d49da302b5afbdf244dd7ca480a827f5de856d957df05dfd7e73b490", + "sha256:a94bd391b955b24948b2986845f9c6ad8abc709c2d57d0515daeacf16a2a3a4c", + "sha256:ad4572bd37c1a6a7a12ff47da4f3578a13e3c8ee85a1f02d2435dfdc6d9ed394", + "sha256:b13b7de1686f1b5da7526dc4f0de410a685f5cb654e984b09ddd8d14be6fffc0", + "sha256:b1724c43c5c0d08b68c3407467e07794b9adf153b6de8300d61883e8d95fa640", + "sha256:b27d29cb718df9ed006f8c75a89dd90534437761b2477dc7a4145bde0daa60fc", + "sha256:b3afa3a78b0f011ff5a09dea37d74fcea9269b318d2828f18b2fbf9dde625a71", + "sha256:bd6a61007e678284178bb00931af59f686a2a55797505e0886241050ec5c243c", + "sha256:befeca45fd7787c08a3286fb72caaccfa4c3962760981dfeb0992f5ba9be5cb2", + "sha256:c2d31b8233f406e00f180e221986f436765c3bb06839e72c898feca31fef1d4e", + "sha256:c3e2518ce442b70314892a594e21157deb13fbc436f77ad6555439cfd9912035", + "sha256:c8d5fbee607db24ef6c7b0bd08c21226d10782df4149b9d6f1f1516c7c85092b", + "sha256:cc2cc804998e852bdffcc87e8d008043ffa85efe6d3516d9784714d709f14774", + "sha256:cd8a681107c6118f60a0714671cec7b301533f25984a5c898e547a33a01af75c", + "sha256:d056831ebf3fa8116672ae970ad19a9f5f1427a2217cd0e01c1eaac5f8222668", + "sha256:d5ac3e8e3f66ff88819205dbc67e6f771cbb80529325ca9f3bc03fa00c5c83aa", + "sha256:dba15ca2da7859300ae79d2ea2eb8bb0eb827b93a2f104981783add16a97058a", + "sha256:de6cabb89248b60ea9bb9d7848de78dfb824abfdc15f52448a8efe821dd7d559", + "sha256:e02f6d1cc2005b847176dd8770fdfe90f04a34a3f094b79a8369bde0aa8f6a04", + "sha256:e514bd4b27c953c46485b2be0ecd2421aa196c5a0cd7d67f1ccec16a56b00507", + "sha256:e53464124379764f982a69f5ab34d0d5c527e8ac1e788db86a25f79045e5b18d", + "sha256:e9cf59660a543bef86de457c671c1d78ad2d88c53bb9eb3fce6ce0cb9729d490", + "sha256:edfc1bc732bc5e62fdaea268a541eb442d5e04927cb27dfd8e92ef07213658d2", + "sha256:ee8e7a66be70a18f5e0558f2f6a89e39c608f87b027234848f76a6699975dcf8", + "sha256:effb7072efef7dca10a98c24be0cc882a40edc78e293b41f5b6dc7f1952215ed", + "sha256:f04e4ee7e3c123ac7f21cee6f819cfa9b5a376e656257dfa7a4d133b3590bdd9", + "sha256:f0531c7abe963affebd3fb6cf9ea87eb8c63a0240535d81d0223945bd41be254", + "sha256:f5afd1c216315682a6bbf606618de0e3817ed8eeafc27ad7660ef2f581d4fd46", + "sha256:f93d3c74e00268ac6042c080653a34d0f0e8903697fd8dc480c1e3de81c90faf", + "sha256:fbc4e6452cc48c3e1398fe930349e2ec9ad76a2c00e729f3e797700c2f0646e6", + "sha256:fc73fc2889a01a43737c7a7c7fb9ee13aa56065b22abbed0e787cc58a3747808" + ], + "markers": "python_version >= '3.7'", + "version": "==1.4.2" + }, "rdflib": { "hashes": [ - "sha256:5402310a9f0f3c07d453d73fd0ad6ba35616286fe95d3670db2b725f3f539673", - "sha256:f3dcb4c106a8cd9e060d92f43d593d09ebc3d07adc244f4c7315856a12e383ee" + "sha256:72f4adb1990fa5241abd22ddaf36d7cafa5d91d9ff2ba13f3086d339b213d997", + "sha256:fed46e24f26a788e2ab8e445f7077f00edcf95abb73bcef4b86cefa8b62dd174" ], "index": "pypi", "markers": "python_full_version >= '3.8.1' and python_full_version < '4.0.0'", - "version": "==7.1.3" + "version": "==7.1.4" }, "referencing": { "hashes": [ @@ -1375,112 +1602,123 @@ }, "rpds-py": { "hashes": [ - "sha256:09cd7dbcb673eb60518231e02874df66ec1296c01a4fcd733875755c02014b19", - "sha256:0f3288930b947cbebe767f84cf618d2cbe0b13be476e749da0e6a009f986248c", - "sha256:0fced9fd4a07a1ded1bac7e961ddd9753dd5d8b755ba8e05acba54a21f5f1522", - "sha256:112b8774b0b4ee22368fec42749b94366bd9b536f8f74c3d4175d4395f5cbd31", - "sha256:11dd60b2ffddba85715d8a66bb39b95ddbe389ad2cfcf42c833f1bcde0878eaf", - "sha256:178f8a60fc24511c0eb756af741c476b87b610dba83270fce1e5a430204566a4", - "sha256:1b08027489ba8fedde72ddd233a5ea411b85a6ed78175f40285bd401bde7466d", - "sha256:1bf5be5ba34e19be579ae873da515a2836a2166d8d7ee43be6ff909eda42b72b", - "sha256:1ed7de3c86721b4e83ac440751329ec6a1102229aa18163f84c75b06b525ad7e", - "sha256:1eedaaccc9bb66581d4ae7c50e15856e335e57ef2734dbc5fd8ba3e2a4ab3cb6", - "sha256:243241c95174b5fb7204c04595852fe3943cc41f47aa14c3828bc18cd9d3b2d6", - "sha256:26bb3e8de93443d55e2e748e9fd87deb5f8075ca7bc0502cfc8be8687d69a2ec", - "sha256:271fa2184cf28bdded86bb6217c8e08d3a169fe0bbe9be5e8d96e8476b707122", - "sha256:28358c54fffadf0ae893f6c1050e8f8853e45df22483b7fff2f6ab6152f5d8bf", - "sha256:285019078537949cecd0190f3690a0b0125ff743d6a53dfeb7a4e6787af154f5", - "sha256:2893d778d4671ee627bac4037a075168b2673c57186fb1a57e993465dbd79a93", - "sha256:2a54027554ce9b129fc3d633c92fa33b30de9f08bc61b32c053dc9b537266fed", - "sha256:2c6ae11e6e93728d86aafc51ced98b1658a0080a7dd9417d24bfb955bb09c3c2", - "sha256:2cfa07c346a7ad07019c33fb9a63cf3acb1f5363c33bc73014e20d9fe8b01cdd", - "sha256:35d5631ce0af26318dba0ae0ac941c534453e42f569011585cb323b7774502a5", - "sha256:3614d280bf7aab0d3721b5ce0e73434acb90a2c993121b6e81a1c15c665298ac", - "sha256:3902df19540e9af4cc0c3ae75974c65d2c156b9257e91f5101a51f99136d834c", - "sha256:3aaf141d39f45322e44fc2c742e4b8b4098ead5317e5f884770c8df0c332da70", - "sha256:3d8abf7896a91fb97e7977d1aadfcc2c80415d6dc2f1d0fca5b8d0df247248f3", - "sha256:3e77febf227a1dc3220159355dba68faa13f8dca9335d97504abf428469fb18b", - "sha256:3e9212f52074fc9d72cf242a84063787ab8e21e0950d4d6709886fb62bcb91d5", - "sha256:3ee9d6f0b38efb22ad94c3b68ffebe4c47865cdf4b17f6806d6c674e1feb4246", - "sha256:4233df01a250b3984465faed12ad472f035b7cd5240ea3f7c76b7a7016084495", - "sha256:4263320ed887ed843f85beba67f8b2d1483b5947f2dc73a8b068924558bfeace", - "sha256:4ab923167cfd945abb9b51a407407cf19f5bee35001221f2911dc85ffd35ff4f", - "sha256:4caafd1a22e5eaa3732acb7672a497123354bef79a9d7ceed43387d25025e935", - "sha256:50fb62f8d8364978478b12d5f03bf028c6bc2af04082479299139dc26edf4c64", - "sha256:55ff4151cfd4bc635e51cfb1c59ac9f7196b256b12e3a57deb9e5742e65941ad", - "sha256:5b98b6c953e5c2bda51ab4d5b4f172617d462eebc7f4bfdc7c7e6b423f6da957", - "sha256:5c9ff044eb07c8468594d12602291c635da292308c8c619244e30698e7fc455a", - "sha256:5e9c206a1abc27e0588cf8b7c8246e51f1a16a103734f7750830a1ccb63f557a", - "sha256:5fb89edee2fa237584e532fbf78f0ddd1e49a47c7c8cfa153ab4849dc72a35e6", - "sha256:633462ef7e61d839171bf206551d5ab42b30b71cac8f10a64a662536e057fdef", - "sha256:66f8d2a17e5838dd6fb9be6baaba8e75ae2f5fa6b6b755d597184bfcd3cb0eba", - "sha256:6959bb9928c5c999aba4a3f5a6799d571ddc2c59ff49917ecf55be2bbb4e3722", - "sha256:698a79d295626ee292d1730bc2ef6e70a3ab135b1d79ada8fde3ed0047b65a10", - "sha256:721f9c4011b443b6e84505fc00cc7aadc9d1743f1c988e4c89353e19c4a968ee", - "sha256:72e680c1518733b73c994361e4b06441b92e973ef7d9449feec72e8ee4f713da", - "sha256:75307599f0d25bf6937248e5ac4e3bde5ea72ae6618623b86146ccc7845ed00b", - "sha256:754fba3084b70162a6b91efceee8a3f06b19e43dac3f71841662053c0584209a", - "sha256:759462b2d0aa5a04be5b3e37fb8183615f47014ae6b116e17036b131985cb731", - "sha256:7938c7b0599a05246d704b3f5e01be91a93b411d0d6cc62275f025293b8a11ce", - "sha256:7b77e07233925bd33fc0022b8537774423e4c6680b6436316c5075e79b6384f4", - "sha256:7e5413d2e2d86025e73f05510ad23dad5950ab8417b7fc6beaad99be8077138b", - "sha256:7f3240dcfa14d198dba24b8b9cb3b108c06b68d45b7babd9eefc1038fdf7e707", - "sha256:7f9682a8f71acdf59fd554b82b1c12f517118ee72c0f3944eda461606dfe7eb9", - "sha256:8d67beb6002441faef8251c45e24994de32c4c8686f7356a1f601ad7c466f7c3", - "sha256:9441af1d25aed96901f97ad83d5c3e35e6cd21a25ca5e4916c82d7dd0490a4fa", - "sha256:98b257ae1e83f81fb947a363a274c4eb66640212516becaff7bef09a5dceacaa", - "sha256:9e9f3a3ac919406bc0414bbbd76c6af99253c507150191ea79fab42fdb35982a", - "sha256:a1c66e71ecfd2a4acf0e4bd75e7a3605afa8f9b28a3b497e4ba962719df2be57", - "sha256:a1e17d8dc8e57d8e0fd21f8f0f0a5211b3fa258b2e444c2053471ef93fe25a00", - "sha256:a20cb698c4a59c534c6701b1c24a968ff2768b18ea2991f886bd8985ce17a89f", - "sha256:a970bfaf130c29a679b1d0a6e0f867483cea455ab1535fb427566a475078f27f", - "sha256:a98f510d86f689fcb486dc59e6e363af04151e5260ad1bdddb5625c10f1e95f8", - "sha256:a9d3b728f5a5873d84cba997b9d617c6090ca5721caaa691f3b1a78c60adc057", - "sha256:ad76f44f70aac3a54ceb1813ca630c53415da3a24fd93c570b2dfb4856591017", - "sha256:ae28144c1daa61366205d32abd8c90372790ff79fc60c1a8ad7fd3c8553a600e", - "sha256:b03a8d50b137ee758e4c73638b10747b7c39988eb8e6cd11abb7084266455165", - "sha256:b5a96fcac2f18e5a0a23a75cd27ce2656c66c11c127b0318e508aab436b77428", - "sha256:b5ef909a37e9738d146519657a1aab4584018746a18f71c692f2f22168ece40c", - "sha256:b79f5ced71efd70414a9a80bbbfaa7160da307723166f09b69773153bf17c590", - "sha256:b91cceb5add79ee563bd1f70b30896bd63bc5f78a11c1f00a1e931729ca4f1f4", - "sha256:b92f5654157de1379c509b15acec9d12ecf6e3bc1996571b6cb82a4302060447", - "sha256:c04ca91dda8a61584165825907f5c967ca09e9c65fe8966ee753a3f2b019fe1e", - "sha256:c1f8afa346ccd59e4e5630d5abb67aba6a9812fddf764fd7eb11f382a345f8cc", - "sha256:c5334a71f7dc1160382d45997e29f2637c02f8a26af41073189d79b95d3321f1", - "sha256:c617d7453a80e29d9973b926983b1e700a9377dbe021faa36041c78537d7b08c", - "sha256:c632419c3870507ca20a37c8f8f5352317aca097639e524ad129f58c125c61c6", - "sha256:c6760211eee3a76316cf328f5a8bd695b47b1626d21c8a27fb3b2473a884d597", - "sha256:c698d123ce5d8f2d0cd17f73336615f6a2e3bdcedac07a1291bb4d8e7d82a05a", - "sha256:c76b32eb2ab650a29e423525e84eb197c45504b1c1e6e17b6cc91fcfeb1a4b1d", - "sha256:c8f7e90b948dc9dcfff8003f1ea3af08b29c062f681c05fd798e36daa3f7e3e8", - "sha256:c9e799dac1ffbe7b10c1fd42fe4cd51371a549c6e108249bde9cd1200e8f59b4", - "sha256:cafa48f2133d4daa028473ede7d81cd1b9f9e6925e9e4003ebdf77010ee02f35", - "sha256:ce473a2351c018b06dd8d30d5da8ab5a0831056cc53b2006e2a8028172c37ce5", - "sha256:d31ed4987d72aabdf521eddfb6a72988703c091cfc0064330b9e5f8d6a042ff5", - "sha256:d550d7e9e7d8676b183b37d65b5cd8de13676a738973d330b59dc8312df9c5dc", - "sha256:d6adb81564af0cd428910f83fa7da46ce9ad47c56c0b22b50872bc4515d91966", - "sha256:d6f6512a90bd5cd9030a6237f5346f046c6f0e40af98657568fa45695d4de59d", - "sha256:d7031d493c4465dbc8d40bd6cafefef4bd472b17db0ab94c53e7909ee781b9ef", - "sha256:d9f75a06ecc68f159d5d7603b734e1ff6daa9497a929150f794013aa9f6e3f12", - "sha256:db7707dde9143a67b8812c7e66aeb2d843fe33cc8e374170f4d2c50bd8f2472d", - "sha256:e0397dd0b3955c61ef9b22838144aa4bef6f0796ba5cc8edfc64d468b93798b4", - "sha256:e0df046f2266e8586cf09d00588302a32923eb6386ced0ca5c9deade6af9a149", - "sha256:e14f86b871ea74c3fddc9a40e947d6a5d09def5adc2076ee61fb910a9014fb35", - "sha256:e5963ea87f88bddf7edd59644a35a0feecf75f8985430124c253612d4f7d27ae", - "sha256:e768267cbe051dd8d1c5305ba690bb153204a09bf2e3de3ae530de955f5b5580", - "sha256:e9cb79ecedfc156c0692257ac7ed415243b6c35dd969baa461a6888fc79f2f07", - "sha256:ed6f011bedca8585787e5082cce081bac3d30f54520097b2411351b3574e1219", - "sha256:f3429fb8e15b20961efca8c8b21432623d85db2228cc73fe22756c6637aa39e7", - "sha256:f35eff113ad430b5272bbfc18ba111c66ff525828f24898b4e146eb479a2cdda", - "sha256:f3a6cb95074777f1ecda2ca4fa7717caa9ee6e534f42b7575a8f0d4cb0c24013", - "sha256:f7356a6da0562190558c4fcc14f0281db191cdf4cb96e7604c06acfcee96df15", - "sha256:f88626e3f5e57432e6191cd0c5d6d6b319b635e70b40be2ffba713053e5147dd", - "sha256:fad784a31869747df4ac968a351e070c06ca377549e4ace94775aaa3ab33ee06", - "sha256:fc869af5cba24d45fb0399b0cfdbcefcf6910bf4dee5d74036a57cf5264b3ff4", - "sha256:fee513135b5a58f3bb6d89e48326cd5aa308e4bcdf2f7d59f67c861ada482bf8" + "sha256:0047638c3aa0dbcd0ab99ed1e549bbf0e142c9ecc173b6492868432d8989a046", + "sha256:006f4342fe729a368c6df36578d7a348c7c716be1da0a1a0f86e3021f8e98724", + "sha256:041f00419e1da7a03c46042453598479f45be3d787eb837af382bfc169c0db33", + "sha256:04ecf5c1ff4d589987b4d9882872f80ba13da7d42427234fce8f22efb43133bc", + "sha256:04f2b712a2206e13800a8136b07aaedc23af3facab84918e7aa89e4be0260032", + "sha256:0aeb3329c1721c43c58cae274d7d2ca85c1690d89485d9c63a006cb79a85771a", + "sha256:0e374c0ce0ca82e5b67cd61fb964077d40ec177dd2c4eda67dba130de09085c7", + "sha256:0f00c16e089282ad68a3820fd0c831c35d3194b7cdc31d6e469511d9bffc535c", + "sha256:174e46569968ddbbeb8a806d9922f17cd2b524aa753b468f35b97ff9c19cb718", + "sha256:1b221c2457d92a1fb3c97bee9095c874144d196f47c038462ae6e4a14436f7bc", + "sha256:208b3a70a98cf3710e97cabdc308a51cd4f28aa6e7bb11de3d56cd8b74bab98d", + "sha256:20f2712bd1cc26a3cc16c5a1bfee9ed1abc33d4cdf1aabd297fe0eb724df4272", + "sha256:24795c099453e3721fda5d8ddd45f5dfcc8e5a547ce7b8e9da06fecc3832e26f", + "sha256:2a0f156e9509cee987283abd2296ec816225145a13ed0391df8f71bf1d789e2d", + "sha256:2b2356688e5d958c4d5cb964af865bea84db29971d3e563fb78e46e20fe1848b", + "sha256:2c13777ecdbbba2077670285dd1fe50828c8742f6a4119dbef6f83ea13ad10fb", + "sha256:2d3ee4615df36ab8eb16c2507b11e764dcc11fd350bbf4da16d09cda11fcedef", + "sha256:2d53747da70a4e4b17f559569d5f9506420966083a31c5fbd84e764461c4444b", + "sha256:32bab0a56eac685828e00cc2f5d1200c548f8bc11f2e44abf311d6b548ce2e45", + "sha256:34d90ad8c045df9a4259c47d2e16a3f21fdb396665c94520dbfe8766e62187a4", + "sha256:369d9c6d4c714e36d4a03957b4783217a3ccd1e222cdd67d464a3a479fc17796", + "sha256:3a55fc10fdcbf1a4bd3c018eea422c52cf08700cf99c28b5cb10fe97ab77a0d3", + "sha256:3d2d8e4508e15fc05b31285c4b00ddf2e0eb94259c2dc896771966a163122a0c", + "sha256:3fab5f4a2c64a8fb64fc13b3d139848817a64d467dd6ed60dcdd6b479e7febc9", + "sha256:43dba99f00f1d37b2a0265a259592d05fcc8e7c19d140fe51c6e6f16faabeb1f", + "sha256:44d51febb7a114293ffd56c6cf4736cb31cd68c0fddd6aa303ed09ea5a48e029", + "sha256:493fe54318bed7d124ce272fc36adbf59d46729659b2c792e87c3b95649cdee9", + "sha256:4b28e5122829181de1898c2c97f81c0b3246d49f585f22743a1246420bb8d399", + "sha256:4cd031e63bc5f05bdcda120646a0d32f6d729486d0067f09d79c8db5368f4586", + "sha256:528927e63a70b4d5f3f5ccc1fa988a35456eb5d15f804d276709c33fc2f19bda", + "sha256:564c96b6076a98215af52f55efa90d8419cc2ef45d99e314fddefe816bc24f91", + "sha256:5db385bacd0c43f24be92b60c857cf760b7f10d8234f4bd4be67b5b20a7c0b6b", + "sha256:5ef877fa3bbfb40b388a5ae1cb00636a624690dcb9a29a65267054c9ea86d88a", + "sha256:5f6e3cec44ba05ee5cbdebe92d052f69b63ae792e7d05f1020ac5e964394080c", + "sha256:5fc13b44de6419d1e7a7e592a4885b323fbc2f46e1f22151e3a8ed3b8b920405", + "sha256:60748789e028d2a46fc1c70750454f83c6bdd0d05db50f5ae83e2db500b34da5", + "sha256:60d9b630c8025b9458a9d114e3af579a2c54bd32df601c4581bd054e85258143", + "sha256:619ca56a5468f933d940e1bf431c6f4e13bef8e688698b067ae68eb4f9b30e3a", + "sha256:630d3d8ea77eabd6cbcd2ea712e1c5cecb5b558d39547ac988351195db433f6c", + "sha256:63981feca3f110ed132fd217bf7768ee8ed738a55549883628ee3da75bb9cb78", + "sha256:66420986c9afff67ef0c5d1e4cdc2d0e5262f53ad11e4f90e5e22448df485bf0", + "sha256:675269d407a257b8c00a6b58205b72eec8231656506c56fd429d924ca00bb350", + "sha256:6a4a535013aeeef13c5532f802708cecae8d66c282babb5cd916379b72110cf7", + "sha256:6a727fd083009bc83eb83d6950f0c32b3c94c8b80a9b667c87f4bd1274ca30ba", + "sha256:6e1daf5bf6c2be39654beae83ee6b9a12347cb5aced9a29eecf12a2d25fff664", + "sha256:6eea559077d29486c68218178ea946263b87f1c41ae7f996b1f30a983c476a5a", + "sha256:75a810b7664c17f24bf2ffd7f92416c00ec84b49bb68e6a0d93e542406336b56", + "sha256:772cc1b2cd963e7e17e6cc55fe0371fb9c704d63e44cacec7b9b7f523b78919e", + "sha256:78884d155fd15d9f64f5d6124b486f3d3f7fd7cd71a78e9670a0f6f6ca06fb2d", + "sha256:79e8d804c2ccd618417e96720ad5cd076a86fa3f8cb310ea386a3e6229bae7d1", + "sha256:7e80d375134ddb04231a53800503752093dbb65dad8dabacce2c84cccc78e964", + "sha256:8097b3422d020ff1c44effc40ae58e67d93e60d540a65649d2cdaf9466030791", + "sha256:8205ee14463248d3349131bb8099efe15cd3ce83b8ef3ace63c7e976998e7124", + "sha256:8212ff58ac6dfde49946bea57474a386cca3f7706fc72c25b772b9ca4af6b79e", + "sha256:823e74ab6fbaa028ec89615ff6acb409e90ff45580c45920d4dfdddb069f2120", + "sha256:84e0566f15cf4d769dade9b366b7b87c959be472c92dffb70462dd0844d7cbad", + "sha256:896c41007931217a343eff197c34513c154267636c8056fb409eafd494c3dcdc", + "sha256:8aa362811ccdc1f8dadcc916c6d47e554169ab79559319ae9fae7d7752d0d60c", + "sha256:8b3b397eefecec8e8e39fa65c630ef70a24b09141a6f9fc17b3c3a50bed6b50e", + "sha256:8ebc7e65ca4b111d928b669713865f021b7773350eeac4a31d3e70144297baba", + "sha256:9168764133fd919f8dcca2ead66de0105f4ef5659cbb4fa044f7014bed9a1797", + "sha256:921ae54f9ecba3b6325df425cf72c074cd469dea843fb5743a26ca7fb2ccb149", + "sha256:92558d37d872e808944c3c96d0423b8604879a3d1c86fdad508d7ed91ea547d5", + "sha256:951cc481c0c395c4a08639a469d53b7d4afa252529a085418b82a6b43c45c240", + "sha256:998c01b8e71cf051c28f5d6f1187abbdf5cf45fc0efce5da6c06447cba997034", + "sha256:9abc80fe8c1f87218db116016de575a7998ab1629078c90840e8d11ab423ee25", + "sha256:9be4f99bee42ac107870c61dfdb294d912bf81c3c6d45538aad7aecab468b6b7", + "sha256:9c39438c55983d48f4bb3487734d040e22dad200dab22c41e331cee145e7a50d", + "sha256:9d7e8ce990ae17dda686f7e82fd41a055c668e13ddcf058e7fb5e9da20b57793", + "sha256:9ea7f4174d2e4194289cb0c4e172d83e79a6404297ff95f2875cf9ac9bced8ba", + "sha256:a18fc371e900a21d7392517c6f60fe859e802547309e94313cd8181ad9db004d", + "sha256:a36b452abbf29f68527cf52e181fced56685731c86b52e852053e38d8b60bc8d", + "sha256:a5b66d1b201cc71bc3081bc2f1fc36b0c1f268b773e03bbc39066651b9e18391", + "sha256:a824d2c7a703ba6daaca848f9c3d5cb93af0505be505de70e7e66829affd676e", + "sha256:a88c0d17d039333a41d9bf4616bd062f0bd7aa0edeb6cafe00a2fc2a804e944f", + "sha256:aa6800adc8204ce898c8a424303969b7aa6a5e4ad2789c13f8648739830323b7", + "sha256:aad911555286884be1e427ef0dc0ba3929e6821cbeca2194b13dc415a462c7fd", + "sha256:afc6e35f344490faa8276b5f2f7cbf71f88bc2cda4328e00553bd451728c571f", + "sha256:b9a4df06c35465ef4d81799999bba810c68d29972bf1c31db61bfdb81dd9d5bb", + "sha256:bb2954155bb8f63bb19d56d80e5e5320b61d71084617ed89efedb861a684baea", + "sha256:bbc4362e06f950c62cad3d4abf1191021b2ffaf0b31ac230fbf0526453eee75e", + "sha256:c0145295ca415668420ad142ee42189f78d27af806fcf1f32a18e51d47dd2052", + "sha256:c30ff468163a48535ee7e9bf21bd14c7a81147c0e58a36c1078289a8ca7af0bd", + "sha256:c347a20d79cedc0a7bd51c4d4b7dbc613ca4e65a756b5c3e57ec84bd43505b47", + "sha256:c43583ea8517ed2e780a345dd9960896afc1327e8cf3ac8239c167530397440d", + "sha256:c61a2cb0085c8783906b2f8b1f16a7e65777823c7f4d0a6aaffe26dc0d358dd9", + "sha256:c9ca89938dff18828a328af41ffdf3902405a19f4131c88e22e776a8e228c5a8", + "sha256:cc31e13ce212e14a539d430428cd365e74f8b2d534f8bc22dd4c9c55b277b875", + "sha256:cdabcd3beb2a6dca7027007473d8ef1c3b053347c76f685f5f060a00327b8b65", + "sha256:cf86f72d705fc2ef776bb7dd9e5fbba79d7e1f3e258bf9377f8204ad0fc1c51e", + "sha256:d09dc82af2d3c17e7dd17120b202a79b578d79f2b5424bda209d9966efeed114", + "sha256:d3aa13bdf38630da298f2e0d77aca967b200b8cc1473ea05248f6c5e9c9bdb44", + "sha256:d69d003296df4840bd445a5d15fa5b6ff6ac40496f956a221c4d1f6f7b4bc4d9", + "sha256:d6e109a454412ab82979c5b1b3aee0604eca4bbf9a02693bb9df027af2bfa91a", + "sha256:d8551e733626afec514b5d15befabea0dd70a343a9f23322860c4f16a9430205", + "sha256:d8754d872a5dfc3c5bf9c0e059e8107451364a30d9fd50f1f1a85c4fb9481164", + "sha256:d8f9a6e7fd5434817526815f09ea27f2746c4a51ee11bb3439065f5fc754db58", + "sha256:dbcbb6db5582ea33ce46a5d20a5793134b5365110d84df4e30b9d37c6fd40ad3", + "sha256:e0f3ef95795efcd3b2ec3fe0a5bcfb5dadf5e3996ea2117427e524d4fbf309c6", + "sha256:e13ae74a8a3a0c2f22f450f773e35f893484fcfacb00bb4344a7e0f4f48e1f97", + "sha256:e274f62cbd274359eff63e5c7e7274c913e8e09620f6a57aae66744b3df046d6", + "sha256:e838bf2bb0b91ee67bf2b889a1a841e5ecac06dd7a2b1ef4e6151e2ce155c7ae", + "sha256:e8acd55bd5b071156bae57b555f5d33697998752673b9de554dd82f5b5352727", + "sha256:e8e5ab32cf9eb3647450bc74eb201b27c185d3857276162c101c0f8c6374e098", + "sha256:ebcb786b9ff30b994d5969213a8430cbb984cdd7ea9fd6df06663194bd3c450c", + "sha256:ebea2821cdb5f9fef44933617be76185b80150632736f3d76e54829ab4a3b4d1", + "sha256:ed0ef550042a8dbcd657dfb284a8ee00f0ba269d3f2286b0493b15a5694f9fe8", + "sha256:eda5c1e2a715a4cbbca2d6d304988460942551e4e5e3b7457b50943cd741626d", + "sha256:f5c0ed12926dec1dfe7d645333ea59cf93f4d07750986a586f511c0bc61fe103", + "sha256:f6016bd950be4dcd047b7475fdf55fb1e1f59fc7403f387be0e8123e4a576d30", + "sha256:f9e0057a509e096e47c87f753136c9b10d7a91842d8042c2ee6866899a717c0d", + "sha256:fc1c892b1ec1f8cbd5da8de287577b455e388d9c328ad592eabbdcb6fc93bee5", + "sha256:fc2c1e1b00f88317d9de6b2c2b39b012ebbfe35fe5e7bef980fd2a91f6100a07", + "sha256:fd822f019ccccd75c832deb7aa040bb02d70a92eb15a2f16c7987b7ad4ee8d83" ], "markers": "python_version >= '3.9'", - "version": "==0.23.1" + "version": "==0.24.0" }, "six": { "hashes": [ @@ -1492,66 +1730,66 @@ }, "sqlalchemy": { "hashes": [ - "sha256:018ee97c558b499b58935c5a152aeabf6d36b3d55d91656abeb6d93d663c0c4c", - "sha256:01da15490c9df352fbc29859d3c7ba9cd1377791faeeb47c100832004c99472c", - "sha256:04545042969833cb92e13b0a3019549d284fd2423f318b6ba10e7aa687690a3c", - "sha256:06205eb98cb3dd52133ca6818bf5542397f1dd1b69f7ea28aa84413897380b06", - "sha256:08cf721bbd4391a0e765fe0fe8816e81d9f43cece54fdb5ac465c56efafecb3d", - "sha256:0d7e3866eb52d914aea50c9be74184a0feb86f9af8aaaa4daefe52b69378db0b", - "sha256:125a7763b263218a80759ad9ae2f3610aaf2c2fbbd78fff088d584edf81f3782", - "sha256:23c5aa33c01bd898f879db158537d7e7568b503b15aad60ea0c8da8109adf3e7", - "sha256:2600a50d590c22d99c424c394236899ba72f849a02b10e65b4c70149606408b5", - "sha256:2d7332868ce891eda48896131991f7f2be572d65b41a4050957242f8e935d5d7", - "sha256:2ed107331d188a286611cea9022de0afc437dd2d3c168e368169f27aa0f61338", - "sha256:3395e7ed89c6d264d38bea3bfb22ffe868f906a7985d03546ec7dc30221ea980", - "sha256:344cd1ec2b3c6bdd5dfde7ba7e3b879e0f8dd44181f16b895940be9b842fd2b6", - "sha256:34d5c49f18778a3665d707e6286545a30339ad545950773d43977e504815fa70", - "sha256:35e72518615aa5384ef4fae828e3af1b43102458b74a8c481f69af8abf7e802a", - "sha256:3eb14ba1a9d07c88669b7faf8f589be67871d6409305e73e036321d89f1d904e", - "sha256:412c6c126369ddae171c13987b38df5122cb92015cba6f9ee1193b867f3f1530", - "sha256:4600c7a659d381146e1160235918826c50c80994e07c5b26946a3e7ec6c99249", - "sha256:463ecfb907b256e94bfe7bcb31a6d8c7bc96eca7cbe39803e448a58bb9fcad02", - "sha256:4a06e6c8e31c98ddc770734c63903e39f1947c9e3e5e4bef515c5491b7737dde", - "sha256:4b2de1523d46e7016afc7e42db239bd41f2163316935de7c84d0e19af7e69538", - "sha256:4dabd775fd66cf17f31f8625fc0e4cfc5765f7982f94dc09b9e5868182cb71c0", - "sha256:4eff9c270afd23e2746e921e80182872058a7a592017b2713f33f96cc5f82e32", - "sha256:52607d0ebea43cf214e2ee84a6a76bc774176f97c5a774ce33277514875a718e", - "sha256:533e0f66c32093a987a30df3ad6ed21170db9d581d0b38e71396c49718fbb1ca", - "sha256:5493a8120d6fc185f60e7254fc056a6742f1db68c0f849cfc9ab46163c21df47", - "sha256:5d2d1fe548def3267b4c70a8568f108d1fed7cbbeccb9cc166e05af2abc25c22", - "sha256:5dfbc543578058c340360f851ddcecd7a1e26b0d9b5b69259b526da9edfa8875", - "sha256:66a40003bc244e4ad86b72abb9965d304726d05a939e8c09ce844d27af9e6d37", - "sha256:67de057fbcb04a066171bd9ee6bcb58738d89378ee3cabff0bffbf343ae1c787", - "sha256:6827f8c1b2f13f1420545bd6d5b3f9e0b85fe750388425be53d23c760dcf176b", - "sha256:6b35e07f1d57b79b86a7de8ecdcefb78485dab9851b9638c2c793c50203b2ae8", - "sha256:7399d45b62d755e9ebba94eb89437f80512c08edde8c63716552a3aade61eb42", - "sha256:788b6ff6728072b313802be13e88113c33696a9a1f2f6d634a97c20f7ef5ccce", - "sha256:78f1b79132a69fe8bd6b5d91ef433c8eb40688ba782b26f8c9f3d2d9ca23626f", - "sha256:79f4f502125a41b1b3b34449e747a6abfd52a709d539ea7769101696bdca6716", - "sha256:7a8517b6d4005facdbd7eb4e8cf54797dbca100a7df459fdaff4c5123265c1cd", - "sha256:7bd5c5ee1448b6408734eaa29c0d820d061ae18cb17232ce37848376dcfa3e92", - "sha256:7f5243357e6da9a90c56282f64b50d29cba2ee1f745381174caacc50d501b109", - "sha256:805cb481474e111ee3687c9047c5f3286e62496f09c0e82e8853338aaaa348f8", - "sha256:871f55e478b5a648c08dd24af44345406d0e636ffe021d64c9b57a4a11518304", - "sha256:87a1ce1f5e5dc4b6f4e0aac34e7bb535cb23bd4f5d9c799ed1633b65c2bcad8c", - "sha256:8a10ca7f8a1ea0fd5630f02feb055b0f5cdfcd07bb3715fc1b6f8cb72bf114e4", - "sha256:995c2bacdddcb640c2ca558e6760383dcdd68830160af92b5c6e6928ffd259b4", - "sha256:9f03143f8f851dd8de6b0c10784363712058f38209e926723c80654c1b40327a", - "sha256:a1c6b0a5e3e326a466d809b651c63f278b1256146a377a528b6938a279da334f", - "sha256:a28f9c238f1e143ff42ab3ba27990dfb964e5d413c0eb001b88794c5c4a528a9", - "sha256:b2cf5b5ddb69142511d5559c427ff00ec8c0919a1e6c09486e9c32636ea2b9dd", - "sha256:b761a6847f96fdc2d002e29e9e9ac2439c13b919adfd64e8ef49e75f6355c548", - "sha256:bf555f3e25ac3a70c67807b2949bfe15f377a40df84b71ab2c58d8593a1e036e", - "sha256:c08a972cbac2a14810463aec3a47ff218bb00c1a607e6689b531a7c589c50723", - "sha256:c457a38351fb6234781d054260c60e531047e4d07beca1889b558ff73dc2014b", - "sha256:c4c433f78c2908ae352848f56589c02b982d0e741b7905228fad628999799de4", - "sha256:d9f119e7736967c0ea03aff91ac7d04555ee038caf89bb855d93bbd04ae85b41", - "sha256:e6b0a1c7ed54a5361aaebb910c1fa864bae34273662bb4ff788a527eafd6e14d", - "sha256:f2bcb085faffcacf9319b1b1445a7e1cfdc6fb46c03f2dce7bc2d9a4b3c1cdc5", - "sha256:fe193d3ae297c423e0e567e240b4324d6b6c280a048e64c77a3ea6886cc2aa87" + "sha256:00a494ea6f42a44c326477b5bee4e0fc75f6a80c01570a32b57e89cf0fbef85a", + "sha256:0bb933a650323e476a2e4fbef8997a10d0003d4da996aad3fd7873e962fdde4d", + "sha256:110179728e442dae85dd39591beb74072ae4ad55a44eda2acc6ec98ead80d5f2", + "sha256:15d08d5ef1b779af6a0909b97be6c1fd4298057504eb6461be88bd1696cb438e", + "sha256:16d325ea898f74b26ffcd1cf8c593b0beed8714f0317df2bed0d8d1de05a8f26", + "sha256:1abb387710283fc5983d8a1209d9696a4eae9db8d7ac94b402981fe2fe2e39ad", + "sha256:1ffdf9c91428e59744f8e6f98190516f8e1d05eec90e936eb08b257332c5e870", + "sha256:2be94d75ee06548d2fc591a3513422b873490efb124048f50556369a834853b0", + "sha256:2cbafc8d39ff1abdfdda96435f38fab141892dc759a2165947d1a8fffa7ef596", + "sha256:2ee5f9999a5b0e9689bed96e60ee53c3384f1a05c2dd8068cc2e8361b0df5b7a", + "sha256:32587e2e1e359276957e6fe5dad089758bc042a971a8a09ae8ecf7a8fe23d07a", + "sha256:35904d63412db21088739510216e9349e335f142ce4a04b69e2528020ee19ed4", + "sha256:37a5c21ab099a83d669ebb251fddf8f5cee4d75ea40a5a1653d9c43d60e20867", + "sha256:37f7a0f506cf78c80450ed1e816978643d3969f99c4ac6b01104a6fe95c5490a", + "sha256:46628ebcec4f23a1584fb52f2abe12ddb00f3bb3b7b337618b80fc1b51177aff", + "sha256:4a4c5a2905a9ccdc67a8963e24abd2f7afcd4348829412483695c59e0af9a705", + "sha256:4aeb939bcac234b88e2d25d5381655e8353fe06b4e50b1c55ecffe56951d18c2", + "sha256:50f5885bbed261fc97e2e66c5156244f9704083a674b8d17f24c72217d29baf5", + "sha256:519624685a51525ddaa7d8ba8265a1540442a2ec71476f0e75241eb8263d6f51", + "sha256:5434223b795be5c5ef8244e5ac98056e290d3a99bdcc539b916e282b160dda00", + "sha256:55028d7a3ebdf7ace492fab9895cbc5270153f75442a0472d8516e03159ab364", + "sha256:5654d1ac34e922b6c5711631f2da497d3a7bffd6f9f87ac23b35feea56098011", + "sha256:574aea2c54d8f1dd1699449f332c7d9b71c339e04ae50163a3eb5ce4c4325ee4", + "sha256:5cfa124eda500ba4b0d3afc3e91ea27ed4754e727c7f025f293a22f512bcd4c9", + "sha256:5ea9181284754d37db15156eb7be09c86e16e50fbe77610e9e7bee09291771a1", + "sha256:641ee2e0834812d657862f3a7de95e0048bdcb6c55496f39c6fa3d435f6ac6ad", + "sha256:650490653b110905c10adac69408380688cefc1f536a137d0d69aca1069dc1d1", + "sha256:6959738971b4745eea16f818a2cd086fb35081383b078272c35ece2b07012716", + "sha256:6cfedff6878b0e0d1d0a50666a817ecd85051d12d56b43d9d425455e608b5ba0", + "sha256:7e0505719939e52a7b0c65d20e84a6044eb3712bb6f239c6b1db77ba8e173a37", + "sha256:8b6b28d303b9d57c17a5164eb1fd2d5119bb6ff4413d5894e74873280483eeb5", + "sha256:8bb131ffd2165fae48162c7bbd0d97c84ab961deea9b8bab16366543deeab625", + "sha256:915866fd50dd868fdcc18d61d8258db1bf9ed7fbd6dfec960ba43365952f3b01", + "sha256:9408fd453d5f8990405cc9def9af46bfbe3183e6110401b407c2d073c3388f47", + "sha256:957f8d85d5e834397ef78a6109550aeb0d27a53b5032f7a57f2451e1adc37e98", + "sha256:9c7a80ed86d6aaacb8160a1caef6680d4ddd03c944d985aecee940d168c411d1", + "sha256:9d3b31d0a1c44b74d3ae27a3de422dfccd2b8f0b75e51ecb2faa2bf65ab1ba0d", + "sha256:a669cbe5be3c63f75bcbee0b266779706f1a54bcb1000f302685b87d1b8c1500", + "sha256:a8aae085ea549a1eddbc9298b113cffb75e514eadbb542133dd2b99b5fb3b6af", + "sha256:ae9597cab738e7cc823f04a704fb754a9249f0b6695a6aeb63b74055cd417a96", + "sha256:afe63b208153f3a7a2d1a5b9df452b0673082588933e54e7c8aac457cf35e758", + "sha256:b5a5bbe29c10c5bfd63893747a1bf6f8049df607638c786252cb9243b86b6706", + "sha256:baf7cee56bd552385c1ee39af360772fbfc2f43be005c78d1140204ad6148438", + "sha256:bb19e30fdae77d357ce92192a3504579abe48a66877f476880238a962e5b96db", + "sha256:bece9527f5a98466d67fb5d34dc560c4da964240d8b09024bb21c1246545e04e", + "sha256:c0cae71e20e3c02c52f6b9e9722bca70e4a90a466d59477822739dc31ac18b4b", + "sha256:c268b5100cfeaa222c40f55e169d484efa1384b44bf9ca415eae6d556f02cb08", + "sha256:c7b927155112ac858357ccf9d255dd8c044fd9ad2dc6ce4c4149527c901fa4c3", + "sha256:c884de19528e0fcd9dc34ee94c810581dd6e74aef75437ff17e696c2bfefae3e", + "sha256:cd2f75598ae70bcfca9117d9e51a3b06fe29edd972fdd7fd57cc97b4dbf3b08a", + "sha256:cf0e99cdb600eabcd1d65cdba0d3c91418fee21c4aa1d28db47d095b1064a7d8", + "sha256:d827099289c64589418ebbcaead0145cd19f4e3e8a93919a0100247af245fa00", + "sha256:e8040680eaacdce4d635f12c55c714f3d4c7f57da2bc47a01229d115bd319191", + "sha256:f0fda83e113bb0fb27dc003685f32a5dcb99c9c4f41f4fa0838ac35265c23b5c", + "sha256:f1ea21bef99c703f44444ad29c2c1b6bd55d202750b6de8e06a955380f4725d7", + "sha256:f6bacab7514de6146a1976bc56e1545bee247242fab030b89e5f70336fc0003e", + "sha256:fe147fcd85aaed53ce90645c91ed5fca0cc88a797314c70dfd9d35925bd5d106" ], "markers": "python_version >= '3.7'", - "version": "==2.0.39" + "version": "==2.0.40" }, "sqlalchemy-utils": { "hashes": [ @@ -1595,19 +1833,27 @@ }, "typing-extensions": { "hashes": [ - "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", - "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" + "sha256:0a4ac55a5820789d87e297727d229866c9650f6521b64206413c4fbada24d95b", + "sha256:c8dd92cc0d6425a97c18fbb9d1954e5ff92c1ca881a309c45f06ebc0b79058e5" ], "markers": "python_version >= '3.8'", - "version": "==4.12.2" + "version": "==4.13.0" + }, + "typing-inspection": { + "hashes": [ + "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f", + "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122" + ], + "markers": "python_version >= '3.9'", + "version": "==0.4.0" }, "tzdata": { "hashes": [ - "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694", - "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639" + "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", + "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9" ], "markers": "python_version >= '2'", - "version": "==2025.1" + "version": "==2025.2" }, "urllib3": { "hashes": [ @@ -1617,6 +1863,118 @@ "markers": "python_version >= '3.9'", "version": "==2.3.0" }, + "urllib3-future": { + "hashes": [ + "sha256:3adfa22c5718caee5ca69bc7f7461dc529f4396494d4d9b1db8af7c56cd3ac34", + "sha256:9cd79ce61da77b5d56681bc126f42955c2153e9c0da2f0a62bca8e0a05641f92" + ], + "markers": "python_version >= '3.7'", + "version": "==2.12.915" + }, + "verlib2": { + "hashes": [ + "sha256:2862f19528db400d130253a2b71c7c3616ee14e1d54bf6833bc0929d2cddd141", + "sha256:cf8e2be044b834a2670f2d4c20a93cfc674933c0070543a6f61d531439cca200" + ], + "markers": "python_version >= '3.6'", + "version": "==0.3.1" + }, + "wassima": { + "hashes": [ + "sha256:10508102696d5e2cf4df6942a8ae251c136a49dc32591e9c3f7dd007f5ea1c2f", + "sha256:1102836ba373912537eba891e7e5893532d4ee915ee2486e981b73f925f63c37", + "sha256:11887557464e0c3f9694fb16406bb56c1fb1566178cd04bfb5b4624fad183b31", + "sha256:12c855cc5b96a2ac32d405ab7de1563fc91be54108b4fb16b06d125d07ea892b", + "sha256:134e863b692c35afe8f5ccbe8082fa39963804e20439a4c7aa98510197034704", + "sha256:17f129f4d36591772d906bcc893b76b236363fda61b575067ddfa8250f84ad30", + "sha256:17f132ffbab294902f8740708f27fd995ea04182fe4b4fde20be563f8a010715", + "sha256:18bc78b2230c6f1f9ddbeb6ca38439fea4cc8f60836af4f3538ed259e60e5eb8", + "sha256:194c3fad38603618dec03307d10a4ece852516df56560e04fb2562506f79c175", + "sha256:1b18ec743ab98dcbfc221749026b23fc573891651342f20971e53bdbf56d28ae", + "sha256:1fa19a3652509edd18f693cd9c873d8f73c9d1624eae6c3bf93e561b18ae2766", + "sha256:24bdb1a2b90c215e11ed7ce82ed7eada339c7dca8e0366916e4e3215b3b9d8d3", + "sha256:27d518f0863788c826faf387326f3babb3ea95a0b908f5b3ad2bc1fcc3c5a37d", + "sha256:350b5854dfb3eeb95cd17723b0f3503de0c01454da5ae7d60f192be2009239eb", + "sha256:3b3a4c8ffa76147507f0c88c5cc8c76ef96ab93b81e49b288a3a0b94ebfb34af", + "sha256:3e00fa8ff1aef7d8aad2e1b957add6cba8549a42e415400bd72ff1b61dc9da9d", + "sha256:3f29045dd0a7c287f850f1dc3948632a2d2cf7dd7ec02271c5f248f058da5650", + "sha256:4a528244e4a0f9e01b8593b1c8a60ac1d80ce8b13fe079f44b38328e4be075e3", + "sha256:4c4f5ca102fd083aa2b05c65a1fd18175e3dc7a889525fd2964219ee3c51edef", + "sha256:52358d86195954816231d2aa8c2919b85075320b6d3ba5b96216985c3182bfa0", + "sha256:52f473233ec4d57322c6295e85b3912dc1fc400d6308a04bd427b863934aa74e", + "sha256:556cded582aef3089de889b5a6efcf6d87fabfec55d574fcc3a4ada21308d487", + "sha256:564eda7bf0420c8cbebe5e8efc15f1b27fdcb37ebc4c2f92b8461ca83381b223", + "sha256:57a0ab5aed596f129fd4ea7584336b11fbef25c07d1351e37a959901dea8728e", + "sha256:58f1fddd660da8c8f30f4b8460129e2f217c226cd1b54b1cabb6465881fd788a", + "sha256:597b0d8ba697f4319bc1f301ed31630ca783c9fe82d2a2434dd2f7f709c4e394", + "sha256:5b194f0de77a4ae7bcf217a3ccd10798e94ca430cec6307628098a61cd2ac230", + "sha256:5f5ee564f4b836ed1b70ddb187c817e8f6f1ffb521a636bb20676f07b523396b", + "sha256:601f96340e4c8071994a39a76d4278e8e1d087cf385781dba795c5334262d865", + "sha256:61bfa09f38c36f1b1e6e44e7af888bb8f9d739e86099082a3b45875651a425e2", + "sha256:67fd323b8ad0e057c06b153983d8c50f812aad979ac89b07ed6952c345f6da02", + "sha256:69cb51f629d118256da3d2373575190c7e30d3fa67c344dc655f6c8ab3e83f0d", + "sha256:6b1d7ceeede8d8eed48616d2d33ed23d2dff307d0b17c577eafdadafe86a0478", + "sha256:6b7d696155ddd7ab5739ac221e8854115d0d8171bbf805074d9484083de386aa", + "sha256:6d23e9483756b81850b82e8b7ed20fd23de22b50d6a678f765c660d4206b7ce9", + "sha256:7b0229fecc849234f2a2d11e948ac38a9bab02d201fa4d6ad43c143e18c1a66e", + "sha256:7c53050b670d702eed541503175bd5441fc4bdf3898714f8eac8c6ae9db548ac", + "sha256:7d65676f1fc138d1742f704bf490045571b9c2c48cab7d2c2076a52729c143e5", + "sha256:7db25328c40cd574e5a68ef6507c5af4d1fa2a44cb3c028ff9ca6b522f8faf32", + "sha256:83ce1b09e9eb2ae033c303b74ecc4f3186bbc0897db1d8cd9942153b0631b8e0", + "sha256:86c509900cbb90b7b75155c580b22af591b696fa059059bcdbd75bc74179df85", + "sha256:87f80d0075f0d396b73d41bb1626a2dd5607e0db4b74cb17e55d874fcd538971", + "sha256:8b719755d556649f2fbf226cf1ca8581ade114751df1facec96f94e75bffdb3c", + "sha256:8e739d4192758df6e5363791f527deb91c615d63020ee8965df4bcd1a217f9a5", + "sha256:923d3bf8770dfeb3d94bdfee1c5b5a081592de69766436a395e1e6203c19cf71", + "sha256:97772bb55cb47da3de49ca4b59309a9bd91ead730a7cfac1992932486fb41352", + "sha256:98bdfdf734144277132f34f770eeb6b0db2c4de87415f34b178adee766632f24", + "sha256:98f38b1b01e6f270b9279d76261d6f222b72ef06b025cbd4911b962bb6de4c98", + "sha256:99318b5ea78843e3c3e19cd56367216774674a99848f00a6f2dcf84e36039641", + "sha256:9c623ef06876d432dc8acc93ed3494d3453333d767b1b06bba1a016ea9d850c9", + "sha256:9d0f9720dfd0155432d23bcc3605fe5831cd0f586ede4f14ff6f3bebe8fb867a", + "sha256:9e79216760faac6395bee8ca4077a53a309312faba0f71982127ad8625861780", + "sha256:a470c908fd9baaecf41715ea3c30c57b530d598ae5e9de7e0bd532755e66bb1b", + "sha256:a634b9b79e059f45a56ff3ef6e7241662bc6f0e5a096ee6eed6770ea368e8278", + "sha256:acd8195a53d0e84ea95bdf15a2651c53b829a3ddead21b4a620b6a0c5e1ae2ff", + "sha256:addbd207df3718fc9d9de5b6c90a5e3fbe667830cf629186c9fdcafbb6578cb4", + "sha256:ae2aec9d55e108ae2d22fd0bda24450a6c13c116f9698b9e7ba2c6492c4fe715", + "sha256:af6b70ca9788964c5da5b59ca412b62db2ea7f2386a91c0117667bdd963e828c", + "sha256:afa7d60a9203db36a55b6f2868da90aaa829ab415a21fba7fa75678789aeb16f", + "sha256:b08c1931c44e3c034e645f3e3a7f4c47e8b0758fb8f09a52d1e880a307a1066f", + "sha256:b22e356914e606ff398c002b9925df4454c5deca9dbe55b3ba4a5c9b2365cf0f", + "sha256:b8c0f50397c51086df941b48057c82f85d9da000bf4fe6f4bc64c4f649b26a5b", + "sha256:bc068bcd79fe017866f536e0ad9424793220be34e3124476e17e6cb77a97e690", + "sha256:bc30f5a605a366acb7f301b3421508eaec3c1a515c960791bd776cb63d016302", + "sha256:c0d246b3f8a771578279eab9cfcb820dedefd3dd5dc0e34b37a337fe46271fc0", + "sha256:c0fee0a8593028bde17b57527b1ac21fea74f209b3522363e3ba0197ffaa6323", + "sha256:c139d5b103bb1f085d8918815d62ad946224a658ac1a7cc1b93dc44bd498ff9a", + "sha256:c25235cec12c0e38b4104268e312c9c2f3527ebc126d296cff69ea7aa13434dc", + "sha256:c7429d038dc383966c692e752010cbb4d5dab0e515f231aa01cd746aed9db359", + "sha256:c85cd2e64967c0dce2927ad7c62c090aae6d6b7f9e3a6b9fb91f58b890ea6adc", + "sha256:ca04984df012020dd846599b8555666c544982c2a91dc6135565e6708624eb71", + "sha256:cb7d43c07d58ba13736e70dc3e064496efeb1ed4475a28afb26b7a3b030b89df", + "sha256:d018e05cb61eed3050d45bd0c0ef9b75420899f6ae254e68e7f2ef26975098c9", + "sha256:d24d42881eb74729b34014e2e87f3a4d0419c43db309de2dff3f39118716865f", + "sha256:d6e17f218af856ca22c30d1a1ac58b19bccf768b8589eb8d6e45e1f1ff258404", + "sha256:d855d0be1759c5efc404c04977ee48a8b6260aef6441e72c10973924dbde5a73", + "sha256:dea0dcc0e50978ef73be8cb384694b71a6e64b46847ee7decad96dc85fbf650c", + "sha256:e1e9228049cf2442ac486a03a0d543c5dff3089a915a3e39ab809b22672e1d76", + "sha256:e26d052a248d5be2257d848d6078d932cc1fd4e8226639f550344d0a7a2b8813", + "sha256:ee6ccb8197936a308a4034c90a42b30b37c46b7cbda66101d439d6983f59b368", + "sha256:eea9c37b45e73cebb4670afd1779db138eeff0f84ffc0871d2fb90c04c8d3aa8", + "sha256:f195bf641276261e6bc5f79f52601850c9bdbff8af401483b4805dbff535ed30", + "sha256:f264827618400ebeab16708c8acf7870f693b03bfb4d7e95253eb9b35074db5c", + "sha256:f44ccd2eaa433ff1a10f70242dc33315fc192b81664696154127bdd66ad7d3b2", + "sha256:f7a6068d8857c403e105e62132a00e9d9d401bd0efbff7f8b5b5bc8ab768a2d8", + "sha256:f9886176fe4bf1ac008c02adb5bd103f1191799f1897777d203ee44f615325a5", + "sha256:fa1f38d5583d283b40f998e2f13471bfa952e0c423ff95ec2ec329f3e1898107", + "sha256:fa65494e7bd0e3ba33b3e5a5ab30c2b6e95d3d1762baaa56151a0861618dc261", + "sha256:fd7186e23963714bab3c9a2ab75d002078335110d2c9fc883c65cbce43717f26", + "sha256:fec32c22b521fcdeb9aa7dee4373b2d81ca2d3fc8edc532f3e189d6f4f6f1f81" + ], + "markers": "python_version >= '3.7'", + "version": "==1.2.2" + }, "werkzeug": { "hashes": [ "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", @@ -1908,73 +2266,73 @@ }, "coverage": { "hashes": [ - "sha256:056d3017ed67e7ddf266e6f57378ece543755a4c9231e997789ab3bd11392c94", - "sha256:0ce8cf59e09d31a4915ff4c3b94c6514af4c84b22c4cc8ad7c3c546a86150a92", - "sha256:104bf640f408f4e115b85110047c7f27377e1a8b7ba86f7db4fa47aa49dc9a8e", - "sha256:1393e5aa9441dafb0162c36c8506c648b89aea9565b31f6bfa351e66c11bcd82", - "sha256:1586ad158523f4133499a4f322b230e2cfef9cc724820dbd58595a5a236186f4", - "sha256:180e3fc68ee4dc5af8b33b6ca4e3bb8aa1abe25eedcb958ba5cff7123071af68", - "sha256:1b336d06af14f8da5b1f391e8dec03634daf54dfcb4d1c4fb6d04c09d83cef90", - "sha256:1c8fbce80b2b8bf135d105aa8f5b36eae0c57d702a1cc3ebdea2a6f03f6cdde5", - "sha256:2d673e3add00048215c2cc507f1228a7523fd8bf34f279ac98334c9b07bd2656", - "sha256:316f29cc3392fa3912493ee4c83afa4a0e2db04ff69600711f8c03997c39baaa", - "sha256:33c1394d8407e2771547583b66a85d07ed441ff8fae5a4adb4237ad39ece60db", - "sha256:37cbc7b0d93dfd133e33c7ec01123fbb90401dce174c3b6661d8d36fb1e30608", - "sha256:39abcacd1ed54e2c33c54bdc488b310e8ef6705833f7148b6eb9a547199d375d", - "sha256:3ab7090f04b12dc6469882ce81244572779d3a4b67eea1c96fb9ecc8c607ef39", - "sha256:3b0e6e54591ae0d7427def8a4d40fca99df6b899d10354bab73cd5609807261c", - "sha256:416e2a8845eaff288f97eaf76ab40367deafb9073ffc47bf2a583f26b05e5265", - "sha256:4545485fef7a8a2d8f30e6f79ce719eb154aab7e44217eb444c1d38239af2072", - "sha256:4c124025430249118d018dcedc8b7426f39373527c845093132196f2a483b6dd", - "sha256:4fbb7a0c3c21908520149d7751cf5b74eb9b38b54d62997b1e9b3ac19a8ee2fe", - "sha256:52fc89602cde411a4196c8c6894afb384f2125f34c031774f82a4f2608c59d7d", - "sha256:55143aa13c49491f5606f05b49ed88663446dce3a4d3c5d77baa4e36a16d3573", - "sha256:57f3bd0d29bf2bd9325c0ff9cc532a175110c4bf8f412c05b2405fd35745266d", - "sha256:5b2f144444879363ea8834cd7b6869d79ac796cb8f864b0cfdde50296cd95816", - "sha256:5efdeff5f353ed3352c04e6b318ab05c6ce9249c25ed3c2090c6e9cadda1e3b2", - "sha256:60e6347d1ed882b1159ffea172cb8466ee46c665af4ca397edbf10ff53e9ffaf", - "sha256:693d921621a0c8043bfdc61f7d4df5ea6d22165fe8b807cac21eb80dd94e4bbd", - "sha256:708f0a1105ef2b11c79ed54ed31f17e6325ac936501fc373f24be3e6a578146a", - "sha256:70f0925c4e2bfc965369f417e7cc72538fd1ba91639cf1e4ef4b1a6b50439b3b", - "sha256:7789e700f33f2b133adae582c9f437523cd5db8de845774988a58c360fc88253", - "sha256:7b6c96d69928a3a6767fab8dc1ce8a02cf0156836ccb1e820c7f45a423570d98", - "sha256:7d2a65876274acf544703e943c010b60bd79404e3623a1e5d52b64a6e2728de5", - "sha256:7f18d47641282664276977c604b5a261e51fefc2980f5271d547d706b06a837f", - "sha256:89078312f06237417adda7c021c33f80f7a6d2db8572a5f6c330d89b080061ce", - "sha256:8c938c6ae59be67ac19a7204e079efc94b38222cd7d0269f96e45e18cddeaa59", - "sha256:8e336b56301774ace6be0017ff85c3566c556d938359b61b840796a0202f805c", - "sha256:a0a207c87a9f743c8072d059b4711f8d13c456eb42dac778a7d2e5d4f3c253a7", - "sha256:a2454b12a3f12cc4698f3508912e6225ec63682e2ca5a96f80a2b93cef9e63f3", - "sha256:a538a23119d1e2e2ce077e902d02ea3d8e0641786ef6e0faf11ce82324743944", - "sha256:aa4dff57fc21a575672176d5ab0ef15a927199e775c5e8a3d75162ab2b0c7705", - "sha256:ad0edaa97cb983d9f2ff48cadddc3e1fb09f24aa558abeb4dc9a0dbacd12cbb4", - "sha256:ae8006772c6b0fa53c33747913473e064985dac4d65f77fd2fdc6474e7cd54e4", - "sha256:b0fac2088ec4aaeb5468b814bd3ff5e5978364bfbce5e567c44c9e2854469f6c", - "sha256:b3e212a894d8ae07fde2ca8b43d666a6d49bbbddb10da0f6a74ca7bd31f20054", - "sha256:b54a1ee4c6f1905a436cbaa04b26626d27925a41cbc3a337e2d3ff7038187f07", - "sha256:b667b91f4f714b17af2a18e220015c941d1cf8b07c17f2160033dbe1e64149f0", - "sha256:b8c36093aca722db73633cf2359026ed7782a239eb1c6db2abcff876012dc4cf", - "sha256:bb356e7ae7c2da13f404bf8f75be90f743c6df8d4607022e759f5d7d89fe83f8", - "sha256:bce730d484038e97f27ea2dbe5d392ec5c2261f28c319a3bb266f6b213650135", - "sha256:c075d167a6ec99b798c1fdf6e391a1d5a2d054caffe9593ba0f97e3df2c04f0e", - "sha256:c4e09534037933bf6eb31d804e72c52ec23219b32c1730f9152feabbd7499463", - "sha256:c5f8a5364fc37b2f172c26a038bc7ec4885f429de4a05fc10fdcb53fb5834c5c", - "sha256:cb203c0afffaf1a8f5b9659a013f8f16a1b2cad3a80a8733ceedc968c0cf4c57", - "sha256:cc41374d2f27d81d6558f8a24e5c114580ffefc197fd43eabd7058182f743322", - "sha256:cd879d4646055a573775a1cec863d00c9ff8c55860f8b17f6d8eee9140c06166", - "sha256:d013c07061751ae81861cae6ec3a4fe04e84781b11fd4b6b4201590234b25c7b", - "sha256:d8c7524779003d59948c51b4fcbf1ca4e27c26a7d75984f63488f3625c328b9b", - "sha256:d9710521f07f526de30ccdead67e6b236fe996d214e1a7fba8b36e2ba2cd8261", - "sha256:e1ffde1d6bc2a92f9c9207d1ad808550873748ac2d4d923c815b866baa343b3f", - "sha256:e7f559c36d5cdc448ee13e7e56ed7b6b5d44a40a511d584d388a0f5d940977ba", - "sha256:f2a1e18a85bd066c7c556d85277a7adf4651f259b2579113844835ba1a74aafd", - "sha256:f32b165bf6dfea0846a9c9c38b7e1d68f313956d60a15cde5d1709fddcaf3bee", - "sha256:f5a2f71d6a91238e7628f23538c26aa464d390cbdedf12ee2a7a0fb92a24482a", - "sha256:f81fe93dc1b8e5673f33443c0786c14b77e36f1025973b85e07c70353e46882b" + "sha256:042e7841a26498fff7a37d6fda770d17519982f5b7d8bf5278d140b67b61095f", + "sha256:04bfec25a8ef1c5f41f5e7e5c842f6b615599ca8ba8391ec33a9290d9d2db3a3", + "sha256:0915742f4c82208ebf47a2b154a5334155ed9ef9fe6190674b8a46c2fb89cb05", + "sha256:18c5ae6d061ad5b3e7eef4363fb27a0576012a7447af48be6c75b88494c6cf25", + "sha256:2931f66991175369859b5fd58529cd4b73582461877ecfd859b6549869287ffe", + "sha256:2e4b6b87bb0c846a9315e3ab4be2d52fac905100565f4b92f02c445c8799e257", + "sha256:3043ba1c88b2139126fc72cb48574b90e2e0546d4c78b5299317f61b7f718b78", + "sha256:379fe315e206b14e21db5240f89dc0774bdd3e25c3c58c2c733c99eca96f1ada", + "sha256:42421e04069fb2cbcbca5a696c4050b84a43b05392679d4068acbe65449b5c64", + "sha256:4dfd9a93db9e78666d178d4f08a5408aa3f2474ad4d0e0378ed5f2ef71640cb6", + "sha256:52a523153c568d2c0ef8826f6cc23031dc86cffb8c6aeab92c4ff776e7951b28", + "sha256:554fec1199d93ab30adaa751db68acec2b41c5602ac944bb19187cb9a41a8067", + "sha256:581a40c7b94921fffd6457ffe532259813fc68eb2bdda60fa8cc343414ce3733", + "sha256:5a26c0c795c3e0b63ec7da6efded5f0bc856d7c0b24b2ac84b4d1d7bc578d676", + "sha256:5a570cd9bd20b85d1a0d7b009aaf6c110b52b5755c17be6962f8ccd65d1dbd23", + "sha256:5aaeb00761f985007b38cf463b1d160a14a22c34eb3f6a39d9ad6fc27cb73008", + "sha256:5ac46d0c2dd5820ce93943a501ac5f6548ea81594777ca585bf002aa8854cacd", + "sha256:5c8a5c139aae4c35cbd7cadca1df02ea8cf28a911534fc1b0456acb0b14234f3", + "sha256:6b8af63b9afa1031c0ef05b217faa598f3069148eeee6bb24b79da9012423b82", + "sha256:769773614e676f9d8e8a0980dd7740f09a6ea386d0f383db6821df07d0f08545", + "sha256:771eb7587a0563ca5bb6f622b9ed7f9d07bd08900f7589b4febff05f469bea00", + "sha256:77af0f6447a582fdc7de5e06fa3757a3ef87769fbb0fdbdeba78c23049140a47", + "sha256:7a3d62b3b03b4b6fd41a085f3574874cf946cb4604d2b4d3e8dca8cd570ca501", + "sha256:821f7bcbaa84318287115d54becb1915eece6918136c6f91045bb84e2f88739d", + "sha256:89b1f4af0d4afe495cd4787a68e00f30f1d15939f550e869de90a86efa7e0814", + "sha256:8a1d96e780bdb2d0cbb297325711701f7c0b6f89199a57f2049e90064c29f6bd", + "sha256:8a40fcf208e021eb14b0fac6bdb045c0e0cab53105f93ba0d03fd934c956143a", + "sha256:8f99eb72bf27cbb167b636eb1726f590c00e1ad375002230607a844d9e9a2318", + "sha256:90e7fbc6216ecaffa5a880cdc9c77b7418c1dcb166166b78dbc630d07f278cc3", + "sha256:94ec0be97723ae72d63d3aa41961a0b9a6f5a53ff599813c324548d18e3b9e8c", + "sha256:95aa6ae391a22bbbce1b77ddac846c98c5473de0372ba5c463480043a07bff42", + "sha256:96121edfa4c2dfdda409877ea8608dd01de816a4dc4a0523356067b305e4e17a", + "sha256:a1f406a8e0995d654b2ad87c62caf6befa767885301f3b8f6f73e6f3c31ec3a6", + "sha256:a321c61477ff8ee705b8a5fed370b5710c56b3a52d17b983d9215861e37b642a", + "sha256:a5761c70c017c1b0d21b0815a920ffb94a670c8d5d409d9b38857874c21f70d7", + "sha256:a9abbccd778d98e9c7e85038e35e91e67f5b520776781d9a1e2ee9d400869487", + "sha256:ad80e6b4a0c3cb6f10f29ae4c60e991f424e6b14219d46f1e7d442b938ee68a4", + "sha256:b44674870709017e4b4036e3d0d6c17f06a0e6d4436422e0ad29b882c40697d2", + "sha256:b571bf5341ba8c6bc02e0baeaf3b061ab993bf372d982ae509807e7f112554e9", + "sha256:b8194fb8e50d556d5849753de991d390c5a1edeeba50f68e3a9253fbd8bf8ccd", + "sha256:b87eb6fc9e1bb8f98892a2458781348fa37e6925f35bb6ceb9d4afd54ba36c73", + "sha256:bbb5cc845a0292e0c520656d19d7ce40e18d0e19b22cb3e0409135a575bf79fc", + "sha256:be945402e03de47ba1872cd5236395e0f4ad635526185a930735f66710e1bd3f", + "sha256:bf13d564d310c156d1c8e53877baf2993fb3073b2fc9f69790ca6a732eb4bfea", + "sha256:cf60dd2696b457b710dd40bf17ad269d5f5457b96442f7f85722bdb16fa6c899", + "sha256:d1ba00ae33be84066cfbe7361d4e04dec78445b2b88bdb734d0d1cbab916025a", + "sha256:d39fc4817fd67b3915256af5dda75fd4ee10621a3d484524487e33416c6f3543", + "sha256:d766a4f0e5aa1ba056ec3496243150698dc0481902e2b8559314368717be82b1", + "sha256:dbf364b4c5e7bae9250528167dfe40219b62e2d573c854d74be213e1e52069f7", + "sha256:dd19608788b50eed889e13a5d71d832edc34fc9dfce606f66e8f9f917eef910d", + "sha256:e013b07ba1c748dacc2a80e69a46286ff145935f260eb8c72df7185bf048f502", + "sha256:e5d2b9be5b0693cf21eb4ce0ec8d211efb43966f6657807f6859aab3814f946b", + "sha256:e5ff52d790c7e1628241ffbcaeb33e07d14b007b6eb00a19320c7b8a7024c040", + "sha256:e75a2ad7b647fd8046d58c3132d7eaf31b12d8a53c0e4b21fa9c4d23d6ee6d3c", + "sha256:e7ac22a0bb2c7c49f441f7a6d46c9c80d96e56f5a8bc6972529ed43c8b694e27", + "sha256:ed2144b8a78f9d94d9515963ed273d620e07846acd5d4b0a642d4849e8d91a0c", + "sha256:f017a61399f13aa6d1039f75cd467be388d157cd81f1a119b9d9a68ba6f2830d", + "sha256:f1d8a2a57b47142b10374902777e798784abf400a004b14f1b0b9eaf1e528ba4", + "sha256:f2d32f95922927186c6dbc8bc60df0d186b6edb828d299ab10898ef3f40052fe", + "sha256:f319bae0321bc838e205bf9e5bc28f0a3165f30c203b610f17ab5552cff90323", + "sha256:f3c38e4e5ccbdc9198aecc766cedbb134b2d89bf64533973678dfcf07effd883", + "sha256:f9983d01d7705b2d1f7a95e10bbe4091fabc03a46881a256c2787637b087003f", + "sha256:fa260de59dfb143af06dcf30c2be0b200bed2a73737a8a59248fcb9fa601ef0f" ], "index": "pypi", "markers": "python_version >= '3.9'", - "version": "==7.7.0" + "version": "==7.8.0" }, "idna": { "hashes": [ @@ -1986,11 +2344,11 @@ }, "iniconfig": { "hashes": [ - "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", - "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" + "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", + "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760" ], - "markers": "python_version >= '3.7'", - "version": "==2.0.0" + "markers": "python_version >= '3.8'", + "version": "==2.1.0" }, "packaging": { "hashes": [ diff --git a/dbrepo-search-service/app.py b/dbrepo-search-service/app.py index 8e265465326bea0a61a9772c93b22143243921a3..1ee06add21875e5a946c15e8397b2af3fea30427 100644 --- a/dbrepo-search-service/app.py +++ b/dbrepo-search-service/app.py @@ -4,15 +4,13 @@ import os from json import dumps from typing import List, Any -import requests -from clients.keycloak_client import User, KeycloakClient -from clients.opensearch_client import OpenSearchClient, flatten from dbrepo.api.dto import Database, ApiError +from dbrepo.core.client.auth import User, AuthServiceClient +from dbrepo.core.client.search import SearchServiceClient, flatten from flasgger import LazyJSONEncoder, Swagger, swag_from from flask import Flask, request, Response from flask_cors import CORS from flask_httpauth import HTTPTokenAuth, HTTPBasicAuth, MultiAuth -from jwt.exceptions import JWTDecodeError from opensearchpy import NotFoundError from prometheus_flask_exporter import PrometheusMetrics from pydantic import ValidationError @@ -135,7 +133,24 @@ template = { "type": "object" } } - } + }, + "ApiError": { + "properties": { + "message": { + "example": "Message", + "type": "string" + }, + "status": { + "example": "BAD_REQUEST", + "type": "string" + }, + "code": { + "example": "error.dashboard.create", + "type": "string" + } + }, + "type": "object" + }, }, "securitySchemes": { "bearerAuth": { @@ -154,7 +169,7 @@ template = { "info": { "title": "Database Repository Search Service API", "description": "Service that searches the search database", - "version": "1.5", + "version": "1.8.0", "contact": { "name": "Prof. Andreas Rauber", "email": "andreas.rauber@tuwien.ac.at" @@ -166,7 +181,7 @@ template = { }, "externalDocs": { "description": "Sourcecode Documentation", - "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.5/" + "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.7/" }, "servers": [ { @@ -185,7 +200,7 @@ app.config["METADATA_SERVICE_ENDPOINT"] = os.getenv("METADATA_SERVICE_ENDPOINT", app.config["JWT_ALGORITHM"] = "HS256" app.config["JWT_PUBKEY"] = '-----BEGIN PUBLIC KEY-----\n' + os.getenv("JWT_PUBKEY", "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB") + '\n-----END PUBLIC KEY-----' -app.config["AUTH_SERVICE_ENDPOINT"] = os.getenv("AUTH_SERVICE_ENDPOINT", "http://auth-service:8080") +app.config["AUTH_SERVICE_ENDPOINT"] = os.getenv("AUTH_SERVICE_ENDPOINT", "http://localhost:8080") app.config["AUTH_SERVICE_CLIENT"] = os.getenv("AUTH_SERVICE_CLIENT", "dbrepo-client") app.config["AUTH_SERVICE_CLIENT_SECRET"] = os.getenv("AUTH_SERVICE_CLIENT_SECRET", "MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG") app.config["OPENSEARCH_HOST"] = os.getenv('OPENSEARCH_HOST', 'search-db') @@ -195,41 +210,31 @@ app.config["OPENSEARCH_PASSWORD"] = os.getenv('OPENSEARCH_PASSWORD', 'admin') app.json_encoder = LazyJSONEncoder +auth_client = AuthServiceClient(app.config["AUTH_SERVICE_ENDPOINT"], app.config["AUTH_SERVICE_CLIENT"], + app.config["AUTH_SERVICE_CLIENT_SECRET"], app.config["JWT_PUBKEY"]) + @token_auth.verify_token def verify_token(token: str) -> bool | User: - if token is None or token == "": - return False - try: - client = KeycloakClient() - return client.verify_jwt(access_token=token) - except JWTDecodeError: - return False + return auth_client.is_valid_token(token) @basic_auth.verify_password def verify_password(username: str, password: str) -> Any: - if username is None or username == "" or password is None or password == "": - return False - client = KeycloakClient() - try: - return client.verify_jwt(access_token=client.obtain_user_token(username=username, password=password)) - except AssertionError as error: - logging.error(error) - return False - except requests.exceptions.ConnectionError as error: - logging.error(f"Failed to connect to Authentication Service {error}") - return False + return auth_client.is_valid_password(username, password) @token_auth.get_user_roles def get_user_roles(user: User) -> List[str]: - return user.roles + return auth_client.get_user_roles(user) @basic_auth.get_user_roles def get_user_roles(user: User) -> List[str]: - return user.roles + return auth_client.get_user_roles(user) + + +headers = {'Content-Type': 'application/json'} def general_filter(index, results): @@ -264,9 +269,14 @@ def general_filter(index, results): return results +def search_client(): + return SearchServiceClient(app.config["OPENSEARCH_HOST"], int(app.config["OPENSEARCH_PORT"]), + app.config["OPENSEARCH_USERNAME"], app.config["OPENSEARCH_PASSWORD"]) + + @app.route("/health", methods=["GET"], endpoint="actuator_health") def health(): - return dict({"status": "UP"}), 200 + return dict({"status": "UP"}), 200, headers @app.route("/api/search/<string:index>", methods=["GET"], endpoint="search_get_index") @@ -279,7 +289,7 @@ def get_index(index: str): :return: list of the results """ logging.debug(f'endpoint get search type: {index}') - results = OpenSearchClient().query_index_by_term_opensearch("*", "contains") + results = search_client().query_index_by_term_opensearch("*", "contains") try: results = general_filter(index, results) @@ -287,10 +297,10 @@ def get_index(index: str): max_pages = math.ceil(len(results) / results_per_page) page = min(request.args.get("page", 1, type=int), max_pages) results = results[(results_per_page * (page - 1)): (results_per_page * page)] - return Response(dumps(results, default=pydantic_encoder)), 200, {'Content-Type': 'application/json'} + return Response(dumps(results, default=pydantic_encoder)), 200, headers except KeyError: return ApiError(status='NOT_FOUND', message=f'Failed to find get index: {index}', - code='search.index.missing').model_dump(), 404 + code='search.index.missing').model_dump(), 404, headers @app.route("/api/search/<string:field_type>/fields", methods=["GET"], endpoint="search_get_index_fields") @@ -304,12 +314,12 @@ def get_fields(field_type: str): """ logging.debug(f'endpoint get search type fields: {field_type}') try: - fields = OpenSearchClient().get_fields_for_index(field_type) + fields = search_client().get_fields_for_index(field_type) logging.debug(f'get fields for field_type {field_type} resulted in {len(fields)} field(s)') - return Response(dumps(fields, default=pydantic_encoder)), 200, {'Content-Type': 'application/json'} + return Response(dumps(fields, default=pydantic_encoder)), 200, headers except NotFoundError: return ApiError(status='NOT_FOUND', message=f'Failed to find fields for search type {field_type}', - code='search.type.missing').model_dump(), 404 + code='search.type.missing').model_dump(), 404, headers @app.route("/api/search", methods=["GET"], endpoint="search_fuzzy_search") @@ -326,13 +336,13 @@ def get_fuzzy_search(): return ApiError(status='BAD_REQUEST', message='Provide a search term with ?q=term', code='search.fuzzy.invalid').model_dump(), 400 logging.debug(f"search request query: {search_term}") - user_id, error, status = KeycloakClient().userId(request.headers.get('Authorization')) + user_id, error, status = auth_client.get_user_id(request.headers.get('Authorization')) if error is not None and status is not None: - return error, status - results: [Database] = OpenSearchClient().fuzzy_search(search_term=search_term, - user_id=user_id, - user_token=request.headers.get('Authorization')) - return Response(dumps(results, default=pydantic_encoder)), 200, {'Content-Type': 'application/json'} + return error, status, headers + results = search_client().fuzzy_search(search_term=search_term, + user_id=user_id, + user_token=request.headers.get('Authorization')) + return Response(dumps(results, default=pydantic_encoder)), 200, headers @app.route("/api/search/<string:field_type>", methods=["POST"], endpoint="search_post_general_search") @@ -354,16 +364,16 @@ def post_general_search(field_type): t2 = request.args.get("t2") if not str(t2).isdigit(): t2 = None - user_id, error, status = KeycloakClient().userId(request.headers.get('Authorization')) + user_id, error, status = auth_client.get_user_id(request.headers.get('Authorization')) if error is not None and status is not None: return error, status if t1 is not None and t2 is not None and "unit.uri" in value_pairs and "concept.uri" in value_pairs: - response: [Database] = OpenSearchClient().unit_independent_search(t1, t2, value_pairs, user_id) + response = search_client().unit_independent_search(t1, t2, value_pairs, user_id) else: - response: [Database] = OpenSearchClient().general_search(field_type=field_type, - field_value_pairs=value_pairs, - user_id=user_id, - user_token=request.headers.get('Authorization')) + response = search_client().general_search(field_type=field_type, + field_value_pairs=value_pairs, + user_id=user_id, + user_token=request.headers.get('Authorization')) # filter by type tables = [table for table in flatten([database.tables for database in response]) if table.is_public or table.is_schema_public or (user_id is not None and table.owner.id == user_id)] @@ -408,34 +418,34 @@ def post_general_search(field_type): response = tmp elif field_type == 'view': response = views - return Response(dumps(response, default=pydantic_encoder)), 200, {'Content-Type': 'application/json'} + return Response(dumps(response, default=pydantic_encoder)), 200, headers -@app.route("/api/search/database/<string:database_id>", methods=["PUT"], endpoint="search_put_database") -@metrics.gauge(name='dbrepo_search_update_database', +@app.route("/api/search/database/<string:database_id>", methods=["PUT"], endpoint="search_save_database") +@metrics.gauge(name='dbrepo_search_save_database', description='Time needed to update a database in the search database') @auth.login_required(role=['update-search-index']) -def update_database(database_id: str): - logging.debug(f"updating database with id: {database_id}") +def save_database(database_id: str): + logging.debug(f"save database with id: {database_id}") try: - payload: Database = Database.model_validate(request.json) + payload = Database.model_validate(request.json) except ValidationError as e: logging.error(f"Failed to validate: {e}") return ApiError(status='BAD_REQUEST', message=f'Malformed payload: {e}', code='search.general.missing').model_dump(), 400 - database = OpenSearchClient().update_database(database_id, payload) - logging.info(f"Updated database with id: {database_id}") - return database.model_dump(), 202 + search_client().save_database(database_id, payload) + return Response(), 202, headers @app.route("/api/search/database/<string:database_id>", methods=["DELETE"], endpoint="database_delete_database") @metrics.gauge(name='dbrepo_search_delete_database', description='Time needed to delete a database in the search database') -@auth.login_required(role=['admin']) +@auth.login_required(role=['system']) def delete_database(database_id: str): + logging.debug(f"delete database with id: {database_id}") try: - OpenSearchClient().delete_database(database_id) - return Response(dumps({})), 202 + search_client().delete_database(database_id) + return Response(dumps({})), 202, headers except NotFoundError: return ApiError(status='NOT_FOUND', message='Failed to find database', code='search.database.missing').model_dump(), 404 diff --git a/dbrepo-search-service/examples/database/fields_response_payload.json b/dbrepo-search-service/examples/database/fields_response_payload.json deleted file mode 100644 index 2eab72954376499883bcf4363152c6888a9f5ce6..0000000000000000000000000000000000000000 --- a/dbrepo-search-service/examples/database/fields_response_payload.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "fields": [ - { - "attribute_name": "_class", - "type": "keyword" - }, - { - "attribute_name": "container", - "type": "nested" - }, - { - "attribute_name": "container.properties._class", - "type": "keyword" - }, - { - "attribute_name": "container.properties.created", - "type": "date" - }, - { - "attribute_name": "created", - "type": "date" - }, - { - "attribute_name": "creator", - "type": "nested" - }, - { - "attribute_name": "creator.properties._class", - "type": "keyword" - }, - { - "attribute_name": "description", - "type": "text" - }, - { - "attribute_name": "exchange_name", - "type": "keyword" - }, - { - "attribute_name": "id", - "type": "keyword" - }, - { - "attribute_name": "internal_name", - "type": "keyword" - }, - { - "attribute_name": "is_public", - "type": "boolean" - }, - { - "attribute_name": "name", - "type": "keyword" - }, - { - "attribute_name": "owner", - "type": "nested" - }, - { - "attribute_name": "owner.properties._class", - "type": "keyword" - } - ], - "status": 200 -} \ No newline at end of file diff --git a/dbrepo-search-service/examples/database/search_request_payload.json b/dbrepo-search-service/examples/database/search_request_payload.json deleted file mode 100644 index de7101b1b2a4527c277bc8dcee15f5b7ac68e77f..0000000000000000000000000000000000000000 --- a/dbrepo-search-service/examples/database/search_request_payload.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "database.created": "2022-05-27", - "database.description": "Some description", - "database.is_public": true, - "id": "5", - "internal_name": "test_db", - "name": "Test DB", - "search_term": "free text here", - "type": "database" -} \ No newline at end of file diff --git a/dbrepo-search-service/examples/unit/fields_response_payload.json b/dbrepo-search-service/examples/unit/fields_response_payload.json deleted file mode 100644 index e6bca5a6fefde9774af4e6f1f8d4df5aec402c34..0000000000000000000000000000000000000000 --- a/dbrepo-search-service/examples/unit/fields_response_payload.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "fields": [ - { - "attribute_name": "_class", - "type": "keyword" - }, - { - "attribute_name": "created", - "type": "date" - }, - { - "attribute_name": "description", - "type": "text" - }, - { - "attribute_name": "id", - "type": "keyword" - }, - { - "attribute_name": "name", - "type": "keyword" - }, - { - "attribute_name": "uri", - "type": "keyword" - } - ], - "status": 200 -} \ No newline at end of file diff --git a/dbrepo-search-service/examples/unit/search_request_payload.json b/dbrepo-search-service/examples/unit/search_request_payload.json deleted file mode 100644 index 28356ec8dbc331c294cff3cd6469ee8683ebc117..0000000000000000000000000000000000000000 --- a/dbrepo-search-service/examples/unit/search_request_payload.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "id": "7", - "name": "Test DB", - "search_term": "free text here", - "type": "unit", - "unit.uri": "some uri" -} \ No newline at end of file diff --git a/dbrepo-search-service/friendly_names_overrides.json b/dbrepo-search-service/friendly_names_overrides.json new file mode 100644 index 0000000000000000000000000000000000000000..8aca718186f840d438b4906cbd039debda15f179 --- /dev/null +++ b/dbrepo-search-service/friendly_names_overrides.json @@ -0,0 +1,18 @@ +{ + "tables.name": "Table Name", + "owner.id": "Owner ID", + "owner.username": "Owner Username", + "owner.attributes.orcid": "Owner ORCID", + "creator.orcid": "Creator ORCID", + "identifiers.doi": "DOI", + "identifiers.licenses.uri": "License URI", + "identifiers.funders.funder_identifier": "Funder PID", + "identifiers.table_id": "Table ID", + "identifiers.query_id": "Subset ID", + "identifiers.view_id": "View ID", + "identifiers.database_id": "Database ID", + "identifiers.creator.username": "Creator Username", + "is_public": "Public", + "tables.columns.concept.uri": "URI", + "tables.columns.unit.uri": "URI" +} \ No newline at end of file diff --git a/dbrepo-search-service/init/Dockerfile b/dbrepo-search-service/init/Dockerfile index b3874230bc62362ffd0dac80d399d38d6c5e707d..e61e29e080b2c08c3e080caa1e8c61ad610670a4 100644 --- a/dbrepo-search-service/init/Dockerfile +++ b/dbrepo-search-service/init/Dockerfile @@ -1,9 +1,10 @@ FROM python:3.11-alpine3.21 LABEL org.opencontainers.image.authors="martin.weise@tuwien.ac.at" -RUN apk add --no-cache curl bash jq - -WORKDIR /home/alpine +RUN apk add --no-cache \ + curl \ + bash \ + jq COPY Pipfile Pipfile.lock ./ @@ -13,12 +14,12 @@ RUN pip install pipenv && \ pipenv install gunicorn && \ pipenv install --system --deploy -USER 1001 +RUN adduser -D dbrepo --uid 1001 WORKDIR /app -COPY --chown=1001 ./clients ./clients -COPY --chown=1001 ./omlib ./omlib +USER 1001 + COPY --chown=1001 ./app.py ./app.py COPY --chown=1001 ./database.json ./database.json diff --git a/dbrepo-search-service/init/Pipfile b/dbrepo-search-service/init/Pipfile index 9f970d4c87e74de4c2f4df06221a6bdf9fab846b..c28f804c8ac2a61b301c5248e73f12e666340701 100644 --- a/dbrepo-search-service/init/Pipfile +++ b/dbrepo-search-service/init/Pipfile @@ -9,8 +9,9 @@ opensearch-py = "~=2.2" python-dotenv = "~=1.0" testcontainers-opensearch = "*" pytest = "*" -dbrepo = {path = "./lib/dbrepo-1.7.3.tar.gz"} +dbrepo = {path = "./lib/dbrepo-1.8.0.tar.gz"} rdflib = "*" +grafana-client = "*" [dev-packages] coverage = "*" diff --git a/dbrepo-search-service/init/Pipfile.lock b/dbrepo-search-service/init/Pipfile.lock index 55997adfc46e49c9c9f756236bb1f8d8b31deab2..be7988331ca1ced11e54f7778ad75c6456c413b3 100644 --- a/dbrepo-search-service/init/Pipfile.lock +++ b/dbrepo-search-service/init/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "902ab105fecae6a9ffa50c6db24de91d2f41d0494033ffd7f3284049a9ba4add" + "sha256": "67eb310e10e744b0fdb8dae9f252a9f80529fd2fd82cd4eb586cb22fd3fa56be" }, "pipfile-spec": 6, "requires": { @@ -26,90 +26,90 @@ }, "aiohttp": { "hashes": [ - "sha256:04eb541ce1e03edc1e3be1917a0f45ac703e913c21a940111df73a2c2db11d73", - "sha256:05582cb2d156ac7506e68b5eac83179faedad74522ed88f88e5861b78740dc0e", - "sha256:0a29be28e60e5610d2437b5b2fed61d6f3dcde898b57fb048aa5079271e7f6f3", - "sha256:0b2501f1b981e70932b4a552fc9b3c942991c7ae429ea117e8fba57718cdeed0", - "sha256:0df3788187559c262922846087e36228b75987f3ae31dd0a1e5ee1034090d42f", - "sha256:12c5869e7ddf6b4b1f2109702b3cd7515667b437da90a5a4a50ba1354fe41881", - "sha256:14fc03508359334edc76d35b2821832f092c8f092e4b356e74e38419dfe7b6de", - "sha256:1a7169ded15505f55a87f8f0812c94c9412623c744227b9e51083a72a48b68a5", - "sha256:1c68e41c4d576cd6aa6c6d2eddfb32b2acfb07ebfbb4f9da991da26633a3db1a", - "sha256:20412c7cc3720e47a47e63c0005f78c0c2370020f9f4770d7fc0075f397a9fb0", - "sha256:22a8107896877212130c58f74e64b77f7007cb03cea8698be317272643602d45", - "sha256:28a3d083819741592685762d51d789e6155411277050d08066537c5edc4066e6", - "sha256:2b86efe23684b58a88e530c4ab5b20145f102916bbb2d82942cafec7bd36a647", - "sha256:2d0b46abee5b5737cb479cc9139b29f010a37b1875ee56d142aefc10686a390b", - "sha256:321238a42ed463848f06e291c4bbfb3d15ba5a79221a82c502da3e23d7525d06", - "sha256:3a8a0d127c10b8d89e69bbd3430da0f73946d839e65fec00ae48ca7916a31948", - "sha256:3a8b0321e40a833e381d127be993b7349d1564b756910b28b5f6588a159afef3", - "sha256:3b420d076a46f41ea48e5fcccb996f517af0d406267e31e6716f480a3d50d65c", - "sha256:3b512f1de1c688f88dbe1b8bb1283f7fbeb7a2b2b26e743bb2193cbadfa6f307", - "sha256:413fe39fd929329f697f41ad67936f379cba06fcd4c462b62e5b0f8061ee4a77", - "sha256:41cf0cefd9e7b5c646c2ef529c8335e7eafd326f444cc1cdb0c47b6bc836f9be", - "sha256:4848ae31ad44330b30f16c71e4f586cd5402a846b11264c412de99fa768f00f3", - "sha256:4b0a200e85da5c966277a402736a96457b882360aa15416bf104ca81e6f5807b", - "sha256:4e2e8ef37d4bc110917d038807ee3af82700a93ab2ba5687afae5271b8bc50ff", - "sha256:4edcbe34e6dba0136e4cabf7568f5a434d89cc9de5d5155371acda275353d228", - "sha256:51ba80d473eb780a329d73ac8afa44aa71dfb521693ccea1dea8b9b5c4df45ce", - "sha256:5409a59d5057f2386bb8b8f8bbcfb6e15505cedd8b2445db510563b5d7ea1186", - "sha256:572def4aad0a4775af66d5a2b5923c7de0820ecaeeb7987dcbccda2a735a993f", - "sha256:599b66582f7276ebefbaa38adf37585e636b6a7a73382eb412f7bc0fc55fb73d", - "sha256:59a05cdc636431f7ce843c7c2f04772437dd816a5289f16440b19441be6511f1", - "sha256:602d4db80daf4497de93cb1ce00b8fc79969c0a7cf5b67bec96fa939268d806a", - "sha256:65c75b14ee74e8eeff2886321e76188cbe938d18c85cff349d948430179ad02c", - "sha256:69bb252bfdca385ccabfd55f4cd740d421dd8c8ad438ded9637d81c228d0da49", - "sha256:6d3986112e34eaa36e280dc8286b9dd4cc1a5bcf328a7f147453e188f6fe148f", - "sha256:6dd9766da617855f7e85f27d2bf9a565ace04ba7c387323cd3e651ac4329db91", - "sha256:70ab0f61c1a73d3e0342cedd9a7321425c27a7067bebeeacd509f96695b875fc", - "sha256:749f1eb10e51dbbcdba9df2ef457ec060554842eea4d23874a3e26495f9e87b1", - "sha256:781c8bd423dcc4641298c8c5a2a125c8b1c31e11f828e8d35c1d3a722af4c15a", - "sha256:7e7abe865504f41b10777ac162c727af14e9f4db9262e3ed8254179053f63e6d", - "sha256:7f2dadece8b85596ac3ab1ec04b00694bdd62abc31e5618f524648d18d9dd7fa", - "sha256:86135c32d06927339c8c5e64f96e4eee8825d928374b9b71a3c42379d7437058", - "sha256:8778620396e554b758b59773ab29c03b55047841d8894c5e335f12bfc45ebd28", - "sha256:87f0e003fb4dd5810c7fbf47a1239eaa34cd929ef160e0a54c570883125c4831", - "sha256:8aa5c68e1e68fff7cd3142288101deb4316b51f03d50c92de6ea5ce646e6c71f", - "sha256:8d14e274828561db91e4178f0057a915f3af1757b94c2ca283cb34cbb6e00b50", - "sha256:8d1dd75aa4d855c7debaf1ef830ff2dfcc33f893c7db0af2423ee761ebffd22b", - "sha256:92007c89a8cb7be35befa2732b0b32bf3a394c1b22ef2dff0ef12537d98a7bda", - "sha256:92868f6512714efd4a6d6cb2bfc4903b997b36b97baea85f744229f18d12755e", - "sha256:948abc8952aff63de7b2c83bfe3f211c727da3a33c3a5866a0e2cf1ee1aa950f", - "sha256:95d7787f2bcbf7cb46823036a8d64ccfbc2ffc7d52016b4044d901abceeba3db", - "sha256:997b57e38aa7dc6caab843c5e042ab557bc83a2f91b7bd302e3c3aebbb9042a1", - "sha256:99b8bbfc8111826aa8363442c0fc1f5751456b008737ff053570f06a151650b3", - "sha256:9e73fa341d8b308bb799cf0ab6f55fc0461d27a9fa3e4582755a3d81a6af8c09", - "sha256:a0d2c04a623ab83963576548ce098baf711a18e2c32c542b62322a0b4584b990", - "sha256:a40087b82f83bd671cbeb5f582c233d196e9653220404a798798bfc0ee189fff", - "sha256:ad1f2fb9fe9b585ea4b436d6e998e71b50d2b087b694ab277b30e060c434e5db", - "sha256:b05774864c87210c531b48dfeb2f7659407c2dda8643104fb4ae5e2c311d12d9", - "sha256:b41693b7388324b80f9acfabd479bd1c84f0bc7e8f17bab4ecd9675e9ff9c734", - "sha256:b42dbd097abb44b3f1156b4bf978ec5853840802d6eee2784857be11ee82c6a0", - "sha256:b4e7c7ec4146a94a307ca4f112802a8e26d969018fabed526efc340d21d3e7d0", - "sha256:b59d096b5537ec7c85954cb97d821aae35cfccce3357a2cafe85660cc6295628", - "sha256:b9c60d1de973ca94af02053d9b5111c4fbf97158e139b14f1be68337be267be6", - "sha256:bccd2cb7aa5a3bfada72681bdb91637094d81639e116eac368f8b3874620a654", - "sha256:c32593ead1a8c6aabd58f9d7ee706e48beac796bb0cb71d6b60f2c1056f0a65f", - "sha256:c7571f99525c76a6280f5fe8e194eeb8cb4da55586c3c61c59c33a33f10cfce7", - "sha256:c8b2df9feac55043759aa89f722a967d977d80f8b5865a4153fc41c93b957efc", - "sha256:ca9f835cdfedcb3f5947304e85b8ca3ace31eef6346d8027a97f4de5fb687534", - "sha256:cc9253069158d57e27d47a8453d8a2c5a370dc461374111b5184cf2f147a3cc3", - "sha256:ced66c5c6ad5bcaf9be54560398654779ec1c3695f1a9cf0ae5e3606694a000a", - "sha256:d173c0ac508a2175f7c9a115a50db5fd3e35190d96fdd1a17f9cb10a6ab09aa1", - "sha256:d6edc538c7480fa0a3b2bdd705f8010062d74700198da55d16498e1b49549b9c", - "sha256:daf20d9c3b12ae0fdf15ed92235e190f8284945563c4b8ad95b2d7a31f331cd3", - "sha256:dc311634f6f28661a76cbc1c28ecf3b3a70a8edd67b69288ab7ca91058eb5a33", - "sha256:e2bc827c01f75803de77b134afdbf74fa74b62970eafdf190f3244931d7a5c0d", - "sha256:e365034c5cf6cf74f57420b57682ea79e19eb29033399dd3f40de4d0171998fa", - "sha256:e906da0f2bcbf9b26cc2b144929e88cb3bf943dd1942b4e5af066056875c7618", - "sha256:e9faafa74dbb906b2b6f3eb9942352e9e9db8d583ffed4be618a89bd71a4e914", - "sha256:ec6cd1954ca2bbf0970f531a628da1b1338f594bf5da7e361e19ba163ecc4f3b", - "sha256:f296d637a50bb15fb6a229fbb0eb053080e703b53dbfe55b1e4bb1c5ed25d325", - "sha256:f30fc72daf85486cdcdfc3f5e0aea9255493ef499e31582b34abadbfaafb0965", - "sha256:fe846f0a98aa9913c2852b630cd39b4098f296e0907dd05f6c7b30d911afa4c3" + "sha256:004511d3413737700835e949433536a2fe95a7d0297edd911a1e9705c5b5ea43", + "sha256:0902e887b0e1d50424112f200eb9ae3dfed6c0d0a19fc60f633ae5a57c809656", + "sha256:09b00dd520d88eac9d1768439a59ab3d145065c91a8fab97f900d1b5f802895e", + "sha256:0a2f451849e6b39e5c226803dcacfa9c7133e9825dcefd2f4e837a2ec5a3bb98", + "sha256:0a950c2eb8ff17361abd8c85987fd6076d9f47d040ebffce67dce4993285e973", + "sha256:0ad1fb47da60ae1ddfb316f0ff16d1f3b8e844d1a1e154641928ea0583d486ed", + "sha256:13ceac2c5cdcc3f64b9015710221ddf81c900c5febc505dbd8f810e770011540", + "sha256:14461157d8426bcb40bd94deb0450a6fa16f05129f7da546090cebf8f3123b0f", + "sha256:16f8a2c9538c14a557b4d309ed4d0a7c60f0253e8ed7b6c9a2859a7582f8b1b8", + "sha256:17ae4664031aadfbcb34fd40ffd90976671fa0c0286e6c4113989f78bebab37a", + "sha256:1ce63ae04719513dd2651202352a2beb9f67f55cb8490c40f056cea3c5c355ce", + "sha256:23a15727fbfccab973343b6d1b7181bfb0b4aa7ae280f36fd2f90f5476805682", + "sha256:2540ddc83cc724b13d1838026f6a5ad178510953302a49e6d647f6e1de82bc34", + "sha256:37dcee4906454ae377be5937ab2a66a9a88377b11dd7c072df7a7c142b63c37c", + "sha256:38bea84ee4fe24ebcc8edeb7b54bf20f06fd53ce4d2cc8b74344c5b9620597fd", + "sha256:3ab3367bb7f61ad18793fea2ef71f2d181c528c87948638366bf1de26e239183", + "sha256:3ad1d59fd7114e6a08c4814983bb498f391c699f3c78712770077518cae63ff7", + "sha256:3b4e6db8dc4879015b9955778cfb9881897339c8fab7b3676f8433f849425913", + "sha256:3e061b09f6fa42997cf627307f220315e313ece74907d35776ec4373ed718b86", + "sha256:42864e70a248f5f6a49fdaf417d9bc62d6e4d8ee9695b24c5916cb4bb666c802", + "sha256:493910ceb2764f792db4dc6e8e4b375dae1b08f72e18e8f10f18b34ca17d0979", + "sha256:4d0c970c0d602b1017e2067ff3b7dac41c98fef4f7472ec2ea26fd8a4e8c2149", + "sha256:54eb3aead72a5c19fad07219acd882c1643a1027fbcdefac9b502c267242f955", + "sha256:56a3443aca82abda0e07be2e1ecb76a050714faf2be84256dae291182ba59049", + "sha256:576f5ca28d1b3276026f7df3ec841ae460e0fc3aac2a47cbf72eabcfc0f102e1", + "sha256:58ede86453a6cf2d6ce40ef0ca15481677a66950e73b0a788917916f7e35a0bb", + "sha256:61c721764e41af907c9d16b6daa05a458f066015abd35923051be8705108ed17", + "sha256:634d96869be6c4dc232fc503e03e40c42d32cfaa51712aee181e922e61d74814", + "sha256:696ef00e8a1f0cec5e30640e64eca75d8e777933d1438f4facc9c0cdf288a810", + "sha256:69a2cbd61788d26f8f1e626e188044834f37f6ae3f937bd9f08b65fc9d7e514e", + "sha256:6a792ce34b999fbe04a7a71a90c74f10c57ae4c51f65461a411faa70e154154e", + "sha256:6ac13b71761e49d5f9e4d05d33683bbafef753e876e8e5a7ef26e937dd766713", + "sha256:6fdec0213244c39973674ca2a7f5435bf74369e7d4e104d6c7473c81c9bcc8c4", + "sha256:72b1b03fb4655c1960403c131740755ec19c5898c82abd3961c364c2afd59fe7", + "sha256:745f1ed5e2c687baefc3c5e7b4304e91bf3e2f32834d07baaee243e349624b24", + "sha256:776c8e959a01e5e8321f1dec77964cb6101020a69d5a94cd3d34db6d555e01f7", + "sha256:780df0d837276276226a1ff803f8d0fa5f8996c479aeef52eb040179f3156cbd", + "sha256:78e6e23b954644737e385befa0deb20233e2dfddf95dd11e9db752bdd2a294d3", + "sha256:7951decace76a9271a1ef181b04aa77d3cc309a02a51d73826039003210bdc86", + "sha256:7ba92a2d9ace559a0a14b03d87f47e021e4fa7681dc6970ebbc7b447c7d4b7cd", + "sha256:7f6428fee52d2bcf96a8aa7b62095b190ee341ab0e6b1bcf50c615d7966fd45b", + "sha256:87944bd16b7fe6160607f6a17808abd25f17f61ae1e26c47a491b970fb66d8cb", + "sha256:87a6e922b2b2401e0b0cf6b976b97f11ec7f136bfed445e16384fbf6fd5e8602", + "sha256:8cb0688a8d81c63d716e867d59a9ccc389e97ac7037ebef904c2b89334407180", + "sha256:8df6612df74409080575dca38a5237282865408016e65636a76a2eb9348c2567", + "sha256:911a6e91d08bb2c72938bc17f0a2d97864c531536b7832abee6429d5296e5b27", + "sha256:92b7ee222e2b903e0a4b329a9943d432b3767f2d5029dbe4ca59fb75223bbe2e", + "sha256:938f756c2b9374bbcc262a37eea521d8a0e6458162f2a9c26329cc87fdf06534", + "sha256:9756d9b9d4547e091f99d554fbba0d2a920aab98caa82a8fb3d3d9bee3c9ae85", + "sha256:98b88a2bf26965f2015a771381624dd4b0839034b70d406dc74fd8be4cc053e3", + "sha256:9b751a6306f330801665ae69270a8a3993654a85569b3469662efaad6cf5cc50", + "sha256:a2a450bcce4931b295fc0848f384834c3f9b00edfc2150baafb4488c27953de6", + "sha256:a3814760a1a700f3cfd2f977249f1032301d0a12c92aba74605cfa6ce9f78489", + "sha256:a5abcbba9f4b463a45c8ca8b7720891200658f6f46894f79517e6cd11f3405ca", + "sha256:a6db7458ab89c7d80bc1f4e930cc9df6edee2200127cfa6f6e080cf619eddfbd", + "sha256:ad497f38a0d6c329cb621774788583ee12321863cd4bd9feee1effd60f2ad133", + "sha256:ad9509ffb2396483ceacb1eee9134724443ee45b92141105a4645857244aecc8", + "sha256:bbcba75fe879ad6fd2e0d6a8d937f34a571f116a0e4db37df8079e738ea95c71", + "sha256:c10d85e81d0b9ef87970ecbdbfaeec14a361a7fa947118817fcea8e45335fa46", + "sha256:c15b2271c44da77ee9d822552201180779e5e942f3a71fb74e026bf6172ff287", + "sha256:ca37057625693d097543bd88076ceebeb248291df9d6ca8481349efc0b05dcd0", + "sha256:cc3a145479a76ad0ed646434d09216d33d08eef0d8c9a11f5ae5cdc37caa3540", + "sha256:ccf10f16ab498d20e28bc2b5c1306e9c1512f2840f7b6a67000a517a4b37d5ee", + "sha256:cd464ba806e27ee24a91362ba3621bfc39dbbb8b79f2e1340201615197370f7c", + "sha256:d007aa39a52d62373bd23428ba4a2546eed0e7643d7bf2e41ddcefd54519842c", + "sha256:d0666afbe984f6933fe72cd1f1c3560d8c55880a0bdd728ad774006eb4241ecd", + "sha256:d07502cc14ecd64f52b2a74ebbc106893d9a9717120057ea9ea1fd6568a747e7", + "sha256:d489d9778522fbd0f8d6a5c6e48e3514f11be81cb0a5954bdda06f7e1594b321", + "sha256:df7db76400bf46ec6a0a73192b14c8295bdb9812053f4fe53f4e789f3ea66bbb", + "sha256:e3538bc9fe1b902bef51372462e3d7c96fce2b566642512138a480b7adc9d508", + "sha256:e87fd812899aa78252866ae03a048e77bd11b80fb4878ce27c23cade239b42b2", + "sha256:ecdb8173e6c7aa09eee342ac62e193e6904923bd232e76b4157ac0bfa670609f", + "sha256:f244b8e541f414664889e2c87cac11a07b918cb4b540c36f7ada7bfa76571ea2", + "sha256:f4065145bf69de124accdd17ea5f4dc770da0a6a6e440c53f6e0a8c27b3e635c", + "sha256:f420bfe862fb357a6d76f2065447ef6f484bc489292ac91e29bc65d2d7a2c84d", + "sha256:f6ddd90d9fb4b501c97a4458f1c1720e42432c26cb76d28177c5b5ad4e332601", + "sha256:fa73e8c2656a3653ae6c307b3f4e878a21f87859a9afab228280ddccd7369d71", + "sha256:fadbb8f1d4140825069db3fedbbb843290fd5f5bc0a5dbd7eaf81d91bf1b003b", + "sha256:fb3d0cc5cdb926090748ea60172fa8a213cec728bd6c54eae18b96040fcd6227", + "sha256:fb46bb0f24813e6cede6cc07b1961d4b04f331f7112a23b5e21f567da4ee50aa", + "sha256:fd36c119c5d6551bce374fcb5c19269638f8d09862445f85a5a48596fd59f4bb" ], "markers": "python_version >= '3.9'", - "version": "==3.11.14" + "version": "==3.11.16" }, "aiosignal": { "hashes": [ @@ -259,9 +259,9 @@ }, "dbrepo": { "hashes": [ - "sha256:ad01d6dc5d99f3c0c9caf3fb11b51502bec5390c72ff28b6b725e2755f5a2f7c" + "sha256:55de6a4934010e14a574032b5a5179bf3dac9895ef74e5cd4a221a625a75674b" ], - "path": "./lib/dbrepo-1.7.3.tar.gz" + "path": "./lib/dbrepo-1.8.0.tar.gz" }, "docker": { "hashes": [ @@ -384,6 +384,23 @@ "markers": "python_version >= '3.8'", "version": "==1.5.0" }, + "grafana-client": { + "hashes": [ + "sha256:2477a47b923fd0637947e620b0b777c641af18a3025464fa4505783dbf05dfcc", + "sha256:8cb61bb2a87ec07bca10974df276b9a1a95bfdb63f3a696f065692ffc9b8c389" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==4.3.2" + }, + "h11": { + "hashes": [ + "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", + "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761" + ], + "markers": "python_version >= '3.7'", + "version": "==0.14.0" + }, "idna": { "hashes": [ "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", @@ -394,11 +411,11 @@ }, "iniconfig": { "hashes": [ - "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", - "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" + "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", + "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760" ], - "markers": "python_version >= '3.7'", - "version": "==2.0.0" + "markers": "python_version >= '3.8'", + "version": "==2.1.0" }, "itsdangerous": { "hashes": [ @@ -408,6 +425,108 @@ "markers": "python_version >= '3.8'", "version": "==2.2.0" }, + "jh2": { + "hashes": [ + "sha256:038091480cd1544e9389b0adbb1b1645a797689dcb68ceae7e45eec96ed24497", + "sha256:0c8e336df8ed1687590695f4469f480eeb4159bf13bb6193791c6530fe114b49", + "sha256:0c9bf2d5e4ef45c1686c6f76935e7ca263f5eae4de92bf5d1873a0e737e4eb7d", + "sha256:0faf6e96f74d27b8ca816b40217904891f91b664ed1c0388737949ceb50ac15d", + "sha256:10ea7f497e6226372e1d4fdbf42c8381f4887819a643ab930bff4072ad298d84", + "sha256:11650f7ed77ee1df30f25d6b3b74b2fa1c94124e074fd455abafea3cbc913d53", + "sha256:12ead3ee3e9c7caa00356b528a5cc7fe210fbe2060628af6e19ed76b8416572e", + "sha256:136b3c5b08883681fcb58f12393a5bbfa422d6e2d5ba887e263e776874276bc6", + "sha256:17d6e1691154ea9f726e43dcb717df48e56c66b5a01c90ad675c6494c36e5be1", + "sha256:19cb987915cc0d321746a12f2a693d087ffb721c37ac9a153cc088c57d4d90eb", + "sha256:1cdf15de698c4026e64fd914fead3180e52bf2a7bcbe44a3392404582dbf2d22", + "sha256:1e81e1c64e33506b8508ba5e3c7c139b2577e78b079c2c16a8e7a02a161f1080", + "sha256:2226c76e4ff2149c5d9f94bed22bf9c4f3411d38cc53d4a7ddfbe0899c8b558c", + "sha256:2837412fb7b684c6ce7392c8bc57440c6dbadaf1bde7a53144381f7df7083c1c", + "sha256:293f0f3da3c391e997e0d55fdb85540e98a8b0406622bb4ba57fb7617697f31e", + "sha256:2b9cc6c0239215a349d28c192fa4c4e7a7348eee7980531525c01bffe39eea80", + "sha256:2f3ad679f84ff236a0d7b71ddc4b3c09fe467abee2f1a86671f0cd417be5352b", + "sha256:358cad2f328c52c15756cf32b0ad17afb0d617e7cdfe93d59aa2616966d825b7", + "sha256:3663712305b509f79c002c8c0ca9994f716cadba576f5a59632dda1aec1ca8c6", + "sha256:41794820ccca039ca2ead6245f30b34601dd1456eee5b5dde620672bb989e79d", + "sha256:44b7e64aff542471c474c24f771eae5efd9152da02a12556f7cb7607020e1420", + "sha256:45770eb0990166026538d3c2fd7d92f17cfde13ca6567570c4baec3ce9162936", + "sha256:498060078a4d1b458e9381fefb027d85329397b50d65287712b3d48233e20836", + "sha256:4c2f18f337c2393f84e45e5011c8b02697b81638b1cec49da60a01b9ed067695", + "sha256:5162d6e475d2762035fb8ea25982bcbec6c58715e33bd0951499f743cd90b110", + "sha256:51e8c890bb59008c95b3a552cefd8bd9ce50a7466a6c920a78cf586e885d7449", + "sha256:56ad3839ac6ac5fd3d023cf59d4b04264b74bb4cb44c0780faf51d6b5ff38fbc", + "sha256:5821638ef0d7c973071810a6786f59b305172197f7e7e469a2ce169e7f4978e3", + "sha256:5ac1b2d379f4d40c13dcce537e69704452943cddbe991fd54a84fdb2da9026d5", + "sha256:5b465d4311b0429fe6fa85df8e2cfcb038c9fface95396dd14e838ecabaaadf2", + "sha256:5d8656b98057329bd03d968aac8d5198389cf51517511295cfc4cb827a507e39", + "sha256:5dcfb3e823ef4b91b70b92848570d1d8cfd584304bd2bd54272dc100c9494def", + "sha256:5e40d23ea43f683f3a7c032dde391104f609b05c21b6d284101120b51dbd50c1", + "sha256:63a01522bde161c713f7fa5ee5d850fee6386fc386073490ebcd438f14579cf2", + "sha256:6b2a3d7756035dde13571f4ad232629b78b7f35c2cd5fda7b464079fc697db3a", + "sha256:6b3be1a6bf6c965aea3b4e3a40df9d2c134c516d89c76cf2b6c81f67e6c5c6ed", + "sha256:6c7bea3357f2dc653756e6da55f66cd21c73d3875c8f3dc4e8d196a876252de0", + "sha256:6e6c8e229507cf29333a2f491cbaa7dff5b8a4a3e613af8090ccce9ce3e4f7a0", + "sha256:6fad27f2a63884ee45d491aebec4b1f38752cd6aaccc625038c21e7f43c02c49", + "sha256:71bfef52547c2b8b145897fa8d1b5142bc52313cfa38c0742e0ef755f0d09c60", + "sha256:72370d312323282b1bf74426e53fae861a310d7ae519b419da46673c38e7d147", + "sha256:76c7d36043a9c478b0c846fcec7da5cb095983722473e503e0122ccd170182b5", + "sha256:78d8a81ef51edb9a2f278a6fb278789b49e304b12bb21bccf2fe7e344f71a9fb", + "sha256:798a6b159ce32181a5e7ab7611c17d1080e74a5541fec47f961b728dab25a76f", + "sha256:7e370567f66a57e2c0e3ae2afcc6f126e1d6babd36831cfd0caad279b05c1c88", + "sha256:8004b845f606b95a8b17efa112aa10b327e46e95dcda604a257b4633d4ed45c8", + "sha256:80b20bf9ea4e709b3b9ae364ac298dfa872b084c186e5c1d60b0b79c79a7ee7e", + "sha256:87303f4bb1b493997f911a4f126123ccd2827d3a2e7dd2390cc6143fbc75805b", + "sha256:8d423f4631395b92dceda39f481a463498131ac02a58581124a44495491f715b", + "sha256:94ee262192db50fb9c069a0be7bb1a426fb1b43af26ce12bf4c6c30e13f46b56", + "sha256:960e4be2e7de340300ab4bcc2b45bed46be1d62330575b8265e6602dbcb9a14c", + "sha256:99397d5e1da6b345cec3e6125e2902b0e6864eb8eaa4be43a2013f059c502c93", + "sha256:9abbb8c1bad08817bad62ae1ea76c01bdbd0ee8c827d05f3ba038c9f6d6f14bb", + "sha256:9c0b8fadf80bc70d341032f92702bda1b0ed78c01e9c495f0df701938c99bcf5", + "sha256:9f977da9abae170eebdcf02bda33727c342fad5dcdbc08498bfdfb6cc6c65489", + "sha256:a6be712ca39d5e9c89b705bc9800be36739436fefb8d0b52b2d332f7d6d22a01", + "sha256:aa434418d6ee44b0ba3a5a407bc9e1543cf496328f43f149e9b58f74a63d5c21", + "sha256:ac4f778e32f7de0ba63346893a4af87c2280ffc1783f594a117be51d908a10da", + "sha256:ac85d65ee369c09b2904b55078ad589961e2e2e03c810963d35a26e6a3931425", + "sha256:ad5d78c664d39960435d4162db31117c8945ba74fb0c414e79ba85a8bdeafdec", + "sha256:ad91f57c3485d87a8edee558dafab0f08c716857d748731c0998dcefe9d3fd5f", + "sha256:afd255d42b340036883ca95bded553b29065b064e2fe5db64ad5988517db9694", + "sha256:b1c2c74f100a0c2110a8e30445554ae331860d32f145c60a2a1e1c27702022a2", + "sha256:b49a8c71378d40d43c6a56eaa536d7823baa43c27c93e082aeb60a9717be0c10", + "sha256:b5f52611323e8e35705e6750a760f32165b41c052d22da154ae343871e7cd50d", + "sha256:b6bf99ae529ac359263269710356d3ddb173c15d8f8dc8849ae794ab811e5cd0", + "sha256:ba361bf87c4701f11241be92c99ef5cf916865dd225955cccb2376bf76717b3c", + "sha256:bc351aa2158575e68943d8e1d5531719ad86bf6607776627ed5a1a60657664af", + "sha256:bd6eb7b1e12e4dd0b75cab1b023272f1333494add5ad61deedac738af1ffeede", + "sha256:bf8852595f5e2d2b072e24c29394b5aca7fba96ecc8656d56660535f9e9872c9", + "sha256:c1dd66541569a2bdbe92589cc96a89f470b20d168f2238fd463e1b59ee3e2d49", + "sha256:c36a7a004cba4e370d0675826eeefe4e42a256638b6b1432263ddb4af317bc02", + "sha256:c886cda61da4d39010be84802bed11bc75f03e8a6094cc18016957a2c80254d4", + "sha256:cc7aa83946f80c66a5d2dea7e165f15aa3eb21e7b74b24d8f850afc0d44bb00e", + "sha256:cea9c4bef70d1358bafec6019164abce362f4de15d79d1ecd64ae31c1749d77a", + "sha256:cfe1951e80869695857986be104a40a1e7fa8ec7de05f86bcbd7bd20854be764", + "sha256:d36cf6f139da3279644794fcfda18af425c8bb122ef9c2e7c762a937bbf7b0f4", + "sha256:d81308faaa9393b7e6ed20718d465c4c2b73c24d5e4826024961acf4b87b1524", + "sha256:db51ea1f9c5ac790848bc271fcdf4108ad1b77a77c6949a96320477962cf7ba5", + "sha256:dd05c18c920a15e00d7a52df37bffd3930fe2c004c690f9422b20e12077e6dbd", + "sha256:df05918a11e1db0198d00486e36673b4b4a89390e4458ff9479b4908dde357ac", + "sha256:e4c31dccf6be131709e545d0258eb5b75c5fac304857ad3976331c6740e8b9d6", + "sha256:e60954d673040430802b29fe5bba698e262182b5ba5f302ff4458e39f8101881", + "sha256:e60e2d2c88a0552e61c37172fe377f6a8abf479130a445314886de4a360ba940", + "sha256:e786f773ddc153846b2ebdb854011cfd1f7c874b8ee79cced3706801341c9f5d", + "sha256:e7cd91548fb95b69edd376f5204e27115ac7d093ec7d80066123a5bdb31c71d9", + "sha256:eaef2ea4f5602aefaaf3d6e8235f3b9ffde35aff15aac1c16cc802f6bbf0a3b5", + "sha256:ec8c5ea93a03775fbadd08462200cf34ce617ec75a032abfa44fd6d3a00e5424", + "sha256:eddeb8574bc9d9abb8491d4a46b60e553c2cea235b80373756acb06568101175", + "sha256:eeb300b0e4b428aab2f70d785cad4306529262af6de8c8c5fe6a4b41a674a434", + "sha256:f39d71ece8e97cf069e4154868eaac1256b133fe23e0459829432e4bb6406472", + "sha256:f4840ddad2b9d53710e92361391944da89e3576641a290066a1719520059247c", + "sha256:f70723a00bcbce0f9a216853139955be45da35741335eb3afead304e77662560", + "sha256:f829cf2ba5b553e6529d6238928c07096f1feb47f4ad536b7f06bca6cc77173f", + "sha256:f96386910467725895f7972939a6faabd6e96b1de0cc2c092e4bd2c40e956e25", + "sha256:fe259a9d6f555bc79aed9bb4b9a7fff73db443b4c483e4a81a428c8a2860428b" + ], + "markers": "python_version >= '3.7'", + "version": "==5.0.8" + }, "jinja2": { "hashes": [ "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", @@ -485,101 +604,109 @@ }, "multidict": { "hashes": [ - "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f", - "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056", - "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761", - "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3", - "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b", - "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6", - "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748", - "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966", - "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f", - "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1", - "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6", - "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada", - "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305", - "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2", - "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d", - "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a", - "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef", - "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c", - "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb", - "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60", - "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6", - "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4", - "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478", - "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81", - "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7", - "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56", - "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3", - "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6", - "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30", - "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb", - "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", - "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0", - "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925", - "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c", - "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6", - "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e", - "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95", - "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2", - "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133", - "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2", - "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa", - "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3", - "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3", - "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436", - "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657", - "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581", - "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492", - "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43", - "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2", - "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2", - "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926", - "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057", - "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc", - "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80", - "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255", - "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1", - "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972", - "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53", - "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1", - "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423", - "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a", - "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160", - "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c", - "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd", - "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa", - "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5", - "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b", - "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa", - "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef", - "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44", - "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4", - "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156", - "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753", - "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28", - "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d", - "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a", - "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304", - "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008", - "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429", - "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72", - "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399", - "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3", - "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392", - "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167", - "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c", - "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774", - "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351", - "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76", - "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875", - "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd", - "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28", - "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db" + "sha256:0085b0afb2446e57050140240a8595846ed64d1cbd26cef936bfab3192c673b8", + "sha256:042028348dc5a1f2be6c666437042a98a5d24cee50380f4c0902215e5ec41844", + "sha256:05fefbc3cddc4e36da209a5e49f1094bbece9a581faa7f3589201fd95df40e5d", + "sha256:063be88bd684782a0715641de853e1e58a2f25b76388538bd62d974777ce9bc2", + "sha256:07bfa8bc649783e703263f783f73e27fef8cd37baaad4389816cf6a133141331", + "sha256:08549895e6a799bd551cf276f6e59820aa084f0f90665c0f03dd3a50db5d3c48", + "sha256:095a2eabe8c43041d3e6c2cb8287a257b5f1801c2d6ebd1dd877424f1e89cf29", + "sha256:0b183a959fb88ad1be201de2c4bdf52fa8e46e6c185d76201286a97b6f5ee65c", + "sha256:0c383d28857f66f5aebe3e91d6cf498da73af75fbd51cedbe1adfb85e90c0460", + "sha256:0d57a01a2a9fa00234aace434d8c131f0ac6e0ac6ef131eda5962d7e79edfb5b", + "sha256:0dc25a3293c50744796e87048de5e68996104d86d940bb24bc3ec31df281b191", + "sha256:0e5a644e50ef9fb87878d4d57907f03a12410d2aa3b93b3acdf90a741df52c49", + "sha256:0f249badb360b0b4d694307ad40f811f83df4da8cef7b68e429e4eea939e49dd", + "sha256:0f74f2fc51555f4b037ef278efc29a870d327053aba5cb7d86ae572426c7cccc", + "sha256:125dd82b40f8c06d08d87b3510beaccb88afac94e9ed4a6f6c71362dc7dbb04b", + "sha256:13551d0e2d7201f0959725a6a769b6f7b9019a168ed96006479c9ac33fe4096b", + "sha256:14ed9ed1bfedd72a877807c71113deac292bf485159a29025dfdc524c326f3e1", + "sha256:163f4604e76639f728d127293d24c3e208b445b463168af3d031b92b0998bb90", + "sha256:19e2819b0b468174de25c0ceed766606a07cedeab132383f1e83b9a4e96ccb4f", + "sha256:1e2a2193d3aa5cbf5758f6d5680a52aa848e0cf611da324f71e5e48a9695cc86", + "sha256:1f3c099d3899b14e1ce52262eb82a5f5cb92157bb5106bf627b618c090a0eadc", + "sha256:214207dcc7a6221d9942f23797fe89144128a71c03632bf713d918db99bd36de", + "sha256:2325105e16d434749e1be8022f942876a936f9bece4ec41ae244e3d7fae42aaf", + "sha256:2529ddbdaa424b2c6c2eb668ea684dd6b75b839d0ad4b21aad60c168269478d7", + "sha256:256d431fe4583c5f1e0f2e9c4d9c22f3a04ae96009b8cfa096da3a8723db0a16", + "sha256:25bb96338512e2f46f615a2bb7c6012fe92a4a5ebd353e5020836a7e33120349", + "sha256:2e87f1926e91855ae61769ba3e3f7315120788c099677e0842e697b0bfb659f2", + "sha256:2fc6af8e39f7496047c7876314f4317736eac82bf85b54c7c76cf1a6f8e35d98", + "sha256:3157126b028c074951839233647bd0e30df77ef1fedd801b48bdcad242a60f4e", + "sha256:32c9b4878f48be3e75808ea7e499d6223b1eea6d54c487a66bc10a1871e3dc6a", + "sha256:32ed748ff9ac682eae7859790d3044b50e3076c7d80e17a44239683769ff485e", + "sha256:3501621d5e86f1a88521ea65d5cad0a0834c77b26f193747615b7c911e5422d2", + "sha256:437c33561edb6eb504b5a30203daf81d4a9b727e167e78b0854d9a4e18e8950b", + "sha256:48d39b1824b8d6ea7de878ef6226efbe0773f9c64333e1125e0efcfdd18a24c7", + "sha256:4ac3fcf9a2d369bd075b2c2965544036a27ccd277fc3c04f708338cc57533081", + "sha256:4ccfd74957ef53fa7380aaa1c961f523d582cd5e85a620880ffabd407f8202c0", + "sha256:52b05e21ff05729fbea9bc20b3a791c3c11da61649ff64cce8257c82a020466d", + "sha256:5389445f0173c197f4a3613713b5fb3f3879df1ded2a1a2e4bc4b5b9c5441b7e", + "sha256:5c5e7d2e300d5cb3b2693b6d60d3e8c8e7dd4ebe27cd17c9cb57020cac0acb80", + "sha256:5d26547423e5e71dcc562c4acdc134b900640a39abd9066d7326a7cc2324c530", + "sha256:5dd7106d064d05896ce28c97da3f46caa442fe5a43bc26dfb258e90853b39b44", + "sha256:5f8cb1329f42fadfb40d6211e5ff568d71ab49be36e759345f91c69d1033d633", + "sha256:61d5541f27533f803a941d3a3f8a3d10ed48c12cf918f557efcbf3cd04ef265c", + "sha256:639556758c36093b35e2e368ca485dada6afc2bd6a1b1207d85ea6dfc3deab27", + "sha256:641cf2e3447c9ecff2f7aa6e9eee9eaa286ea65d57b014543a4911ff2799d08a", + "sha256:6aed763b6a1b28c46c055692836879328f0b334a6d61572ee4113a5d0c859872", + "sha256:6e2a2d6749e1ff2c9c76a72c6530d5baa601205b14e441e6d98011000f47a7ac", + "sha256:7243c5a6523c5cfeca76e063efa5f6a656d1d74c8b1fc64b2cd1e84e507f7e2a", + "sha256:76b34c12b013d813e6cb325e6bd4f9c984db27758b16085926bbe7ceeaace626", + "sha256:781b5dd1db18c9e9eacc419027b0acb5073bdec9de1675c0be25ceb10e2ad133", + "sha256:7c611345bbe7cb44aabb877cb94b63e86f2d0db03e382667dbd037866d44b4f8", + "sha256:83b78c680d4b15d33042d330c2fa31813ca3974197bddb3836a5c635a5fd013f", + "sha256:84e87a7d75fa36839a3a432286d719975362d230c70ebfa0948549cc38bd5b46", + "sha256:89b3857652183b8206a891168af47bac10b970d275bba1f6ee46565a758c078d", + "sha256:8cd1a0644ccaf27e9d2f6d9c9474faabee21f0578fe85225cc5af9a61e1653df", + "sha256:8de4d42dffd5ced9117af2ce66ba8722402541a3aa98ffdf78dde92badb68932", + "sha256:94a7bb972178a8bfc4055db80c51efd24baefaced5e51c59b0d598a004e8305d", + "sha256:98aa8325c7f47183b45588af9c434533196e241be0a4e4ae2190b06d17675c02", + "sha256:9e658d1373c424457ddf6d55ec1db93c280b8579276bebd1f72f113072df8a5d", + "sha256:9f49585f4abadd2283034fc605961f40c638635bc60f5162276fec075f2e37a4", + "sha256:9f6cad071960ba1914fa231677d21b1b4a3acdcce463cee41ea30bc82e6040cf", + "sha256:a0cc398350ef31167e03f3ca7c19313d4e40a662adcb98a88755e4e861170bdd", + "sha256:a1133414b771619aa3c3000701c11b2e4624a7f492f12f256aedde97c28331a2", + "sha256:a33273a541f1e1a8219b2a4ed2de355848ecc0254264915b9290c8d2de1c74e1", + "sha256:a3c0ff89fe40a152e77b191b83282c9664357dce3004032d42e68c514ceff27e", + "sha256:a49994481b99cd7dedde07f2e7e93b1d86c01c0fca1c32aded18f10695ae17eb", + "sha256:abf5b17bc0cf626a8a497d89ac691308dbd825d2ac372aa990b1ca114e470151", + "sha256:ac380cacdd3b183338ba63a144a34e9044520a6fb30c58aa14077157a033c13e", + "sha256:ad81012b24b88aad4c70b2cbc2dad84018783221b7f923e926f4690ff8569da3", + "sha256:b2c00ad31fbc2cbac85d7d0fcf90853b2ca2e69d825a2d3f3edb842ef1544a2c", + "sha256:b4c153863dd6569f6511845922c53e39c8d61f6e81f228ad5443e690fca403de", + "sha256:b4f3d66dd0354b79761481fc15bdafaba0b9d9076f1f42cc9ce10d7fcbda205a", + "sha256:b99aac6bb2c37db336fa03a39b40ed4ef2818bf2dfb9441458165ebe88b793af", + "sha256:b9f6392d98c0bd70676ae41474e2eecf4c7150cb419237a41f8f96043fcb81d1", + "sha256:c537da54ce4ff7c15e78ab1292e5799d0d43a2108e006578a57f531866f64025", + "sha256:ca23db5fb195b5ef4fd1f77ce26cadefdf13dba71dab14dadd29b34d457d7c44", + "sha256:cc826b9a8176e686b67aa60fd6c6a7047b0461cae5591ea1dc73d28f72332a8a", + "sha256:cca83a629f77402cfadd58352e394d79a61c8015f1694b83ab72237ec3941f88", + "sha256:cf8d370b2fea27fb300825ec3984334f7dd54a581bde6456799ba3776915a656", + "sha256:d1175b0e0d6037fab207f05774a176d71210ebd40b1c51f480a04b65ec5c786d", + "sha256:d1996ee1330e245cd3aeda0887b4409e3930524c27642b046e4fae88ffa66c5e", + "sha256:d5a36953389f35f0a4e88dc796048829a2f467c9197265504593f0e420571547", + "sha256:da51d8928ad8b4244926fe862ba1795f0b6e68ed8c42cd2f822d435db9c2a8f4", + "sha256:e16e7297f29a544f49340012d6fc08cf14de0ab361c9eb7529f6a57a30cbfda1", + "sha256:e25b11a0417475f093d0f0809a149aff3943c2c56da50fdf2c3c88d57fe3dfbd", + "sha256:e4371591e621579cb6da8401e4ea405b33ff25a755874a3567c4075ca63d56e2", + "sha256:e653d36b1bf48fa78c7fcebb5fa679342e025121ace8c87ab05c1cefd33b34fc", + "sha256:e7d91a230c7f8af86c904a5a992b8c064b66330544693fd6759c3d6162382ecf", + "sha256:e851e6363d0dbe515d8de81fd544a2c956fdec6f8a049739562286727d4a00c3", + "sha256:ef7d48207926edbf8b16b336f779c557dd8f5a33035a85db9c4b0febb0706817", + "sha256:f7716f7e7138252d88607228ce40be22660d6608d20fd365d596e7ca0738e019", + "sha256:facaf11f21f3a4c51b62931feb13310e6fe3475f85e20d9c9fdce0d2ea561b87" ], - "markers": "python_version >= '3.8'", - "version": "==6.1.0" + "markers": "python_version >= '3.9'", + "version": "==6.2.0" + }, + "niquests": { + "hashes": [ + "sha256:68e0a7e9f338466b3606945fffd11f75e3c90af7498aa9336ef03812323b7e36", + "sha256:86e484c2c60444aa96069c15f6295af6e25a8bad50781e1326df1b5c7ab48339" + ], + "markers": "python_version >= '3.7'", + "version": "==3.14.0" }, "numpy": { "hashes": [ @@ -725,229 +852,228 @@ }, "propcache": { "hashes": [ - "sha256:02df07041e0820cacc8f739510078f2aadcfd3fc57eaeeb16d5ded85c872c89e", - "sha256:03acd9ff19021bd0567582ac88f821b66883e158274183b9e5586f678984f8fe", - "sha256:03c091bb752349402f23ee43bb2bff6bd80ccab7c9df6b88ad4322258d6960fc", - "sha256:07700939b2cbd67bfb3b76a12e1412405d71019df00ca5697ce75e5ef789d829", - "sha256:0c3e893c4464ebd751b44ae76c12c5f5c1e4f6cbd6fbf67e3783cd93ad221863", - "sha256:119e244ab40f70a98c91906d4c1f4c5f2e68bd0b14e7ab0a06922038fae8a20f", - "sha256:11ae6a8a01b8a4dc79093b5d3ca2c8a4436f5ee251a9840d7790dccbd96cb649", - "sha256:15010f29fbed80e711db272909a074dc79858c6d28e2915704cfc487a8ac89c6", - "sha256:19d36bb351ad5554ff20f2ae75f88ce205b0748c38b146c75628577020351e3c", - "sha256:1c8f7d896a16da9455f882870a507567d4f58c53504dc2d4b1e1d386dfe4588a", - "sha256:2383a17385d9800b6eb5855c2f05ee550f803878f344f58b6e194de08b96352c", - "sha256:24c04f8fbf60094c531667b8207acbae54146661657a1b1be6d3ca7773b7a545", - "sha256:2578541776769b500bada3f8a4eeaf944530516b6e90c089aa368266ed70c49e", - "sha256:26a67e5c04e3119594d8cfae517f4b9330c395df07ea65eab16f3d559b7068fe", - "sha256:2b975528998de037dfbc10144b8aed9b8dd5a99ec547f14d1cb7c5665a43f075", - "sha256:2d15bc27163cd4df433e75f546b9ac31c1ba7b0b128bfb1b90df19082466ff57", - "sha256:2d913d36bdaf368637b4f88d554fb9cb9d53d6920b9c5563846555938d5450bf", - "sha256:3302c5287e504d23bb0e64d2a921d1eb4a03fb93a0a0aa3b53de059f5a5d737d", - "sha256:36ca5e9a21822cc1746023e88f5c0af6fce3af3b85d4520efb1ce4221bed75cc", - "sha256:3b812b3cb6caacd072276ac0492d249f210006c57726b6484a1e1805b3cfeea0", - "sha256:3c6ec957025bf32b15cbc6b67afe233c65b30005e4c55fe5768e4bb518d712f1", - "sha256:41de3da5458edd5678b0f6ff66691507f9885f5fe6a0fb99a5d10d10c0fd2d64", - "sha256:42924dc0c9d73e49908e35bbdec87adedd651ea24c53c29cac103ede0ea1d340", - "sha256:4544699674faf66fb6b4473a1518ae4999c1b614f0b8297b1cef96bac25381db", - "sha256:46ed02532cb66612d42ae5c3929b5e98ae330ea0f3900bc66ec5f4862069519b", - "sha256:49ea05212a529c2caffe411e25a59308b07d6e10bf2505d77da72891f9a05641", - "sha256:4fa0e7c9c3cf7c276d4f6ab9af8adddc127d04e0fcabede315904d2ff76db626", - "sha256:507c5357a8d8b4593b97fb669c50598f4e6cccbbf77e22fa9598aba78292b4d7", - "sha256:549722908de62aa0b47a78b90531c022fa6e139f9166be634f667ff45632cc92", - "sha256:58e6d2a5a7cb3e5f166fd58e71e9a4ff504be9dc61b88167e75f835da5764d07", - "sha256:5a16167118677d94bb48bfcd91e420088854eb0737b76ec374b91498fb77a70e", - "sha256:5d62c4f6706bff5d8a52fd51fec6069bef69e7202ed481486c0bc3874912c787", - "sha256:5fa159dcee5dba00c1def3231c249cf261185189205073bde13797e57dd7540a", - "sha256:6032231d4a5abd67c7f71168fd64a47b6b451fbcb91c8397c2f7610e67683810", - "sha256:63f26258a163c34542c24808f03d734b338da66ba91f410a703e505c8485791d", - "sha256:65a37714b8ad9aba5780325228598a5b16c47ba0f8aeb3dc0514701e4413d7c0", - "sha256:67054e47c01b7b349b94ed0840ccae075449503cf1fdd0a1fdd98ab5ddc2667b", - "sha256:67dda3c7325691c2081510e92c561f465ba61b975f481735aefdfc845d2cd043", - "sha256:6985a593417cdbc94c7f9c3403747335e450c1599da1647a5af76539672464d3", - "sha256:6a1948df1bb1d56b5e7b0553c0fa04fd0e320997ae99689488201f19fa90d2e7", - "sha256:6b5b7fd6ee7b54e01759f2044f936dcf7dea6e7585f35490f7ca0420fe723c0d", - "sha256:6c929916cbdb540d3407c66f19f73387f43e7c12fa318a66f64ac99da601bcdf", - "sha256:6f4d7a7c0aff92e8354cceca6fe223973ddf08401047920df0fcb24be2bd5138", - "sha256:728af36011bb5d344c4fe4af79cfe186729efb649d2f8b395d1572fb088a996c", - "sha256:742840d1d0438eb7ea4280f3347598f507a199a35a08294afdcc560c3739989d", - "sha256:75e872573220d1ee2305b35c9813626e620768248425f58798413e9c39741f46", - "sha256:794c3dd744fad478b6232289c866c25406ecdfc47e294618bdf1697e69bd64a6", - "sha256:7c0fdbdf6983526e269e5a8d53b7ae3622dd6998468821d660d0daf72779aefa", - "sha256:7c5f5290799a3f6539cc5e6f474c3e5c5fbeba74a5e1e5be75587746a940d51e", - "sha256:7c6e7e4f9167fddc438cd653d826f2222222564daed4116a02a184b464d3ef05", - "sha256:7cedd25e5f678f7738da38037435b340694ab34d424938041aa630d8bac42663", - "sha256:7e2e068a83552ddf7a39a99488bcba05ac13454fb205c847674da0352602082f", - "sha256:8319293e85feadbbfe2150a5659dbc2ebc4afdeaf7d98936fb9a2f2ba0d4c35c", - "sha256:8526b0941ec5a40220fc4dfde76aed58808e2b309c03e9fa8e2260083ef7157f", - "sha256:8884ba1a0fe7210b775106b25850f5e5a9dc3c840d1ae9924ee6ea2eb3acbfe7", - "sha256:8cb625bcb5add899cb8ba7bf716ec1d3e8f7cdea9b0713fa99eadf73b6d4986f", - "sha256:8d663fd71491dde7dfdfc899d13a067a94198e90695b4321084c6e450743b8c7", - "sha256:8ee1983728964d6070ab443399c476de93d5d741f71e8f6e7880a065f878e0b9", - "sha256:997e7b8f173a391987df40f3b52c423e5850be6f6df0dcfb5376365440b56667", - "sha256:9be90eebc9842a93ef8335291f57b3b7488ac24f70df96a6034a13cb58e6ff86", - "sha256:9ddd49258610499aab83b4f5b61b32e11fce873586282a0e972e5ab3bcadee51", - "sha256:9ecde3671e62eeb99e977f5221abcf40c208f69b5eb986b061ccec317c82ebd0", - "sha256:9ff4e9ecb6e4b363430edf2c6e50173a63e0820e549918adef70515f87ced19a", - "sha256:a254537b9b696ede293bfdbc0a65200e8e4507bc9f37831e2a0318a9b333c85c", - "sha256:a2b9bf8c79b660d0ca1ad95e587818c30ccdb11f787657458d6f26a1ea18c568", - "sha256:a61a68d630e812b67b5bf097ab84e2cd79b48c792857dc10ba8a223f5b06a2af", - "sha256:a7080b0159ce05f179cfac592cda1a82898ca9cd097dacf8ea20ae33474fbb25", - "sha256:a8fd93de4e1d278046345f49e2238cdb298589325849b2645d4a94c53faeffc5", - "sha256:a94ffc66738da99232ddffcf7910e0f69e2bbe3a0802e54426dbf0714e1c2ffe", - "sha256:aa806bbc13eac1ab6291ed21ecd2dd426063ca5417dd507e6be58de20e58dfcf", - "sha256:b0c1a133d42c6fc1f5fbcf5c91331657a1ff822e87989bf4a6e2e39b818d0ee9", - "sha256:b58229a844931bca61b3a20efd2be2a2acb4ad1622fc026504309a6883686fbf", - "sha256:bb2f144c6d98bb5cbc94adeb0447cfd4c0f991341baa68eee3f3b0c9c0e83767", - "sha256:be90c94570840939fecedf99fa72839aed70b0ced449b415c85e01ae67422c90", - "sha256:bf0d9a171908f32d54f651648c7290397b8792f4303821c42a74e7805bfb813c", - "sha256:bf15fc0b45914d9d1b706f7c9c4f66f2b7b053e9517e40123e137e8ca8958b3d", - "sha256:bf4298f366ca7e1ad1d21bbb58300a6985015909964077afd37559084590c929", - "sha256:c441c841e82c5ba7a85ad25986014be8d7849c3cfbdb6004541873505929a74e", - "sha256:cacea77ef7a2195f04f9279297684955e3d1ae4241092ff0cfcef532bb7a1c32", - "sha256:cd54895e4ae7d32f1e3dd91261df46ee7483a735017dc6f987904f194aa5fd14", - "sha256:d1323cd04d6e92150bcc79d0174ce347ed4b349d748b9358fd2e497b121e03c8", - "sha256:d383bf5e045d7f9d239b38e6acadd7b7fdf6c0087259a84ae3475d18e9a2ae8b", - "sha256:d3e7420211f5a65a54675fd860ea04173cde60a7cc20ccfbafcccd155225f8bc", - "sha256:d8074c5dd61c8a3e915fa8fc04754fa55cfa5978200d2daa1e2d4294c1f136aa", - "sha256:df03cd88f95b1b99052b52b1bb92173229d7a674df0ab06d2b25765ee8404bce", - "sha256:e45377d5d6fefe1677da2a2c07b024a6dac782088e37c0b1efea4cfe2b1be19b", - "sha256:e53d19c2bf7d0d1e6998a7e693c7e87300dd971808e6618964621ccd0e01fe4e", - "sha256:e560fd75aaf3e5693b91bcaddd8b314f4d57e99aef8a6c6dc692f935cc1e6bbf", - "sha256:ec5060592d83454e8063e487696ac3783cc48c9a329498bafae0d972bc7816c9", - "sha256:ecc2920630283e0783c22e2ac94427f8cca29a04cfdf331467d4f661f4072dac", - "sha256:ed7161bccab7696a473fe7ddb619c1d75963732b37da4618ba12e60899fefe4f", - "sha256:ee0bd3a7b2e184e88d25c9baa6a9dc609ba25b76daae942edfb14499ac7ec374", - "sha256:ee25f1ac091def37c4b59d192bbe3a206298feeb89132a470325bf76ad122a1e", - "sha256:efa44f64c37cc30c9f05932c740a8b40ce359f51882c70883cc95feac842da4d", - "sha256:f47d52fd9b2ac418c4890aad2f6d21a6b96183c98021f0a48497a904199f006e", - "sha256:f857034dc68d5ceb30fb60afb6ff2103087aea10a01b613985610e007053a121", - "sha256:fb91d20fa2d3b13deea98a690534697742029f4fb83673a3501ae6e3746508b5", - "sha256:fddb8870bdb83456a489ab67c6b3040a8d5a55069aa6f72f9d872235fbc52f54" + "sha256:050b571b2e96ec942898f8eb46ea4bfbb19bd5502424747e83badc2d4a99a44e", + "sha256:05543250deac8e61084234d5fc54f8ebd254e8f2b39a16b1dce48904f45b744b", + "sha256:069e7212890b0bcf9b2be0a03afb0c2d5161d91e1bf51569a64f629acc7defbf", + "sha256:09400e98545c998d57d10035ff623266927cb784d13dd2b31fd33b8a5316b85b", + "sha256:0c3c3a203c375b08fd06a20da3cf7aac293b834b6f4f4db71190e8422750cca5", + "sha256:0c86e7ceea56376216eba345aa1fc6a8a6b27ac236181f840d1d7e6a1ea9ba5c", + "sha256:0fbe94666e62ebe36cd652f5fc012abfbc2342de99b523f8267a678e4dfdee3c", + "sha256:17d1c688a443355234f3c031349da69444be052613483f3e4158eef751abcd8a", + "sha256:19a06db789a4bd896ee91ebc50d059e23b3639c25d58eb35be3ca1cbe967c3bf", + "sha256:1c5c7ab7f2bb3f573d1cb921993006ba2d39e8621019dffb1c5bc94cdbae81e8", + "sha256:1eb34d90aac9bfbced9a58b266f8946cb5935869ff01b164573a7634d39fbcb5", + "sha256:1f6cc0ad7b4560e5637eb2c994e97b4fa41ba8226069c9277eb5ea7101845b42", + "sha256:27c6ac6aa9fc7bc662f594ef380707494cb42c22786a558d95fcdedb9aa5d035", + "sha256:2d219b0dbabe75e15e581fc1ae796109b07c8ba7d25b9ae8d650da582bed01b0", + "sha256:2fce1df66915909ff6c824bbb5eb403d2d15f98f1518e583074671a30fe0c21e", + "sha256:319fa8765bfd6a265e5fa661547556da381e53274bc05094fc9ea50da51bfd46", + "sha256:359e81a949a7619802eb601d66d37072b79b79c2505e6d3fd8b945538411400d", + "sha256:3a02a28095b5e63128bcae98eb59025924f121f048a62393db682f049bf4ac24", + "sha256:3e19ea4ea0bf46179f8a3652ac1426e6dcbaf577ce4b4f65be581e237340420d", + "sha256:3e584b6d388aeb0001d6d5c2bd86b26304adde6d9bb9bfa9c4889805021b96de", + "sha256:40d980c33765359098837527e18eddefc9a24cea5b45e078a7f3bb5b032c6ecf", + "sha256:4114c4ada8f3181af20808bedb250da6bae56660e4b8dfd9cd95d4549c0962f7", + "sha256:43593c6772aa12abc3af7784bff4a41ffa921608dd38b77cf1dfd7f5c4e71371", + "sha256:47ef24aa6511e388e9894ec16f0fbf3313a53ee68402bc428744a367ec55b833", + "sha256:4cf9e93a81979f1424f1a3d155213dc928f1069d697e4353edb8a5eba67c6259", + "sha256:4d0dfdd9a2ebc77b869a0b04423591ea8823f791293b527dc1bb896c1d6f1136", + "sha256:563f9d8c03ad645597b8d010ef4e9eab359faeb11a0a2ac9f7b4bc8c28ebef25", + "sha256:58aa11f4ca8b60113d4b8e32d37e7e78bd8af4d1a5b5cb4979ed856a45e62005", + "sha256:5a0a9898fdb99bf11786265468571e628ba60af80dc3f6eb89a3545540c6b0ef", + "sha256:5aed8d8308215089c0734a2af4f2e95eeb360660184ad3912686c181e500b2e7", + "sha256:5b9145c35cc87313b5fd480144f8078716007656093d23059e8993d3a8fa730f", + "sha256:5cb5918253912e088edbf023788de539219718d3b10aef334476b62d2b53de53", + "sha256:5cdb0f3e1eb6dfc9965d19734d8f9c481b294b5274337a8cb5cb01b462dcb7e0", + "sha256:5ced33d827625d0a589e831126ccb4f5c29dfdf6766cac441d23995a65825dcb", + "sha256:603f1fe4144420374f1a69b907494c3acbc867a581c2d49d4175b0de7cc64566", + "sha256:61014615c1274df8da5991a1e5da85a3ccb00c2d4701ac6f3383afd3ca47ab0a", + "sha256:64a956dff37080b352c1c40b2966b09defb014347043e740d420ca1eb7c9b908", + "sha256:668ddddc9f3075af019f784456267eb504cb77c2c4bd46cc8402d723b4d200bf", + "sha256:6d8e309ff9a0503ef70dc9a0ebd3e69cf7b3894c9ae2ae81fc10943c37762458", + "sha256:6f173bbfe976105aaa890b712d1759de339d8a7cef2fc0a1714cc1a1e1c47f64", + "sha256:71ebe3fe42656a2328ab08933d420df5f3ab121772eef78f2dc63624157f0ed9", + "sha256:730178f476ef03d3d4d255f0c9fa186cb1d13fd33ffe89d39f2cda4da90ceb71", + "sha256:7d2d5a0028d920738372630870e7d9644ce437142197f8c827194fca404bf03b", + "sha256:7f30241577d2fef2602113b70ef7231bf4c69a97e04693bde08ddab913ba0ce5", + "sha256:813fbb8b6aea2fc9659815e585e548fe706d6f663fa73dff59a1677d4595a037", + "sha256:82de5da8c8893056603ac2d6a89eb8b4df49abf1a7c19d536984c8dd63f481d5", + "sha256:83be47aa4e35b87c106fc0c84c0fc069d3f9b9b06d3c494cd404ec6747544894", + "sha256:8638f99dca15b9dff328fb6273e09f03d1c50d9b6512f3b65a4154588a7595fe", + "sha256:87380fb1f3089d2a0b8b00f006ed12bd41bd858fabfa7330c954c70f50ed8757", + "sha256:88c423efef9d7a59dae0614eaed718449c09a5ac79a5f224a8b9664d603f04a3", + "sha256:89498dd49c2f9a026ee057965cdf8192e5ae070ce7d7a7bd4b66a8e257d0c976", + "sha256:8a17583515a04358b034e241f952f1715243482fc2c2945fd99a1b03a0bd77d6", + "sha256:916cd229b0150129d645ec51614d38129ee74c03293a9f3f17537be0029a9641", + "sha256:9532ea0b26a401264b1365146c440a6d78269ed41f83f23818d4b79497aeabe7", + "sha256:967a8eec513dbe08330f10137eacb427b2ca52118769e82ebcfcab0fba92a649", + "sha256:975af16f406ce48f1333ec5e912fe11064605d5c5b3f6746969077cc3adeb120", + "sha256:9979643ffc69b799d50d3a7b72b5164a2e97e117009d7af6dfdd2ab906cb72cd", + "sha256:9a8ecf38de50a7f518c21568c80f985e776397b902f1ce0b01f799aba1608b40", + "sha256:9cec3239c85ed15bfaded997773fdad9fb5662b0a7cbc854a43f291eb183179e", + "sha256:9e64e948ab41411958670f1093c0a57acfdc3bee5cf5b935671bbd5313bcf229", + "sha256:9f64d91b751df77931336b5ff7bafbe8845c5770b06630e27acd5dbb71e1931c", + "sha256:a0ab8cf8cdd2194f8ff979a43ab43049b1df0b37aa64ab7eca04ac14429baeb7", + "sha256:a110205022d077da24e60b3df8bcee73971be9575dec5573dd17ae5d81751111", + "sha256:a34aa3a1abc50740be6ac0ab9d594e274f59960d3ad253cd318af76b996dd654", + "sha256:a444192f20f5ce8a5e52761a031b90f5ea6288b1eef42ad4c7e64fef33540b8f", + "sha256:a461959ead5b38e2581998700b26346b78cd98540b5524796c175722f18b0294", + "sha256:a75801768bbe65499495660b777e018cbe90c7980f07f8aa57d6be79ea6f71da", + "sha256:aa8efd8c5adc5a2c9d3b952815ff8f7710cefdcaf5f2c36d26aff51aeca2f12f", + "sha256:aca63103895c7d960a5b9b044a83f544b233c95e0dcff114389d64d762017af7", + "sha256:b0313e8b923b3814d1c4a524c93dfecea5f39fa95601f6a9b1ac96cd66f89ea0", + "sha256:b23c11c2c9e6d4e7300c92e022046ad09b91fd00e36e83c44483df4afa990073", + "sha256:b303b194c2e6f171cfddf8b8ba30baefccf03d36a4d9cab7fd0bb68ba476a3d7", + "sha256:b655032b202028a582d27aeedc2e813299f82cb232f969f87a4fde491a233f11", + "sha256:bd39c92e4c8f6cbf5f08257d6360123af72af9f4da75a690bef50da77362d25f", + "sha256:bef100c88d8692864651b5f98e871fb090bd65c8a41a1cb0ff2322db39c96c27", + "sha256:c2fe5c910f6007e716a06d269608d307b4f36e7babee5f36533722660e8c4a70", + "sha256:c66d8ccbc902ad548312b96ed8d5d266d0d2c6d006fd0f66323e9d8f2dd49be7", + "sha256:cd6a55f65241c551eb53f8cf4d2f4af33512c39da5d9777694e9d9c60872f519", + "sha256:d249609e547c04d190e820d0d4c8ca03ed4582bcf8e4e160a6969ddfb57b62e5", + "sha256:d4e89cde74154c7b5957f87a355bb9c8ec929c167b59c83d90654ea36aeb6180", + "sha256:dc1915ec523b3b494933b5424980831b636fe483d7d543f7afb7b3bf00f0c10f", + "sha256:e1c4d24b804b3a87e9350f79e2371a705a188d292fd310e663483af6ee6718ee", + "sha256:e474fc718e73ba5ec5180358aa07f6aded0ff5f2abe700e3115c37d75c947e18", + "sha256:e4fe2a6d5ce975c117a6bb1e8ccda772d1e7029c1cca1acd209f91d30fa72815", + "sha256:e7fb9a84c9abbf2b2683fa3e7b0d7da4d8ecf139a1c635732a8bda29c5214b0e", + "sha256:e861ad82892408487be144906a368ddbe2dc6297074ade2d892341b35c59844a", + "sha256:ec314cde7314d2dd0510c6787326bbffcbdc317ecee6b7401ce218b3099075a7", + "sha256:ed5f6d2edbf349bd8d630e81f474d33d6ae5d07760c44d33cd808e2f5c8f4ae6", + "sha256:ef2e4e91fb3945769e14ce82ed53007195e616a63aa43b40fb7ebaaf907c8d4c", + "sha256:f011f104db880f4e2166bcdcf7f58250f7a465bc6b068dc84c824a3d4a5c94dc", + "sha256:f1528ec4374617a7a753f90f20e2f551121bb558fcb35926f99e3c42367164b8", + "sha256:f27785888d2fdd918bc36de8b8739f2d6c791399552333721b58193f68ea3e98", + "sha256:f35c7070eeec2cdaac6fd3fe245226ed2a6292d3ee8c938e5bb645b434c5f256", + "sha256:f3bbecd2f34d0e6d3c543fdb3b15d6b60dd69970c2b4c822379e5ec8f6f621d5", + "sha256:f6f1324db48f001c2ca26a25fa25af60711e09b9aaf4b28488602776f4f9a744", + "sha256:f78eb8422acc93d7b69964012ad7048764bb45a54ba7a39bb9e146c72ea29723", + "sha256:fb6e0faf8cb6b4beea5d6ed7b5a578254c6d7df54c36ccd3d8b3eb00d6770277", + "sha256:feccd282de1f6322f56f6845bf1207a537227812f0a9bf5571df52bb418d79d5" ], "markers": "python_version >= '3.9'", - "version": "==0.3.0" + "version": "==0.3.1" }, "pydantic": { "hashes": [ - "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584", - "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236" + "sha256:442557d2910e75c991c39f4b4ab18963d57b9b55122c8b2a9cd176d8c29ce968", + "sha256:5b6c415eee9f8123a14d859be0c84363fec6b1feb6b688d6435801230b56e0b8" ], - "markers": "python_version >= '3.8'", - "version": "==2.10.6" + "markers": "python_version >= '3.9'", + "version": "==2.11.1" }, "pydantic-core": { "hashes": [ - "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278", - "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50", - "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9", - "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f", - "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", - "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", - "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54", - "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630", - "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9", - "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236", - "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", - "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", - "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", - "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", - "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", - "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", - "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", - "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd", - "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", - "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", - "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7", - "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", - "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e", - "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa", - "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", - "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962", - "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", - "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f", - "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", - "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5", - "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", - "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf", - "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a", - "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c", - "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76", - "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362", - "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4", - "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", - "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320", - "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118", - "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96", - "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", - "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046", - "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3", - "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", - "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af", - "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", - "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67", - "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a", - "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", - "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35", - "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", - "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151", - "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b", - "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", - "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133", - "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", - "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145", - "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", - "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", - "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", - "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", - "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", - "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", - "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5", - "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", - "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", - "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8", - "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", - "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da", - "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", - "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc", - "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993", - "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656", - "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4", - "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", - "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb", - "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d", - "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", - "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e", - "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", - "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc", - "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a", - "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9", - "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506", - "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b", - "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1", - "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", - "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", - "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", - "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31", - "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c", - "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", - "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", - "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308", - "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2", - "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228", - "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b", - "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", - "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad" + "sha256:024d136ae44d233e6322027bbf356712b3940bee816e6c948ce4b90f18471b3d", + "sha256:0310524c833d91403c960b8a3cf9f46c282eadd6afd276c8c5edc617bd705dc9", + "sha256:07b4ced28fccae3f00626eaa0c4001aa9ec140a29501770a88dbbb0966019a86", + "sha256:085d8985b1c1e48ef271e98a658f562f29d89bda98bf120502283efbc87313eb", + "sha256:0a98257451164666afafc7cbf5fb00d613e33f7e7ebb322fbcd99345695a9a61", + "sha256:0bcf0bab28995d483f6c8d7db25e0d05c3efa5cebfd7f56474359e7137f39856", + "sha256:138d31e3f90087f42aa6286fb640f3c7a8eb7bdae829418265e7e7474bd2574b", + "sha256:14229c1504287533dbf6b1fc56f752ce2b4e9694022ae7509631ce346158de11", + "sha256:1583539533160186ac546b49f5cde9ffc928062c96920f58bd95de32ffd7bffd", + "sha256:175ab598fb457a9aee63206a1993874badf3ed9a456e0654273e56f00747bbd6", + "sha256:1a69b7596c6603afd049ce7f3835bcf57dd3892fc7279f0ddf987bebed8caa5a", + "sha256:1a73be93ecef45786d7d95b0c5e9b294faf35629d03d5b145b09b81258c7cd6d", + "sha256:1b1262b912435a501fa04cd213720609e2cefa723a07c92017d18693e69bf00b", + "sha256:1b2ea72dea0825949a045fa4071f6d5b3d7620d2a208335207793cf29c5a182d", + "sha256:20d4275f3c4659d92048c70797e5fdc396c6e4446caf517ba5cad2db60cd39d3", + "sha256:23c3e77bf8a7317612e5c26a3b084c7edeb9552d645742a54a5867635b4f2453", + "sha256:26a4ea04195638dcd8c53dadb545d70badba51735b1594810e9768c2c0b4a5da", + "sha256:26bc7367c0961dec292244ef2549afa396e72e28cc24706210bd44d947582c59", + "sha256:2a0147c0bef783fd9abc9f016d66edb6cac466dc54a17ec5f5ada08ff65caf5d", + "sha256:2c0afd34f928383e3fd25740f2050dbac9d077e7ba5adbaa2227f4d4f3c8da5c", + "sha256:30369e54d6d0113d2aa5aee7a90d17f225c13d87902ace8fcd7bbf99b19124db", + "sha256:31860fbda80d8f6828e84b4a4d129fd9c4535996b8249cfb8c720dc2a1a00bb8", + "sha256:34e7fb3abe375b5c4e64fab75733d605dda0f59827752debc99c17cb2d5f3276", + "sha256:40eb8af662ba409c3cbf4a8150ad32ae73514cd7cb1f1a2113af39763dd616b3", + "sha256:41d698dcbe12b60661f0632b543dbb119e6ba088103b364ff65e951610cb7ce0", + "sha256:4726f1f3f42d6a25678c67da3f0b10f148f5655813c5aca54b0d1742ba821b8f", + "sha256:4927564be53239a87770a5f86bdc272b8d1fbb87ab7783ad70255b4ab01aa25b", + "sha256:4b6d77c75a57f041c5ee915ff0b0bb58eabb78728b69ed967bc5b780e8f701b8", + "sha256:4d9149e7528af8bbd76cc055967e6e04617dcb2a2afdaa3dea899406c5521faa", + "sha256:4deac83a8cc1d09e40683be0bc6d1fa4cde8df0a9bf0cda5693f9b0569ac01b6", + "sha256:4f1ab031feb8676f6bd7c85abec86e2935850bf19b84432c64e3e239bffeb1ec", + "sha256:502ed542e0d958bd12e7c3e9a015bce57deaf50eaa8c2e1c439b512cb9db1e3a", + "sha256:5461934e895968655225dfa8b3be79e7e927e95d4bd6c2d40edd2fa7052e71b6", + "sha256:58c1151827eef98b83d49b6ca6065575876a02d2211f259fb1a6b7757bd24dd8", + "sha256:5bdd36b362f419c78d09630cbaebc64913f66f62bda6d42d5fbb08da8cc4f181", + "sha256:5bf637300ff35d4f59c006fff201c510b2b5e745b07125458a5389af3c0dff8c", + "sha256:5bf68bb859799e9cec3d9dd8323c40c00a254aabb56fe08f907e437005932f2b", + "sha256:5d8dc9f63a26f7259b57f46a7aab5af86b2ad6fbe48487500bb1f4b27e051e4c", + "sha256:5f36afd0d56a6c42cf4e8465b6441cf546ed69d3a4ec92724cc9c8c61bd6ecf4", + "sha256:5f72914cfd1d0176e58ddc05c7a47674ef4222c8253bf70322923e73e14a4ac3", + "sha256:6291797cad239285275558e0a27872da735b05c75d5237bbade8736f80e4c225", + "sha256:62c151ce3d59ed56ebd7ce9ce5986a409a85db697d25fc232f8e81f195aa39a1", + "sha256:635702b2fed997e0ac256b2cfbdb4dd0bf7c56b5d8fba8ef03489c03b3eb40e2", + "sha256:64672fa888595a959cfeff957a654e947e65bbe1d7d82f550417cbd6898a1d6b", + "sha256:68504959253303d3ae9406b634997a2123a0b0c1da86459abbd0ffc921695eac", + "sha256:69297418ad644d521ea3e1aa2e14a2a422726167e9ad22b89e8f1130d68e1e9a", + "sha256:6c32a40712e3662bebe524abe8abb757f2fa2000028d64cc5a1006016c06af43", + "sha256:715c62af74c236bf386825c0fdfa08d092ab0f191eb5b4580d11c3189af9d330", + "sha256:71dffba8fe9ddff628c68f3abd845e91b028361d43c5f8e7b3f8b91d7d85413e", + "sha256:7419241e17c7fbe5074ba79143d5523270e04f86f1b3a0dff8df490f84c8273a", + "sha256:759871f00e26ad3709efc773ac37b4d571de065f9dfb1778012908bcc36b3a73", + "sha256:7a25493320203005d2a4dac76d1b7d953cb49bce6d459d9ae38e30dd9f29bc9c", + "sha256:7b79af799630af263eca9ec87db519426d8c9b3be35016eddad1832bac812d87", + "sha256:7c9c84749f5787781c1c45bb99f433402e484e515b40675a5d121ea14711cf61", + "sha256:7da333f21cd9df51d5731513a6d39319892947604924ddf2e24a4612975fb936", + "sha256:82a4eba92b7ca8af1b7d5ef5f3d9647eee94d1f74d21ca7c21e3a2b92e008358", + "sha256:89670d7a0045acb52be0566df5bc8b114ac967c662c06cf5e0c606e4aadc964b", + "sha256:8a1d581e8cdbb857b0e0e81df98603376c1a5c34dc5e54039dcc00f043df81e7", + "sha256:8ec86b5baa36f0a0bfb37db86c7d52652f8e8aa076ab745ef7725784183c3fdd", + "sha256:91301a0980a1d4530d4ba7e6a739ca1a6b31341252cb709948e0aca0860ce0ae", + "sha256:918f2013d7eadea1d88d1a35fd4a1e16aaf90343eb446f91cb091ce7f9b431a2", + "sha256:9cb2390355ba084c1ad49485d18449b4242da344dea3e0fe10babd1f0db7dcfc", + "sha256:9ee65f0cc652261744fd07f2c6e6901c914aa6c5ff4dcfaf1136bc394d0dd26b", + "sha256:a608a75846804271cf9c83e40bbb4dab2ac614d33c6fd5b0c6187f53f5c593ef", + "sha256:a66d931ea2c1464b738ace44b7334ab32a2fd50be023d863935eb00f42be1778", + "sha256:a7a7f2a3f628d2f7ef11cb6188bcf0b9e1558151d511b974dfea10a49afe192b", + "sha256:abaeec1be6ed535a5d7ffc2e6c390083c425832b20efd621562fbb5bff6dc518", + "sha256:abfa44cf2f7f7d7a199be6c6ec141c9024063205545aa09304349781b9a125e6", + "sha256:ade5dbcf8d9ef8f4b28e682d0b29f3008df9842bb5ac48ac2c17bc55771cc976", + "sha256:ae62032ef513fe6281ef0009e30838a01057b832dc265da32c10469622613885", + "sha256:aec79acc183865bad120b0190afac467c20b15289050648b876b07777e67ea48", + "sha256:b716294e721d8060908dbebe32639b01bfe61b15f9f57bcc18ca9a0e00d9520b", + "sha256:b9ec80eb5a5f45a2211793f1c4aeddff0c3761d1c70d684965c1807e923a588b", + "sha256:ba95691cf25f63df53c1d342413b41bd7762d9acb425df8858d7efa616c0870e", + "sha256:bccc06fa0372151f37f6b69834181aa9eb57cf8665ed36405fb45fbf6cac3bae", + "sha256:c860773a0f205926172c6644c394e02c25421dc9a456deff16f64c0e299487d3", + "sha256:ca1103d70306489e3d006b0f79db8ca5dd3c977f6f13b2c59ff745249431a606", + "sha256:ce72d46eb201ca43994303025bd54d8a35a3fc2a3495fac653d6eb7205ce04f4", + "sha256:d20cbb9d3e95114325780f3cfe990f3ecae24de7a2d75f978783878cce2ad585", + "sha256:dcfebee69cd5e1c0b76a17e17e347c84b00acebb8dd8edb22d4a03e88e82a207", + "sha256:e1c69aa459f5609dec2fa0652d495353accf3eda5bdb18782bc5a2ae45c9273a", + "sha256:e2762c568596332fdab56b07060c8ab8362c56cf2a339ee54e491cd503612c50", + "sha256:e37f10f6d4bc67c58fbd727108ae1d8b92b397355e68519f1e4a7babb1473442", + "sha256:e790954b5093dff1e3a9a2523fddc4e79722d6f07993b4cd5547825c3cbf97b5", + "sha256:e81a295adccf73477220e15ff79235ca9dcbcee4be459eb9d4ce9a2763b8386c", + "sha256:e925819a98318d17251776bd3d6aa9f3ff77b965762155bdad15d1a9265c4cfd", + "sha256:ea30239c148b6ef41364c6f51d103c2988965b643d62e10b233b5efdca8c0099", + "sha256:eabf946a4739b5237f4f56d77fa6668263bc466d06a8036c055587c130a46f7b", + "sha256:ecb158fb9b9091b515213bed3061eb7deb1d3b4e02327c27a0ea714ff46b0760", + "sha256:ecc6d02d69b54a2eb83ebcc6f29df04957f734bcf309d346b4f83354d8376862", + "sha256:eddb18a00bbb855325db27b4c2a89a4ba491cd6a0bd6d852b225172a1f54b36c", + "sha256:f00e8b59e1fc8f09d05594aa7d2b726f1b277ca6155fc84c0396db1b373c4555", + "sha256:f1fb026c575e16f673c61c7b86144517705865173f3d0907040ac30c4f9f5915", + "sha256:f200b2f20856b5a6c3a35f0d4e344019f805e363416e609e9b47c552d35fd5ea", + "sha256:f225f3a3995dbbc26affc191d0443c6c4aa71b83358fd4c2b7d63e2f6f0336f9", + "sha256:f22dab23cdbce2005f26a8f0c71698457861f97fc6318c75814a50c75e87d025", + "sha256:f3eb479354c62067afa62f53bb387827bee2f75c9c79ef25eef6ab84d4b1ae3b", + "sha256:fc53e05c16697ff0c1c7c2b98e45e131d4bfb78068fffff92a82d169cbb4c7b7", + "sha256:ff48a55be9da6930254565ff5238d71d5e9cd8c5487a191cb85df3bdb8c77365" ], - "markers": "python_version >= '3.8'", - "version": "==2.27.2" + "markers": "python_version >= '3.9'", + "version": "==2.33.0" }, "pyparsing": { "hashes": [ - "sha256:506ff4f4386c4cec0590ec19e6302d3aedb992fdc02c761e90416f158dacf8e1", - "sha256:61980854fd66de3a90028d679a954d5f2623e83144b5afe5ee86f43d762e5f0a" + "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf", + "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be" ], "markers": "python_version >= '3.9'", - "version": "==3.2.1" + "version": "==3.2.3" }, "pytest": { "hashes": [ @@ -968,28 +1094,129 @@ }, "python-dotenv": { "hashes": [ - "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", - "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" + "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5", + "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d" ], "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==1.0.1" + "markers": "python_version >= '3.9'", + "version": "==1.1.0" }, "pytz": { "hashes": [ - "sha256:89dd22dca55b46eac6eda23b2d72721bf1bdfef212645d81513ef5d03038de57", - "sha256:c2db42be2a2518b28e65f9207c4d05e6ff547d1efa4086469ef855e4ab70178e" + "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", + "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00" ], - "version": "==2025.1" + "version": "==2025.2" + }, + "qh3": { + "hashes": [ + "sha256:0107f576a0524421e1b0f9e0437d2881a1835b1b6105eadd7ea0c1c9bf2da917", + "sha256:06159707895c606a321ccb5630347a2d2a44ee584f22945e5b22b0ad34f21ec8", + "sha256:06255835f99ea1af9e5d358056011686fcccbafaba893454027daa62ab6f701f", + "sha256:09b2305a954e61a9ed8b46a7a45f54e8d95ef870a47d5fd1836e14c7600d3b92", + "sha256:0a51dcffae03a89ddbab1884860569e0d1dbbf95deee47457c1fd29b4ac8d220", + "sha256:0a5d1cd881b7d43481ad60262cf3390a555e0e51751bc2af70ba4a612487e797", + "sha256:0e1c273660f9b8511c22d0b082137556e46d6a7eccf132bd82f95d29f90488b2", + "sha256:0e540cc7e7da65da30381bdb73a789a8635c6aaef98688d904eee3bc587654a5", + "sha256:10ed818f47dc522350a12641e8f2bea19ff824f8ce373c23a8e594b3481fd7a4", + "sha256:195b4ad58cf5a8da218e2368d34f47628c14581f3cc9863fc0406b32e137f3a6", + "sha256:1a80d07249c7ccbaa57bb9015b5ead0ead7ac1940cd5483548dfe56db99ce7a4", + "sha256:1cf0b18823801078d2294a0356abc2be34b4a224bea863a87029c1c97d6c34e0", + "sha256:1fac2ab4b8a2e50894b54a19416cd363defe0fb33f52754686ea58999f98dfc5", + "sha256:205cdaea9da8881b31b76eb6da5b88c9558ba96bc16a3ecf11333098ac7f3859", + "sha256:2294e78bcc40728a3a772df0f8ecf8b8756616d06dd001029016876aa4e5c9de", + "sha256:235236ab195d34e7cd18d186e46b7a4f8aceafe246bf36b42913f72627ded414", + "sha256:25eef1f2be50d79d23e01a567c719e46e4892518a5ccc96685fcb4746357320b", + "sha256:2ae147b756c3adf59699756feb9e07d4a69674f57b4e13d6c25f9d1dc3c8707c", + "sha256:2c9cdd7ea49c79b671e7de35dad61d2aa91920e2498d0c6dfa932d5e05070a5e", + "sha256:2dc9f269d7316b0a44e61ae7a11ffd8daa800b3f5ba773de2e9d8c4ee636a896", + "sha256:2f94d69edb0070ef4ec414deabfc2369aa2100b11bf4a4f2f393f2c28c4bc7ba", + "sha256:311da331e31c55afc3f4f4f2ba9d07a1d700ffb7db5aa4f58300b9f56f2523dc", + "sha256:3578844a9ff4c342a409d010f909782afc52a31680876f7fab65bf133aa3f4db", + "sha256:4032c2898b4c0ff7a25cf7d68c3b1f2abdcaf4f25cc8b6802a941a842f9a95b6", + "sha256:40abd150eddfa0884c139bd281e87ff920d4cd52d685fc4ef25ddcc77ff7a220", + "sha256:43e32602651d07f8a0860ba0a45d8c8fe9ccd537030e7632d1258f7b84881416", + "sha256:45a21d25fe17168f4db09fcaabee5dd171763ad1bd8753c257297837f5ba9197", + "sha256:45bfbb126e31ecf63ef74c249d38d07e149c0663b4a191cf9e2e3445a80758d5", + "sha256:4745667c9956bcfd74ff677edd4c73d6cb578b6b47c5fb3d246aaa223dd6a004", + "sha256:4936a5d8915866b4f08ab18018f41ed93a2593788ad0a80796aada2e23d402e5", + "sha256:4a45a9698b3bcae05f91356f50df8dab3c3fdef3187548b9c4a396a6eb6760b5", + "sha256:4b84c1ca283278e2e22a3b9e2ce8ea55c0a1797d6e86255640a1b6293fe18b2a", + "sha256:4dc88397ed7f3b46f542f87e19050a7f82267225009ce65651ac44cb55b204b1", + "sha256:4e10a872077373c71d7938fb1a7ae0561f2e79aad2b1b5323dbb6325a389041a", + "sha256:4f1b5dcb4d9da5b441e0b14216b816be7b5b5d080c2ccb957adf84266411ff6b", + "sha256:50d25182d598312197f500a65acebf5430391764e6ffcdb73d96e80c5dd06fc7", + "sha256:529c5b9e27fced27befce26e2699eca3110c576f6427dfbd26e30b7666b2d6d1", + "sha256:571da625b22e953731307539b44b2177f6ab13b6142d7698c0f28b9379ae1be6", + "sha256:5a9de89e2480b385a99613798d375e69a0a53d4575bd74b133307c8e83a84751", + "sha256:5bcc46cf89cb1036c2d029c01f360c82180329997a75728b20dc205f34114327", + "sha256:5dfa6238a6236f2bb3ecaac9befd23cee0bcbb9e497003fb3aef875e19325c61", + "sha256:6342b961b18037e3df8692e8914c576816a966bf29f913ee2728e7e838bde9bd", + "sha256:65e112c175a0b0328822dd0d19ead9ef1d7925359d154fb52e46b080945eef38", + "sha256:6f8a2b15c4dd58133e92f95d4312efd09b87ec15b881885629dff70e89f1e751", + "sha256:726f749444d1cc73c1bf221343dc6fdbde2541ffe30860d2d5ef6e310a1f5478", + "sha256:742f39cd807df31c21e035aec63f6f61e139a60545cffb16e8e87f61609d7cba", + "sha256:7840c18ec27aa08ecdd8ff23df348c124378c6f3edf9a0e02b16a5a4ce504c89", + "sha256:79d1de24d3c7345719af8333b64f19a8777dd50a059851bfcfa583c7109eddf2", + "sha256:7ba9303c5334d64b547483be92c4bbacd37964ff3abd0b1e8c82c63ec6f7b3ec", + "sha256:85587d9dfbd2f7f8622cf57f3c1a19cee441b5607a982cdf4c08ef38d45d5a36", + "sha256:8711b86e447e689d1b693419708b6ad64bf0c57091b94a3f65c6d4bd7cfb7d9a", + "sha256:877edc4db25309d86af07d992926394936f491cce84fce439961729552e942fe", + "sha256:8bb17669e362d3456bebd5c69abb0c26e8ab29c10894f123c715b0217aece479", + "sha256:8bb17a1e50e35a8d07cab784caea68b33f739391ccb5e3161afb9db0bde8faf4", + "sha256:8d4640a6bb3aa29797bdcf0c5bae4e86da5f2fbf84b67a7fad549fa34c19aa98", + "sha256:90697f3d9e4b3ddccfb31b40637bac6d44b39288cd57f78e51ff13e70916eccc", + "sha256:90f127f57c00b111ea3ffd95f4c12ad83efebd10310fd718d66771dd64e568f1", + "sha256:95f8f70bca1e880da7559ef38b7f1778a3b39b586fc829b8a7e989e912aa988f", + "sha256:9a60c102a01dfa8c5d737499c9a5d5e7c2b6642009c9b80b27f228ec50ce6fb0", + "sha256:9c7f1821ec749ea29bd9d079e4f13a552371731d0b664962a60cbb2f31d571b5", + "sha256:9f81ee66fadedbfd4d5c49e64151db3b6f353b041ddf5ab0b151340a4467e038", + "sha256:9f8e530e29e1afe9231b1100645aa5cc240b823c0e4162f70046270a3559400c", + "sha256:a0c647db3f156e8c94a63c1fa0fc4f2ce8b70f0eb12f2726e6c19493198b1e99", + "sha256:a0cda60607ab4ffc14fa8425ea7c9ae78ad60923c3c8be94d19c14f83198b1cf", + "sha256:a5bff397d49da302b5afbdf244dd7ca480a827f5de856d957df05dfd7e73b490", + "sha256:a94bd391b955b24948b2986845f9c6ad8abc709c2d57d0515daeacf16a2a3a4c", + "sha256:ad4572bd37c1a6a7a12ff47da4f3578a13e3c8ee85a1f02d2435dfdc6d9ed394", + "sha256:b13b7de1686f1b5da7526dc4f0de410a685f5cb654e984b09ddd8d14be6fffc0", + "sha256:b1724c43c5c0d08b68c3407467e07794b9adf153b6de8300d61883e8d95fa640", + "sha256:b27d29cb718df9ed006f8c75a89dd90534437761b2477dc7a4145bde0daa60fc", + "sha256:b3afa3a78b0f011ff5a09dea37d74fcea9269b318d2828f18b2fbf9dde625a71", + "sha256:bd6a61007e678284178bb00931af59f686a2a55797505e0886241050ec5c243c", + "sha256:befeca45fd7787c08a3286fb72caaccfa4c3962760981dfeb0992f5ba9be5cb2", + "sha256:c2d31b8233f406e00f180e221986f436765c3bb06839e72c898feca31fef1d4e", + "sha256:c3e2518ce442b70314892a594e21157deb13fbc436f77ad6555439cfd9912035", + "sha256:c8d5fbee607db24ef6c7b0bd08c21226d10782df4149b9d6f1f1516c7c85092b", + "sha256:cc2cc804998e852bdffcc87e8d008043ffa85efe6d3516d9784714d709f14774", + "sha256:cd8a681107c6118f60a0714671cec7b301533f25984a5c898e547a33a01af75c", + "sha256:d056831ebf3fa8116672ae970ad19a9f5f1427a2217cd0e01c1eaac5f8222668", + "sha256:d5ac3e8e3f66ff88819205dbc67e6f771cbb80529325ca9f3bc03fa00c5c83aa", + "sha256:dba15ca2da7859300ae79d2ea2eb8bb0eb827b93a2f104981783add16a97058a", + "sha256:de6cabb89248b60ea9bb9d7848de78dfb824abfdc15f52448a8efe821dd7d559", + "sha256:e02f6d1cc2005b847176dd8770fdfe90f04a34a3f094b79a8369bde0aa8f6a04", + "sha256:e514bd4b27c953c46485b2be0ecd2421aa196c5a0cd7d67f1ccec16a56b00507", + "sha256:e53464124379764f982a69f5ab34d0d5c527e8ac1e788db86a25f79045e5b18d", + "sha256:e9cf59660a543bef86de457c671c1d78ad2d88c53bb9eb3fce6ce0cb9729d490", + "sha256:edfc1bc732bc5e62fdaea268a541eb442d5e04927cb27dfd8e92ef07213658d2", + "sha256:ee8e7a66be70a18f5e0558f2f6a89e39c608f87b027234848f76a6699975dcf8", + "sha256:effb7072efef7dca10a98c24be0cc882a40edc78e293b41f5b6dc7f1952215ed", + "sha256:f04e4ee7e3c123ac7f21cee6f819cfa9b5a376e656257dfa7a4d133b3590bdd9", + "sha256:f0531c7abe963affebd3fb6cf9ea87eb8c63a0240535d81d0223945bd41be254", + "sha256:f5afd1c216315682a6bbf606618de0e3817ed8eeafc27ad7660ef2f581d4fd46", + "sha256:f93d3c74e00268ac6042c080653a34d0f0e8903697fd8dc480c1e3de81c90faf", + "sha256:fbc4e6452cc48c3e1398fe930349e2ec9ad76a2c00e729f3e797700c2f0646e6", + "sha256:fc73fc2889a01a43737c7a7c7fb9ee13aa56065b22abbed0e787cc58a3747808" + ], + "markers": "python_version >= '3.7'", + "version": "==1.4.2" }, "rdflib": { "hashes": [ - "sha256:5402310a9f0f3c07d453d73fd0ad6ba35616286fe95d3670db2b725f3f539673", - "sha256:f3dcb4c106a8cd9e060d92f43d593d09ebc3d07adc244f4c7315856a12e383ee" + "sha256:72f4adb1990fa5241abd22ddaf36d7cafa5d91d9ff2ba13f3086d339b213d997", + "sha256:fed46e24f26a788e2ab8e445f7077f00edcf95abb73bcef4b86cefa8b62dd174" ], "index": "pypi", "markers": "python_full_version >= '3.8.1' and python_full_version < '4.0.0'", - "version": "==7.1.3" + "version": "==7.1.4" }, "requests": { "hashes": [ @@ -1040,19 +1267,27 @@ }, "typing-extensions": { "hashes": [ - "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", - "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" + "sha256:0a4ac55a5820789d87e297727d229866c9650f6521b64206413c4fbada24d95b", + "sha256:c8dd92cc0d6425a97c18fbb9d1954e5ff92c1ca881a309c45f06ebc0b79058e5" ], "markers": "python_version >= '3.8'", - "version": "==4.12.2" + "version": "==4.13.0" + }, + "typing-inspection": { + "hashes": [ + "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f", + "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122" + ], + "markers": "python_version >= '3.9'", + "version": "==0.4.0" }, "tzdata": { "hashes": [ - "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694", - "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639" + "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", + "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9" ], "markers": "python_version >= '2'", - "version": "==2025.1" + "version": "==2025.2" }, "urllib3": { "hashes": [ @@ -1062,6 +1297,118 @@ "markers": "python_version >= '3.9'", "version": "==2.3.0" }, + "urllib3-future": { + "hashes": [ + "sha256:3adfa22c5718caee5ca69bc7f7461dc529f4396494d4d9b1db8af7c56cd3ac34", + "sha256:9cd79ce61da77b5d56681bc126f42955c2153e9c0da2f0a62bca8e0a05641f92" + ], + "markers": "python_version >= '3.7'", + "version": "==2.12.915" + }, + "verlib2": { + "hashes": [ + "sha256:2862f19528db400d130253a2b71c7c3616ee14e1d54bf6833bc0929d2cddd141", + "sha256:cf8e2be044b834a2670f2d4c20a93cfc674933c0070543a6f61d531439cca200" + ], + "markers": "python_version >= '3.6'", + "version": "==0.3.1" + }, + "wassima": { + "hashes": [ + "sha256:10508102696d5e2cf4df6942a8ae251c136a49dc32591e9c3f7dd007f5ea1c2f", + "sha256:1102836ba373912537eba891e7e5893532d4ee915ee2486e981b73f925f63c37", + "sha256:11887557464e0c3f9694fb16406bb56c1fb1566178cd04bfb5b4624fad183b31", + "sha256:12c855cc5b96a2ac32d405ab7de1563fc91be54108b4fb16b06d125d07ea892b", + "sha256:134e863b692c35afe8f5ccbe8082fa39963804e20439a4c7aa98510197034704", + "sha256:17f129f4d36591772d906bcc893b76b236363fda61b575067ddfa8250f84ad30", + "sha256:17f132ffbab294902f8740708f27fd995ea04182fe4b4fde20be563f8a010715", + "sha256:18bc78b2230c6f1f9ddbeb6ca38439fea4cc8f60836af4f3538ed259e60e5eb8", + "sha256:194c3fad38603618dec03307d10a4ece852516df56560e04fb2562506f79c175", + "sha256:1b18ec743ab98dcbfc221749026b23fc573891651342f20971e53bdbf56d28ae", + "sha256:1fa19a3652509edd18f693cd9c873d8f73c9d1624eae6c3bf93e561b18ae2766", + "sha256:24bdb1a2b90c215e11ed7ce82ed7eada339c7dca8e0366916e4e3215b3b9d8d3", + "sha256:27d518f0863788c826faf387326f3babb3ea95a0b908f5b3ad2bc1fcc3c5a37d", + "sha256:350b5854dfb3eeb95cd17723b0f3503de0c01454da5ae7d60f192be2009239eb", + "sha256:3b3a4c8ffa76147507f0c88c5cc8c76ef96ab93b81e49b288a3a0b94ebfb34af", + "sha256:3e00fa8ff1aef7d8aad2e1b957add6cba8549a42e415400bd72ff1b61dc9da9d", + "sha256:3f29045dd0a7c287f850f1dc3948632a2d2cf7dd7ec02271c5f248f058da5650", + "sha256:4a528244e4a0f9e01b8593b1c8a60ac1d80ce8b13fe079f44b38328e4be075e3", + "sha256:4c4f5ca102fd083aa2b05c65a1fd18175e3dc7a889525fd2964219ee3c51edef", + "sha256:52358d86195954816231d2aa8c2919b85075320b6d3ba5b96216985c3182bfa0", + "sha256:52f473233ec4d57322c6295e85b3912dc1fc400d6308a04bd427b863934aa74e", + "sha256:556cded582aef3089de889b5a6efcf6d87fabfec55d574fcc3a4ada21308d487", + "sha256:564eda7bf0420c8cbebe5e8efc15f1b27fdcb37ebc4c2f92b8461ca83381b223", + "sha256:57a0ab5aed596f129fd4ea7584336b11fbef25c07d1351e37a959901dea8728e", + "sha256:58f1fddd660da8c8f30f4b8460129e2f217c226cd1b54b1cabb6465881fd788a", + "sha256:597b0d8ba697f4319bc1f301ed31630ca783c9fe82d2a2434dd2f7f709c4e394", + "sha256:5b194f0de77a4ae7bcf217a3ccd10798e94ca430cec6307628098a61cd2ac230", + "sha256:5f5ee564f4b836ed1b70ddb187c817e8f6f1ffb521a636bb20676f07b523396b", + "sha256:601f96340e4c8071994a39a76d4278e8e1d087cf385781dba795c5334262d865", + "sha256:61bfa09f38c36f1b1e6e44e7af888bb8f9d739e86099082a3b45875651a425e2", + "sha256:67fd323b8ad0e057c06b153983d8c50f812aad979ac89b07ed6952c345f6da02", + "sha256:69cb51f629d118256da3d2373575190c7e30d3fa67c344dc655f6c8ab3e83f0d", + "sha256:6b1d7ceeede8d8eed48616d2d33ed23d2dff307d0b17c577eafdadafe86a0478", + "sha256:6b7d696155ddd7ab5739ac221e8854115d0d8171bbf805074d9484083de386aa", + "sha256:6d23e9483756b81850b82e8b7ed20fd23de22b50d6a678f765c660d4206b7ce9", + "sha256:7b0229fecc849234f2a2d11e948ac38a9bab02d201fa4d6ad43c143e18c1a66e", + "sha256:7c53050b670d702eed541503175bd5441fc4bdf3898714f8eac8c6ae9db548ac", + "sha256:7d65676f1fc138d1742f704bf490045571b9c2c48cab7d2c2076a52729c143e5", + "sha256:7db25328c40cd574e5a68ef6507c5af4d1fa2a44cb3c028ff9ca6b522f8faf32", + "sha256:83ce1b09e9eb2ae033c303b74ecc4f3186bbc0897db1d8cd9942153b0631b8e0", + "sha256:86c509900cbb90b7b75155c580b22af591b696fa059059bcdbd75bc74179df85", + "sha256:87f80d0075f0d396b73d41bb1626a2dd5607e0db4b74cb17e55d874fcd538971", + "sha256:8b719755d556649f2fbf226cf1ca8581ade114751df1facec96f94e75bffdb3c", + "sha256:8e739d4192758df6e5363791f527deb91c615d63020ee8965df4bcd1a217f9a5", + "sha256:923d3bf8770dfeb3d94bdfee1c5b5a081592de69766436a395e1e6203c19cf71", + "sha256:97772bb55cb47da3de49ca4b59309a9bd91ead730a7cfac1992932486fb41352", + "sha256:98bdfdf734144277132f34f770eeb6b0db2c4de87415f34b178adee766632f24", + "sha256:98f38b1b01e6f270b9279d76261d6f222b72ef06b025cbd4911b962bb6de4c98", + "sha256:99318b5ea78843e3c3e19cd56367216774674a99848f00a6f2dcf84e36039641", + "sha256:9c623ef06876d432dc8acc93ed3494d3453333d767b1b06bba1a016ea9d850c9", + "sha256:9d0f9720dfd0155432d23bcc3605fe5831cd0f586ede4f14ff6f3bebe8fb867a", + "sha256:9e79216760faac6395bee8ca4077a53a309312faba0f71982127ad8625861780", + "sha256:a470c908fd9baaecf41715ea3c30c57b530d598ae5e9de7e0bd532755e66bb1b", + "sha256:a634b9b79e059f45a56ff3ef6e7241662bc6f0e5a096ee6eed6770ea368e8278", + "sha256:acd8195a53d0e84ea95bdf15a2651c53b829a3ddead21b4a620b6a0c5e1ae2ff", + "sha256:addbd207df3718fc9d9de5b6c90a5e3fbe667830cf629186c9fdcafbb6578cb4", + "sha256:ae2aec9d55e108ae2d22fd0bda24450a6c13c116f9698b9e7ba2c6492c4fe715", + "sha256:af6b70ca9788964c5da5b59ca412b62db2ea7f2386a91c0117667bdd963e828c", + "sha256:afa7d60a9203db36a55b6f2868da90aaa829ab415a21fba7fa75678789aeb16f", + "sha256:b08c1931c44e3c034e645f3e3a7f4c47e8b0758fb8f09a52d1e880a307a1066f", + "sha256:b22e356914e606ff398c002b9925df4454c5deca9dbe55b3ba4a5c9b2365cf0f", + "sha256:b8c0f50397c51086df941b48057c82f85d9da000bf4fe6f4bc64c4f649b26a5b", + "sha256:bc068bcd79fe017866f536e0ad9424793220be34e3124476e17e6cb77a97e690", + "sha256:bc30f5a605a366acb7f301b3421508eaec3c1a515c960791bd776cb63d016302", + "sha256:c0d246b3f8a771578279eab9cfcb820dedefd3dd5dc0e34b37a337fe46271fc0", + "sha256:c0fee0a8593028bde17b57527b1ac21fea74f209b3522363e3ba0197ffaa6323", + "sha256:c139d5b103bb1f085d8918815d62ad946224a658ac1a7cc1b93dc44bd498ff9a", + "sha256:c25235cec12c0e38b4104268e312c9c2f3527ebc126d296cff69ea7aa13434dc", + "sha256:c7429d038dc383966c692e752010cbb4d5dab0e515f231aa01cd746aed9db359", + "sha256:c85cd2e64967c0dce2927ad7c62c090aae6d6b7f9e3a6b9fb91f58b890ea6adc", + "sha256:ca04984df012020dd846599b8555666c544982c2a91dc6135565e6708624eb71", + "sha256:cb7d43c07d58ba13736e70dc3e064496efeb1ed4475a28afb26b7a3b030b89df", + "sha256:d018e05cb61eed3050d45bd0c0ef9b75420899f6ae254e68e7f2ef26975098c9", + "sha256:d24d42881eb74729b34014e2e87f3a4d0419c43db309de2dff3f39118716865f", + "sha256:d6e17f218af856ca22c30d1a1ac58b19bccf768b8589eb8d6e45e1f1ff258404", + "sha256:d855d0be1759c5efc404c04977ee48a8b6260aef6441e72c10973924dbde5a73", + "sha256:dea0dcc0e50978ef73be8cb384694b71a6e64b46847ee7decad96dc85fbf650c", + "sha256:e1e9228049cf2442ac486a03a0d543c5dff3089a915a3e39ab809b22672e1d76", + "sha256:e26d052a248d5be2257d848d6078d932cc1fd4e8226639f550344d0a7a2b8813", + "sha256:ee6ccb8197936a308a4034c90a42b30b37c46b7cbda66101d439d6983f59b368", + "sha256:eea9c37b45e73cebb4670afd1779db138eeff0f84ffc0871d2fb90c04c8d3aa8", + "sha256:f195bf641276261e6bc5f79f52601850c9bdbff8af401483b4805dbff535ed30", + "sha256:f264827618400ebeab16708c8acf7870f693b03bfb4d7e95253eb9b35074db5c", + "sha256:f44ccd2eaa433ff1a10f70242dc33315fc192b81664696154127bdd66ad7d3b2", + "sha256:f7a6068d8857c403e105e62132a00e9d9d401bd0efbff7f8b5b5bc8ab768a2d8", + "sha256:f9886176fe4bf1ac008c02adb5bd103f1191799f1897777d203ee44f615325a5", + "sha256:fa1f38d5583d283b40f998e2f13471bfa952e0c423ff95ec2ec329f3e1898107", + "sha256:fa65494e7bd0e3ba33b3e5a5ab30c2b6e95d3d1762baaa56151a0861618dc261", + "sha256:fd7186e23963714bab3c9a2ab75d002078335110d2c9fc883c65cbce43717f26", + "sha256:fec32c22b521fcdeb9aa7dee4373b2d81ca2d3fc8edc532f3e189d6f4f6f1f81" + ], + "markers": "python_version >= '3.7'", + "version": "==1.2.2" + }, "werkzeug": { "hashes": [ "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", @@ -1426,73 +1773,73 @@ }, "coverage": { "hashes": [ - "sha256:056d3017ed67e7ddf266e6f57378ece543755a4c9231e997789ab3bd11392c94", - "sha256:0ce8cf59e09d31a4915ff4c3b94c6514af4c84b22c4cc8ad7c3c546a86150a92", - "sha256:104bf640f408f4e115b85110047c7f27377e1a8b7ba86f7db4fa47aa49dc9a8e", - "sha256:1393e5aa9441dafb0162c36c8506c648b89aea9565b31f6bfa351e66c11bcd82", - "sha256:1586ad158523f4133499a4f322b230e2cfef9cc724820dbd58595a5a236186f4", - "sha256:180e3fc68ee4dc5af8b33b6ca4e3bb8aa1abe25eedcb958ba5cff7123071af68", - "sha256:1b336d06af14f8da5b1f391e8dec03634daf54dfcb4d1c4fb6d04c09d83cef90", - "sha256:1c8fbce80b2b8bf135d105aa8f5b36eae0c57d702a1cc3ebdea2a6f03f6cdde5", - "sha256:2d673e3add00048215c2cc507f1228a7523fd8bf34f279ac98334c9b07bd2656", - "sha256:316f29cc3392fa3912493ee4c83afa4a0e2db04ff69600711f8c03997c39baaa", - "sha256:33c1394d8407e2771547583b66a85d07ed441ff8fae5a4adb4237ad39ece60db", - "sha256:37cbc7b0d93dfd133e33c7ec01123fbb90401dce174c3b6661d8d36fb1e30608", - "sha256:39abcacd1ed54e2c33c54bdc488b310e8ef6705833f7148b6eb9a547199d375d", - "sha256:3ab7090f04b12dc6469882ce81244572779d3a4b67eea1c96fb9ecc8c607ef39", - "sha256:3b0e6e54591ae0d7427def8a4d40fca99df6b899d10354bab73cd5609807261c", - "sha256:416e2a8845eaff288f97eaf76ab40367deafb9073ffc47bf2a583f26b05e5265", - "sha256:4545485fef7a8a2d8f30e6f79ce719eb154aab7e44217eb444c1d38239af2072", - "sha256:4c124025430249118d018dcedc8b7426f39373527c845093132196f2a483b6dd", - "sha256:4fbb7a0c3c21908520149d7751cf5b74eb9b38b54d62997b1e9b3ac19a8ee2fe", - "sha256:52fc89602cde411a4196c8c6894afb384f2125f34c031774f82a4f2608c59d7d", - "sha256:55143aa13c49491f5606f05b49ed88663446dce3a4d3c5d77baa4e36a16d3573", - "sha256:57f3bd0d29bf2bd9325c0ff9cc532a175110c4bf8f412c05b2405fd35745266d", - "sha256:5b2f144444879363ea8834cd7b6869d79ac796cb8f864b0cfdde50296cd95816", - "sha256:5efdeff5f353ed3352c04e6b318ab05c6ce9249c25ed3c2090c6e9cadda1e3b2", - "sha256:60e6347d1ed882b1159ffea172cb8466ee46c665af4ca397edbf10ff53e9ffaf", - "sha256:693d921621a0c8043bfdc61f7d4df5ea6d22165fe8b807cac21eb80dd94e4bbd", - "sha256:708f0a1105ef2b11c79ed54ed31f17e6325ac936501fc373f24be3e6a578146a", - "sha256:70f0925c4e2bfc965369f417e7cc72538fd1ba91639cf1e4ef4b1a6b50439b3b", - "sha256:7789e700f33f2b133adae582c9f437523cd5db8de845774988a58c360fc88253", - "sha256:7b6c96d69928a3a6767fab8dc1ce8a02cf0156836ccb1e820c7f45a423570d98", - "sha256:7d2a65876274acf544703e943c010b60bd79404e3623a1e5d52b64a6e2728de5", - "sha256:7f18d47641282664276977c604b5a261e51fefc2980f5271d547d706b06a837f", - "sha256:89078312f06237417adda7c021c33f80f7a6d2db8572a5f6c330d89b080061ce", - "sha256:8c938c6ae59be67ac19a7204e079efc94b38222cd7d0269f96e45e18cddeaa59", - "sha256:8e336b56301774ace6be0017ff85c3566c556d938359b61b840796a0202f805c", - "sha256:a0a207c87a9f743c8072d059b4711f8d13c456eb42dac778a7d2e5d4f3c253a7", - "sha256:a2454b12a3f12cc4698f3508912e6225ec63682e2ca5a96f80a2b93cef9e63f3", - "sha256:a538a23119d1e2e2ce077e902d02ea3d8e0641786ef6e0faf11ce82324743944", - "sha256:aa4dff57fc21a575672176d5ab0ef15a927199e775c5e8a3d75162ab2b0c7705", - "sha256:ad0edaa97cb983d9f2ff48cadddc3e1fb09f24aa558abeb4dc9a0dbacd12cbb4", - "sha256:ae8006772c6b0fa53c33747913473e064985dac4d65f77fd2fdc6474e7cd54e4", - "sha256:b0fac2088ec4aaeb5468b814bd3ff5e5978364bfbce5e567c44c9e2854469f6c", - "sha256:b3e212a894d8ae07fde2ca8b43d666a6d49bbbddb10da0f6a74ca7bd31f20054", - "sha256:b54a1ee4c6f1905a436cbaa04b26626d27925a41cbc3a337e2d3ff7038187f07", - "sha256:b667b91f4f714b17af2a18e220015c941d1cf8b07c17f2160033dbe1e64149f0", - "sha256:b8c36093aca722db73633cf2359026ed7782a239eb1c6db2abcff876012dc4cf", - "sha256:bb356e7ae7c2da13f404bf8f75be90f743c6df8d4607022e759f5d7d89fe83f8", - "sha256:bce730d484038e97f27ea2dbe5d392ec5c2261f28c319a3bb266f6b213650135", - "sha256:c075d167a6ec99b798c1fdf6e391a1d5a2d054caffe9593ba0f97e3df2c04f0e", - "sha256:c4e09534037933bf6eb31d804e72c52ec23219b32c1730f9152feabbd7499463", - "sha256:c5f8a5364fc37b2f172c26a038bc7ec4885f429de4a05fc10fdcb53fb5834c5c", - "sha256:cb203c0afffaf1a8f5b9659a013f8f16a1b2cad3a80a8733ceedc968c0cf4c57", - "sha256:cc41374d2f27d81d6558f8a24e5c114580ffefc197fd43eabd7058182f743322", - "sha256:cd879d4646055a573775a1cec863d00c9ff8c55860f8b17f6d8eee9140c06166", - "sha256:d013c07061751ae81861cae6ec3a4fe04e84781b11fd4b6b4201590234b25c7b", - "sha256:d8c7524779003d59948c51b4fcbf1ca4e27c26a7d75984f63488f3625c328b9b", - "sha256:d9710521f07f526de30ccdead67e6b236fe996d214e1a7fba8b36e2ba2cd8261", - "sha256:e1ffde1d6bc2a92f9c9207d1ad808550873748ac2d4d923c815b866baa343b3f", - "sha256:e7f559c36d5cdc448ee13e7e56ed7b6b5d44a40a511d584d388a0f5d940977ba", - "sha256:f2a1e18a85bd066c7c556d85277a7adf4651f259b2579113844835ba1a74aafd", - "sha256:f32b165bf6dfea0846a9c9c38b7e1d68f313956d60a15cde5d1709fddcaf3bee", - "sha256:f5a2f71d6a91238e7628f23538c26aa464d390cbdedf12ee2a7a0fb92a24482a", - "sha256:f81fe93dc1b8e5673f33443c0786c14b77e36f1025973b85e07c70353e46882b" + "sha256:042e7841a26498fff7a37d6fda770d17519982f5b7d8bf5278d140b67b61095f", + "sha256:04bfec25a8ef1c5f41f5e7e5c842f6b615599ca8ba8391ec33a9290d9d2db3a3", + "sha256:0915742f4c82208ebf47a2b154a5334155ed9ef9fe6190674b8a46c2fb89cb05", + "sha256:18c5ae6d061ad5b3e7eef4363fb27a0576012a7447af48be6c75b88494c6cf25", + "sha256:2931f66991175369859b5fd58529cd4b73582461877ecfd859b6549869287ffe", + "sha256:2e4b6b87bb0c846a9315e3ab4be2d52fac905100565f4b92f02c445c8799e257", + "sha256:3043ba1c88b2139126fc72cb48574b90e2e0546d4c78b5299317f61b7f718b78", + "sha256:379fe315e206b14e21db5240f89dc0774bdd3e25c3c58c2c733c99eca96f1ada", + "sha256:42421e04069fb2cbcbca5a696c4050b84a43b05392679d4068acbe65449b5c64", + "sha256:4dfd9a93db9e78666d178d4f08a5408aa3f2474ad4d0e0378ed5f2ef71640cb6", + "sha256:52a523153c568d2c0ef8826f6cc23031dc86cffb8c6aeab92c4ff776e7951b28", + "sha256:554fec1199d93ab30adaa751db68acec2b41c5602ac944bb19187cb9a41a8067", + "sha256:581a40c7b94921fffd6457ffe532259813fc68eb2bdda60fa8cc343414ce3733", + "sha256:5a26c0c795c3e0b63ec7da6efded5f0bc856d7c0b24b2ac84b4d1d7bc578d676", + "sha256:5a570cd9bd20b85d1a0d7b009aaf6c110b52b5755c17be6962f8ccd65d1dbd23", + "sha256:5aaeb00761f985007b38cf463b1d160a14a22c34eb3f6a39d9ad6fc27cb73008", + "sha256:5ac46d0c2dd5820ce93943a501ac5f6548ea81594777ca585bf002aa8854cacd", + "sha256:5c8a5c139aae4c35cbd7cadca1df02ea8cf28a911534fc1b0456acb0b14234f3", + "sha256:6b8af63b9afa1031c0ef05b217faa598f3069148eeee6bb24b79da9012423b82", + "sha256:769773614e676f9d8e8a0980dd7740f09a6ea386d0f383db6821df07d0f08545", + "sha256:771eb7587a0563ca5bb6f622b9ed7f9d07bd08900f7589b4febff05f469bea00", + "sha256:77af0f6447a582fdc7de5e06fa3757a3ef87769fbb0fdbdeba78c23049140a47", + "sha256:7a3d62b3b03b4b6fd41a085f3574874cf946cb4604d2b4d3e8dca8cd570ca501", + "sha256:821f7bcbaa84318287115d54becb1915eece6918136c6f91045bb84e2f88739d", + "sha256:89b1f4af0d4afe495cd4787a68e00f30f1d15939f550e869de90a86efa7e0814", + "sha256:8a1d96e780bdb2d0cbb297325711701f7c0b6f89199a57f2049e90064c29f6bd", + "sha256:8a40fcf208e021eb14b0fac6bdb045c0e0cab53105f93ba0d03fd934c956143a", + "sha256:8f99eb72bf27cbb167b636eb1726f590c00e1ad375002230607a844d9e9a2318", + "sha256:90e7fbc6216ecaffa5a880cdc9c77b7418c1dcb166166b78dbc630d07f278cc3", + "sha256:94ec0be97723ae72d63d3aa41961a0b9a6f5a53ff599813c324548d18e3b9e8c", + "sha256:95aa6ae391a22bbbce1b77ddac846c98c5473de0372ba5c463480043a07bff42", + "sha256:96121edfa4c2dfdda409877ea8608dd01de816a4dc4a0523356067b305e4e17a", + "sha256:a1f406a8e0995d654b2ad87c62caf6befa767885301f3b8f6f73e6f3c31ec3a6", + "sha256:a321c61477ff8ee705b8a5fed370b5710c56b3a52d17b983d9215861e37b642a", + "sha256:a5761c70c017c1b0d21b0815a920ffb94a670c8d5d409d9b38857874c21f70d7", + "sha256:a9abbccd778d98e9c7e85038e35e91e67f5b520776781d9a1e2ee9d400869487", + "sha256:ad80e6b4a0c3cb6f10f29ae4c60e991f424e6b14219d46f1e7d442b938ee68a4", + "sha256:b44674870709017e4b4036e3d0d6c17f06a0e6d4436422e0ad29b882c40697d2", + "sha256:b571bf5341ba8c6bc02e0baeaf3b061ab993bf372d982ae509807e7f112554e9", + "sha256:b8194fb8e50d556d5849753de991d390c5a1edeeba50f68e3a9253fbd8bf8ccd", + "sha256:b87eb6fc9e1bb8f98892a2458781348fa37e6925f35bb6ceb9d4afd54ba36c73", + "sha256:bbb5cc845a0292e0c520656d19d7ce40e18d0e19b22cb3e0409135a575bf79fc", + "sha256:be945402e03de47ba1872cd5236395e0f4ad635526185a930735f66710e1bd3f", + "sha256:bf13d564d310c156d1c8e53877baf2993fb3073b2fc9f69790ca6a732eb4bfea", + "sha256:cf60dd2696b457b710dd40bf17ad269d5f5457b96442f7f85722bdb16fa6c899", + "sha256:d1ba00ae33be84066cfbe7361d4e04dec78445b2b88bdb734d0d1cbab916025a", + "sha256:d39fc4817fd67b3915256af5dda75fd4ee10621a3d484524487e33416c6f3543", + "sha256:d766a4f0e5aa1ba056ec3496243150698dc0481902e2b8559314368717be82b1", + "sha256:dbf364b4c5e7bae9250528167dfe40219b62e2d573c854d74be213e1e52069f7", + "sha256:dd19608788b50eed889e13a5d71d832edc34fc9dfce606f66e8f9f917eef910d", + "sha256:e013b07ba1c748dacc2a80e69a46286ff145935f260eb8c72df7185bf048f502", + "sha256:e5d2b9be5b0693cf21eb4ce0ec8d211efb43966f6657807f6859aab3814f946b", + "sha256:e5ff52d790c7e1628241ffbcaeb33e07d14b007b6eb00a19320c7b8a7024c040", + "sha256:e75a2ad7b647fd8046d58c3132d7eaf31b12d8a53c0e4b21fa9c4d23d6ee6d3c", + "sha256:e7ac22a0bb2c7c49f441f7a6d46c9c80d96e56f5a8bc6972529ed43c8b694e27", + "sha256:ed2144b8a78f9d94d9515963ed273d620e07846acd5d4b0a642d4849e8d91a0c", + "sha256:f017a61399f13aa6d1039f75cd467be388d157cd81f1a119b9d9a68ba6f2830d", + "sha256:f1d8a2a57b47142b10374902777e798784abf400a004b14f1b0b9eaf1e528ba4", + "sha256:f2d32f95922927186c6dbc8bc60df0d186b6edb828d299ab10898ef3f40052fe", + "sha256:f319bae0321bc838e205bf9e5bc28f0a3165f30c203b610f17ab5552cff90323", + "sha256:f3c38e4e5ccbdc9198aecc766cedbb134b2d89bf64533973678dfcf07effd883", + "sha256:f9983d01d7705b2d1f7a95e10bbe4091fabc03a46881a256c2787637b087003f", + "sha256:fa260de59dfb143af06dcf30c2be0b200bed2a73737a8a59248fcb9fa601ef0f" ], "index": "pypi", "markers": "python_version >= '3.9'", - "version": "==7.7.0" + "version": "==7.8.0" }, "cryptography": { "hashes": [ @@ -1545,11 +1892,11 @@ }, "iniconfig": { "hashes": [ - "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", - "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" + "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", + "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760" ], - "markers": "python_version >= '3.7'", - "version": "==2.0.0" + "markers": "python_version >= '3.8'", + "version": "==2.1.0" }, "jwt": { "hashes": [ diff --git a/dbrepo-search-service/init/app.py b/dbrepo-search-service/init/app.py index f8f671bade77541508aec72cd19066157cd162f3..48a59538e01fc232fe49675db5692cb21c2f8942 100644 --- a/dbrepo-search-service/init/app.py +++ b/dbrepo-search-service/init/app.py @@ -4,10 +4,9 @@ import os from logging.config import dictConfig from typing import List -import opensearchpy.exceptions from dbrepo.RestClient import RestClient from dbrepo.api.dto import Database -from opensearchpy import OpenSearch +from dbrepo.core.client.search import SearchServiceClient level = os.getenv("LOG_LEVEL", "DEBUG").upper() logging.basicConfig(level=level) @@ -34,84 +33,35 @@ dictConfig({ } }) +search_client = SearchServiceClient(host=os.getenv("OPENSEARCH_HOST", "search-db"), + port=int(os.getenv("OPENSEARCH_PORT", "9200")), + username=os.getenv("OPENSEARCH_USERNAME", "admin"), + password=os.getenv("OPENSEARCH_PASSWORD", "admin")) -class App: - """ - The client to communicate with the OpenSearch database. - """ - metadata_service_endpoint: str = None - search_host: str = None - search_port: int = None - search_username: str = None - search_password: str = None - search_instance: OpenSearch = None - system_username: str = None - system_password: str = None +rest_client = RestClient(endpoint=os.getenv("METADATA_SERVICE_ENDPOINT", "http://metadata-service:8080"), + username=os.getenv("SYSTEM_USERNAME", "admin"), + password=os.getenv("SYSTEM_PASSWORD", "admin")) - def __init__(self): - self.metadata_service_endpoint = os.getenv("METADATA_SERVICE_ENDPOINT", "http://metadata-service:8080") - self.search_host = os.getenv("OPENSEARCH_HOST", "search-db") - self.search_port = int(os.getenv("OPENSEARCH_PORT", "9200")) - self.search_username = os.getenv("OPENSEARCH_USERNAME", "admin") - self.search_password = os.getenv("OPENSEARCH_PASSWORD", "admin") - self.system_username = os.getenv("SYSTEM_USERNAME", "admin") - self.system_password = os.getenv("SYSTEM_PASSWORD", "admin") - def _instance(self) -> OpenSearch: - """ - Wrapper method to get the instance singleton. +def fetch_databases() -> List[Database]: + databases = [] + for index, database in enumerate(rest_client.get_databases()): + database = rest_client.get_database(database_id=database.id) + logging.debug(f'fetch database details with id: {database.id}') + databases.append(database) + logging.debug(f'fetched {len(databases)} database(s)') + return databases - @returns: The opensearch instance singleton, if successful. - """ - if self.search_instance is None: - self.search_instance = OpenSearch(hosts=[{"host": self.search_host, "port": self.search_port}], - http_compress=True, - http_auth=(self.search_username, self.search_password)) - logging.debug(f"create instance {self.search_host}:{self.search_port}") - return self.search_instance - def database_exists(self, database_id: int): - try: - self._instance().get(index="database", id=database_id) - return True - except opensearchpy.exceptions.NotFoundError: - return False - - def index_update(self) -> None: - if self._instance().indices.exists(index="database"): - logging.debug(f"index 'database' exists, removing...") - self._instance().indices.delete(index="database") - with open('./database.json', 'r') as f: - self._instance().indices.create(index="database", body=json.load(f)) - logging.info(f"Created index 'database'") - - def fetch_databases(self) -> List[Database]: - logging.debug(f"fetching database from endpoint: {self.metadata_service_endpoint}") - client = RestClient(endpoint=self.metadata_service_endpoint, username=self.system_username, - password=self.system_password) - databases = [] - for index, database in enumerate(client.get_databases()): - logging.debug(f"fetching database {index}/{len(databases)} details for database id: {database.id}") - databases.append(client.get_database(database_id=database.id)) - logging.debug(f"fetched {len(databases)} database(s)") - return databases - - def save_databases(self, databases: List[Database]): - index = f'database' - logging.debug(f"save {len(databases)} database(s) in index: {index}") - for doc in databases: - doc: Database = doc - try: - self._instance().delete(index=index, id=doc.id) - logging.debug(f"truncated database with id {doc.id} in index: {index}") - except opensearchpy.NotFoundError: - pass - self._instance().create(index=index, id=doc.id, body=doc.model_dump()) - logging.info(f"Saved database with id {doc.id} in index: {index}") +def save_databases(databases: List[Database]): + logging.debug(f"save {len(databases)} database(s)") + for doc in databases: + search_client.save_database(database_id=doc.id, data=doc) + logging.info(f"Saved database with id {doc.id}") if __name__ == "__main__": - app = App() - update = app.index_update() - app.save_databases(databases=app.fetch_databases()) + with open('./database.json', 'r') as f: + search_client.index_update(mapping=json.load(f)) + save_databases(databases=fetch_databases()) logging.info("Finished. Exiting.") diff --git a/dbrepo-search-service/init/clients/keycloak_client.py b/dbrepo-search-service/init/clients/keycloak_client.py deleted file mode 100644 index e8c277601bb2ce4ec0108ae5cd4dab7c3b061960..0000000000000000000000000000000000000000 --- a/dbrepo-search-service/init/clients/keycloak_client.py +++ /dev/null @@ -1,56 +0,0 @@ -import logging -import os -from dataclasses import dataclass -from typing import List - -import requests -from dbrepo.api.dto import ApiError -from jwt import jwk_from_pem, JWT -from jwt.exceptions import JWTDecodeError - - -@dataclass(init=True, eq=True) -class User: - id: str - username: str - roles: List[str] - - -class KeycloakClient: - - def obtain_user_token(self, username: str, password: str) -> str: - response = requests.post( - f"{os.getenv('AUTH_SERVICE_ENDPOINT', 'http://auth-service:8080')}/realms/dbrepo/protocol/openid-connect/token", - data={ - "username": username, - "password": password, - "grant_type": "password", - "client_id": os.getenv("AUTH_SERVICE_CLIENT", "dbrepo-client"), - "client_secret": os.getenv("AUTH_SERVICE_CLIENT_SECRET", "MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG") - }) - body = response.json() - if "access_token" not in body: - raise AssertionError("Failed to obtain user token(s)") - return response.json()["access_token"] - - def verify_jwt(self, access_token: str) -> ApiError | User: - public_key = jwk_from_pem(str('-----BEGIN PUBLIC KEY-----\n' + os.getenv("JWT_PUBKEY", - "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB") + '\n-----END PUBLIC KEY-----').encode( - 'utf-8')) - payload = JWT().decode(message=access_token, key=public_key, do_time_check=True) - return User(id=payload.get('uid'), username=payload.get('client_id'), - roles=payload.get('realm_access')["roles"]) - - def userId(self, auth_header: str | None) -> (str | None, ApiError, int): - if auth_header is None: - return None, None, None - try: - user = self.verify_jwt(auth_header.split(" ")[1]) - logging.debug(f'mapped JWT to user.id {user.id}') - return user.id, None, None - except JWTDecodeError as e: - logging.error(f'Failed to decode JWT: {e}') - if str(e) == 'JWT Expired': - return None, ApiError(status='UNAUTHORIZED', message=f'Token expired', - code='search.user.unauthorized').model_dump(), 401 - return None, ApiError(status='FORBIDDEN', message=str(e), code='search.user.forbidden').model_dump(), 403 diff --git a/dbrepo-search-service/init/lib/dbrepo-1.7.2.tar.gz b/dbrepo-search-service/init/lib/dbrepo-1.7.2.tar.gz deleted file mode 100644 index 12cef6f73928370726f75f4f3909aa6510049543..0000000000000000000000000000000000000000 Binary files a/dbrepo-search-service/init/lib/dbrepo-1.7.2.tar.gz and /dev/null differ diff --git a/dbrepo-search-service/init/lib/dbrepo-1.7.3-py3-none-any.whl b/dbrepo-search-service/init/lib/dbrepo-1.7.3-py3-none-any.whl deleted file mode 100644 index c1a74fe8c7e3f602651db9b6c30a5f7dcf17d97b..0000000000000000000000000000000000000000 Binary files a/dbrepo-search-service/init/lib/dbrepo-1.7.3-py3-none-any.whl and /dev/null differ diff --git a/dbrepo-search-service/init/lib/dbrepo-1.7.3.tar.gz b/dbrepo-search-service/init/lib/dbrepo-1.7.3.tar.gz deleted file mode 100644 index 7c13793a4936d21d621548c512ca88cfbf914716..0000000000000000000000000000000000000000 Binary files a/dbrepo-search-service/init/lib/dbrepo-1.7.3.tar.gz and /dev/null differ diff --git a/dbrepo-search-service/init/lib/dbrepo-1.8.0-py3-none-any.whl b/dbrepo-search-service/init/lib/dbrepo-1.8.0-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..a285fef8ff07eaeffb5a1dfbab34dd395c0330d9 Binary files /dev/null and b/dbrepo-search-service/init/lib/dbrepo-1.8.0-py3-none-any.whl differ diff --git a/dbrepo-search-service/init/lib/dbrepo-1.8.0.tar.gz b/dbrepo-search-service/init/lib/dbrepo-1.8.0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..4b3de54c835f7085ce9546cc519400bdbc9480b0 Binary files /dev/null and b/dbrepo-search-service/init/lib/dbrepo-1.8.0.tar.gz differ diff --git a/dbrepo-search-service/init/tests/test_app.py b/dbrepo-search-service/init/tests/test_app.py deleted file mode 100644 index 118ccf99c16586e4305967ab22a12e6317fb8ae2..0000000000000000000000000000000000000000 --- a/dbrepo-search-service/init/tests/test_app.py +++ /dev/null @@ -1,21 +0,0 @@ -import unittest - -from app import App -from clients.opensearch_client import OpenSearchClient - - -class AppTest(unittest.TestCase): - - def test_index_update_succeeds(self): - # test - app = App() - app.index_update() - - def test_index_update_not_exists_succeeds(self): - # mock - client = OpenSearchClient() - client._instance().indices.delete(index="database") - - # test - app = App() - app.index_update() diff --git a/dbrepo-search-service/init/tests/test_unit_app.py b/dbrepo-search-service/init/tests/test_unit_app.py new file mode 100644 index 0000000000000000000000000000000000000000..1f8ee06980f1166f7feffb38e6b241bdebe39755 --- /dev/null +++ b/dbrepo-search-service/init/tests/test_unit_app.py @@ -0,0 +1,50 @@ +import unittest + +import requests_mock +from dbrepo.api.dto import UserBrief, DatabaseBrief, Database, ContainerBrief, ImageBrief + +from app import fetch_databases + +exp = DatabaseBrief( + id="6bd39359-b154-456d-b9c2-caa516a45732", + name='test', + owner_id='8638c043-5145-4be8-a3e4-4b79991b0a16', + contact=UserBrief(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise'), + internal_name='test_abcd', + is_public=True, + is_schema_public=True +) + + +class AppIntegrationTest(unittest.TestCase): + + def test_fetch_databases_succeeds(self): + db = Database( + id="6bd39359-b154-456d-b9c2-caa516a45732", + name='test', + owner=UserBrief(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise'), + contact=UserBrief(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise'), + exchange_name='dbrepo', + internal_name='test_abcd', + is_public=True, + is_schema_public=True, + is_dashboard_enabled=True, + container=ContainerBrief( + id="44d811a8-4019-46ba-bd57-ea10a2eb0c74", + name='MariaDB Galera 11.1.3', + internal_name='mariadb', + image=ImageBrief( + id="b104648b-54d2-4d72-9834-8e0e6d428b39", + name='mariadb', + version='11.2.2', + default=True) + ) + ) + with requests_mock.Mocker() as mock: + # mock + mock.get('/api/database', json=[exp.model_dump()]) + mock.get(f'/api/database/{exp.id}', json=db.model_dump()) + # test + response = fetch_databases() + self.assertEqual(1, len(response)) + self.assertEqual(db, response[0]) diff --git a/dbrepo-search-service/lib/dbrepo-1.7.2.tar.gz b/dbrepo-search-service/lib/dbrepo-1.7.2.tar.gz deleted file mode 100644 index 12cef6f73928370726f75f4f3909aa6510049543..0000000000000000000000000000000000000000 Binary files a/dbrepo-search-service/lib/dbrepo-1.7.2.tar.gz and /dev/null differ diff --git a/dbrepo-search-service/lib/dbrepo-1.7.3-py3-none-any.whl b/dbrepo-search-service/lib/dbrepo-1.7.3-py3-none-any.whl deleted file mode 100644 index c1a74fe8c7e3f602651db9b6c30a5f7dcf17d97b..0000000000000000000000000000000000000000 Binary files a/dbrepo-search-service/lib/dbrepo-1.7.3-py3-none-any.whl and /dev/null differ diff --git a/dbrepo-search-service/lib/dbrepo-1.7.3.tar.gz b/dbrepo-search-service/lib/dbrepo-1.7.3.tar.gz deleted file mode 100644 index 7c13793a4936d21d621548c512ca88cfbf914716..0000000000000000000000000000000000000000 Binary files a/dbrepo-search-service/lib/dbrepo-1.7.3.tar.gz and /dev/null differ diff --git a/dbrepo-search-service/lib/dbrepo-1.8.0-py3-none-any.whl b/dbrepo-search-service/lib/dbrepo-1.8.0-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..a285fef8ff07eaeffb5a1dfbab34dd395c0330d9 Binary files /dev/null and b/dbrepo-search-service/lib/dbrepo-1.8.0-py3-none-any.whl differ diff --git a/dbrepo-search-service/lib/dbrepo-1.8.0.tar.gz b/dbrepo-search-service/lib/dbrepo-1.8.0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..4b3de54c835f7085ce9546cc519400bdbc9480b0 Binary files /dev/null and b/dbrepo-search-service/lib/dbrepo-1.8.0.tar.gz differ diff --git a/dbrepo-search-service/os-yml/update_database.yml b/dbrepo-search-service/os-yml/save_database.yml similarity index 75% rename from dbrepo-search-service/os-yml/update_database.yml rename to dbrepo-search-service/os-yml/save_database.yml index e9cd0d56f967a62144dba4af10edea38b055a11c..988cf421c60d2b55b0aa9e105e4ffae7adaed925 100644 --- a/dbrepo-search-service/os-yml/update_database.yml +++ b/dbrepo-search-service/os-yml/save_database.yml @@ -1,8 +1,8 @@ tags: - database-endpoint -summary: Updates a database -operationId: update_database -description: Updates a database +summary: Saves a database +operationId: save_database +description: Save a database consumes: - application/json produces: @@ -18,18 +18,7 @@ security: - basicAuth: [ ] responses: 202: - description: Updated database successfully - content: - application/json: - schema: - required: - - id - type: object - properties: - id: - type: integer - example: 1 - implementation: int64 + description: Saved database successfully 400: description: "Invalid schema" content: diff --git a/dbrepo-search-service/tests/.testpickle b/dbrepo-search-service/tests/.testpickle deleted file mode 100644 index b9f0895c08ef7cdeb31e17c5174fcef1da26a5fe..0000000000000000000000000000000000000000 Binary files a/dbrepo-search-service/tests/.testpickle and /dev/null differ diff --git a/dbrepo-search-service/tests/__init__.py b/dbrepo-search-service/tests/__init__.py index c68ce82814807bb71c88b8f5fe8024bf05f4a147..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/dbrepo-search-service/tests/__init__.py +++ b/dbrepo-search-service/tests/__init__.py @@ -1,3 +0,0 @@ -""" -This (empty) __init__.py file is necessary for importing this module in other python files -""" \ No newline at end of file diff --git a/dbrepo-search-service/tests/test_app.py b/dbrepo-search-service/tests/test_app.py index d2c8f2bd6049220b83a867562f0459b58b8f344d..2cc9b3ba0001b870f2f07f2558858aa135e7fa1a 100644 --- a/dbrepo-search-service/tests/test_app.py +++ b/dbrepo-search-service/tests/test_app.py @@ -16,6 +16,7 @@ req = Database(id="209acf92-5c9b-4633-ad99-113c86f6e948", exchange_name="dbrepo", is_public=True, is_schema_public=True, + is_dashboard_enabled=True, container=ContainerBrief(id="7efe8b27-6cdc-4387-80e3-92ee28f4a7c5", name="MariaDB", internal_name="mariadb", @@ -58,17 +59,19 @@ class JwtTest(unittest.TestCase): def token(self, roles: [str], iat: int = int(time.time())): claims = { 'iat': iat, + 'uid': 'c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502', + 'preferred_username': 'foo', 'realm_access': { 'roles': roles } } - with open('tests/rsa/rs256.key', 'rb') as fh: + with open('./tests/rsa/rs256.key', 'rb') as fh: return jwt.JWT().encode(claims, jwt.jwk_from_pem(fh.read()), alg='RS256') def test_update_database_media_type_fails(self): with app.test_client() as test_client: # test - response = test_client.put('/api/search/database/1', + response = test_client.put(f'/api/search/database/{req.id}', headers={'Authorization': f'Bearer {self.token(["update-search-index"])}'}) self.assertEqual(415, response.status_code) @@ -81,13 +84,13 @@ class JwtTest(unittest.TestCase): def test_update_database_no_auth_fails(self): with app.test_client() as test_client: # test - response = test_client.put('/api/search/database/1') + response = test_client.put(f'/api/search/database/{req.id}') self.assertEqual(401, response.status_code) def test_update_database_no_body_fails(self): with app.test_client() as test_client: # test - response = test_client.put('/api/search/database/1', + response = test_client.put(f'/api/search/database/{req.id}', headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', 'Content-Type': 'application/json'}) self.assertEqual(400, response.status_code) @@ -95,7 +98,7 @@ class JwtTest(unittest.TestCase): def test_update_database_empty_body_fails(self): with app.test_client() as test_client: # test - response = test_client.put('/api/search/database/1', + response = test_client.put(f'/api/search/database/{req.id}', headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', 'Content-Type': 'application/json'}, data={}) @@ -104,7 +107,7 @@ class JwtTest(unittest.TestCase): def test_update_database_malformed_body_fails(self): with app.test_client() as test_client: # test - response = test_client.put('/api/search/database/1', + response = test_client.put(f'/api/search/database/{req.id}', headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', 'Content-Type': 'application/json'}, data=dict({"id": 1})) @@ -113,7 +116,7 @@ class JwtTest(unittest.TestCase): def test_update_database_succeeds(self): with app.test_client() as test_client: # test - response = test_client.put('/api/search/database/1', + response = test_client.put(f'/api/search/database/{req.id}', headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', 'Content-Type': 'application/json'}, data=req.model_dump_json()) @@ -140,27 +143,27 @@ class JwtTest(unittest.TestCase): def test_delete_database_no_role_fails(self): with app.test_client() as test_client: # test - response = test_client.delete('/api/search/database/1', + response = test_client.delete(f'/api/search/database/{req.id}', headers={'Authorization': f'Bearer {self.token([])}'}) self.assertEqual(403, response.status_code) def test_delete_database_succeeds(self): with app.test_client() as test_client: # mock - test_client.put('/api/search/database/1', + test_client.put(f'/api/search/database/{req.id}', headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', 'Content-Type': 'application/json'}, data=req.model_dump_json()) # test - response = test_client.delete('/api/search/database/1', - headers={'Authorization': f'Bearer {self.token(["admin"])}'}) + response = test_client.delete(f'/api/search/database/{req.id}', + headers={'Authorization': f'Bearer {self.token(["system"])}'}) self.assertEqual(202, response.status_code) def test_delete_database_not_found_fails(self): with app.test_client() as test_client: # test - response = test_client.delete('/api/search/database/1', - headers={'Authorization': f'Bearer {self.token(["admin"])}'}) + response = test_client.delete(f'/api/search/database/{req.id}', + headers={'Authorization': f'Bearer {self.token(["system"])}'}) self.assertEqual(404, response.status_code) def test_get_fuzzy_search_succeeds(self): @@ -202,83 +205,83 @@ class JwtTest(unittest.TestCase): def test_post_general_search_succeeds(self): with app.test_client() as test_client: # mock - test_client.put('/api/search/database/1', + test_client.put(f'/api/search/database/{req.id}', headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', 'Content-Type': 'application/json'}, data=req.model_dump_json()) # test response = test_client.post('/api/search/database', headers={'Content-Type': 'application/json'}, - data=json.dumps({'id': 1})) + data=json.dumps({'id': '7b4942c3-6312-4f1d-bff9-cd24ea53ea05'})) self.assertEqual(200, response.status_code) def test_post_general_search_table_succeeds(self): with app.test_client() as test_client: # mock - test_client.put('/api/search/database/1', + test_client.put(f'/api/search/database/{req.id}', headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', 'Content-Type': 'application/json'}, data=req.model_dump_json()) # test response = test_client.post('/api/search/table', headers={'Content-Type': 'application/json'}, - data=json.dumps({'id': 1})) + data=json.dumps({'id': '7b4942c3-6312-4f1d-bff9-cd24ea53ea05'})) self.assertEqual(200, response.status_code) def test_post_general_search_column_succeeds(self): with app.test_client() as test_client: # mock - test_client.put('/api/search/database/1', + test_client.put(f'/api/search/database/{req.id}', headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', 'Content-Type': 'application/json'}, data=req.model_dump_json()) # test response = test_client.post('/api/search/column', headers={'Content-Type': 'application/json'}, - data=json.dumps({'id': 1})) + data=json.dumps({'id': '7b4942c3-6312-4f1d-bff9-cd24ea53ea05'})) self.assertEqual(200, response.status_code) def test_post_general_search_identifier_succeeds(self): with app.test_client() as test_client: # mock - test_client.put('/api/search/database/1', + test_client.put(f'/api/search/database/{req.id}', headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', 'Content-Type': 'application/json'}, data=req.model_dump_json()) # test response = test_client.post('/api/search/identifier', headers={'Content-Type': 'application/json'}, - data=json.dumps({'id': 1})) + data=json.dumps({'id': '7b4942c3-6312-4f1d-bff9-cd24ea53ea05'})) self.assertEqual(200, response.status_code) def test_post_general_search_concept_succeeds(self): with app.test_client() as test_client: # mock - test_client.put('/api/search/database/1', + test_client.put(f'/api/search/database/{req.id}', headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', 'Content-Type': 'application/json'}, data=req.model_dump_json()) # test response = test_client.post('/api/search/concept', headers={'Content-Type': 'application/json'}, - data=json.dumps({'id': 1})) + data=json.dumps({'id': '7b4942c3-6312-4f1d-bff9-cd24ea53ea05'})) self.assertEqual(200, response.status_code) def test_post_general_search_unit_succeeds(self): with app.test_client() as test_client: # mock - test_client.put('/api/search/database/1', + test_client.put(f'/api/search/database/{req.id}', headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', 'Content-Type': 'application/json'}, data=req.model_dump_json()) # test response = test_client.post('/api/search/unit', headers={'Content-Type': 'application/json'}, - data=json.dumps({'id': 1})) + data=json.dumps({'id': '7b4942c3-6312-4f1d-bff9-cd24ea53ea05'})) self.assertEqual(200, response.status_code) def test_post_general_search_view_succeeds(self): with app.test_client() as test_client: # mock - test_client.put('/api/search/database/1', + test_client.put(f'/api/search/database/{req.id}', headers={'Authorization': f'Bearer {self.token(["update-search-index"])}', 'Content-Type': 'application/json'}, data=req.model_dump_json()) # test response = test_client.post('/api/search/view', headers={'Content-Type': 'application/json'}, - data=json.dumps({'id': 1})) + data=json.dumps({'id': '7b4942c3-6312-4f1d-bff9-cd24ea53ea05'})) self.assertEqual(200, response.status_code) diff --git a/dbrepo-search-service/tests/test_jwt.py b/dbrepo-search-service/tests/test_jwt.py deleted file mode 100644 index 6c2b16989300e49196f6ece00ad18b5296f7cff6..0000000000000000000000000000000000000000 --- a/dbrepo-search-service/tests/test_jwt.py +++ /dev/null @@ -1,98 +0,0 @@ -import time -import unittest - -import jwt -import requests_mock - -from app import verify_token, app, verify_password, get_user_roles -from clients.keycloak_client import User - - -class JwtTest(unittest.TestCase): - - def response(self, roles: [str]) -> dict: - return dict({ - 'client_id': 'username', - 'realm_access': { - 'roles': roles - } - }) - - def token(self, roles: [str], iat: int = int(time.time())) -> str: - claims = { - 'iat': iat, - 'realm_access': { - 'roles': roles - } - } - with open('tests/rsa/rs256.key', 'rb') as fh: - return jwt.JWT().encode(claims, jwt.jwk_from_pem(fh.read()), alg='RS256') - - def test_verify_token_no_token_fails(self): - with app.app_context(): - # test - user = verify_token(None) - self.assertFalse(user) - - def test_verify_token_empty_token_fails(self): - with app.app_context(): - # test - user = verify_token('') - self.assertFalse(user) - - def test_verify_token_malformed_token_fails(self): - with app.app_context(): - # test - user = verify_token('eyEYEY12345') - self.assertFalse(user) - - def test_verify_token_succeeds(self): - with app.app_context(): - with requests_mock.Mocker() as mock: - # mock - mock.post('http://auth-service:8080/api/auth/realms/dbrepo/protocol/openid-connect/token', - json=self.response([])) - # test - user = verify_token(self.token([])) - self.assertEqual([], user.roles) - - def test_verify_password_no_username_fails(self): - with app.app_context(): - # test - user = verify_password(None, 'pass') - self.assertFalse(user) - - def test_verify_password_empty_username_fails(self): - with app.app_context(): - # test - user = verify_password('', 'pass') - self.assertFalse(user) - - def test_verify_password_no_password_fails(self): - with app.app_context(): - # test - user = verify_password('username', None) - self.assertFalse(user) - - def test_verify_password_empty_password_fails(self): - with app.app_context(): - # test - user = verify_password('username', '') - self.assertFalse(user) - - def test_verify_password_succeeds(self): - with app.app_context(): - with requests_mock.Mocker() as mock: - # mock - mock.post('http://auth-service:8080/realms/dbrepo/protocol/openid-connect/token', - json=self.response([])) - # test - user = verify_password('username', 'password') - self.assertIsNotNone(user) - - def test_get_user_roles_succeeds(self): - with app.app_context(): - # test - roles: [str] = get_user_roles( - User(id='b98415d8-28bc-4472-84ff-3d09cc79aff6', username='username', roles=[])) - self.assertEqual([], roles) diff --git a/dbrepo-ui/components/database/DatabaseToolbar.vue b/dbrepo-ui/components/database/DatabaseToolbar.vue index 3e661cd754b98ca94519bda6a7f4ad49d4ff0378..0e69b9a91bd913353f24ea8953223ce908591a70 100644 --- a/dbrepo-ui/components/database/DatabaseToolbar.vue +++ b/dbrepo-ui/components/database/DatabaseToolbar.vue @@ -63,14 +63,15 @@ :text="$t('toolbars.database.info.tab')" :to="`/database/${$route.params.database_id}/info`" /> <v-tab - :text="$t('toolbars.database.tables.tab')" - :to="`/database/${$route.params.database_id}/table`" /> + :text="$t('toolbars.database.views.tab')" + :to="`/database/${$route.params.database_id}/view`" /> <v-tab + v-if="database && database.is_public" :text="$t('toolbars.database.subsets.tab')" :to="`/database/${$route.params.database_id}/subset`" /> <v-tab - :text="$t('toolbars.database.views.tab')" - :to="`/database/${$route.params.database_id}/view`" /> + :text="$t('toolbars.database.tables.tab')" + :to="`/database/${$route.params.database_id}/table`" /> <v-tab v-if="isOwner" :text="$t('toolbars.database.settings.tab')" diff --git a/dbrepo-ui/components/identifier/Citation.vue b/dbrepo-ui/components/identifier/Citation.vue index a52cd87159b23f4cad7d64ae5dd4fe177a489b65..570ab267901e8b09e428c41e985106d82d5ee36a 100644 --- a/dbrepo-ui/components/identifier/Citation.vue +++ b/dbrepo-ui/components/identifier/Citation.vue @@ -15,7 +15,6 @@ :items="styles" item-title="title" item-value="value" - dense variant="outlined" single-line /> </v-col> diff --git a/dbrepo-ui/components/subset/Builder.vue b/dbrepo-ui/components/subset/Builder.vue index 52fff4c4df37a474b3686c0c6d5cffda85cae7af..4e4fe21eecb64311937e737fd2a0f7aeaf2f56f3 100644 --- a/dbrepo-ui/components/subset/Builder.vue +++ b/dbrepo-ui/components/subset/Builder.vue @@ -91,9 +91,9 @@ <v-col lg="4"> <v-select - v-model="table" + v-model="datasource" :disabled="isExecuted" - :items="tables" + :items="datasources" item-title="name" return-object persistent-hint @@ -108,7 +108,7 @@ <v-select v-model="select" item-title="internal_name" - :disabled="!table || isExecuted" + :disabled="!datasource || isExecuted" :items="columns" :rules="[v => !!v || $t('validation.required')]" required @@ -375,7 +375,7 @@ export default { }, data () { return { - table: null, + datasource: null, views: [], columns: [], sorts: [], @@ -393,7 +393,8 @@ export default { resultId: null, errorKeyword: null, query: { - table_id: null, + datasource_id: null, + datasource_type: null, columns: [], filter: null }, @@ -424,11 +425,14 @@ export default { } return this.database.container.image.operators }, - tables () { + datasources () { if (!this.database) { return [] } - return this.database.tables + if (this.isView) { + return this.database.tables + } + return this.database.views }, database () { return this.cacheStore.getDatabase @@ -467,11 +471,12 @@ export default { return this.$config.public.database.unsupported.split(',') }, subset () { - if (!this.table || !this.select) { + if (!this.datasource || !this.select) { return null } return { - table_id: this.table.id, + datasource_id: this.datasource.id, + datasource_type: this.isView ? 'table' : 'view', columns: this.select.map(column => column.id), filter: this.clauses ? this.clauses.map(clause => { if (clause.type === 'or' || clause.type === 'and') { @@ -479,7 +484,7 @@ export default { type: clause.type } } - const filtered_column = this.table.columns.filter(column => column.internal_name === clause.params[0]) + const filtered_column = this.datasource.columns.filter(column => column.internal_name === clause.params[0]) const filtered_operator = this.database.container.image.operators.filter(operator => operator.value === clause.params[1]) if (!filtered_column || filtered_column.length === 0 || !filtered_operator || filtered_operator.length === 0) { return null @@ -514,16 +519,21 @@ export default { } }, watch: { - table () { + datasource () { this.select = [] - if (!this.table) { + if (!this.datasource) { + return + } + if (!this.isView) { + this.fetchViewColumns(this.datasource?.id) return } - this.fetchTableColumns(this.table?.id) + this.fetchTableColumns(this.datasource?.id) } }, mounted () { this.selectTable() + this.selectView() this.initViewVisibility() }, methods: { @@ -544,6 +554,23 @@ export default { toast.error(this.$t(code)) }) }, + fetchViewColumns (viewId) { + this.loadingColumns = true + const viewService = useViewService() + viewService.findOne(this.$route.params.database_id, viewId) + .then((view) => { + this.columns = view.columns + this.loadingColumns = false + }) + .catch(({code}) => { + this.loadingColumns = false + const toast = useToastInstance() + if (typeof code !== 'string') { + return + } + toast.error(this.$t(code)) + }) + }, initViewVisibility () { if (!this.database) { return @@ -564,13 +591,24 @@ export default { } const tid = this.$route.query.tid const selection = this.tables.filter(t => t.id === tid) - if (selection.length > 0) { - this.table = selection[0] - console.info('Preselect table with id', tid) - console.debug('preselected table', this.table) - } else { + if (selection.length === 0) { console.warn('Failed to find table with id', tid) + return + } + this.datasource = selection[0] + console.info('Preselect table with id', tid) + }, + selectView () { + if (this.$route.query.vid === undefined) { + return + } + const vid = this.$route.query.vid + const selection = this.views.filter(v => v.id === vid) + if (selection.length === 0) { + console.warn('Failed to find view with id', vid) } + this.datasource = selection[0] + console.info('Preselect view with id', vid) }, execute () { if (this.isView) { diff --git a/dbrepo-ui/composables/axios-instance.ts b/dbrepo-ui/composables/axios-instance.ts index cd3737f2bfad4bbd40d15f6cb5cf334a73d0c334..31746818e93d3dbd4c62b4950edf2f2f9e7fed4e 100644 --- a/dbrepo-ui/composables/axios-instance.ts +++ b/dbrepo-ui/composables/axios-instance.ts @@ -2,6 +2,24 @@ import axios, {type AxiosInstance} from 'axios' let instance: AxiosInstance | null = null; +function tokenToExpiryDate(token: string): number { + if (!token) { + return -1 + } + const exp: number = jwtDecode<Token>(token).exp + if (exp) { + return exp * 1000 + } + return -1 +} + +function isExpiredToken(token: string): boolean { + if (!token) { + return false + } + return tokenToExpiryDate(token) < Date.now() +} + export const useAxiosInstance = () => { const config = useRuntimeConfig() if (!instance) { @@ -15,11 +33,14 @@ export const useAxiosInstance = () => { }, baseURL: config.public.api.client }); - instance.interceptors.request.use((config) => { - const { loggedIn, user } = useOidcAuth() + instance.interceptors.request.use(async (config) => { + const { loggedIn, user, canRefresh, refresh } = useOidcAuth() if (!loggedIn) { return config } + if (canRefresh) { + await refresh() + } const { accessToken } = user.value if (!accessToken) { return config diff --git a/dbrepo-ui/composables/database-service.ts b/dbrepo-ui/composables/database-service.ts index 0609373923d3fd75d06cfb341cc350d99ad50b3f..204f99dd351d1b80df3033e8fda0fd4b21eb235e 100644 --- a/dbrepo-ui/composables/database-service.ts +++ b/dbrepo-ui/composables/database-service.ts @@ -66,7 +66,7 @@ export const useDatabaseService = (): any => { }); } - async function findOne(id: string, rawError: boolean = false): Promise<DatabaseDto | null> { + async function findOne(id: string, rawError: boolean = false): Promise<DatabaseDto> { const axios = useAxiosInstance(); console.debug('find database with id', id); return new Promise((resolve, reject) => { @@ -101,7 +101,7 @@ export const useDatabaseService = (): any => { }); } - async function updateVisibility(id: string, payload: DatabaseModifyVisibilityDto): Promise<DatabaseDto | null> { + async function updateVisibility(id: string, payload: DatabaseModifyVisibilityDto): Promise<DatabaseDto> { const axios = useAxiosInstance() console.debug('update database visibility for database with id', id); return new Promise((resolve, reject) => { @@ -117,7 +117,7 @@ export const useDatabaseService = (): any => { }); } - async function updateImage(id: string, payload: DatabaseModifyImageDto): Promise<DatabaseDto | null> { + async function updateImage(id: string, payload: DatabaseModifyImageDto): Promise<DatabaseDto> { const axios = useAxiosInstance() console.debug('update database image for database with id', id); return new Promise((resolve, reject) => { @@ -133,7 +133,7 @@ export const useDatabaseService = (): any => { }); } - async function updateOwner(id: string, payload: DatabaseTransferDto): Promise<DatabaseDto | null> { + async function updateOwner(id: string, payload: DatabaseTransferDto): Promise<DatabaseDto> { const axios = useAxiosInstance() console.debug('update database owner for database with id', id); return new Promise((resolve, reject) => { diff --git a/dbrepo-ui/dto/index.ts b/dbrepo-ui/dto/index.ts index 43c3ca2d19d53997864ffeddb53afe5b2ecb2529..e05e0fc4d48e3b224131dec7d12bf25023c3faf0 100644 --- a/dbrepo-ui/dto/index.ts +++ b/dbrepo-ui/dto/index.ts @@ -5,6 +5,7 @@ interface DatabaseDto { owner: UserDto; contact: UserDto; created: Date; + dashboard_uid: string; exchange_name: string; internal_name: string; is_public: boolean; @@ -613,7 +614,8 @@ interface OrderDto { } interface SubsetDto { - table_id: string; + datasource_id: string; + datasource_type: string; columns: string[]; filter: FilterDto[] | null; order: OrderDto[] | null; diff --git a/dbrepo-ui/locales/en-US.json b/dbrepo-ui/locales/en-US.json index 55a9692c2d4650d2fb3970322aafe026e2da8d10..242f48a5db0c9062dbc614b972ac96829db41b03 100644 --- a/dbrepo-ui/locales/en-US.json +++ b/dbrepo-ui/locales/en-US.json @@ -38,7 +38,9 @@ "help": "Help", "visibility": "Visibility", "update": "Update", - "you": "You" + "you": "You", + "enabled": "Enabled", + "disabled": "Disabled" }, "pages": { "identifier": { @@ -330,7 +332,7 @@ "title": "Owner" }, "creation": { - "title": "Creation" + "title": "Created" }, "import": { "title": "Import dataset into" @@ -595,6 +597,18 @@ "title": "Preview Image", "alt": "Database preview image representing the dataset" }, + "dashboard": { + "title": "Dashboard", + "text": "View", + "visibility": { + "label": "Managed Dashboard", + "hint": "Required, enables/disables the managed dashboard", + "warn": "Note that disabling the dashboard management also disables automatic visibility permission management of the dashboard!" + } + }, + "creation": { + "title": "Created" + }, "name": { "title": "Name" }, @@ -919,7 +933,7 @@ "title": "Owner" }, "creation": { - "title": "Creation" + "title": "Created" }, "visibility": { "title": "Visibility" @@ -940,7 +954,7 @@ "hint": "Required" }, "table": { - "label": "Data Table", + "label": "Datasource", "hint": "Required" }, "columns": { @@ -1136,10 +1150,14 @@ "missing": "Failed to find access in metadata database" }, "axios": { - "connection": "Failed to contact backend", + "connection": "Failed to establish connection to backend", "malformed": "Malformed request", "timeout": "Connection timed out" }, + "dashboard": { + "connection": "Failed to establish connection with dashboard service", + "invalid": "Failed to perform action at dashboard service" + }, "concept": { "missing": "Failed to find concept in metadata database" }, diff --git a/dbrepo-ui/nuxt.config.ts b/dbrepo-ui/nuxt.config.ts index b3694d5b8bfdad9cc618cd5d0ff53e912c3ea3ec..f63592bf75f0e4c72d1e3961b240181c2c0da2d3 100644 --- a/dbrepo-ui/nuxt.config.ts +++ b/dbrepo-ui/nuxt.config.ts @@ -81,6 +81,9 @@ export default defineNuxtConfig({ contrast: 'flat', } }, + dashboard: { + url: 'http://localhost:3000' + }, api: { client: 'http://localhost', server: 'http://gateway-service', diff --git a/dbrepo-ui/pages/database/[database_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/info.vue index 9f2d42655304118c5b585d8618f157fbc86d9627..89583c5f4f450d6462a6f4aaa5343fee3d184b82 100644 --- a/dbrepo-ui/pages/database/[database_id]/info.vue +++ b/dbrepo-ui/pages/database/[database_id]/info.vue @@ -45,6 +45,16 @@ :max-width="maxWidth" :max-height="maxHeight" /> </v-list-item> + <v-list-item + v-if="canViewDashboard" + :title="$t('pages.database.dashboard.title')" + density="compact"> + <NuxtLink + target="_blank" + :href="`${config.public.dashboard.url}/d/${database.dashboard_uid}`"> + {{ $t('pages.database.dashboard.text') }} + </NuxtLink> + </v-list-item> <v-list-item :title="$t('pages.database.name.title')" density="compact"> @@ -108,6 +118,11 @@ :other-user="cacheUser" /> </div> </v-list-item> + <v-list-item + v-if="database.created" + :title="$t('pages.database.creation.title')"> + {{ formatUTC(database.created) }} + </v-list-item> </v-list> </v-card-text> </v-card> @@ -187,7 +202,7 @@ 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 { formatTimestampUTCLabel, sizeToHumanLabel } from '@/utils' import { useCacheStore } from '@/stores/cache.js' export default { @@ -222,6 +237,10 @@ export default { tab () { return 0 }, + buttonVariant () { + const runtimeConfig = useRuntimeConfig() + return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.button.contrast : runtimeConfig.public.variant.button.normal + }, description () { if (!this.identifier) { return '' @@ -341,6 +360,20 @@ export default { const userService = useUserService() return userService.hasReadAccess(this.access) }, + canViewDashboard () { + if (!this.database || !this.database.views) { + return false + } + if (!this.database.is_public && !this.database.is_schema_public) { + return false + } + return this.database.dashboard_uid + } + }, + methods: { + formatUTC (timestamp) { + return formatTimestampUTCLabel(timestamp) + } } } </script> diff --git a/dbrepo-ui/pages/database/[database_id]/settings.vue b/dbrepo-ui/pages/database/[database_id]/settings.vue index f20ce2be68298a33f5c3312f93c2f5397e076017..cefd76e6396bb95d46cb882ffe033246582d02dd 100644 --- a/dbrepo-ui/pages/database/[database_id]/settings.vue +++ b/dbrepo-ui/pages/database/[database_id]/settings.vue @@ -165,6 +165,34 @@ :hint="$t('pages.database.resource.schema.hint', { resource: 'database', schema: 'tables, views, subsets' })" /> </v-col> </v-row> + <v-row + v-if="isDashboardDisabled"> + <v-col + lg="8"> + <v-alert + border="start" + color="warning"> + {{ $t('pages.database.dashboard.visibility.warn') }} + </v-alert> + </v-col> + </v-row> + <v-row + dense> + <v-col + lg="4"> + <v-select + v-model="modifyVisibility.is_dashboard_enabled" + :items="dashboardOptions" + persistent-hint + :variant="inputVariant" + required + :rules="[ + v => v !== null || $t('validation.required') + ]" + :label="$t('pages.database.dashboard.visibility.label')" + :hint="$t('pages.database.dashboard.visibility.hint')" /> + </v-col> + </v-row> <v-row> <v-col> <v-btn @@ -275,7 +303,8 @@ export default { editVisibilityDialog: false, modifyVisibility: { is_public: null, - is_schema_public: null + is_schema_public: null, + is_dashboard_enabled: null, }, modifyOwner: { id: null @@ -291,6 +320,10 @@ export default { { title: this.$t('pages.database.resource.schema.enabled'), value: true }, { title: this.$t('pages.database.resource.schema.disabled'), value: false }, ], + dashboardOptions: [ + { title: this.$t('navigation.enabled'), value: true }, + { title: this.$t('navigation.disabled'), value: false }, + ], headers: [ { title: this.$t('pages.user.qualified-name.label'), @@ -356,7 +389,7 @@ export default { if (!this.modifyVisibility || !this.database) { return false } - return this.modifyVisibility.is_public === this.database.is_public && this.modifyVisibility.is_schema_public === this.database.is_schema_public + return this.modifyVisibility.is_public === this.database.is_public && this.modifyVisibility.is_schema_public === this.database.is_schema_public && this.modifyVisibility.is_dashboard_enabled === this.database.is_dashboard_enabled }, canModifyVisibility () { if (!this.roles) { @@ -416,6 +449,12 @@ export default { maxHeight () { return this.$config.public.database.image.height }, + isDashboardDisabled () { + if (!this.database) { + return false + } + return this.database.is_dashboard_enabled && !this.modifyVisibility.is_dashboard_enabled + }, uploadErrorMessages () { if (!this.file || this.file.size < 1_000_000) { return [] @@ -449,6 +488,7 @@ export default { } this.modifyVisibility.is_public = this.database.is_public this.modifyVisibility.is_schema_public = this.database.is_schema_public + this.modifyVisibility.is_dashboard_enabled = this.database.is_dashboard_enabled this.modifyOwner.id = this.database.owner.id }, methods: { @@ -463,7 +503,7 @@ export default { this.loading = true const databaseService = useDatabaseService() databaseService.updateVisibility(this.$route.params.database_id, this.modifyVisibility) - .then((database) => { + .then(() => { const toast = useToastInstance() toast.success(this.$t('success.database.visibility')) this.cacheStore.reloadDatabase() diff --git a/dbrepo-ui/pages/database/[database_id]/subset/index.vue b/dbrepo-ui/pages/database/[database_id]/subset/index.vue index d7127d90af180e7f70f497bbdeae395de5fe776a..dee6e18c6414567de060542791bd797ad8d8d6ea 100644 --- a/dbrepo-ui/pages/database/[database_id]/subset/index.vue +++ b/dbrepo-ui/pages/database/[database_id]/subset/index.vue @@ -46,7 +46,7 @@ export default { if (!this.database) { return false } - if (this.database.is_public || this.database.is_schema_public) { + if (this.database.is_public) { return true } if (!this.access) { 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 18662f55ddf87daafb6d055a17d67f93fb2be737..808e725bc20c20b1ed4475660f20c3dcf652f0a3 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 @@ -66,6 +66,11 @@ :user="table.owner" :other-user="cacheUser" /> </v-list-item> + <v-list-item + v-if="table.created" + :title="$t('pages.table.creation.title')"> + {{ formatUTC(table.created) }} + </v-list-item> </v-list> </v-card-text> </v-card> @@ -142,6 +147,7 @@ import Select from '@/components/identifier/Select.vue' import Summary from '@/components/identifier/Summary.vue' import UserBadge from '@/components/user/UserBadge.vue' import { useCacheStore } from '@/stores/cache.js' +import { formatTimestampUTCLabel } from '@/utils' export default { components: { @@ -276,6 +282,11 @@ export default { return this.$t('pages.table.connection.permissions.read') } } + }, + methods: { + formatUTC (timestamp) { + return formatTimestampUTCLabel(timestamp) + } } } </script> 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 b5266b79f20ac518984a716e1c130580f7dd1f56..aece8572cf6bff744a9c50d6b9469d61fb1e6e6a 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 @@ -166,7 +166,7 @@ export default { if (!this.view) { return false } - if (this.view.is_public) { + if (this.database.is_public || this.database.is_schema_public) { return true } if (!this.access) { 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 41285c4d3be02f005736e61c44c534dce0a041e0..6bd0864445b047e70e707a06c350b3788c04e852 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 @@ -286,6 +286,7 @@ export default { const toast = useToastInstance() toast.success(this.$t('success.view.modified')) this.cacheStore.reloadView() + this.cacheStore.reloadDatabase() }) .catch(({code, message}) => { this.loading = false diff --git a/docker-compose.yml b/docker-compose.yml index e3c665faeb6ebc37990a97c68706fdeb78117262..8151d2c55c031162feed8868e5232667e48d2bd5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,7 +6,7 @@ volumes: search-db-data: identity-service-data: metric-db-data: - dashboard-service-data: + dashboard-ui-data: services: dbrepo-metadata-db: @@ -39,12 +39,13 @@ services: image: docker.io/bitnami/mariadb-galera:11.3.2-debian-12-r9 volumes: - data-db-data:/bitnami/mariadb - - "${SHARED_VOLUME:-/tmp}:/tmp" ports: - "3307:3306" environment: - MARIADB_ROOT_PASSWORD: "${DATA_DB_PASSWORD:-dbrepo}" MARIADB_GALERA_MARIABACKUP_PASSWORD: "${DATA_DB_BACKUP_PASSWORD:-dbrepobackup}" + MARIADB_PASSWORD: "${READONLY_PASSWORD:-user}" + MARIADB_ROOT_PASSWORD: "${DATA_DB_PASSWORD:-dbrepo}" + MARIADB_USER: "${READONLY_USERNAME:-user}" healthcheck: test: mysqladmin ping --user=root --password="${DATA_DB_PASSWORD:-dbrepo}" --silent interval: 10s @@ -129,10 +130,13 @@ services: METADATA_DB: "${METADATA_DB:-dbrepo}" METADATA_DB_PASSWORD: "${METADATA_DB_PASSWORD:-dbrepo}" METADATA_USERNAME: "root" + READONLY_USERNAME: "${READONLY_USERNAME:-user}" SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}" depends_on: dbrepo-auth-service: condition: service_healthy + dbrepo-gateway-service: + condition: service_healthy dbrepo-metadata-db: condition: service_healthy logging: @@ -148,8 +152,6 @@ services: network: host ports: - "9099:8080" - volumes: - - "${SHARED_VOLUME:-/tmp}:/tmp" environment: ADMIN_EMAIL: "${ADMIN_EMAIL:-noreply@localhost}" ANALYSE_SERVICE_ENDPOINT: "${ANALYSE_SERVICE_ENDPOINT:-http://analyse-service:8080}" @@ -162,12 +164,13 @@ services: BROKER_EXCHANGE_NAME: ${BROKER_EXCHANGE_NAME:-dbrepo} BROKER_QUEUE_NAME: ${BROKER_QUEUE_NAME:-dbrepo} BROKER_HOST: "${BROKER_ENDPOINT:-broker-service}" - BROKER_PASSWORD: ${BROKER_PASSWORD:-admin} + BROKER_PASSWORD: ${SYSTEM_PASSWORD:-admin} BROKER_PORT: ${BROKER_PORT:-5672} BROKER_SERVICE_ENDPOINT: ${BROKER_SERVICE_ENDPOINT:-http://broker-service:15672} - BROKER_USERNAME: ${BROKER_USERNAME:-admin} + BROKER_USERNAME: ${SYSTEM_USERNAME:-admin} BROKER_VIRTUALHOST: "${BROKER_VIRTUALHOST:-dbrepo}" CROSSREF_ENDPOINT: "${CROSSREF_ENDPOINT:-http://data.crossref.org}" + DASHBOARD_SERVICE_ENDPOINT: "${DASHBOARD_SERVICE_ENDPOINT:-http://dashboard-service:8080}" DATA_SERVICE_ENDPOINT: ${DATA_SERVICE_ENDPOINT:-http://data-service:8080} DELETED_RECORD: "${DELETED_RECORD:-persistent}" GRANULARITY: "${GRANULARITY:-YYYY-MM-DDThh:mm:ssZ}" @@ -201,6 +204,10 @@ services: condition: service_healthy dbrepo-data-service: condition: service_healthy + dbrepo-dashboard-service: + condition: service_healthy + dbrepo-search-service: + condition: service_healthy dbrepo-metadata-db: condition: service_healthy logging: @@ -215,7 +222,7 @@ services: context: ./dbrepo-analyse-service network: host ports: - - "5000:8080" + - "4050:8080" environment: AUTH_SERVICE_CLIENT: ${AUTH_SERVICE_CLIENT:-dbrepo-client} AUTH_SERVICE_CLIENT_SECRET: ${AUTH_SERVICE_CLIENT:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG} @@ -229,8 +236,6 @@ services: METADATA_SERVICE_ENDPOINT: ${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080} SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}" SYSTEM_PASSWORD: "${SYSTEM_PASSWORD:-admin}" - volumes: - - "${SHARED_FILESYSTEM:-/tmp}:/tmp" healthcheck: test: curl -sSL localhost:8080/health | grep 'UP' || exit 1 interval: 10s @@ -271,26 +276,16 @@ services: restart: "no" container_name: dbrepo-search-db hostname: search-db - image: dbrepo-search-db:latest - build: - context: ./dbrepo-search-db - network: host + image: docker.io/bitnami/opensearch:2.10.0 + ports: + - "9200:9200" healthcheck: - test: curl -sSL localhost:9200/_plugins/_security/health | jq .status | grep UP + test: curl -sSL 127.0.0.1:9200 interval: 10s timeout: 5s retries: 12 - environment: - ES_JAVA_OPTS: "-Xms4g -Xmx4g" - logger.level: "WARN" - deploy: - resources: - limits: - memory: 4G - ports: - - "9200:9200" volumes: - - search-db-data:/usr/share/elasticsearch/data + - search-db-data:/bitnami/opensearch/data logging: driver: json-file @@ -303,7 +298,7 @@ services: context: ./dbrepo-search-service network: host ports: - - "4000:8080" + - "4060:8080" environment: AUTH_SERVICE_CLIENT: ${AUTH_SERVICE_CLIENT:-dbrepo-client} AUTH_SERVICE_CLIENT_SECRET: ${AUTH_SERVICE_CLIENT_SECRET:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG} @@ -313,8 +308,6 @@ services: METADATA_SERVICE_ENDPOINT: ${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080} OPENSEARCH_HOST: ${OPENSEARCH_HOST:-search-db} OPENSEARCH_PORT: ${OPENSEARCH_PORT:-9200} - OPENSEARCH_USERNAME: ${SEARCH_DB_USERNAME:-admin} - OPENSEARCH_PASSWORD: ${SEARCH_DB_PASSWORD:-admin} SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}" SYSTEM_PASSWORD: "${SYSTEM_PASSWORD:-admin}" healthcheck: @@ -322,6 +315,8 @@ services: interval: 10s timeout: 5s retries: 12 + logging: + driver: json-file dbrepo-ui: restart: "no" @@ -336,7 +331,7 @@ services: network: host 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_OIDC_PROVIDERS_KEYCLOAK_BASE_URL: "${BASE_URL:-http://localhost}/realms/dbrepo" 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}" @@ -350,7 +345,7 @@ services: dbrepo-search-service: condition: service_healthy healthcheck: - test: curl -fsSL http://127.0.0.1:3000 && curl -fsSL http://127.0.0.1:3000/health + test: curl -fsSL 127.0.0.1:3000 && curl -fsSL 127.0.0.1:3000/health interval: 10s timeout: 5s retries: 12 @@ -368,6 +363,11 @@ services: - "80:8080" volumes: - ./dbrepo-gateway-service/dbrepo.conf:/etc/nginx/conf.d/default.conf + healthcheck: + test: lsof -i TCP:80 || exit 1 + interval: 10s + timeout: 5s + retries: 12 depends_on: dbrepo-analyse-service: condition: service_healthy @@ -395,8 +395,8 @@ services: environment: LDAP_ADMIN_USERNAME: "${IDENTITY_SERVICE_ADMIN_USERNAME:-admin}" LDAP_ADMIN_PASSWORD: "${IDENTITY_SERVICE_ADMIN_PASSWORD:-admin}" - LDAP_USERS: "${SYSTEM_USERNAME:-admin}" - LDAP_PASSWORDS: "${SYSTEM_PASSWORD:-admin}" + LDAP_USERS: "${SYSTEM_USERNAME:-admin},${READONLY_USERNAME:-user}" + LDAP_PASSWORDS: "${SYSTEM_PASSWORD:-admin},${READONLY_PASSWORD:-user}" LDAP_GROUP: "${ADMIN_GROUP:-system}" LDAP_ROOT: "${IDENTITY_SERVICE_ROOT:-dc=dbrepo,dc=at}" LDAP_ADMIN_DN: "${IDENTITY_SERVICE_ADMIN_DN:-cn=admin,dc=dbrepo,dc=at}" @@ -422,8 +422,6 @@ services: METADATA_SERVICE_ENDPOINT: ${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080} OPENSEARCH_HOST: ${OPENSEARCH_HOST:-search-db} OPENSEARCH_PORT: ${OPENSEARCH_PORT:-9200} - OPENSEARCH_USERNAME: ${SEARCH_DB_USERNAME:-admin} - OPENSEARCH_PASSWORD: ${SEARCH_DB_PASSWORD:-admin} SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}" SYSTEM_PASSWORD: "${SYSTEM_PASSWORD:-admin}" depends_on: @@ -434,6 +432,29 @@ services: logging: driver: json-file + dbrepo-dashboard-service-init: + restart: "no" + init: true + container_name: dbrepo-dashboard-service-init + hostname: search-dashboard-init + image: dbrepo-dashboard-service-init:latest + build: + context: ./dbrepo-dashboard-service/init + network: host + environment: + LOG_LEVEL: ${LOG_LEVEL:-info} + DASHBOARD_UI_ENDPOINT: "${DASHBOARD_UI_ENDPOINT:-http://dashboard-ui:3000}" + METADATA_SERVICE_ENDPOINT: ${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080} + SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}" + SYSTEM_PASSWORD: "${SYSTEM_PASSWORD:-admin}" + depends_on: + dbrepo-dashboard-ui: + condition: service_healthy + dbrepo-metadata-service: + condition: service_healthy + logging: + driver: json-file + dbrepo-storage-service: restart: "no" container_name: dbrepo-storage-service @@ -461,8 +482,6 @@ services: volumes: - ./dbrepo-metric-db/prometheus.yml:/etc/prometheus/prometheus.yml - metric-db-data:/opt/bitnami/prometheus/data - ports: - - 9090:9090 healthcheck: test: promtool check healthy interval: 10s @@ -471,35 +490,6 @@ services: logging: driver: json-file - dbrepo-dashboard-service: - restart: "no" - container_name: dbrepo-dashboard-service - hostname: dashboard-service - image: dbrepo-dashboard-service:latest - build: - context: ./dbrepo-dashboard-service - network: host - ports: - - "3000:3000" - volumes: - - dashboard-service-data:/opt/bitnami/grafana/data - environment: - GF_SERVER_DOMAIN: "dashboard-service" - GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION: "true" - LDAP_ADMIN_USERNAME: "${IDENTITY_SERVICE_ADMIN_USERNAME:-admin}" - LDAP_ADMIN_PASSWORD: "${IDENTITY_SERVICE_ADMIN_PASSWORD:-admin}" - LDAP_ROOT: "${IDENTITY_SERVICE_ROOT:-dc=dbrepo,dc=at}" - healthcheck: - test: curl -fsSL --head http://127.0.0.1:3000 - interval: 10s - timeout: 5s - retries: 12 - depends_on: - dbrepo-metric-db: - condition: service_started - logging: - driver: json-file - dbrepo-storage-service-init: restart: "no" init: true @@ -530,8 +520,6 @@ services: network: host ports: - "9093:8080" - volumes: - - "${SHARED_VOLUME:-/tmp}:/tmp" environment: AUTH_SERVICE_ADMIN: "${AUTH_SERVICE_ADMIN:-admin}" AUTH_SERVICE_ADMIN_PASSWORD: "${AUTH_SERVICE_ADMIN_PASSWORD:-admin}" @@ -555,16 +543,12 @@ services: GRANT_DEFAULT_WRITE: "${GRANT_DEFAULT_WRITE:-SELECT, CREATE, CREATE VIEW, CREATE ROUTINE, CREATE TEMPORARY TABLES, LOCK TABLES, INDEX, TRIGGER, INSERT, UPDATE, DELETE}" JWT_PUBKEY: "${JWT_PUBKEY:-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB}" LOG_LEVEL: ${LOG_LEVEL:-info} - MIN_CONCURRENT_CONSUMERS: ${MIN_CONCURRENT_CONSUMERS:-1} - MAX_CONCURRENT_CONSUMERS: ${MAX_CONCURRENT_CONSUMERS:-5} QUEUE_NAME: ${QUEUE_NAME:-dbrepo} REQUEUE_REJECTED: ${REQUEUE_REJECTED:-false} ROUTING_KEY: "${ROUTING_KEY:-dbrepo.#}" S3_ACCESS_KEY_ID: "${S3_ACCESS_KEY_ID:-seaweedfsadmin}" S3_BUCKET: "${S3_BUCKET:-dbrepo}" S3_ENDPOINT: "${S3_ENDPOINT:-http://storage-service:9000}" - S3_FILE_PATH: "${S3_FILE_PATH:-/tmp}" - S3_IMPORT_BUCKET: "${S3_IMPORT_BUCKET:-dbrepo-upload}" S3_SECRET_ACCESS_KEY: "${S3_SECRET_ACCESS_KEY:-seaweedfsadmin}" SPARK_USER: "${COMPUTE_SERVICE_USERNAME:-spark}" SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}" @@ -579,3 +563,65 @@ services: condition: service_healthy logging: driver: json-file + + dbrepo-dashboard-ui: + restart: "no" + container_name: dbrepo-dashboard-ui + hostname: dashboard-ui + image: dbrepo-dashboard-ui:latest + build: + context: ./dbrepo-dashboard-ui + network: host + ports: + - "3000:3000" + volumes: + - dashboard-ui-data:/opt/bitnami/grafana/data + environment: + BASE_URL: "${BASE_URL:-http://localhost}" + GF_INSTALL_PLUGINS: "yesoreyeram-infinity-datasource" + GF_SERVER_DOMAIN: "dashboard-service" + GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION: "true" + LDAP_ADMIN_USERNAME: "${IDENTITY_SERVICE_ADMIN_USERNAME:-admin}" + LDAP_ADMIN_PASSWORD: "${IDENTITY_SERVICE_ADMIN_PASSWORD:-admin}" + LDAP_ROOT: "${IDENTITY_SERVICE_ROOT:-dc=dbrepo,dc=at}" + healthcheck: + test: curl -fsSL --head 127.0.0.1:3000 + interval: 10s + timeout: 5s + retries: 12 + depends_on: + dbrepo-metric-db: + condition: service_started + extra_hosts: + - "localhost:host-gateway" + logging: + driver: json-file + + dbrepo-dashboard-service: + restart: "no" + container_name: dbrepo-dashboard-service + hostname: dashboard-service + image: dbrepo-dashboard-service:latest + build: + context: ./dbrepo-dashboard-service + network: host + ports: + - "4070:8080" + environment: + AUTH_SERVICE_ADMIN: ${AUTH_SERVICE_ADMIN:-admin} + AUTH_SERVICE_ADMIN_PASSWORD: ${AUTH_SERVICE_ADMIN_PASSWORD:-admin} + AUTH_SERVICE_ENDPOINT: ${AUTH_SERVICE_ENDPOINT:-http://auth-service:8080} + BASE_URL: "${BASE_URL:-http://localhost}" + DASHBOARD_UI_ENDPOINT: "${DASHBOARD_UI_ENDPOINT:-http://dashboard-ui:3000}" + SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}" + SYSTEM_PASSWORD: "${SYSTEM_PASSWORD:-admin}" + healthcheck: + test: curl -fsSL --head 127.0.0.1:8080/health + interval: 10s + timeout: 5s + retries: 12 + depends_on: + dbrepo-metric-db: + condition: service_started + logging: + driver: json-file diff --git a/grafana/grafana.ini b/grafana/grafana.ini new file mode 100644 index 0000000000000000000000000000000000000000..df8b9eb1b46e93de904d0c69a448a441f646260f --- /dev/null +++ b/grafana/grafana.ini @@ -0,0 +1,5 @@ +[server] +domain = grafana +root_url = http://grafana/grafana +serve_from_sub_path = true + diff --git a/helm/dbrepo/Chart.lock b/helm/dbrepo/Chart.lock index 297b4b1a9287732c869533cd2f2fe261ae43f4a5..e26b869016fcfee00e7f08f1a1f18a306429a6fa 100644 --- a/helm/dbrepo/Chart.lock +++ b/helm/dbrepo/Chart.lock @@ -26,5 +26,5 @@ dependencies: - name: nginx repository: https://charts.bitnami.com/bitnami version: 18.3.1 -digest: sha256:aa148a5f656ad17971203ea710206117d6de6f27b6940f9d532a6c5762e5df25 -generated: "2025-02-04T22:01:27.370259572+01:00" +digest: sha256:acb36fe9078b39dd50381a03827c318897d401c1946aee453611b3b58c924a54 +generated: "2025-04-01T13:07:24.905667677+02:00" diff --git a/helm/dbrepo/Chart.yaml b/helm/dbrepo/Chart.yaml index 1c5fa27f8c25f8e6c5424251bb21922b4809872a..7b5f38ac5d634b44d8095bf5ceea783a5f6600c7 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.7.3" -appVersion: "1.7.3" +version: "1.8.0" +appVersion: "1.8.0" keywords: - dbrepo maintainers: @@ -48,10 +48,10 @@ dependencies: repository: file://../seaweedfs condition: storageservice.enabled - name: grafana - alias: dashboardservice + alias: dashboardui version: 11.4.2 repository: https://charts.bitnami.com/bitnami - condition: dashboardservice.enabled + condition: dashboardui.enabled - name: prometheus alias: metricdb version: 1.3.22 diff --git a/helm/dbrepo/README.md b/helm/dbrepo/README.md index ba2f3836682da6c381daff984d6d8a805469f701..2fd53053375841cfb6bd4934aa6630ed4ce279df 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.7.3" +helm install my-release "oci://registry.datalab.tuwien.ac.at/dbrepo/helm/dbrepo" --values ./values.yaml --version "1.8.0" ``` ## Prerequisites @@ -34,7 +34,7 @@ variable when you increase the available Pod memory for performance. 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.7.3" +helm install my-release "oci://oci://registry.datalab.tuwien.ac.at/dbrepo/helm" --values ./values.yaml --version "1.8.0" ``` The command deploys DBRepo on the Kubernetes cluster in the default configuration. The Parameters section lists the @@ -94,11 +94,9 @@ 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.extraStartupArgs` | Extra arguments for the Keycloak container. | `--hostname-strict false --proxy-headers xforwarded` | | `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` | -| `authservice.tls.existingSecret` | The secret containing the `tls.crt`, `tls.key` and `ca.crt`. | `auth-service-secret` | | `authservice.client.id` | The client id for the microservices. | `dbrepo-client` | | `authservice.client.secret` | The client secret for the microservices. | `MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG` | | `authservice.setupJob.resourcesPreset` | The container resource preset | `nano` | @@ -113,6 +111,8 @@ The command removes all the Kubernetes components associated with the chart and | `datadb.rootUser.user` | The root username. | `root` | | `datadb.rootUser.password` | The root user password. | `dbrepo` | | `datadb.db.name` | The database name. | `dbrepo` | +| `datadb.db.user` | The database username for the dashboard service. | `user` | +| `datadb.db.password` | The database user password for the dashboard service. | `user` | | `datadb.galera.mariabackup.user` | The database backup username. | `backup` | | `datadb.galera.mariabackup.password` | The database backup user password | `backup` | | `datadb.jdbcExtraArgs` | The extra arguments for JDBC connections in the microservices. | `""` | @@ -137,32 +137,6 @@ The command removes all the Kubernetes components associated with the chart and | `searchdb.data.replicaCount` | The number of pod replicas. | `1` | | `searchdb.clusterName` | The cluster name. | `search-db` | -### Upload Service - -| Name | Description | Value | -| ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | -------------------------------- | -| `uploadservice.enabled` | Enable the Upload Service. | `true` | -| `uploadservice.s3.endpoint` | The S3-capable endpoint the microservice connects to. | `http://storage-service-s3:8333` | -| `uploadservice.s3.bucket` | The S3 bucket name. | `dbrepo` | -| `uploadservice.s3.maxSize` | The maximum file size in bytes. | `2000000000` | -| `uploadservice.podSecurityContext.enabled` | Enable pods' Security Context | `true` | -| `uploadservice.podSecurityContext.fsGroupChangePolicy` | Set filesystem group change policy | `Always` | -| `uploadservice.podSecurityContext.sysctls` | Set kernel settings using the sysctl interface | `[]` | -| `uploadservice.podSecurityContext.supplementalGroups` | Set filesystem extra groups | `[]` | -| `uploadservice.podSecurityContext.fsGroup` | Set RabbitMQ pod's Security Context fsGroup | `0` | -| `uploadservice.containerSecurityContext.enabled` | Enable containers' Security Context | `true` | -| `uploadservice.containerSecurityContext.seLinuxOptions` | Set SELinux options in container | `{}` | -| `uploadservice.containerSecurityContext.runAsUser` | Set RabbitMQ containers' Security Context runAsUser | `1000` | -| `uploadservice.containerSecurityContext.runAsGroup` | Set RabbitMQ containers' Security Context runAsGroup | `1000` | -| `uploadservice.containerSecurityContext.runAsNonRoot` | Set RabbitMQ container's Security Context runAsNonRoot | `true` | -| `uploadservice.containerSecurityContext.allowPrivilegeEscalation` | Set container's privilege escalation | `false` | -| `uploadservice.containerSecurityContext.readOnlyRootFilesystem` | Set container's Security Context readOnlyRootFilesystem | `false` | -| `uploadservice.containerSecurityContext.capabilities.drop` | Set container's Security Context runAsNonRoot | `["ALL"]` | -| `uploadservice.containerSecurityContext.seccompProfile.type` | Set container's Security Context seccomp profile | `RuntimeDefault` | -| `uploadservice.resourcesPreset` | The container resource preset | `nano` | -| `uploadservice.resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | -| `uploadservice.replicaCount` | The number of replicas. | `2` | - ### Broker Service | Name | Description | Value | @@ -406,17 +380,46 @@ mqtt.prefetch = 10 ### Dashboard Service -| Name | Description | Value | -| --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ------ | -| `dashboardservice.enabled` | Enable the Dashboard Service. | `true` | -| `dashboardservice.metrics.enabled` | Enable the metrics sidecar. | `true` | -| `dashboardservice.dashboardsProvider.enabled` | Enable the default dashboard provisioning provider to routinely import dashboards from /opt/bitnami/grafana/dashboards | `true` | +| Name | Description | Value | +| -------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | -------------------------- | +| `dashboardservice.enabled` | Enable the Dashboard Service. | `true` | +| `dashboardservice.endpoint` | The endpoint for the microservices. | `http://dashboard-service` | +| `dashboardservice.podSecurityContext.enabled` | Enable pods' Security Context | `true` | +| `dashboardservice.podSecurityContext.fsGroupChangePolicy` | Set filesystem group change policy | `Always` | +| `dashboardservice.podSecurityContext.sysctls` | Set kernel settings using the sysctl interface | `[]` | +| `dashboardservice.podSecurityContext.supplementalGroups` | Set filesystem extra groups | `[]` | +| `dashboardservice.podSecurityContext.fsGroup` | Set RabbitMQ pod's Security Context fsGroup | `0` | +| `dashboardservice.containerSecurityContext.enabled` | Enable containers' Security Context | `true` | +| `dashboardservice.containerSecurityContext.seLinuxOptions` | Set SELinux options in container | `{}` | +| `dashboardservice.containerSecurityContext.runAsUser` | Set RabbitMQ containers' Security Context runAsUser | `1001` | +| `dashboardservice.containerSecurityContext.runAsGroup` | Set RabbitMQ containers' Security Context runAsGroup | `1001` | +| `dashboardservice.containerSecurityContext.runAsNonRoot` | Set RabbitMQ container's Security Context runAsNonRoot | `true` | +| `dashboardservice.containerSecurityContext.allowPrivilegeEscalation` | Set container's privilege escalation | `false` | +| `dashboardservice.containerSecurityContext.readOnlyRootFilesystem` | Set container's Security Context readOnlyRootFilesystem | `false` | +| `dashboardservice.containerSecurityContext.capabilities.drop` | Set container's Security Context runAsNonRoot | `["ALL"]` | +| `dashboardservice.containerSecurityContext.seccompProfile.type` | Set container's Security Context seccomp profile | `RuntimeDefault` | +| `dashboardservice.resourcesPreset` | The container resource preset | `micro` | +| `dashboardservice.resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | +| `dashboardservice.replicaCount` | The number of replicas. | `2` | +| `dashboardservice.init.resourcesPreset` | The container resource preset | `nano` | +| `dashboardservice.init.resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | +| `dashboardservice.replicaCount` | The number of replicas. | `2` | + +### Dashboard UI + +| Name | Description | Value | +| ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | --------------------- | +| `dashboardui.enabled` | Enable the Dashboard UI. | `true` | +| `dashboardui.metrics.enabled` | Enable the metrics sidecar. | `true` | +| `dashboardui.endpoint` | The endpoint for the microservices. | `http://dashboard-ui` | +| `dashboardui.dashboardsProvider.enabled` | Enable the default dashboard provisioning provider to routinely import dashboards from /opt/bitnami/grafana/dashboards | `true` | ### Metric Service -| Name | Description | Value | -| ------------------ | -------------------------- | ------ | -| `metricdb.enabled` | Enable the Metric Service. | `true` | +| Name | Description | Value | +| ------------------- | ------------------------------- | ------------------------- | +| `metricdb.enabled` | Enable the Metric Service. | `true` | +| `metricdb.endpoint` | The endpoint for microservices. | `http://metric-db-server` | ### Gateway Service diff --git a/helm/dbrepo/charts/seaweedfs-4.2.1.tgz b/helm/dbrepo/charts/seaweedfs-4.2.1.tgz index b26358e59779d3206d9c834f59b08e7f2f84149b..3b21c83737040745d9723e6662e83b1cdef9966e 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 7e7978cad83580c330a28ef03ce3fd84623ee01e..4ba9d70b174dca5b3481d8042f47c332afc4cf2b 100644 --- a/helm/dbrepo/files/01-setup-schema.sql +++ b/helm/dbrepo/files/01-setup-schema.sql @@ -52,6 +52,8 @@ CREATE TABLE IF NOT EXISTS `mdb_containers` privileged_username VARCHAR(255) NOT NULL, privileged_password VARCHAR(255) NOT NULL, quota INT, + readonly_username VARCHAR(255) NOT NULL, + readonly_password VARCHAR(255) NOT NULL, PRIMARY KEY (`id`), FOREIGN KEY (`image_id`) REFERENCES mdb_images (`id`) ) WITH SYSTEM VERSIONING; @@ -67,20 +69,22 @@ CREATE TABLE IF NOT EXISTS `mdb_licenses` CREATE TABLE IF NOT EXISTS `mdb_databases` ( - id VARCHAR(36) NOT NULL DEFAULT UUID(), - cid VARCHAR(36) NOT NULL, - name VARCHAR(255) NOT NULL, - internal_name VARCHAR(255) NOT NULL, - exchange_name VARCHAR(255) NOT NULL, - description TEXT, - engine VARCHAR(20), - is_public BOOLEAN NOT NULL DEFAULT TRUE, - is_schema_public BOOLEAN NOT NULL DEFAULT TRUE, - image LONGBLOB, - owned_by VARCHAR(36) NOT NULL, - contact_person VARCHAR(36) NOT NULL, - created TIMESTAMP NOT NULL DEFAULT NOW(), - last_modified TIMESTAMP, + id VARCHAR(36) NOT NULL DEFAULT UUID(), + cid VARCHAR(36) NOT NULL, + grafana_dashboard_uid character varying(255), + name VARCHAR(255) NOT NULL, + internal_name VARCHAR(255) NOT NULL, + exchange_name VARCHAR(255) NOT NULL, + description TEXT, + engine VARCHAR(20), + is_public BOOLEAN NOT NULL DEFAULT TRUE, + is_schema_public BOOLEAN NOT NULL DEFAULT TRUE, + is_dashboard_enabled BOOLEAN NOT NULL DEFAULT TRUE, + image LONGBLOB, + owned_by VARCHAR(36) NOT NULL, + contact_person VARCHAR(36) NOT NULL, + created TIMESTAMP NOT NULL DEFAULT NOW(), + last_modified TIMESTAMP, PRIMARY KEY (`id`), FOREIGN KEY (`cid`) REFERENCES mdb_containers (`id`), FOREIGN KEY (`owned_by`) REFERENCES mdb_users (`id`), @@ -291,7 +295,7 @@ CREATE TABLE IF NOT EXISTS `mdb_messages` type ENUM ('ERROR', 'WARNING', 'INFO') NOT NULL DEFAULT 'INFO', message TEXT NOT NULL, link TEXT NULL, - link_TEXT VARCHAR(255) NULL, + link_text VARCHAR(255) NULL, display_start TIMESTAMP NULL, display_end TIMESTAMP NULL, PRIMARY KEY (`id`) diff --git a/helm/dbrepo/files/create-event-listener.jar b/helm/dbrepo/files/create-event-listener.jar index 9fb1271c4361841c3d4061e536d23bc16b590d0e..42cd10a361a5b4a644dabc8044ccc4a52f5870b9 100644 Binary files a/helm/dbrepo/files/create-event-listener.jar and b/helm/dbrepo/files/create-event-listener.jar differ diff --git a/helm/dbrepo/templates/auth-secret.yaml b/helm/dbrepo/templates/auth-secret.yaml deleted file mode 100644 index 0d1b5625c5f289c749ad8d1f565212516d7359b6..0000000000000000000000000000000000000000 --- a/helm/dbrepo/templates/auth-secret.yaml +++ /dev/null @@ -1,94 +0,0 @@ -{{- if .Values.authservice.enabled }} -{{/*openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 3650 -nodes -subj "/C=XX/ST=StateName/L=CityName/O=CompanyName/OU=CompanySectionName/CN=CommonNameOrHostname"*/}} ---- -apiVersion: v1 -kind: Secret -metadata: - name: auth-service-secret - namespace: {{ include "common.names.namespace" . | quote }} -stringData: - tls.key: |- - -----BEGIN PRIVATE KEY----- - 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 - Px0kzVCk41nBfNgjXe3s2BLlEhh3Lrk= - -----END PRIVATE KEY----- - tls.crt: |- - -----BEGIN CERTIFICATE----- - MIIFDzCCAvegAwIBAgIUCRgz8OLg6bHay9kWHFgSp9SF3RAwDQYJKoZIhvcNAQEL - BQAwFzEVMBMGA1UEAwwMYXV0aC1zZXJ2aWNlMB4XDTI1MDMwNDE5NDUxOVoXDTM1 - MDMwMjE5NDUxOVowFzEVMBMGA1UEAwwMYXV0aC1zZXJ2aWNlMIICIjANBgkqhkiG - 9w0BAQEFAAOCAg8AMIICCgKCAgEA3YEkafjPSOG/2HNtUlwJ0aY6vOVNruM7wd7X - EUr2aclrbAbsB2NjhBlFQpTxGL0/EIUUTHXColwO/EORYlzxonXN5CYYLdjxOEeR - mqCxubxhkIppwEhN9X/eMvsw1obzcQpbosdPBTO2dlR6WEB1mRb3pbT9Y3+vIJkA - 4LvfYWf2a4vYoPG/favcSE1zMOoG5nXrGnZTS2gBE8IwSXuOPmP7kN1R0FAiD0MY - Dz8xIr3HkdW3lKZ33JlWJjvDuH9LuTr8jdQWyIXY7VVbdvbP1fEDw7BPDHJyJqEy - zddHAAquur6JZw065TPceRq4PPRpc26ULD5ATJbWPTUz9/jRUq6X7u1YxFWDvzuZ - OiRRXzJah1LcoGjYu3TnjmNyIsrS+678VixlEGAe23uuthEyvJ8ORfshomnurKWT - 3+55iNoi7PI2uUJ3lOpkKyn6jvykSQXocGT9u+9Z40TtwSMiT5taMoJ4oVhvo08v - cw2AoLiaz2dX9Yb1M35qQircqmsRpsTwPGA7uHci/ayYH96E+X2L95w6THjw2Id2 - dfGHqmCX+KZg7+d1rrOQqF1EX3NzUUU6jECiyjmL1Vk4jOKHWOPlZG4DlDqy8Tiu - ZZWUgemzudinHCqUJ0C7d9KJBkFw5bEdYWxSAwCNTVopRbK8uCaVXMY0yRkDFdlt - E3Bvn5ECAwEAAaNTMFEwHQYDVR0OBBYEFBWE851rO2U9WR+0md9lfAbkAtevMB8G - A1UdIwQYMBaAFBWE851rO2U9WR+0md9lfAbkAtevMA8GA1UdEwEB/wQFMAMBAf8w - DQYJKoZIhvcNAQELBQADggIBAI2dI9hT/xfnwtYAdBlyIJRW1IMn1vVo6Xm/UVrl - PPmbB2vQ13Z07vWi0Djwou+BwUhFSq6YRIe+bhQjg6On8O2581aNve97K1AwwB3O - YZztiyyJ5Moccrkb9Wy2MyfUiPqNY3O8Q0BRl793Tbv9G0gyNudO6FmmdWpfu/VT - ZAfiKRvNycC0BZp7A7tkvbtYWOQ7cGa9qpcVSBHvALj+3b+RKwDVf7K+YBkOXamT - Y2xE6KhHz0FJmFNTIkdwjA2M3CCh5M3QVHyXRDApNKiav5yU6TWBT7JQqZA6GV/+ - jrVNl5fZwT5AHQmwQB0k1q1azjFREMLQXzgkfuSK5AiW+70KRpILxOMzx616FoZH - 2D+7sZ5EXnBVZmAL5WLSraOjwia+jyOUrTIUY8t+4kabxdKhQMhwOATUe4dAxIZK - VGHVHKNJ9+ktZ+j56AUUUNRWNx85LoMjh46e4T3rYm4CG9cBQAHGEXSn1i4bt14q - j4+9BNow4f/66XcUOsvPmiQGqPNWFYVj0QIq84yakzzVWdMm6MEu4WtlVPGlZmRV - OUHuaqiSmdGcHRVGdmqkTTpRUGASw7HR/7nPn3YFwP3yfZFUa44hbtAdQQll1O5Z - IuuDir8s195hl0UJ+9HilYEuOVjB7bS0Wc3sZxOP2U/98CBa4UzMuVDMhJ/WKs5U - znPt - -----END CERTIFICATE----- -{{- end }} diff --git a/helm/dbrepo/templates/dashboard-configmap.yaml b/helm/dbrepo/templates/dashboard-configmap.yaml deleted file mode 100644 index 9643f539d2ae7b4aec491f1ba7b73b9202daa85f..0000000000000000000000000000000000000000 --- a/helm/dbrepo/templates/dashboard-configmap.yaml +++ /dev/null @@ -1,11 +0,0 @@ -{{- if .Values.dashboardservice.enabled }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: dashboard-service-config - namespace: {{ include "common.names.namespace" . | quote }} -data: - {{ (.Files.Glob "files/system.json").AsConfig | nindent 2 }} - {{ (.Files.Glob "files/rabbitmq.json").AsConfig | nindent 2 }} - {{ (.Files.Glob "files/mariadb.json").AsConfig | nindent 2 }} -{{- end }} \ No newline at end of file diff --git a/helm/dbrepo/templates/dashboard-deployment.yaml b/helm/dbrepo/templates/dashboard-deployment.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f2c1a6fff16b55ada432db13abca7fb40f5d45e8 --- /dev/null +++ b/helm/dbrepo/templates/dashboard-deployment.yaml @@ -0,0 +1,77 @@ +{{- if .Values.dashboardservice.enabled }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dashboard-service + namespace: {{ include "common.names.namespace" . | quote }} + labels: + app: dashboard-service + service: dashboard-service +spec: + replicas: {{ .Values.dashboardservice.replicaCount }} + strategy: + type: {{ .Values.strategyType }} + selector: + matchLabels: + app: dashboard-service + service: dashboard-service + template: + metadata: + labels: + app: dashboard-service + service: dashboard-service + spec: + {{- if .Values.dashboardservice.podSecurityContext.enabled }} + securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.dashboardservice.podSecurityContext "context" $) | nindent 8 }} + {{- end }} + initContainers: + - name: init + image: {{ .Values.dashboardservice.init.image.name }} + imagePullPolicy: {{ .Values.dashboardservice.init.image.pullPolicy | default "IfNotPresent" }} + {{- if .Values.dashboardservice.containerSecurityContext.enabled }} + securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.dashboardservice.containerSecurityContext "context" $) | nindent 12 }} + {{- end }} + envFrom: + - secretRef: + name: dashboard-service-secret + {{- if .Values.dashboardservice.init.resources }} + resources: {{- toYaml .Values.dashboardservice.init.resources | nindent 12 }} + {{- else if ne .Values.dashboardservice.init.resourcesPreset "none" }} + resources: {{- include "common.resources.preset" (dict "type" .Values.dashboardservice.init.resourcesPreset) | nindent 12 }} + {{- end }} + containers: + - name: dashboard-service + image: {{ .Values.dashboardservice.image.name }} + imagePullPolicy: {{ .Values.dashboardservice.image.pullPolicy | default "IfNotPresent" }} + {{- if .Values.dashboardservice.containerSecurityContext.enabled }} + securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.dashboardservice.containerSecurityContext "context" $) | nindent 12 }} + {{- end }} + ports: + - containerPort: 8080 + protocol: TCP + envFrom: + - secretRef: + name: dashboard-service-secret + livenessProbe: + exec: + command: + - /bin/bash + - -ec + - "curl -sSL localhost:8080/health | grep 'UP' || exit 1" + initialDelaySeconds: 150 + periodSeconds: 10 + readinessProbe: + exec: + command: + - /bin/bash + - -ec + - "curl -sSL localhost:8080/health | grep 'UP' || exit 1" + initialDelaySeconds: 30 + periodSeconds: 10 + {{- if .Values.dashboardservice.resources }} + resources: {{- toYaml .Values.dashboardservice.resources | nindent 12 }} + {{- else if ne .Values.dashboardservice.resourcesPreset "none" }} + resources: {{- include "common.resources.preset" (dict "type" .Values.dashboardservice.resourcesPreset) | nindent 12 }} + {{- end }} +{{- end }} diff --git a/helm/dbrepo/templates/dashboard-secret.yaml b/helm/dbrepo/templates/dashboard-secret.yaml index 7fdb1fed8d3d17f7a86dc5cabd3f83bff464f010..21ae5b1311667b43383a17c0246d22d432e00d93 100644 --- a/helm/dbrepo/templates/dashboard-secret.yaml +++ b/helm/dbrepo/templates/dashboard-secret.yaml @@ -6,53 +6,12 @@ metadata: name: dashboard-service-secret namespace: {{ include "common.names.namespace" . | quote }} stringData: - GF_SERVER_PROTOCOL: "http" - GF_SERVER_DOMAIN: "{{ .Values.hostname }}" - GF_SERVER_ROOT_URL: "https://%(domain)s/dashboard/" - GF_AUTH_ANONYMOUS_ENABLED: "true" - GF_AUTH_ANONYMOUS_ORG_ROLE: "Viewer" - GF_SERVER_SERVE_FROM_SUB_PATH: "true" - GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION: "true" - LDAP_ADMIN_USERNAME: "{{ .Values.identityservice.global.adminUser }}" - LDAP_ADMIN_PASSWORD: "{{ .Values.identityservice.global.adminPassword }}" - LDAP_ROOT: "{{ .Values.identityservice.global.ldapDomain }}" - ldap.toml: | - [[servers]] - host = "identity-service" - port = 389 - use_ssl = false - - # Search user bind dn - bind_dn = "cn=${LDAP_ADMIN_USERNAME},${LDAP_ROOT}" - bind_password = "${LDAP_ADMIN_PASSWORD}" - - # Timeout in seconds. Applies to each host specified in the 'host' entry (space separated). - timeout = 10 - - # User search filter, for example "(cn=%s)" or "(sAMAccountName=%s)" or "(uid=%s)" - # Allow login from email or username, example "(|(sAMAccountName=%s)(userPrincipalName=%s))" - search_filter = "(cn=%s)" - - # An array of base dns to search through - search_base_dns = ["${LDAP_ROOT}"] - - group_search_base_dns = ["ou=users,${LDAP_ROOT}"] - group_search_filter = "(&(objectClass=groupOfNames)(member=cn=%s,ou=users,${LDAP_ROOT}))" - group_search_filter_user_attribute = "uid" - - [servers.attributes] - name = "givenName" - surname = "sn" - username = "cn" - member_of = "member" - email = "email" - - [[servers.group_mappings]] - group_dn = "cn=${LDAP_ADMIN_USERNAME},ou=users,${LDAP_ROOT}" - org_role = "Admin" - grafana_admin = true - - [[servers.group_mappings]] - group_dn = "*" - org_role = "Viewer" + AUTH_SERVICE_ADMIN: "{{ .Values.authservice.auth.adminUser }}" + AUTH_SERVICE_ADMIN_PASSWORD: "{{ .Values.authservice.auth.adminPassword }}" + AUTH_SERVICE_ENDPOINT: "{{ .Values.authservice.endpoint }}" + BASE_URL: "{{ .Values.gateway }}" + DASHBOARD_UI_ENDPOINT: "{{ .Values.dashboardui.endpoint }}" + METADATA_SERVICE_ENDPOINT: "{{ .Values.metadataservice.endpoint }}" + SYSTEM_USERNAME: "{{ .Values.identityservice.users }}" + SYSTEM_PASSWORD: "{{ .Values.identityservice.userPasswords }}" {{- end }} diff --git a/helm/dbrepo/templates/dashboard-ui-prov-datasources-secret.yaml b/helm/dbrepo/templates/dashboard-ui-prov-datasources-secret.yaml new file mode 100644 index 0000000000000000000000000000000000000000..2d10baefd2145f026e88e940b2b077fa947dfab9 --- /dev/null +++ b/helm/dbrepo/templates/dashboard-ui-prov-datasources-secret.yaml @@ -0,0 +1,33 @@ +{{- if .Values.dashboardui.enabled }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: dashboard-ui-prov-datasources-secret + namespace: {{ include "common.names.namespace" . | quote }} +stringData: + infinity.yaml: |- + apiVersion: 1 + datasources: + - name: dbrepo-json + uid: dbrepojson0 + type: yesoreyeram-infinity-datasource + basicAuth: true + basicAuthUser: {{ .Values.datadb.db.user }} + url: {{ .Values.gateway }} + jsonData: + auth_method: 'basicAuth' + httpHeaderName1: Accept + allowedHosts: + - '{{ .Values.gateway }}' + secureJsonData: + basicAuthPassword: {{ .Values.datadb.db.password }} + httpHeaderValue1: application/json + prometheus.yaml: |- + apiVersion: 1 + datasources: + - name: dbrepo-metrics + type: prometheus + uid: dbrepometrics0 + url: {{ .Values.metricdb.endpoint }} +{{- end }} diff --git a/helm/dbrepo/templates/dashboard-ui-secret.yaml b/helm/dbrepo/templates/dashboard-ui-secret.yaml new file mode 100644 index 0000000000000000000000000000000000000000..0816c696377d28c3c3e9ab1358e5bce69e4e36b2 --- /dev/null +++ b/helm/dbrepo/templates/dashboard-ui-secret.yaml @@ -0,0 +1,58 @@ +{{- if .Values.dashboardui.enabled }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: dashboard-ui-secret + namespace: {{ include "common.names.namespace" . | quote }} +stringData: + GF_SERVER_PROTOCOL: "http" + GF_SERVER_DOMAIN: "{{ .Values.hostname }}" + GF_SERVER_ROOT_URL: "https://%(domain)s/dashboard/" + GF_AUTH_ANONYMOUS_ENABLED: "true" + GF_AUTH_ANONYMOUS_ORG_ROLE: "Viewer" + GF_SERVER_SERVE_FROM_SUB_PATH: "true" + GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION: "true" + LDAP_ADMIN_USERNAME: "{{ .Values.identityservice.global.adminUser }}" + LDAP_ADMIN_PASSWORD: "{{ .Values.identityservice.global.adminPassword }}" + LDAP_ROOT: "{{ .Values.identityservice.global.ldapDomain }}" + ldap.toml: | + [[servers]] + host = "identity-service" + port = 389 + use_ssl = false + + # Search user bind dn + bind_dn = "cn=${LDAP_ADMIN_USERNAME},${LDAP_ROOT}" + bind_password = "${LDAP_ADMIN_PASSWORD}" + + # Timeout in seconds. Applies to each host specified in the 'host' entry (space separated). + timeout = 10 + + # User search filter, for example "(cn=%s)" or "(sAMAccountName=%s)" or "(uid=%s)" + # Allow login from email or username, example "(|(sAMAccountName=%s)(userPrincipalName=%s))" + search_filter = "(uid=%s)" + + # An array of base dns to search through + search_base_dns = ["${LDAP_ROOT}"] + + group_search_base_dns = ["ou=users,${LDAP_ROOT}"] + group_search_filter = "(&(objectClass=groupOfNames)(member=cn=%s,ou=users,${LDAP_ROOT}))" + group_search_filter_user_attribute = "uid" + + [servers.attributes] + name = "cn" + surname = "sn" + username = "uid" + member_of = "member" + email = "mail" + + [[servers.group_mappings]] + group_dn = "cn=${LDAP_ADMIN_USERNAME},ou=users,${LDAP_ROOT}" + org_role = "Admin" + grafana_admin = true + + [[servers.group_mappings]] + group_dn = "*" + org_role = "Viewer" +{{- end }} diff --git a/helm/dbrepo/templates/gateway-configmap.yaml b/helm/dbrepo/templates/gateway-configmap.yaml index 6405e801f1d5e313eb38e7b907976b4fd76d1c9e..79078be7ea5b7457e28b0d17d34c18f847f49cb0 100644 --- a/helm/dbrepo/templates/gateway-configmap.yaml +++ b/helm/dbrepo/templates/gateway-configmap.yaml @@ -32,58 +32,79 @@ data: location /dashboard { rewrite ^/dashboard/(.*) /$1 break; - proxy_set_header Host $host; + proxy_set_header Host $http_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-For $proxy_protocol_addr; proxy_set_header X-Forwarded-Proto $scheme; - proxy_pass http://dashboard-service:3000; + proxy_pass http://dashboard-ui; proxy_read_timeout 90; } # Proxy Grafana Live WebSocket connections. - location /dashboard/api/live { - proxy_set_header Host $host; + location /dashboard/api/live/ { + rewrite ^/dashboard/(.*) /$1 break; + proxy_set_header Host $http_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-For $proxy_protocol_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_http_version 1.1; - proxy_pass http://dashboard-service:3000; + proxy_pass http://dashboard-ui; 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-For $proxy_protocol_addr; proxy_set_header X-Forwarded-Proto $scheme; - proxy_pass https://auth-service; + 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-For $proxy_protocol_addr; proxy_set_header X-Forwarded-Proto $scheme; - proxy_pass https://auth-service; + 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; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-For $proxy_protocol_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://search-service; proxy_read_timeout 90; } + location /api/datasource { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_protocol_addr; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_pass http://dashboard-service; + proxy_read_timeout 90; + } + + location /api/dashboard { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_protocol_addr; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_pass http://dashboard-service; + proxy_read_timeout 90; + } + location /api/upload { 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-For $proxy_protocol_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; proxy_pass http://data-service; @@ -97,25 +118,25 @@ data: location /api/analyse { 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-For $proxy_protocol_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://analyse-service; proxy_read_timeout 90; } - location ~ "/api/database/([0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/table/([0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/(data|history)" { + location ~ "/api/database/([0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/table/([0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/(data|statistic|history)" { 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-For $proxy_protocol_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://data-service; proxy_read_timeout 90; } - location ~ "/api/database/([0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/view/([0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/data" { + location ~ "/api/database/([0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/view/([0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/(data|statistic)" { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-For $proxy_protocol_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://data-service; proxy_read_timeout 90; @@ -124,7 +145,7 @@ data: location ~ "/api/database/([0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/view" { 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-For $proxy_protocol_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://metadata-service; proxy_read_timeout 90; @@ -133,7 +154,7 @@ data: location ~ "/api/database/([0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/subset" { 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-For $proxy_protocol_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://data-service; proxy_read_timeout 600; @@ -142,7 +163,7 @@ data: location ~ "/api/(database|concept|container|identifier|image|message|license|oai|ontology|unit|user)" { 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-For $proxy_protocol_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://metadata-service; proxy_read_timeout 90; @@ -151,7 +172,7 @@ data: location ~ "/api/identifier/([0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})" { 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-For $proxy_protocol_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://metadata-service; proxy_read_timeout 90; @@ -161,7 +182,7 @@ data: rewrite /pid/(.*) /api/identifier/$1 break; 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-For $proxy_protocol_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://metadata-service; proxy_read_timeout 90; @@ -170,7 +191,7 @@ data: location / { 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-For $proxy_protocol_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://ui; proxy_read_timeout 90; diff --git a/helm/dbrepo/templates/identity-secret.yaml b/helm/dbrepo/templates/identity-secret.yaml index e395bad11ec496d54e57839b3e783674c443d8d9..b2eeb25d3cda5751d60715fedb0ad8dc7fa4e3c2 100644 --- a/helm/dbrepo/templates/identity-secret.yaml +++ b/helm/dbrepo/templates/identity-secret.yaml @@ -6,11 +6,11 @@ metadata: name: identity-service-secret namespace: {{ include "common.names.namespace" . | quote }} stringData: - LDAP_ADMIN_USERNAME: "{{ .Values.identityservice.global.adminUser}}" - LDAP_ADMIN_PASSWORD: "{{ .Values.identityservice.global.adminPassword}}" - LDAP_USERS: "{{ .Values.identityservice.users}}" - LDAP_PASSWORDS: "{{ .Values.identityservice.userPasswords}}" - LDAP_GROUP: "{{ .Values.identityservice.group}}" + LDAP_ADMIN_USERNAME: "{{ .Values.identityservice.global.adminUser }}" + LDAP_ADMIN_PASSWORD: "{{ .Values.identityservice.global.adminPassword }}" + LDAP_USERS: "{{ .Values.identityservice.users }},{{ .Values.datadb.db.user }}" + LDAP_PASSWORDS: "{{ .Values.identityservice.userPasswords }},{{ .Values.datadb.db.password }}" + LDAP_GROUP: "{{ .Values.identityservice.group }}" LDAP_ROOT: "{{ .Values.identityservice.global.ldapDomain }}" - LDAP_ADMIN_DN: "cn={{ .Values.identityservice.global.adminUser}},{{ .Values.identityservice.global.ldapDomain }}" + LDAP_ADMIN_DN: "cn={{ .Values.identityservice.global.adminUser }},{{ .Values.identityservice.global.ldapDomain }}" {{- end }} diff --git a/helm/dbrepo/templates/metadata-configmap.yaml b/helm/dbrepo/templates/metadata-configmap.yaml index a6b7ad8212839ab1b14fec02b304335ff90e974a..e837c8072ada18d0bb9a364456834bfaecc3e697 100644 --- a/helm/dbrepo/templates/metadata-configmap.yaml +++ b/helm/dbrepo/templates/metadata-configmap.yaml @@ -13,9 +13,12 @@ data: 02-setup-data.sql: |- BEGIN; INSERT INTO `mdb_containers` (id, name, internal_name, image_id, host, port, ui_host, ui_port, privileged_username, - privileged_password) + privileged_password, readonly_username, readonly_password) VALUES ('6cfb3b8e-1792-4e46-871a-f3d103527203', 'mariadb:11.1.3-debian-11-r6', 'mariadb_11_1_3', - 'd79cb089-363c-488b-9717-649e44d8fcc5', 'data-db', {{ .Values.datadb.containerPorts.mysql }}, '{{ .Values.hostname }}', {{ .Values.datadb.containerPorts.mysql }}, '{{ .Values.datadb.rootUser.user }}', '{{ .Values.datadb.rootUser.password }}'); + 'd79cb089-363c-488b-9717-649e44d8fcc5', 'data-db', {{ .Values.datadb.containerPorts.mysql }}, + '{{ .Values.hostname }}', {{ .Values.datadb.containerPorts.mysql }}, '{{ .Values.datadb.rootUser.user }}', + '{{ .Values.datadb.rootUser.password }}', '{{ .Values.datadb.db.user }}', + '{{ .Values.datadb.db.password }}'); COMMIT; {{ (.Files.Glob "files/my.cnf").AsConfig | nindent 2 }} {{- end }} diff --git a/helm/dbrepo/templates/metadata-secret.yaml b/helm/dbrepo/templates/metadata-secret.yaml index 84b0b614e35bd0833b0ff81ab21f94f7b4c66dbb..7ab8533f4541361946d96dcab9b43bd444aff5fc 100644 --- a/helm/dbrepo/templates/metadata-secret.yaml +++ b/helm/dbrepo/templates/metadata-secret.yaml @@ -24,6 +24,7 @@ stringData: BROKER_USERNAME: "{{ .Values.brokerservice.auth.username }}" BROKER_VIRTUALHOST: "{{ .Values.brokerservice.virtualHost }}" CROSSREF_ENDPOINT: "{{ .Values.metadataservice.crossref.endpoint}}" + DASHBOARD_SERVICE_ENDPOINT: "{{ .Values.dashboardservice.endpoint }}" DATA_SERVICE_ENDPOINT: "{{ .Values.dataservice.endpoint }}" DATACITE_URL: "{{ .Values.metadataservice.datacite.url }}" DATACITE_PREFIX: "{{ .Values.metadataservice.datacite.prefix | toString }}" diff --git a/helm/dbrepo/values.schema.json b/helm/dbrepo/values.schema.json index f99941e2f829db6b86e837ce71e8c132af9e9bc2..dcb506dba44127137a146ce53222abed01054db1 100644 --- a/helm/dbrepo/values.schema.json +++ b/helm/dbrepo/values.schema.json @@ -129,6 +129,9 @@ "extraEnvVarsCM": { "type": "string" }, + "extraStartupArgs": { + "type": "string" + }, "extraVolumeMounts": { "items": { "properties": { @@ -227,9 +230,6 @@ }, "type": "object" }, - "production": { - "type": "boolean" - }, "replicaCount": { "type": "integer" }, @@ -255,20 +255,6 @@ } }, "type": "object" - }, - "tls": { - "properties": { - "enabled": { - "type": "boolean" - }, - "existingSecret": { - "type": "string" - }, - "usePem": { - "type": "boolean" - } - }, - "type": "object" } }, "type": "object" @@ -458,43 +444,133 @@ }, "dashboardservice": { "properties": { - "dashboardsProvider": { + "containerSecurityContext": { "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "properties": { + "drop": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, "enabled": { "type": "boolean" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "integer" + }, + "seLinuxOptions": { + "properties": {}, + "type": "object" + }, + "seccompProfile": { + "properties": { + "type": { + "type": "string" + } + }, + "type": "object" } }, "type": "object" }, - "datasources": { + "enabled": { + "type": "boolean" + }, + "endpoint": { + "type": "string" + }, + "image": { "properties": { - "secretDefinition": { + "name": { + "type": "string" + } + }, + "type": "object" + }, + "init": { + "properties": { + "image": { "properties": { - "apiVersion": { - "type": "integer" - }, - "datasources": { - "items": { - "properties": { - "name": { - "type": "string" - }, - "type": { - "type": "string" - }, - "uid": { - "type": "string" - }, - "url": { - "type": "string" - } - }, - "type": "object" - }, - "type": "array" + "name": { + "type": "string" } }, "type": "object" + }, + "resources": { + "properties": {}, + "type": "object" + }, + "resourcesPreset": { + "type": "string" + } + }, + "type": "object" + }, + "podSecurityContext": { + "properties": { + "enabled": { + "type": "boolean" + }, + "fsGroup": { + "type": "integer" + }, + "fsGroupChangePolicy": { + "type": "string" + }, + "supplementalGroups": { + "type": "array" + }, + "sysctls": { + "type": "array" + } + }, + "type": "object" + }, + "replicaCount": { + "type": "integer" + }, + "resources": { + "properties": {}, + "type": "object" + }, + "resourcesPreset": { + "type": "string" + } + }, + "type": "object" + }, + "dashboardui": { + "properties": { + "dashboardsProvider": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, + "datasources": { + "properties": { + "secretName": { + "type": "string" } }, "type": "object" @@ -502,28 +578,14 @@ "enabled": { "type": "boolean" }, + "endpoint": { + "type": "string" + }, "fullnameOverride": { "type": "string" }, "grafana": { "properties": { - "extraConfigmaps": { - "items": { - "properties": { - "mountPath": { - "type": "string" - }, - "name": { - "type": "string" - }, - "readOnly": { - "type": "boolean" - } - }, - "type": "object" - }, - "type": "array" - }, "extraEnvVarsSecret": { "type": "string" }, @@ -559,6 +621,19 @@ } }, "type": "object" + }, + "service": { + "properties": { + "ports": { + "properties": { + "grafana": { + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" } }, "type": "object" @@ -569,6 +644,12 @@ "properties": { "name": { "type": "string" + }, + "password": { + "type": "string" + }, + "user": { + "type": "string" } }, "type": "object" @@ -1302,6 +1383,9 @@ "enabled": { "type": "boolean" }, + "endpoint": { + "type": "string" + }, "fullnameOverride": { "type": "string" }, @@ -1880,173 +1964,6 @@ } }, "type": "object" - }, - "uploadservice": { - "properties": { - "containerArgs": { - "items": { - "type": "string" - }, - "type": "array" - }, - "containerSecurityContext": { - "properties": { - "allowPrivilegeEscalation": { - "type": "boolean" - }, - "capabilities": { - "properties": { - "drop": { - "items": { - "type": "string" - }, - "type": "array" - } - }, - "type": "object" - }, - "enabled": { - "type": "boolean" - }, - "readOnlyRootFilesystem": { - "type": "boolean" - }, - "runAsGroup": { - "type": "integer" - }, - "runAsNonRoot": { - "type": "boolean" - }, - "runAsUser": { - "type": "integer" - }, - "seLinuxOptions": { - "properties": {}, - "type": "object" - }, - "seccompProfile": { - "properties": { - "type": { - "type": "string" - } - }, - "type": "object" - } - }, - "type": "object" - }, - "enabled": { - "type": "boolean" - }, - "envFrom": { - "items": { - "properties": { - "secretRef": { - "properties": { - "name": { - "type": "string" - } - }, - "type": "object" - } - }, - "type": "object" - }, - "type": "array" - }, - "image": { - "properties": { - "name": { - "type": "string" - } - }, - "type": "object" - }, - "podSecurityContext": { - "properties": { - "enabled": { - "type": "boolean" - }, - "fsGroup": { - "type": "integer" - }, - "fsGroupChangePolicy": { - "type": "string" - }, - "supplementalGroups": { - "type": "array" - }, - "sysctls": { - "type": "array" - } - }, - "type": "object" - }, - "replicaCount": { - "type": "integer" - }, - "resources": { - "properties": {}, - "type": "object" - }, - "resourcesPreset": { - "type": "string" - }, - "s3": { - "properties": { - "bucket": { - "type": "string" - }, - "endpoint": { - "type": "string" - }, - "maxSize": { - "type": "string" - } - }, - "type": "object" - }, - "volumeMounts": { - "items": { - "properties": { - "mountPath": { - "type": "string" - }, - "name": { - "type": "string" - }, - "subPath": { - "type": "string" - } - }, - "type": "object" - }, - "type": "array" - }, - "volumes": { - "items": { - "properties": { - "configMap": { - "properties": { - "defaultMode": { - "type": "integer" - }, - "name": { - "type": "string" - } - }, - "type": "object" - }, - "name": { - "type": "string" - } - }, - "type": "object" - }, - "type": "array" - } - }, - "type": "object" } }, "type": "object" diff --git a/helm/dbrepo/values.yaml b/helm/dbrepo/values.yaml index b82eb12cecd1118c217e2552e9ee3dbaf982d580..56ac85d0be9f0ef60d0de523b121b8b58410773e 100644 --- a/helm/dbrepo/values.yaml +++ b/helm/dbrepo/values.yaml @@ -85,26 +85,19 @@ authservice: debug: false ## @param authservice.endpoint The hostname for the microservices. endpoint: http://auth-service + ## @param authservice.extraStartupArgs Extra arguments for the Keycloak container. + extraStartupArgs: --hostname-strict false --proxy-headers xforwarded ## @skip authservice.postgresql postgresql: enabled: true 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: ## @param authservice.jwt.pubkey The JWT public key from the `dbrepo-client`. pubkey: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB" - tls: - ## @param authservice.tls.enabled Enable TLS/SSL communication. Required for HTTPS. - enabled: true - ## @param authservice.tls.existingSecret The secret containing the `tls.crt`, `tls.key` and `ca.crt`. - existingSecret: auth-service-secret - ## @skip authservice.tls.usePem - usePem: true metrics: ## @skip authservice.metrics.enabled enabled: true @@ -122,7 +115,7 @@ authservice: setupJob: image: ## @skip authservice.setupJob.image.name - name: registry.datalab.tuwien.ac.at/dbrepo/auth-service-init:1.7.3 + name: registry.datalab.tuwien.ac.at/dbrepo/auth-service-init:1.8.0 ## @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) @@ -176,6 +169,10 @@ datadb: db: ## @param datadb.db.name The database name. name: dbrepo + ## @param datadb.db.user The database username for the dashboard service. + user: user + ## @param datadb.db.password The database user password for the dashboard service. + password: user galera: mariabackup: ## @param datadb.galera.mariabackup.user The database backup username. @@ -218,7 +215,7 @@ searchdb: enabled: false ## @param searchdb.ingest.resourcesPreset The container resource preset resourcesPreset: "micro" - ## @param searchdb.ingest.replicaCount The number of pod replicas. + ## @param searchdb.ingest.replicaCount The number of pod replicas. replicaCount: 1 master: ## @param searchdb.master.resourcesPreset The container resource preset @@ -236,90 +233,6 @@ searchdb: ## @param searchdb.clusterName The cluster name. clusterName: search-db -## @section Upload Service - -uploadservice: - ## @param uploadservice.enabled Enable the Upload Service. - enabled: true - ## @skip uploadservice.image - image: - name: docker.io/tusproject/tusd:v1.12 - s3: - ## @param uploadservice.s3.endpoint The S3-capable endpoint the microservice connects to. - endpoint: http://storage-service-s3:8333 - ## @param uploadservice.s3.bucket The S3 bucket name. - bucket: dbrepo - ## @param uploadservice.s3.maxSize The maximum file size in bytes. - maxSize: "2000000000" - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod - podSecurityContext: - ## @param uploadservice.podSecurityContext.enabled Enable pods' Security Context - enabled: true - ## @param uploadservice.podSecurityContext.fsGroupChangePolicy Set filesystem group change policy - fsGroupChangePolicy: Always - ## @param uploadservice.podSecurityContext.sysctls Set kernel settings using the sysctl interface - sysctls: [ ] - ## @param uploadservice.podSecurityContext.supplementalGroups Set filesystem extra groups - supplementalGroups: [ ] - ## @param uploadservice.podSecurityContext.fsGroup Set RabbitMQ pod's Security Context fsGroup - fsGroup: 0 - containerSecurityContext: - ## @param uploadservice.containerSecurityContext.enabled Enable containers' Security Context - enabled: true - ## @param uploadservice.containerSecurityContext.seLinuxOptions Set SELinux options in container - seLinuxOptions: { } - ## @param uploadservice.containerSecurityContext.runAsUser Set RabbitMQ containers' Security Context runAsUser - runAsUser: 1000 - ## @param uploadservice.containerSecurityContext.runAsGroup Set RabbitMQ containers' Security Context runAsGroup - runAsGroup: 1000 - ## @param uploadservice.containerSecurityContext.runAsNonRoot Set RabbitMQ container's Security Context runAsNonRoot - runAsNonRoot: true - ## @param uploadservice.containerSecurityContext.allowPrivilegeEscalation Set container's privilege escalation - allowPrivilegeEscalation: false - ## @param uploadservice.containerSecurityContext.readOnlyRootFilesystem Set container's Security Context readOnlyRootFilesystem - readOnlyRootFilesystem: false - capabilities: - ## @param uploadservice.containerSecurityContext.capabilities.drop Set container's Security Context runAsNonRoot - drop: [ "ALL" ] - seccompProfile: - ## @param uploadservice.containerSecurityContext.seccompProfile.type Set container's Security Context seccomp profile - type: "RuntimeDefault" - ## @param uploadservice.resourcesPreset The container resource preset - resourcesPreset: "nano" - ## @param uploadservice.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) - resources: { } - ## requests: - ## cpu: 250m - ## memory: 64Mi - ## limits: - ## cpu: 500m - ## memory: 1024Mi - ## @skip uploadservice.containerArgs - containerArgs: - - "-behind-proxy" - - "-max-size=2000000000" - - "-base-path=/api/upload/files/" - - "-hooks-dir=/srv/tusd-hooks/" - - "-s3-endpoint=http://storage-service-s3:8333" - - "-s3-bucket=dbrepo" - ## @skip uploadservice.envFrom - envFrom: - - secretRef: - name: upload-service-secret - ## @skip uploadservice.volumes - volumes: - - name: config - configMap: - name: upload-service-setup - defaultMode: 0777 - ## @skip uploadservice.volumeMounts - volumeMounts: - - name: config - mountPath: /srv/tusd-hooks/pre-create - subPath: pre-create - ## @param uploadservice.replicaCount The number of replicas. - replicaCount: 2 - ## @section Broker Service brokerservice: @@ -415,7 +328,7 @@ analyseservice: enabled: true image: ## @skip analyseservice.image.name - name: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.7.3 + name: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.8.0 ## 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 @@ -476,7 +389,7 @@ metadataservice: enabled: true image: ## @skip metadataservice.image.name - name: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.7.3 + name: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.8.0 ## 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 @@ -573,7 +486,7 @@ dataservice: endpoint: http://data-service image: ## @skip dataservice.image.name - name: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.7.3 + name: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.8.0 ## 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 @@ -659,7 +572,7 @@ searchservice: endpoint: http://search-service image: ## @skip searchservice.image.name - name: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.7.3 + name: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.8.0 ## 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 @@ -706,7 +619,7 @@ searchservice: init: image: ## @skip searchservice.init.image.name - name: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.7.3 + name: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.8.0 ## @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) @@ -767,7 +680,7 @@ storageservice: init: image: ## @skip storageservice.init.image.name - name: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.7.3 + name: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.8.0 s3: ## @param storageservice.init.s3.endpoint The S3-capable endpoint the microservice connects to. endpoint: http://storage-service-s3:8333 @@ -876,7 +789,7 @@ ui: enabled: true image: ## @skip ui.image.name - name: registry.datalab.tuwien.ac.at/dbrepo/ui:1.7.3 + name: registry.datalab.tuwien.ac.at/dbrepo/ui:1.8.0 ## 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 @@ -981,40 +894,106 @@ ui: dashboardservice: ## @param dashboardservice.enabled Enable the Dashboard Service. enabled: true + image: + ## @skip dashboardservice.image.name + name: registry.datalab.tuwien.ac.at/dbrepo/auth-service-init:1.8.0 + ## @param dashboardservice.endpoint The endpoint for the microservices. + endpoint: http://dashboard-service + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod + podSecurityContext: + ## @param dashboardservice.podSecurityContext.enabled Enable pods' Security Context + enabled: true + ## @param dashboardservice.podSecurityContext.fsGroupChangePolicy Set filesystem group change policy + fsGroupChangePolicy: Always + ## @param dashboardservice.podSecurityContext.sysctls Set kernel settings using the sysctl interface + sysctls: [ ] + ## @param dashboardservice.podSecurityContext.supplementalGroups Set filesystem extra groups + supplementalGroups: [ ] + ## @param dashboardservice.podSecurityContext.fsGroup Set RabbitMQ pod's Security Context fsGroup + fsGroup: 0 + containerSecurityContext: + ## @param dashboardservice.containerSecurityContext.enabled Enable containers' Security Context + enabled: true + ## @param dashboardservice.containerSecurityContext.seLinuxOptions Set SELinux options in container + seLinuxOptions: { } + ## @param dashboardservice.containerSecurityContext.runAsUser Set RabbitMQ containers' Security Context runAsUser + runAsUser: 1001 + ## @param dashboardservice.containerSecurityContext.runAsGroup Set RabbitMQ containers' Security Context runAsGroup + runAsGroup: 1001 + ## @param dashboardservice.containerSecurityContext.runAsNonRoot Set RabbitMQ container's Security Context runAsNonRoot + runAsNonRoot: true + ## @param dashboardservice.containerSecurityContext.allowPrivilegeEscalation Set container's privilege escalation + allowPrivilegeEscalation: false + ## @param dashboardservice.containerSecurityContext.readOnlyRootFilesystem Set container's Security Context readOnlyRootFilesystem + readOnlyRootFilesystem: false + capabilities: + ## @param dashboardservice.containerSecurityContext.capabilities.drop Set container's Security Context runAsNonRoot + drop: [ "ALL" ] + seccompProfile: + ## @param dashboardservice.containerSecurityContext.seccompProfile.type Set container's Security Context seccomp profile + type: "RuntimeDefault" + ## @param dashboardservice.resourcesPreset The container resource preset + resourcesPreset: "micro" + ## @param dashboardservice.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) + resources: { } + ## requests: + ## cpu: 250m + ## memory: 64Mi + ## limits: + ## cpu: 500m + ## memory: 1024Mi + ## @param dashboardservice.replicaCount The number of replicas. + init: + image: + ## @skip dashboardservice.init.image.name + name: registry.datalab.tuwien.ac.at/dbrepo/dashboard-service-init:1.8.0 + ## @param dashboardservice.init.resourcesPreset The container resource preset + resourcesPreset: "nano" + ## @param dashboardservice.init.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) + resources: { } + ## requests: + ## cpu: 250m + ## memory: 64Mi + ## limits: + ## cpu: 500m + ## memory: 1024Mi + ## @param dashboardservice.replicaCount The number of replicas. + replicaCount: 2 + +## @section Dashboard UI + +dashboardui: + ## @param dashboardui.enabled Enable the Dashboard UI. + enabled: true + ## @skip dashboardui.fullnameOverride + fullnameOverride: dashboard-ui metrics: - ## @param dashboardservice.metrics.enabled Enable the metrics sidecar. + ## @param dashboardui.metrics.enabled Enable the metrics sidecar. enabled: true - ## @skip dashboardservice.fullnameOverride - fullnameOverride: dashboard-service + ## @param dashboardui.endpoint The endpoint for the microservices. + endpoint: http://dashboard-ui ldap: - ## @skip dashboardservice.ldap.enabled + ## @skip dashboardui.ldap.enabled enabled: true - ## @skip dashboardservice.ldap.allowSignUp + ## @skip dashboardui.ldap.allowSignUp allowSignUp: true - ## @skip dashboardservice.ldap.secretName - secretName: dashboard-service-secret + ## @skip dashboardui.ldap.secretName + secretName: dashboard-ui-secret grafana: updateStrategy: - ## @skip dashboardservice.grafana.updateStrategy.type + ## @skip dashboardui.grafana.updateStrategy.type type: Recreate - ## @skip dashboardservice.grafana.extraEnvVarsSecret - extraEnvVarsSecret: dashboard-service-secret - ## @skip dashboardservice.grafana.extraConfigmaps - extraConfigmaps: - - name: dashboard-service-config - mountPath: /opt/bitnami/grafana/dashboards - readOnly: true + ## @skip dashboardui.grafana.extraEnvVarsSecret + extraEnvVarsSecret: dashboard-ui-secret + service: + ports: + ## @skip dashboardui.service.ports.grafana + grafana: 80 datasources: - ## @skip dashboardservice.datasources.secretDefinition - secretDefinition: - apiVersion: 1 - datasources: - - name: "dbrepo-metric-db" - uid: "P18F45E9DC7E75912" - type: "prometheus" - url: "http://metric-db-server" + ## @skip dashboardui.datasources.secretName + secretName: "dashboard-ui-prov-datasources-secret" dashboardsProvider: - ## @param dashboardservice.dashboardsProvider.enabled Enable the default dashboard provisioning provider to routinely import dashboards from /opt/bitnami/grafana/dashboards + ## @param dashboardui.dashboardsProvider.enabled Enable the default dashboard provisioning provider to routinely import dashboards from /opt/bitnami/grafana/dashboards enabled: true ## @section Metric Service @@ -1024,6 +1003,8 @@ metricdb: enabled: true ## @skip metricdb.fullnameOverride fullnameOverride: metric-db + ## @param metricdb.endpoint The endpoint for microservices. + endpoint: http://metric-db-server alertmanager: ## @skip metricdb.alertmanager.enabled enabled: false @@ -1053,7 +1034,7 @@ metricdb: - job_name: 'dashboard scrape' metrics_path: '/dashboard/metrics' static_configs: - - targets: [ 'dashboard-service:3000' ] + - targets: [ 'dashboard-service' ] ## @section Gateway Service diff --git a/helm/seaweedfs/Chart.lock b/helm/seaweedfs/Chart.lock index a6802a09cf77b8371a86d178399c67d7717544c5..775b1e81f93de470835107658007a907cd82df66 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.4.1 + version: 20.4.2 - name: postgresql repository: oci://registry-1.docker.io/bitnamicharts - version: 16.4.16 + version: 16.6.0 - name: common repository: oci://registry-1.docker.io/bitnamicharts version: 2.30.0 -digest: sha256:20dba9f2a4322ee4b5e734cc85f7f10a47a090b0cc34bf9c1658feb774fad06e -generated: "2025-03-04T21:41:17.631905476+01:00" +digest: sha256:d254c9a52e16d0b7cb0f2b1a33ca9b0ac162589b72708e55848f2b0d316c1e7b +generated: "2025-04-01T13:05:20.598251993+02:00" diff --git a/helm/seaweedfs/charts/mariadb-20.4.1.tgz b/helm/seaweedfs/charts/mariadb-20.4.1.tgz deleted file mode 100644 index 924d07c3e7f88655b179085c3546f5d3de5c6e75..0000000000000000000000000000000000000000 Binary files a/helm/seaweedfs/charts/mariadb-20.4.1.tgz and /dev/null differ diff --git a/helm/seaweedfs/charts/mariadb-20.4.2.tgz b/helm/seaweedfs/charts/mariadb-20.4.2.tgz new file mode 100644 index 0000000000000000000000000000000000000000..5d58a0a1104ab1c9d8312d3117d5d2ece8b1d5a9 Binary files /dev/null and b/helm/seaweedfs/charts/mariadb-20.4.2.tgz differ diff --git a/helm/seaweedfs/charts/postgresql-16.4.16.tgz b/helm/seaweedfs/charts/postgresql-16.4.16.tgz deleted file mode 100644 index b862ff5d0d42b34d83ea4f479ed90070f1e4ee16..0000000000000000000000000000000000000000 Binary files a/helm/seaweedfs/charts/postgresql-16.4.16.tgz and /dev/null differ diff --git a/helm/seaweedfs/charts/postgresql-16.6.0.tgz b/helm/seaweedfs/charts/postgresql-16.6.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..865acadee30f59e1a872f84f12eaeae096f457aa Binary files /dev/null and b/helm/seaweedfs/charts/postgresql-16.6.0.tgz differ diff --git a/install.sh b/install.sh index b453e92ad6096fe07d6dc7355103e75d56b004fd..8f6069b644605453c3d8951856b61515ce3a05c0 100644 --- a/install.sh +++ b/install.sh @@ -1,7 +1,7 @@ #!/bin/bash # preset -VERSION="1.7.3" +VERSION="1.8.0" MIN_CPU=8 MIN_RAM=4 MIN_MAP_COUNT=262144 diff --git a/lib/java/dbrepo-core/.gitignore b/lib/java/dbrepo-core/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..b425f09ad0e75e91fc43f1aee01bb3a918eec8c0 --- /dev/null +++ b/lib/java/dbrepo-core/.gitignore @@ -0,0 +1,35 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/lib/java/dbrepo-core/Dockerfile b/lib/java/dbrepo-core/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..8a6348bbcef25836c318e41ae226295f90549a66 --- /dev/null +++ b/lib/java/dbrepo-core/Dockerfile @@ -0,0 +1,12 @@ +###### FIRST STAGE ###### +FROM maven:3-amazoncorretto-17 AS build +LABEL org.opencontainers.image.authors="martin.weise@tuwien.ac.at" + +COPY ./pom.xml ./ + +RUN mvn dependency:go-offline + +COPY ./src/ ./src/ + +# Make sure it compiles +RUN mvn clean install -DskipTests \ No newline at end of file diff --git a/lib/java/dbrepo-core/pom.xml b/lib/java/dbrepo-core/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..87dd20ddc7c0842759a29bb022a2c4b3c24bc1d3 --- /dev/null +++ b/lib/java/dbrepo-core/pom.xml @@ -0,0 +1,167 @@ +<?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.springframework.boot</groupId> + <artifactId>spring-boot-starter-parent</artifactId> + <version>3.3.5</version> + </parent> + + <organization> + <name>TU Wien</name> + <url>https://www.tuwien.ac.at</url> + </organization> + + <groupId>at.ac.tuwien.ifs.dbrepo</groupId> + <artifactId>dbrepo-core</artifactId> + <name>dbrepo-core</name> + <version>1.8.0</version> + + <description>Core library for DBRepo</description> + + <url>https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.8/</url> + <developers> + <developer> + <name>Martin Weise</name> + <email>martin.weise@tuwien.ac.at</email> + <organization>TU Wien</organization> + </developer> + </developers> + + <properties> + <maven.compiler.source>17</maven.compiler.source> + <maven.compiler.target>17</maven.compiler.target> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <lombok.version>1.18.36</lombok.version> + <keycloak.version>26.0.4</keycloak.version> + <mapstruct.version>1.6.3</mapstruct.version> + <spring-cloud.version>4.1.4</spring-cloud.version> + <jackson-datatype.version>2.15.0</jackson-datatype.version> + <springdoc-openapi.version>2.8.5</springdoc-openapi.version> + </properties> + + <dependencies><dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-validation</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-security</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-test</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework.cloud</groupId> + <artifactId>spring-cloud-starter-bootstrap</artifactId> + <version>${spring-cloud.version}</version> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-thymeleaf</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-data-jpa</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-actuator</artifactId> + </dependency> + <!-- Mapping --> + <dependency> + <groupId>org.keycloak</groupId> + <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>org.mapstruct</groupId> + <artifactId>mapstruct-processor</artifactId> + <version>${mapstruct.version}</version> + <optional>true</optional> + </dependency> + <dependency> + <groupId>org.mapstruct</groupId> + <artifactId>mapstruct</artifactId> + <version>${mapstruct.version}</version> + </dependency> + <!-- Api --> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>${lombok.version}</version> + <scope>compile</scope> + </dependency> + <!-- Entities --> + <dependency> + <groupId>com.fasterxml.jackson.datatype</groupId> + <artifactId>jackson-datatype-jsr310</artifactId> + <version>${jackson-datatype.version}</version> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.datatype</groupId> + <artifactId>jackson-datatype-hibernate6</artifactId> + <version>${jackson-datatype.version}</version> + </dependency> + <!-- Open API --> + <dependency> + <groupId>org.springdoc</groupId> + <artifactId>springdoc-openapi-starter-webmvc-api</artifactId> + <version>${springdoc-openapi.version}</version> + </dependency> + <!-- Tests --> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-test</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>${java.version}</source> + <target>${java.version}</target> + <annotationProcessorPaths> + <path> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>${lombok.version}</version> + </path> + <!-- keep this order https://stackoverflow.com/questions/47676369/mapstruct-and-lombok-not-working-together#answer-65021876 --> + <path> + <groupId>org.mapstruct</groupId> + <artifactId>mapstruct-processor</artifactId> + <version>${mapstruct.version}</version> + </path> + </annotationProcessorPaths> + </configuration> + </plugin> + </plugins> + </build> + + <licenses> + <license> + <name>Apache-2.0</name> + <url>http://www.apache.org/licenses/LICENSE-2.0.html</url> + <distribution>repo</distribution> + </license> + </licenses> + +</project> \ No newline at end of file diff --git a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/Serialize.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/Serialize.java new file mode 100644 index 0000000000000000000000000000000000000000..073a7c669901c33384a9b402b2c247cb50993694 --- /dev/null +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/Serialize.java @@ -0,0 +1,32 @@ +package at.ac.tuwien.ifs.dbrepo.core; + +import at.ac.tuwien.ifs.dbrepo.core.test.BaseTest; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.hibernate6.Hibernate6Module; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; + +import java.io.IOException; +import java.util.TimeZone; + +public class Serialize extends BaseTest { + + public static ObjectMapper objectMapper() { + final ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new Jdk8Module()); + objectMapper.registerModule(new JavaTimeModule()); + objectMapper.registerModule(new Hibernate6Module()); /* lazy load mapping on REST endpoints */ + objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + objectMapper.setTimeZone(TimeZone.getTimeZone("UTC")); + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + objectMapper.enable(SerializationFeature.INDENT_OUTPUT); + return objectMapper; + } + + public static void main(String[] args) throws IOException { +// objectMapper().writeValue(new File("./src/main/resources/database-1.json"), IDENTIFIER_1); + } + +} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/CacheableDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/CacheableDto.java similarity index 91% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/CacheableDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/CacheableDto.java index e947ece6320820e926a3674834310c785042603d..25d248dc4f9796aaac5149ce9fd52663fb5f388b 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/CacheableDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/CacheableDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api; +package at.ac.tuwien.ifs.dbrepo.core.api; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/ExportResourceDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/ExportResourceDto.java similarity index 86% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/ExportResourceDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/ExportResourceDto.java index 5c5bf22005be92dbd172bfa4abd580dd298d6d5c..fb7e87ec86cd79cda530241f7c97fc29648f6c29 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/ExportResourceDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/ExportResourceDto.java @@ -1,4 +1,4 @@ -package at.tuwien; +package at.ac.tuwien.ifs.dbrepo.core.api; import lombok.*; import org.springframework.core.io.InputStreamResource; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/ChannelDetailsDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/ChannelDetailsDto.java similarity index 93% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/ChannelDetailsDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/ChannelDetailsDto.java index 03aeb19ab41e375822af6741e61b3161d67a7591..861602a1564516a1186a4f9431281806dcea04b4 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/ChannelDetailsDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/ChannelDetailsDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.amqp; +package at.ac.tuwien.ifs.dbrepo.core.api.amqp; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/ConsumerDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/ConsumerDto.java similarity index 94% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/ConsumerDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/ConsumerDto.java index ad82492d7d4d867c4c706bfbc1f1549e9fafcd95..6d40bbe0ef2e731c772a1812e32630496eac95b4 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/ConsumerDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/ConsumerDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.amqp; +package at.ac.tuwien.ifs.dbrepo.core.api.amqp; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/CreateExchangeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/CreateExchangeDto.java similarity index 92% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/CreateExchangeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/CreateExchangeDto.java index dffe2c1e0e300fb631d7af34a09e605e1064a462..57fccbcc2f0431494f92d208fef8933eec1d4884 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/CreateExchangeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/CreateExchangeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.amqp; +package at.ac.tuwien.ifs.dbrepo.core.api.amqp; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/CreateUserDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/CreateUserDto.java similarity index 89% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/CreateUserDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/CreateUserDto.java index 372ce8219b0ee2ac63308c9f8028361d8471cb10..4f5171daae15bc9ff41c3d8b4a331ce8accee283 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/CreateUserDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/CreateUserDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.amqp; +package at.ac.tuwien.ifs.dbrepo.core.api.amqp; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/CreateVirtualHostDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/CreateVirtualHostDto.java similarity index 90% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/CreateVirtualHostDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/CreateVirtualHostDto.java index b27ea597c20a670df8897834b28bc62fcb95c0f7..841d4ee8365dbe663c2a527a6d434b54ab212b77 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/CreateVirtualHostDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/CreateVirtualHostDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.amqp; +package at.ac.tuwien.ifs.dbrepo.core.api.amqp; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/ExchangeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/ExchangeDto.java similarity index 93% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/ExchangeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/ExchangeDto.java index 403a04f00b4d437db1746cca1977989e61a85dc8..b42bef7e89b19e465755a2dccfe7c0e2578a85b8 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/ExchangeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/ExchangeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.amqp; +package at.ac.tuwien.ifs.dbrepo.core.api.amqp; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/GrantExchangePermissionsDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/GrantExchangePermissionsDto.java similarity index 91% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/GrantExchangePermissionsDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/GrantExchangePermissionsDto.java index 054548dbf06e683bcd787109afbff0359b59ca65..64bc4c1990b942216b635b90c37031225e224b5e 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/GrantExchangePermissionsDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/GrantExchangePermissionsDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.amqp; +package at.ac.tuwien.ifs.dbrepo.core.api.amqp; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/GrantVirtualHostPermissionsDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/GrantVirtualHostPermissionsDto.java similarity index 91% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/GrantVirtualHostPermissionsDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/GrantVirtualHostPermissionsDto.java index 7e84edb80eb21faafbc4eb0ca87f4c5aa65464e4..a49b3b5cb20cd0e4e79f43cf5af9f56999a36a4c 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/GrantVirtualHostPermissionsDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/GrantVirtualHostPermissionsDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.amqp; +package at.ac.tuwien.ifs.dbrepo.core.api.amqp; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/QueueBriefDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/QueueBriefDto.java similarity index 90% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/QueueBriefDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/QueueBriefDto.java index 8a266043a1a63f216d2ca0a378d69f11458e6555..7e9ee27d4b051af6ca1fea2bfa4bb7d618b50d2e 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/QueueBriefDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/QueueBriefDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.amqp; +package at.ac.tuwien.ifs.dbrepo.core.api.amqp; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/QueueDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/QueueDto.java similarity index 93% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/QueueDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/QueueDto.java index acc2091d41a158b07c7b23679be7e7ac1c385fc5..4ddd5e270d7b445cc1e7a4ea29b75154d0809f39 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/QueueDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/QueueDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.amqp; +package at.ac.tuwien.ifs.dbrepo.core.api.amqp; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/TopicPermissionDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/TopicPermissionDto.java similarity index 93% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/TopicPermissionDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/TopicPermissionDto.java index bdd806f71e1312c05d27f034704297fa7c2bd885..50fc100b134d0618455ba72db9eec3b3f1954af8 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/TopicPermissionDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/TopicPermissionDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.amqp; +package at.ac.tuwien.ifs.dbrepo.core.api.amqp; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/UserDetailsDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/UserDetailsDto.java similarity index 94% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/UserDetailsDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/UserDetailsDto.java index a786456efd0945d480ace653457f3e8a284ab78c..07a9a1ef61f77fca127aa1b49704d40c05ab5d31 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/UserDetailsDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/UserDetailsDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.amqp; +package at.ac.tuwien.ifs.dbrepo.core.api.amqp; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/VirtualHostPermissionDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/VirtualHostPermissionDto.java similarity index 93% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/VirtualHostPermissionDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/VirtualHostPermissionDto.java index 0602c418da993c7bea9e2e557203128c9772fc8c..0d1f1fe96966154ce4bda299dad8c1ca5155e391 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/amqp/VirtualHostPermissionDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/amqp/VirtualHostPermissionDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.amqp; +package at.ac.tuwien.ifs.dbrepo.core.api.amqp; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/CreateUserDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/auth/CreateUserDto.java similarity index 95% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/CreateUserDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/auth/CreateUserDto.java index 9742986ae08df9f9d00f5c1bc9da15b245bad8fc..eb0f1ed91a17e901ec6b66bf957feb1389edbe35 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/CreateUserDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/auth/CreateUserDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.auth; +package at.ac.tuwien.ifs.dbrepo.core.api.auth; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/RealmAccessDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/auth/RealmAccessDto.java similarity index 90% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/RealmAccessDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/auth/RealmAccessDto.java index b759aff16843ef5cf8cc13466af20c1383599996..eb308018c42cb00502da8364af74da31d023450d 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/RealmAccessDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/auth/RealmAccessDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.auth; +package at.ac.tuwien.ifs.dbrepo.core.api.auth; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerActionTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/ContainerActionTypeDto.java similarity index 81% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerActionTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/ContainerActionTypeDto.java index 9d641d510db834390a078d1b1947a52141d5a0b0..42c40ab7af6af697064ab5b4302c08c463ea68b9 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerActionTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/ContainerActionTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.container; +package at.ac.tuwien.ifs.dbrepo.core.api.container; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; @@ -12,7 +12,7 @@ public enum ContainerActionTypeDto { @JsonProperty("stop") STOP("stop"); - private String name; + private final String name; ContainerActionTypeDto(String name) { this.name = name; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/ContainerBriefDto.java similarity index 86% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/ContainerBriefDto.java index 91253b12baaefc02c0b078bf31fd832a01f29864..ec879665e930d0a8daa92fa2b4e3d790189714ba 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/ContainerBriefDto.java @@ -1,7 +1,6 @@ -package at.tuwien.api.container; +package at.ac.tuwien.ifs.dbrepo.core.api.container; -import at.tuwien.api.container.image.ImageBriefDto; -import com.fasterxml.jackson.annotation.JsonFormat; +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageBriefDto; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; @@ -9,7 +8,6 @@ import jakarta.validation.constraints.NotNull; import lombok.*; import lombok.extern.jackson.Jacksonized; -import java.time.Instant; import java.util.UUID; @Getter diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/ContainerDto.java similarity index 89% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/ContainerDto.java index 39eb0116527395ca9dcfdf634e44b675fc46b122..12589bc7214ed0a08cdeb890e2286b726508cec9 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/ContainerDto.java @@ -1,7 +1,7 @@ -package at.tuwien.api.container; +package at.ac.tuwien.ifs.dbrepo.core.api.container; -import at.tuwien.api.CacheableDto; -import at.tuwien.api.container.image.ImageDto; +import at.ac.tuwien.ifs.dbrepo.core.api.CacheableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageDto; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/CreateContainerDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/CreateContainerDto.java similarity index 96% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/CreateContainerDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/CreateContainerDto.java index f2ac7df46abb989797bc1bab23d8145d71ee5687..77e7b026c7c304d129107649d8e2d6be1c1ba9b2 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/CreateContainerDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/CreateContainerDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.container; +package at.ac.tuwien.ifs.dbrepo.core.api.container; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/DataTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/image/DataTypeDto.java similarity index 97% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/DataTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/image/DataTypeDto.java index 908f54a1b45fb247f13550b15cf8c2ce5d80e821..3455de43a917408b837dd28735e36d67b92a60e2 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/DataTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/image/DataTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.container.image; +package at.ac.tuwien.ifs.dbrepo.core.api.container.image; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageBriefDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/image/ImageBriefDto.java similarity index 93% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageBriefDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/image/ImageBriefDto.java index ecbd050966f43c6f8fbe8a04b6f458570448fd59..7239fdcfb74944bb72cf4b0471460c3312344604 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageBriefDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/image/ImageBriefDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.container.image; +package at.ac.tuwien.ifs.dbrepo.core.api.container.image; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageChangeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/image/ImageChangeDto.java similarity index 94% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageChangeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/image/ImageChangeDto.java index 520449d1de7bfb8d92f33f15763c13813e6c935b..0a73939c2323fb594c0751dfc492ce16cc59ac1b 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageChangeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/image/ImageChangeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.container.image; +package at.ac.tuwien.ifs.dbrepo.core.api.container.image; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageCreateDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/image/ImageCreateDto.java similarity index 96% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageCreateDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/image/ImageCreateDto.java index 4e9fea5b7cbada74155ad2760ccdc99fb2e23490..cce376f5b7fb054409e84b7f48ee4467fde5bd52 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageCreateDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/image/ImageCreateDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.container.image; +package at.ac.tuwien.ifs.dbrepo.core.api.container.image; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.Parameter; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/image/ImageDto.java similarity index 94% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/image/ImageDto.java index ec4b0ad4894bcb220d03d4bb86828ba3b25bfc63..9d4049a173107d50ae5e14844a054649165b7aac 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/image/ImageDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.container.image; +package at.ac.tuwien.ifs.dbrepo.core.api.container.image; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/OperatorDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/image/OperatorDto.java similarity index 93% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/OperatorDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/image/OperatorDto.java index 7eaee0481064384e762b296661565f5534714beb..38f39f5d827679892e9dfb5bbee78f6fc630466c 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/OperatorDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/container/image/OperatorDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.container.image; +package at.ac.tuwien.ifs.dbrepo.core.api.container.image; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/crossref/CrossrefDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/CrossRefDto.java similarity index 60% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/crossref/CrossrefDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/CrossRefDto.java index 4a689a69ce93dead9cbb6bd27916326a986f22f1..f32d2d412508df48a7b1677ee6f562020e43f4bc 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/crossref/CrossrefDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/CrossRefDto.java @@ -1,6 +1,6 @@ -package at.tuwien.api.crossref; +package at.ac.tuwien.ifs.dbrepo.core.api.crossref; -import at.tuwien.api.crossref.label.CrossrefPrefLabelDto; +import at.ac.tuwien.ifs.dbrepo.core.api.crossref.label.CrossRefPrefLabelDto; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; import lombok.extern.jackson.Jacksonized; @@ -13,11 +13,11 @@ import lombok.extern.jackson.Jacksonized; @AllArgsConstructor @Jacksonized @ToString -public class CrossrefDto { +public class CrossRefDto { @Schema(example = "https://doi.org/10.13039/100000001") private String id; - private CrossrefPrefLabelDto prefLabel; + private CrossRefPrefLabelDto prefLabel; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/crossref/form/CrossrefLiteralFormDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/form/CrossRefLiteralFormDto.java similarity index 79% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/crossref/form/CrossrefLiteralFormDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/form/CrossRefLiteralFormDto.java index b493cf89ff6ea61df68ef919c6a380b9a81769d2..473937a111be4a7611780cb5a2ea45315ccac588 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/crossref/form/CrossrefLiteralFormDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/form/CrossRefLiteralFormDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.crossref.form; +package at.ac.tuwien.ifs.dbrepo.core.api.crossref.form; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; @@ -12,7 +12,7 @@ import lombok.extern.jackson.Jacksonized; @AllArgsConstructor @Jacksonized @ToString -public class CrossrefLiteralFormDto { +public class CrossRefLiteralFormDto { @Schema(example = "en") private String lang; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/crossref/label/CrossrefLabelDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/label/CrossRefLabelDto.java similarity index 60% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/crossref/label/CrossrefLabelDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/label/CrossRefLabelDto.java index 7bdaf0f93117c31dd91017f0e3fcda885060cd54..684557115fa65da4104ba5cd9b703a1bfbeae211 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/crossref/label/CrossrefLabelDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/label/CrossRefLabelDto.java @@ -1,6 +1,6 @@ -package at.tuwien.api.crossref.label; +package at.ac.tuwien.ifs.dbrepo.core.api.crossref.label; -import at.tuwien.api.crossref.form.CrossrefLiteralFormDto; +import at.ac.tuwien.ifs.dbrepo.core.api.crossref.form.CrossRefLiteralFormDto; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; import lombok.extern.jackson.Jacksonized; @@ -13,9 +13,9 @@ import lombok.extern.jackson.Jacksonized; @AllArgsConstructor @Jacksonized @ToString -public class CrossrefLabelDto { +public class CrossRefLabelDto { - private CrossrefLiteralFormDto literalForm; + private CrossRefLiteralFormDto literalForm; @Schema(example = "http://data.crossref.org/fundingdata/vocabulary/Label-36515") private String about; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/crossref/label/CrossrefPrefLabelDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/label/CrossRefPrefLabelDto.java similarity index 66% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/crossref/label/CrossrefPrefLabelDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/label/CrossRefPrefLabelDto.java index a70c161d83752cc338c0e0ccf416cc84a8ee8c8b..0ec889622bc2cc99bf78807745bde0e767d74ed2 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/crossref/label/CrossrefPrefLabelDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/crossref/label/CrossRefPrefLabelDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.crossref.label; +package at.ac.tuwien.ifs.dbrepo.core.api.crossref.label; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; @@ -12,9 +12,9 @@ import lombok.extern.jackson.Jacksonized; @AllArgsConstructor @Jacksonized @ToString -public class CrossrefPrefLabelDto { +public class CrossRefPrefLabelDto { @JsonProperty("Label") - private CrossrefLabelDto label; + private CrossRefLabelDto label; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/AccessTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/AccessTypeDto.java similarity index 85% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/AccessTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/AccessTypeDto.java index fa0f6fea49e0aaf1823ba26f70aa918ecd96d98d..fb3f34957e7a12401479b467992af467365fb81f 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/AccessTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/AccessTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database; +package at.ac.tuwien.ifs.dbrepo.core.api.database; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; @@ -17,7 +17,7 @@ public enum AccessTypeDto { @JsonProperty("write_all") WRITE_ALL("write_all"); - private String name; + private final String name; AccessTypeDto(String name) { this.name = name; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateAccessDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/CreateAccessDto.java similarity index 88% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateAccessDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/CreateAccessDto.java index 965e10afd50884605ca8788a4653b2b2dc3b9f09..1ba876cc5ea1743c6475c1ba13fc4b606a0b7bd2 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateAccessDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/CreateAccessDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database; +package at.ac.tuwien.ifs.dbrepo.core.api.database; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateDatabaseDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/CreateDatabaseDto.java similarity index 94% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateDatabaseDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/CreateDatabaseDto.java index e7fd08e771176346fb13d361f2c436ce3aaf6627..9c9e7082628b8608068b84eb41c610fad33fda06 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateDatabaseDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/CreateDatabaseDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database; +package at.ac.tuwien.ifs.dbrepo.core.api.database; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateViewDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/CreateViewDto.java similarity index 87% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateViewDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/CreateViewDto.java index 9a9558470f575e07e9baf77b531911a80dac8757..9ab87017a69ede115b51ba212f56fc2b616b44d6 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateViewDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/CreateViewDto.java @@ -1,6 +1,6 @@ -package at.tuwien.api.database; +package at.ac.tuwien.ifs.dbrepo.core.api.database; -import at.tuwien.api.database.query.SubsetDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.SubsetDto; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseAccessDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/DatabaseAccessDto.java similarity index 84% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseAccessDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/DatabaseAccessDto.java index 7e393561f844b3f10f8fc450b04a29158e3e3cbd..22a423f7d8dd3b05380cf214b2f077ff02a0c99e 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseAccessDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/DatabaseAccessDto.java @@ -1,7 +1,7 @@ -package at.tuwien.api.database; +package at.ac.tuwien.ifs.dbrepo.core.api.database; -import at.tuwien.api.user.UserBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserBriefDto; import com.fasterxml.jackson.annotation.JsonIgnore; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/DatabaseBriefDto.java similarity index 88% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/DatabaseBriefDto.java index 4bb262b781d3c18013cf3ae65401e39f2469c3e1..f84649ff6399e2ac1a4e04cf167500b0b88d4805 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/DatabaseBriefDto.java @@ -1,7 +1,7 @@ -package at.tuwien.api.database; +package at.ac.tuwien.ifs.dbrepo.core.api.database; -import at.tuwien.api.identifier.IdentifierBriefDto; -import at.tuwien.api.user.UserBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserBriefDto; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/DatabaseDto.java similarity index 70% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/DatabaseDto.java index 0c8c85a41c54fa81bcf9a37a15fe0187df4182eb..0a8ca41eb5a02d166bfd4231629f7901888427b2 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/DatabaseDto.java @@ -1,11 +1,11 @@ -package at.tuwien.api.database; - -import at.tuwien.api.CacheableDto; -import at.tuwien.api.container.ContainerBriefDto; -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; +package at.ac.tuwien.ifs.dbrepo.core.api.database; + +import at.ac.tuwien.ifs.dbrepo.core.api.CacheableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.ContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserBriefDto; +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; @@ -35,6 +35,10 @@ public class DatabaseDto extends CacheableDto { @Schema(example = "Air Quality") private String name; + @JsonProperty("dashboard_uid") + @Schema(example = "abcdef") + private String dashboardUid; + @NotBlank @JsonProperty("exchange_name") @Schema(example = "dbrepo") @@ -68,6 +72,11 @@ public class DatabaseDto extends CacheableDto { @Schema(example = "true") private Boolean isSchemaPublic; + @NotNull + @JsonProperty("is_dashboard_enabled") + @Schema(example = "true") + private Boolean isDashboardEnabled; + private ContainerDto container; @NotNull @@ -88,6 +97,11 @@ public class DatabaseDto extends CacheableDto { @JsonProperty("preview_image") private String previewImage; + @NotNull + @Schema(example = "2022-01-01 08:00:00.000") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "UTC") + private Instant created; + /* lombok limitations prevent from convenient builder functions */ @JsonProperty("last_retrieved") diff --git a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/DatabaseModifyDashboardDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/DatabaseModifyDashboardDto.java new file mode 100644 index 0000000000000000000000000000000000000000..f4375d2ea35ab46e4a69657cbacf52082a4b0b51 --- /dev/null +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/DatabaseModifyDashboardDto.java @@ -0,0 +1,20 @@ +package at.ac.tuwien.ifs.dbrepo.core.api.database; + +import jakarta.validation.constraints.NotNull; +import lombok.*; +import lombok.extern.jackson.Jacksonized; + +@Getter +@Setter +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Jacksonized +@ToString +public class DatabaseModifyDashboardDto { + + @NotNull + private String uid; + +} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseModifyImageDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/DatabaseModifyImageDto.java similarity index 82% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseModifyImageDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/DatabaseModifyImageDto.java index 5160ae76bfc3b9fc6445a33ff9c1bb277f9bc4dd..f8907baa3aa330a6f8a86da98ae3b79585da043d 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseModifyImageDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/DatabaseModifyImageDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database; +package at.ac.tuwien.ifs.dbrepo.core.api.database; import lombok.*; import lombok.extern.jackson.Jacksonized; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseModifyVisibilityDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/DatabaseModifyVisibilityDto.java similarity index 76% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseModifyVisibilityDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/DatabaseModifyVisibilityDto.java index e641deade282e838c478b87f249e9b26676c4972..818f5461081631fbcd5cccb36f2ff5fbc386fe7b 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseModifyVisibilityDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/DatabaseModifyVisibilityDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database; +package at.ac.tuwien.ifs.dbrepo.core.api.database; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; @@ -26,4 +26,9 @@ public class DatabaseModifyVisibilityDto { @Schema(example = "true") private Boolean isSchemaPublic; + @NotNull + @JsonProperty("is_dashboard_enabled") + @Schema(example = "true") + private Boolean isDashboardEnabled; + } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseTransferDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/DatabaseTransferDto.java similarity index 85% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseTransferDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/DatabaseTransferDto.java index 5a8e6beb1086a996aa77f47ff4f1530b62af00df..f0ba38ebaf47a4bbdbaead229b0522f07eee876d 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseTransferDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/DatabaseTransferDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database; +package at.ac.tuwien.ifs.dbrepo.core.api.database; import jakarta.validation.constraints.NotNull; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/LanguageTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/LanguageTypeDto.java similarity index 98% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/LanguageTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/LanguageTypeDto.java index fe57dd2444db3e834e1e79d1d731b977b38b45ed..c585a5f1ba0fb7836f2d485540daf92c3273ccda 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/LanguageTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/LanguageTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database; +package at.ac.tuwien.ifs.dbrepo.core.api.database; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; @@ -558,7 +558,7 @@ public enum LanguageTypeDto { @JsonProperty("zu") ZU("zu"); - private String value; + private final String value; LanguageTypeDto(String value) { this.value = value; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/LicenseDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/LicenseDto.java similarity index 94% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/LicenseDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/LicenseDto.java index a6384b3487bf1df7d320c2befa303ad59613d5f1..eada3be8ea0ddf5db34c33fdc1fe07e172247444 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/LicenseDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/LicenseDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database; +package at.ac.tuwien.ifs.dbrepo.core.api.database; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/LoadFileDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/LoadFileDto.java similarity index 88% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/LoadFileDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/LoadFileDto.java index 65f5120d9b7cc78442bd071a6b02cbf70f534a41..d5c42425748aac720768435eb0d0f7564de38779 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/LoadFileDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/LoadFileDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database; +package at.ac.tuwien.ifs.dbrepo.core.api.database; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewBriefDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/ViewBriefDto.java similarity index 96% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewBriefDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/ViewBriefDto.java index 47107ac54fe042b026e3a0ac954e5be2650b59d8..046aa97d10c147a2983e11dc491e524ddcd3a165 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewBriefDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/ViewBriefDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database; +package at.ac.tuwien.ifs.dbrepo.core.api.database; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/ViewColumnDto.java similarity index 76% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/ViewColumnDto.java index 766fbfd32103992a8af744c1c105948ebc02f09a..c8744f423888a329e10119cf9de0560f48d91627 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/ViewColumnDto.java @@ -1,6 +1,8 @@ -package at.tuwien.api.database; +package at.ac.tuwien.ifs.dbrepo.core.api.database; -import at.tuwien.api.database.table.columns.ColumnTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.EnumDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.SetDto; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; @@ -9,6 +11,7 @@ import jakarta.validation.constraints.Size; import lombok.*; import lombok.extern.jackson.Jacksonized; +import java.util.List; import java.util.UUID; @Getter @@ -74,4 +77,10 @@ public class ViewColumnDto { @Schema(example = "false") private Boolean isNullAllowed; + @Schema(description = "enum values, only considered when type = ENUM") + private List<EnumDto> enums; + + @Schema(description = "enum values, only considered when type = ENUM") + private List<SetDto> sets; + } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/ViewDto.java similarity index 80% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/ViewDto.java index 1e54da2978935edcb21d396ae66258e37281f785..76cf990c0692adac8e23c3c6694e5c5e067cc4fa 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/ViewDto.java @@ -1,8 +1,9 @@ -package at.tuwien.api.database; +package at.ac.tuwien.ifs.dbrepo.core.api.database; -import at.tuwien.api.CacheableDto; -import at.tuwien.api.identifier.IdentifierDto; -import at.tuwien.api.user.UserBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.CacheableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserBriefDto; +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; @@ -72,6 +73,11 @@ public class ViewDto extends CacheableDto { @NotNull private List<ViewColumnDto> columns; + @NotNull + @Schema(example = "2022-01-01 08:00:00.000") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "UTC") + private Instant created; + /* lombok limitations prevent from convenient builder functions */ @JsonProperty("last_retrieved") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewUpdateDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/ViewUpdateDto.java similarity index 91% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewUpdateDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/ViewUpdateDto.java index 434ce0d9b695ba45d127bcc16725cc72e3bc83c2..01badab2739e366ffb91a512d113aa5bf80594ce 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewUpdateDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/ViewUpdateDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database; +package at.ac.tuwien.ifs.dbrepo.core.api.database; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/internal/CreateDatabaseDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/internal/CreateDatabaseDto.java similarity index 79% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/internal/CreateDatabaseDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/internal/CreateDatabaseDto.java index 76ee117931565173e94b4eb8684bc9a7ecd6d0d1..476adbbd9a6ac73a4c9850eb6d867a671c9f1d72 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/internal/CreateDatabaseDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/internal/CreateDatabaseDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.internal; +package at.ac.tuwien.ifs.dbrepo.core.api.database.internal; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; @@ -38,6 +38,16 @@ public class CreateDatabaseDto { @Schema(example = "mariadb") private String privilegedPassword; + @NotBlank + @JsonProperty("readonly_username") + @Schema(example = "user") + private String readonlyUsername; + + @NotBlank + @JsonProperty("readonly_password") + @Schema(example = "mariadb") + private String readonlyPassword; + @NotNull @JsonProperty("user_id") @Schema(example = "0e695ea5-9249-4a75-a77a-eeac3ec1c2c0") diff --git a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/DatasourceType.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/DatasourceType.java new file mode 100644 index 0000000000000000000000000000000000000000..a4f8a83d8018237808206699231acba791807a2c --- /dev/null +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/DatasourceType.java @@ -0,0 +1,25 @@ +package at.ac.tuwien.ifs.dbrepo.core.api.database.query; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema +public enum DatasourceType { + + @JsonProperty("table") + TABLE("table"), + + @JsonProperty("view") + VIEW("view"); + + private final String name; + + DatasourceType(String name) { + this.name = name; + } + + @Override + public String toString() { + return this.name; + } +} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/FilterDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/FilterDto.java similarity index 93% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/FilterDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/FilterDto.java index 3fe8744661c4308d7403b950a15bfed104d9e5a1..2e6b1a03d7b5243612123b97e6df104b182f2807 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/FilterDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/FilterDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.query; +package at.ac.tuwien.ifs.dbrepo.core.api.database.query; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/FilterTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/FilterTypeDto.java similarity index 82% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/FilterTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/FilterTypeDto.java index eb9c12f7b2a19c85a79de149e356d4e362037daf..aab604117ca6b936874ec27eec0c36945904130d 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/FilterTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/FilterTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.query; +package at.ac.tuwien.ifs.dbrepo.core.api.database.query; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; @@ -15,7 +15,7 @@ public enum FilterTypeDto { @JsonProperty("and") AND("and"); - private String name; + private final String name; FilterTypeDto(String name) { this.name = name; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ImportDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/ImportDto.java similarity index 93% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ImportDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/ImportDto.java index 20817e017622ff5619cf1eaf284f238ba02dff4b..4a0a04abd655d4454ce900b03c2d69b333b1e4bb 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ImportDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/ImportDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.query; +package at.ac.tuwien.ifs.dbrepo.core.api.database.query; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/OrderDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/OrderDto.java similarity index 90% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/OrderDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/OrderDto.java index bb58ad483145927ee0f12fd60d553123228f488d..1412edf16a8354b09f90dc34b4f19838fe210124 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/OrderDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/OrderDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.query; +package at.ac.tuwien.ifs.dbrepo.core.api.database.query; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/OrderTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/OrderTypeDto.java similarity index 80% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/OrderTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/OrderTypeDto.java index ee05a75e47995ef1153a0d8517430cb103cbcc34..a7afcbcd5e9befed4632c3c78c4f35efc8270437 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/OrderTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/OrderTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.query; +package at.ac.tuwien.ifs.dbrepo.core.api.database.query; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; @@ -12,7 +12,7 @@ public enum OrderTypeDto { @JsonProperty("desc") DESC("desc"); - private String name; + private final String name; OrderTypeDto(String name) { this.name = name; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryBriefDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/QueryBriefDto.java similarity index 90% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryBriefDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/QueryBriefDto.java index c55a108cfcb215bca68e2d826ab09be39283cccf..24e3f60130d1de00bcf82ee6c14309fd2c387c62 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryBriefDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/QueryBriefDto.java @@ -1,7 +1,7 @@ -package at.tuwien.api.database.query; +package at.ac.tuwien.ifs.dbrepo.core.api.database.query; -import at.tuwien.api.identifier.IdentifierBriefDto; -import at.tuwien.api.user.UserBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserBriefDto; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/QueryDto.java similarity index 91% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/QueryDto.java index 24915a3dd5f4cbe82dd93744d214b2488b99acd5..58568fa4c3a8537ed5444207cf248284de3e062c 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/QueryDto.java @@ -1,8 +1,7 @@ -package at.tuwien.api.database.query; +package at.ac.tuwien.ifs.dbrepo.core.api.database.query; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.identifier.IdentifierBriefDto; -import at.tuwien.api.user.UserBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserBriefDto; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryPersistDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/QueryPersistDto.java similarity index 86% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryPersistDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/QueryPersistDto.java index 5bc3ac2054452f007c256917c8eaa6a3288f1a1a..90012d7a0309eca266e2d28c49d78c665d16020d 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryPersistDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/QueryPersistDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.query; +package at.ac.tuwien.ifs.dbrepo.core.api.database.query; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/QueryTypeDto.java similarity index 81% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/QueryTypeDto.java index 4df28733cdba0830b0e1579805284a92581c42bb..e19dccf0969f34b1a74516b6221588be24810817 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/QueryTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.query; +package at.ac.tuwien.ifs.dbrepo.core.api.database.query; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; @@ -12,7 +12,7 @@ public enum QueryTypeDto { @JsonProperty("view") VIEW("view"); - private String name; + private final String name; QueryTypeDto(String name) { this.name = name; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/SaveStatementDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/SaveStatementDto.java similarity index 87% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/SaveStatementDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/SaveStatementDto.java index 876dd5dfdd3c3f6a1e199138dfa7a3bfadc6292f..aaefacf7976ef09d5c33ff1ad2d3afa83479b2b5 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/SaveStatementDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/SaveStatementDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.query; +package at.ac.tuwien.ifs.dbrepo.core.api.database.query; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/SubsetDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/SubsetDto.java similarity index 75% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/SubsetDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/SubsetDto.java index 6e8c238417a7d81d65a08b639fb3ddcd9b1750df..5fb53d0741ed3740b1d045b2b524d58cb2e7a9e5 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/SubsetDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/query/SubsetDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.query; +package at.ac.tuwien.ifs.dbrepo.core.api.database.query; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; @@ -20,9 +20,13 @@ import java.util.UUID; public class SubsetDto { @NotNull - @JsonProperty("table_id") + @JsonProperty("datasource_id") @Schema(example = "f7df2a7d-4ade-4c78-97b0-7c744d0893c7") - private UUID tableId; + private UUID datasourceId; + + @NotNull + @JsonProperty("datasource_type") + private DatasourceType datasourceType; @NotNull @Schema(example = "[\"e891ba86-0258-41a6-a8d9-ff58bc10b618\"]") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/CreateTableDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/CreateTableDto.java similarity index 81% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/CreateTableDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/CreateTableDto.java index 15a798ee2d6bd237a6f578678d8885ca3b0f87dd..af2c3a80cce868d054faa10e687045654b1e43df 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/CreateTableDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/CreateTableDto.java @@ -1,7 +1,7 @@ -package at.tuwien.api.database.table; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table; -import at.tuwien.api.database.table.columns.CreateTableColumnDto; -import at.tuwien.api.database.table.constraints.CreateTableConstraintsDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.CreateTableColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.CreateTableConstraintsDto; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/HistoryEventTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/HistoryEventTypeDto.java similarity index 83% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/HistoryEventTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/HistoryEventTypeDto.java index 83d8441752b2922860997b2703131317ed69dd63..90a216c1242b0abc6cf4387616a38bb60eb90763 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/HistoryEventTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/HistoryEventTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; @@ -14,7 +14,7 @@ public enum HistoryEventTypeDto { @JsonProperty("delete") DELETE("delete"); - private String name; + private final String name; HistoryEventTypeDto(String name) { this.name = name; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/SortType.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/SortType.java similarity index 76% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/SortType.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/SortType.java index e101dfc9eb87c000fbbb72824ae44088203773dc..841587f4b09087f3f98830907c11fbefb3c98b68 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/SortType.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/SortType.java @@ -1,4 +1,4 @@ -package at.tuwien; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table; import com.fasterxml.jackson.annotation.JsonProperty; @@ -10,7 +10,7 @@ public enum SortType { @JsonProperty("desc") DESC("desc"); - private String type; + private final String type; SortType(String type) { this.type = type; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/SortTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/SortTypeDto.java similarity index 73% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/SortTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/SortTypeDto.java index 2964bb14968ef4c0740972fb7d2640f8df3f887c..0a7cbeeb4cf72cf35c5c287c45b7e6b722a067ec 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/SortTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/SortTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table; import com.fasterxml.jackson.annotation.JsonProperty; @@ -10,7 +10,7 @@ public enum SortTypeDto { @JsonProperty("desc") DESC("desc"); - private String type; + private final String type; SortTypeDto(String type) { this.type = type; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableBriefDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TableBriefDto.java similarity index 96% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableBriefDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TableBriefDto.java index 3ba910b97950253569a080246cd603ccec6d9854..92540c205193b21fca330cb3aed611d0bd2512f8 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableBriefDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TableBriefDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableCreateRawQuery.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TableCreateRawQuery.java similarity index 88% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableCreateRawQuery.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TableCreateRawQuery.java index ec221ae5f0ac5f1e9063a1cfbfcbcc2813f6ff60..8ba7b7ab6283cebeb2ca1f59040731e99c8fd00c 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableCreateRawQuery.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TableCreateRawQuery.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table; import lombok.*; import lombok.extern.jackson.Jacksonized; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TableDto.java similarity index 80% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TableDto.java index 3dde7091830b02f226a0526885986c264e93704d..9cb2848e5b010869ab53ebbb71585f0c35182b34 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TableDto.java @@ -1,14 +1,11 @@ -package at.tuwien.api.database.table; - -import at.tuwien.api.CacheableDto; -import at.tuwien.api.container.ContainerDto; -import at.tuwien.api.database.DatabaseBriefDto; -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; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table; + +import at.ac.tuwien.ifs.dbrepo.core.api.CacheableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.ConstraintsDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.IdentifierDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserBriefDto; +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; @@ -112,6 +109,11 @@ public class TableDto extends CacheableDto { @NotNull private ConstraintsDto constraints; + @NotNull + @Schema(example = "2022-01-01 08:00:00.000") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "UTC") + private Instant created; + /* lombok limitations prevent from convenient builder functions */ @JsonProperty("last_retrieved") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableHistoryDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TableHistoryDto.java similarity index 92% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableHistoryDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TableHistoryDto.java index e6ed6672350788bf3dc730a5273f0a5b35ec0c7d..3b6d8df35f64b9f55d1527f72d34b34663c2685a 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableHistoryDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TableHistoryDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableInsertRawQuery.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TableInsertRawQuery.java similarity index 85% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableInsertRawQuery.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TableInsertRawQuery.java index de6ff7feb7f35eeeb82fa8b028409268a473a7ed..caab6394143e732a46f6500d78eb4d06aacbdf27 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableInsertRawQuery.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TableInsertRawQuery.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table; import lombok.*; import lombok.extern.jackson.Jacksonized; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableStatisticDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TableStatisticDto.java similarity index 67% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableStatisticDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TableStatisticDto.java index 6b5529a0a1d08f75b803575e944cc5e624177eca..1b728df71cdabadfdc733921b317061536fd7f31 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableStatisticDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TableStatisticDto.java @@ -1,13 +1,13 @@ -package at.tuwien.api.database.table; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table; -import at.tuwien.api.database.table.columns.ColumnStatisticDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnStatisticDto; 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.Map; +import java.util.List; @Getter @Setter @@ -19,9 +19,14 @@ import java.util.Map; @ToString public class TableStatisticDto { - @JsonProperty("rows") + @JsonProperty("total_rows") @Schema(example = "5") - private Long rows; + private Long totalRows; + + @NotNull + @JsonProperty("total_columns") + @Schema(example = "2") + private Long totalColumns; @JsonProperty("data_length") @Schema(example = "16384", description = "in bytes") @@ -36,5 +41,5 @@ public class TableStatisticDto { private Long avgRowLength; @NotNull - private Map<String, ColumnStatisticDto> columns; + private List<ColumnStatisticDto> columns; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableUpdateDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TableUpdateDto.java similarity index 92% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableUpdateDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TableUpdateDto.java index d8db27005306a871fc3b8c250fcda5737abd79ef..f4fd37a37423c6fa4d453fd5cb56c4ed9668125a 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableUpdateDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TableUpdateDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleDeleteDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TupleDeleteDto.java similarity index 87% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleDeleteDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TupleDeleteDto.java index f74ffb3d89a1cfc5582be30e89ff0cb6a573f8c5..78d04b5361d12a3bdc0d7029b5a3709b6c64eebd 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleDeleteDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TupleDeleteDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TupleDto.java similarity index 87% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TupleDto.java index 13dc2b9723e763a5b255c762f1d94974ef90d074..db1d91770938c0f65716ac4e6e73638b3fe35b52 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TupleDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleUpdateDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TupleUpdateDto.java similarity index 89% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleUpdateDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TupleUpdateDto.java index ab3f1ae8758c69a9bfa0958e9a53e5326d8c91a9..eac3886de2bbdf6d866fbd4df34c8911ca9658be 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleUpdateDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/TupleUpdateDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnBriefDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/ColumnBriefDto.java similarity index 95% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnBriefDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/ColumnBriefDto.java index 08ee40caa46f977fe3b7bd81055d94ab18d410c5..8ebc4f9e386c7144d78353d94a47bf209398a0ad 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnBriefDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/ColumnBriefDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table.columns; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/ColumnDto.java similarity index 87% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/ColumnDto.java index 0df8efbf23e1aef143ed7d999cd9fd252e691349..d5c73436944cbbfacbe5ebbc7765a878738e2821 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/ColumnDto.java @@ -1,9 +1,8 @@ -package at.tuwien.api.database.table.columns; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns; -import at.tuwien.api.database.table.columns.concepts.ConceptBriefDto; -import at.tuwien.api.database.table.columns.concepts.UnitBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.concepts.ConceptBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.concepts.UnitBriefDto; import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; @@ -120,10 +119,10 @@ public class ColumnDto { @Schema(example = "false") private Boolean isNullAllowed; - @Parameter(description = "enum values, only considered when type = ENUM") + @Schema(description = "enum values, only considered when type = ENUM") private List<EnumDto> enums; - @Parameter(description = "enum values, only considered when type = ENUM") + @Schema(description = "enum values, only considered when type = ENUM") private List<SetDto> sets; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnStatisticDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/ColumnStatisticDto.java similarity index 80% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnStatisticDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/ColumnStatisticDto.java index a7d76a47b260b7eac7e6b2c39a7c768abedbbe3c..01f3e2b6527f42a7f93956eeacb9bc239f2bddef 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnStatisticDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/ColumnStatisticDto.java @@ -1,6 +1,7 @@ -package at.tuwien.api.database.table.columns; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.*; import lombok.extern.jackson.Jacksonized; @@ -17,6 +18,9 @@ import java.math.BigDecimal; @ToString public class ColumnStatisticDto { + @NotBlank + private String name; + @NotNull private BigDecimal mean; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/ColumnTypeDto.java similarity index 95% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/ColumnTypeDto.java index a96337082937c085e28957b7768a354dc5ed8dd6..fbe35b9c64160d82e5e9dc0ababdda1c6d229ce9 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/ColumnTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table.columns; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; @@ -99,7 +99,7 @@ public enum ColumnTypeDto { @JsonProperty("year") YEAR("year"); - private String type; + private final String type; ColumnTypeDto(String type) { this.type = type; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/CreateTableColumnDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/CreateTableColumnDto.java similarity index 95% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/CreateTableColumnDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/CreateTableColumnDto.java index 9733f64a163fcede451627fbbe2fc6a9b8df405d..b26ca9582a9de82b78596bde24d254a63130b830 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/CreateTableColumnDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/CreateTableColumnDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table.columns; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/EnumDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/EnumDto.java similarity index 88% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/EnumDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/EnumDto.java index 9038648513bb949a99895070cfcedf6e96260bbb..3a5889324fdfcb87d8c554cb27b2d49ce876232f 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/EnumDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/EnumDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table.columns; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/SetDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/SetDto.java similarity index 88% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/SetDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/SetDto.java index 6986212592d56a16633fc41b0b7ce4b28257bc97..cd0aa8c92113e0baa73f0e17dd4f920d00606d85 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/SetDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/SetDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table.columns; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/SiUnitDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/SiUnitDto.java similarity index 86% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/SiUnitDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/SiUnitDto.java index 70da894411e664c92db6ac47c5e1bbc2d5e1cdd6..2de0da75aea300756d708320d73a800fead1f668 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/SiUnitDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/SiUnitDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table.columns; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; @@ -27,7 +27,7 @@ public enum SiUnitDto { @JsonProperty("candela") CANDELA("candela"); - private String name; + private final String name; SiUnitDto(String name) { this.name = name; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ColumnSemanticsUpdateDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/concepts/ColumnSemanticsUpdateDto.java similarity index 83% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ColumnSemanticsUpdateDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/concepts/ColumnSemanticsUpdateDto.java index 9c74981f1416740ee6e5679d1ea2ed3fbc59e2bc..26d921cf8846508d4a9dfca7dc4e62bf62257163 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ColumnSemanticsUpdateDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/concepts/ColumnSemanticsUpdateDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table.columns.concepts; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.concepts; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ConceptBriefDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/concepts/ConceptBriefDto.java similarity index 91% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ConceptBriefDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/concepts/ConceptBriefDto.java index 160807e7aaf1e7c59e33dc7813a4d4691fd06ba3..0540dfbba40a4f5dbf78c439bb91bedabddd784c 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ConceptBriefDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/concepts/ConceptBriefDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table.columns.concepts; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.concepts; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ConceptDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/concepts/ConceptDto.java similarity index 80% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ConceptDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/concepts/ConceptDto.java index 13595569439bc999e40c58a2be29469883631909..29d906e90f40e54377c5cedceddfef0aff3b463f 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ConceptDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/concepts/ConceptDto.java @@ -1,6 +1,6 @@ -package at.tuwien.api.database.table.columns.concepts; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.concepts; -import at.tuwien.api.database.table.columns.ColumnBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnBriefDto; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ConceptSaveDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/concepts/ConceptSaveDto.java similarity index 83% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ConceptSaveDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/concepts/ConceptSaveDto.java index b61d911ef9b3141954fe041fa18f8ee9d1362680..bdfebd73ff1899935bcd1be020b006519fd81356 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ConceptSaveDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/concepts/ConceptSaveDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table.columns.concepts; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.concepts; import jakarta.validation.constraints.NotBlank; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/UnitBriefDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/concepts/UnitBriefDto.java similarity index 90% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/UnitBriefDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/concepts/UnitBriefDto.java index 789f3de1500900848205e0598e8fab89f9a50c11..47658b49cc7eaf6b6ac75fec66c4dbad0366067e 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/UnitBriefDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/concepts/UnitBriefDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table.columns.concepts; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.concepts; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/UnitDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/concepts/UnitDto.java similarity index 80% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/UnitDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/concepts/UnitDto.java index ca3899f7cc1f7d858d4e85fa0aa3107e6633dbf7..6af216e06783adbcfb7c970a414f9419e9768676 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/UnitDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/concepts/UnitDto.java @@ -1,6 +1,6 @@ -package at.tuwien.api.database.table.columns.concepts; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.concepts; -import at.tuwien.api.database.table.columns.ColumnBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnBriefDto; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/UnitSaveDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/concepts/UnitSaveDto.java similarity index 83% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/UnitSaveDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/concepts/UnitSaveDto.java index 530c7c8fbb806e8ffc2eac124f0bd6fec3321ea4..7a13c015212f8d1f09f8c863fd509c12f1a7724d 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/UnitSaveDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/columns/concepts/UnitSaveDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table.columns.concepts; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.concepts; import jakarta.validation.constraints.NotBlank; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/ConstraintsDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/ConstraintsDto.java similarity index 64% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/ConstraintsDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/ConstraintsDto.java index b9288b659bb7e2accb18c14e8258f631327d10f3..35648bd768a4c70c3298393bba47d04f53fbb6fd 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/ConstraintsDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/ConstraintsDto.java @@ -1,8 +1,8 @@ -package at.tuwien.api.database.table.constraints; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints; -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 at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign.ForeignKeyDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.primary.PrimaryKeyDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.unique.UniqueDto; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/CreateTableConstraintsDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/CreateTableConstraintsDto.java similarity index 79% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/CreateTableConstraintsDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/CreateTableConstraintsDto.java index 7b223372d2ae0057149e3b9ed95824c7a5baa05d..b2bf3ed73226ae752fc4c66a868f2bd60e20f9fc 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/CreateTableConstraintsDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/CreateTableConstraintsDto.java @@ -1,6 +1,6 @@ -package at.tuwien.api.database.table.constraints; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints; -import at.tuwien.api.database.table.constraints.foreign.CreateForeignKeyDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign.CreateForeignKeyDto; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotNull; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/CreateForeignKeyDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/foreign/CreateForeignKeyDto.java similarity index 92% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/CreateForeignKeyDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/foreign/CreateForeignKeyDto.java index 5e1d0a9f86c8055c69d5c4c03ac8f7c06aec6206..cfbba36281b3449ee481799d84d6db82208899af 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/CreateForeignKeyDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/foreign/CreateForeignKeyDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table.constraints.foreign; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyBriefDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/foreign/ForeignKeyBriefDto.java similarity index 81% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyBriefDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/foreign/ForeignKeyBriefDto.java index 4acc205efdebaec4b6e82c322a539d9fb945a30c..307d57af0181a1ddd4eff4e9be91def2cafe6f73 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyBriefDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/foreign/ForeignKeyBriefDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table.constraints.foreign; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/foreign/ForeignKeyDto.java similarity index 81% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/foreign/ForeignKeyDto.java index 94063c77dc579a13aad2c52af5ac32739fdf89d0..625156027a1b99690c2f412659d8996dbbfffb6a 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/foreign/ForeignKeyDto.java @@ -1,8 +1,6 @@ -package at.tuwien.api.database.table.constraints.foreign; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign; -import at.tuwien.api.database.table.TableBriefDto; -import at.tuwien.api.database.table.TableDto; -import at.tuwien.api.database.table.columns.ColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableBriefDto; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyReferenceDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/foreign/ForeignKeyReferenceDto.java similarity index 81% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyReferenceDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/foreign/ForeignKeyReferenceDto.java index 2423b92a624042f6b638b8baa1b1dbe818b14235..4beab3e1eea19901c42c73ab11fec6346f04051e 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyReferenceDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/foreign/ForeignKeyReferenceDto.java @@ -1,6 +1,6 @@ -package at.tuwien.api.database.table.constraints.foreign; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign; -import at.tuwien.api.database.table.columns.ColumnBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnBriefDto; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ReferenceTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/foreign/ReferenceTypeDto.java similarity index 93% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ReferenceTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/foreign/ReferenceTypeDto.java index 239b95e7e916a01e596e78e41154d0fdae6e9bf8..a2467407182b9a1c420cb61cb3404406669fd266 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ReferenceTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/foreign/ReferenceTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.database.table.constraints.foreign; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/primary/PrimaryKeyDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/primary/PrimaryKeyDto.java similarity index 68% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/primary/PrimaryKeyDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/primary/PrimaryKeyDto.java index 59117a579576e86cd9b01828695de57aaece9fd7..74d55ead188a1b047ba8387ff53e76735d105fca 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/primary/PrimaryKeyDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/primary/PrimaryKeyDto.java @@ -1,7 +1,7 @@ -package at.tuwien.api.database.table.constraints.primary; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.primary; -import at.tuwien.api.database.table.TableBriefDto; -import at.tuwien.api.database.table.columns.ColumnBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnBriefDto; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/unique/UniqueDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/unique/UniqueDto.java similarity index 72% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/unique/UniqueDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/unique/UniqueDto.java index 64db6dfde0b0ce6d8de017a0cba9f61c7e64d304..6f1c613779df3e4976883abf404ce6c13f6b6805 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/unique/UniqueDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/constraints/unique/UniqueDto.java @@ -1,7 +1,7 @@ -package at.tuwien.api.database.table.constraints.unique; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.unique; -import at.tuwien.api.database.table.TableBriefDto; -import at.tuwien.api.database.table.columns.ColumnBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnBriefDto; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/internal/TableCreateDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/internal/TableCreateDto.java similarity index 80% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/internal/TableCreateDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/internal/TableCreateDto.java index f8db928e8e9bb3d7491e67ea36756b95749a4482..200bfef48f1562a970cd699c8a2583e82ae8a44f 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/internal/TableCreateDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/database/table/internal/TableCreateDto.java @@ -1,7 +1,7 @@ -package at.tuwien.api.database.table.internal; +package at.ac.tuwien.ifs.dbrepo.core.api.database.table.internal; -import at.tuwien.api.database.table.columns.CreateTableColumnDto; -import at.tuwien.api.database.table.constraints.CreateTableConstraintsDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.CreateTableColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.CreateTableConstraintsDto; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/DataCiteBody.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/DataCiteBody.java similarity index 84% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/DataCiteBody.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/DataCiteBody.java index 8ef874acba25e24be3ad2e8240bfea157e1cdffc..272484e84a15b7bb98a36ca67bc2af033c4372aa 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/DataCiteBody.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/DataCiteBody.java @@ -1,4 +1,4 @@ -package at.tuwien.api.datacite; +package at.ac.tuwien.ifs.dbrepo.core.api.datacite; import lombok.*; import lombok.extern.jackson.Jacksonized; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/DataCiteData.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/DataCiteData.java similarity index 89% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/DataCiteData.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/DataCiteData.java index 62b8ad411c343b30188e5feaffb87d2b473f6568..1209e36fd3eeaa2a4372dd2eaea793a120cc30b9 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/DataCiteData.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/DataCiteData.java @@ -1,4 +1,4 @@ -package at.tuwien.api.datacite; +package at.ac.tuwien.ifs.dbrepo.core.api.datacite; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/DataCiteError.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/DataCiteError.java similarity index 84% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/DataCiteError.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/DataCiteError.java index dcbc312d31d2ac4ac6a5799ba96876ce9f5854f8..872de43921485906b975ab16a8da7d8e4359bf62 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/DataCiteError.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/DataCiteError.java @@ -1,4 +1,4 @@ -package at.tuwien.api.datacite; +package at.ac.tuwien.ifs.dbrepo.core.api.datacite; import lombok.*; import lombok.extern.jackson.Jacksonized; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteCreateDoi.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteCreateDoi.java similarity index 94% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteCreateDoi.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteCreateDoi.java index 24da7bc82a2cfbfd5346abd87bcfc66e6cf9dd27..27749b4b33a80c292dfd0ae34c809926170de13f 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteCreateDoi.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteCreateDoi.java @@ -1,4 +1,4 @@ -package at.tuwien.api.datacite.doi; +package at.ac.tuwien.ifs.dbrepo.core.api.datacite.doi; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoi.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoi.java similarity index 86% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoi.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoi.java index 5d3e0b2c1e30f2924e2ef6fa6dd3710f7e1d5507..837f38143dfcae0129fcd3b3c9c3ab427ed50ed9 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoi.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoi.java @@ -1,4 +1,4 @@ -package at.tuwien.api.datacite.doi; +package at.ac.tuwien.ifs.dbrepo.core.api.datacite.doi; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiCreator.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiCreator.java similarity index 92% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiCreator.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiCreator.java index 3d093adf74d7bf9cc834f87bf0d9362c737b2d2b..a95a9dd1213f193161a0d3e0c4eddafab66072c8 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiCreator.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiCreator.java @@ -1,4 +1,4 @@ -package at.tuwien.api.datacite.doi; +package at.ac.tuwien.ifs.dbrepo.core.api.datacite.doi; import jakarta.validation.constraints.NotNull; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiCreatorAffiliation.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiCreatorAffiliation.java similarity index 87% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiCreatorAffiliation.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiCreatorAffiliation.java index a361452b96dcae2cb0de304df4011f88f930c790..b07a86eea3c9ad4cf42140118e3dabe0387e8528 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiCreatorAffiliation.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiCreatorAffiliation.java @@ -1,4 +1,4 @@ -package at.tuwien.api.datacite.doi; +package at.ac.tuwien.ifs.dbrepo.core.api.datacite.doi; import lombok.*; import lombok.extern.jackson.Jacksonized; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiCreatorNameIdentifier.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiCreatorNameIdentifier.java similarity index 86% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiCreatorNameIdentifier.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiCreatorNameIdentifier.java index 449c814171c45070a74b8e62447893f82b3ca0dc..a75f6fc333499530ac6aa67bc751297da104c2db 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiCreatorNameIdentifier.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiCreatorNameIdentifier.java @@ -1,4 +1,4 @@ -package at.tuwien.api.datacite.doi; +package at.ac.tuwien.ifs.dbrepo.core.api.datacite.doi; import lombok.*; import lombok.extern.jackson.Jacksonized; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiEvent.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiEvent.java similarity index 90% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiEvent.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiEvent.java index 35b6c670da99c68d75754fd9ea0c9c75768d152d..5c753dd6b6444c45002cb5805f27962ea3073bee 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiEvent.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiEvent.java @@ -1,4 +1,4 @@ -package at.tuwien.api.datacite.doi; +package at.ac.tuwien.ifs.dbrepo.core.api.datacite.doi; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiFundingReference.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiFundingReference.java similarity index 88% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiFundingReference.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiFundingReference.java index 595c808a24ec96e2e1e9bf36235b590b3c09911e..546094183cef6aba87ec8f47a6c63a44f0a3e962 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiFundingReference.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiFundingReference.java @@ -1,4 +1,4 @@ -package at.tuwien.api.datacite.doi; +package at.ac.tuwien.ifs.dbrepo.core.api.datacite.doi; import lombok.*; import lombok.extern.jackson.Jacksonized; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiFundingReferenceIdentifier.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiFundingReferenceIdentifier.java similarity index 85% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiFundingReferenceIdentifier.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiFundingReferenceIdentifier.java index 1bdc94605f935766ebd89e9a9d32c8a683cb6f2e..00fedaa15bdd1a1a6ca52acd6f30572a01d9eb79 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiFundingReferenceIdentifier.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiFundingReferenceIdentifier.java @@ -1,4 +1,4 @@ -package at.tuwien.api.datacite.doi; +package at.ac.tuwien.ifs.dbrepo.core.api.datacite.doi; import lombok.*; import lombok.extern.jackson.Jacksonized; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiRelatedIdentifier.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiRelatedIdentifier.java similarity index 88% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiRelatedIdentifier.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiRelatedIdentifier.java index d446029eae714ac0146bbe70ff7eb71d2ab5df94..3e246944d9ab54d37bbea47c30e584aeeaab0511 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiRelatedIdentifier.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiRelatedIdentifier.java @@ -1,4 +1,4 @@ -package at.tuwien.api.datacite.doi; +package at.ac.tuwien.ifs.dbrepo.core.api.datacite.doi; import lombok.*; import lombok.extern.jackson.Jacksonized; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiRights.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiRights.java similarity index 85% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiRights.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiRights.java index 4a53c7f7c5b651d5e88f2111473a443eb19a066d..0bef60756ff411aee8f4bee802e2bbc3e5b494ba 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiRights.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiRights.java @@ -1,4 +1,4 @@ -package at.tuwien.api.datacite.doi; +package at.ac.tuwien.ifs.dbrepo.core.api.datacite.doi; import lombok.*; import lombok.extern.jackson.Jacksonized; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiTitle.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiTitle.java similarity index 94% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiTitle.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiTitle.java index a0358da69a1aead0263a679b3fe4ceca7ff87abb..38114a19cda7ed3dbc30d406da7a6423f748c423 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiTitle.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiTitle.java @@ -1,4 +1,4 @@ -package at.tuwien.api.datacite.doi; +package at.ac.tuwien.ifs.dbrepo.core.api.datacite.doi; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiTypes.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiTypes.java similarity index 91% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiTypes.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiTypes.java index 778853ce78e6ea24a2b1748b8ffbb977a9211a80..c69ece3ac076e8d4bd07d0ecbe579df28bd239ee 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteDoiTypes.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteDoiTypes.java @@ -1,4 +1,4 @@ -package at.tuwien.api.datacite.doi; +package at.ac.tuwien.ifs.dbrepo.core.api.datacite.doi; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteNameType.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteNameType.java similarity index 82% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteNameType.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteNameType.java index b9940ab5f49900611589e61c4e2f7381db5222b8..c6e551e5335649be52ca801b862c11e53b6e7682 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/datacite/doi/DataCiteNameType.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/datacite/doi/DataCiteNameType.java @@ -1,4 +1,4 @@ -package at.tuwien.api.datacite.doi; +package at.ac.tuwien.ifs.dbrepo.core.api.datacite.doi; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; @@ -12,7 +12,7 @@ public enum DataCiteNameType { @JsonProperty("Organizational") ORGANIZATIONAL("Organizational"); - private String name; + private final String name; DataCiteNameType(String name) { this.name = name; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/error/ApiErrorDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/error/ApiErrorDto.java similarity index 92% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/error/ApiErrorDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/error/ApiErrorDto.java index bb271f5ed6065595898f0a4f73b9758f66da2294..49ea5af60f99807e277cab80074248651285c964 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/error/ApiErrorDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/error/ApiErrorDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.error; +package at.ac.tuwien.ifs.dbrepo.core.api.error; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/file/UploadResponseDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/file/UploadResponseDto.java similarity index 86% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/file/UploadResponseDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/file/UploadResponseDto.java index 3b1cdab22301aa8d97a9427d9fc58fe5398d542d..6a8b9b818b2267f24d0cf31d173b59d82c72a9a3 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/file/UploadResponseDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/file/UploadResponseDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.file; +package at.ac.tuwien.ifs.dbrepo.core.api.file; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; diff --git a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/grafana/AccessTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/grafana/AccessTypeDto.java new file mode 100644 index 0000000000000000000000000000000000000000..39447d8e730e260852e2070bcf1e6923af2a7e55 --- /dev/null +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/grafana/AccessTypeDto.java @@ -0,0 +1,24 @@ +package at.ac.tuwien.ifs.dbrepo.core.api.grafana; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; + +@Getter +@Schema +public enum AccessTypeDto { + + @JsonProperty("proxy") + PROXY("proxy"); + + private final String name; + + AccessTypeDto(String name) { + this.name = name; + } + + @Override + public String toString() { + return this.name; + } +} diff --git a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/grafana/CreateDashboardDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/grafana/CreateDashboardDto.java new file mode 100644 index 0000000000000000000000000000000000000000..6b7a879b5b17a116b8c639496f4bd09f41658d02 --- /dev/null +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/grafana/CreateDashboardDto.java @@ -0,0 +1,39 @@ +package at.ac.tuwien.ifs.dbrepo.core.api.grafana; + +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 CreateDashboardDto { + + @NotNull + @JsonProperty("database_name") + @Schema(example = "Some Database") + private String databaseName; + + @NotNull + @JsonProperty("is_public") + @Schema(example = "true") + private Boolean isPublic; + + @NotNull + @JsonProperty("is_schema_public") + @Schema(example = "true") + private Boolean isSchemaPublic; + + @NotBlank + @JsonProperty("owner_username") + @Schema(example = "foobar") + private String ownerUsername; +} diff --git a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/grafana/CreateDashboardResponseDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/grafana/CreateDashboardResponseDto.java new file mode 100644 index 0000000000000000000000000000000000000000..cc4bcfa40bc67ecce126c881a754835161891d7b --- /dev/null +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/grafana/CreateDashboardResponseDto.java @@ -0,0 +1,25 @@ +package at.ac.tuwien.ifs.dbrepo.core.api.grafana; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.*; +import lombok.extern.jackson.Jacksonized; + +@Getter +@Setter +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Jacksonized +@ToString +public class CreateDashboardResponseDto { + + @NotNull + @Schema(example = "3") + private Long id; + + @NotNull + @Schema(example = "eeckcuwfsfbi8b") + private String uid; +} diff --git a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/grafana/DatasourceDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/grafana/DatasourceDto.java new file mode 100644 index 0000000000000000000000000000000000000000..e670c99ff6c4ff68f4923e02abd64a82d7603b9b --- /dev/null +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/grafana/DatasourceDto.java @@ -0,0 +1,80 @@ +package at.ac.tuwien.ifs.dbrepo.core.api.grafana; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.*; +import lombok.extern.jackson.Jacksonized; + +@Getter +@Setter +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@JsonIgnoreProperties(ignoreUnknown = true) +@Jacksonized +@ToString +public class DatasourceDto { + + @NotNull + @Schema(example = "1") + private Long id; + + @NotNull + @Schema(example = "kLtEtcRGk") + private String uid; + + @NotNull + @Schema(example = "1") + private Long orgId; + + @NotNull + @Schema(example = "some_datasource") + private String name; + + @NotNull + @Schema(example = "plugins/logo.svg") + private String typeLogoUrl; + + @NotNull + @Schema(example = "PROXY") + private AccessTypeDto access; + + @Schema(example = "http://example.com") + private String url; + + @Schema(example = "s3cr3t") + private String password; + + @Schema(example = "user") + private String user; + + @Schema(example = "true") + private Boolean basicAuth; + + @Schema(example = "user") + private String basicAuthUser; + + @Schema(example = "s3cr3t") + private String basicAuthPassword; + + @Schema(example = "false") + private Boolean withCredentials; + + @Schema(example = "false") + private Boolean isDefault; + + @NotNull + @Schema(example = "true") + private Boolean readOnly; + + @NotNull + @Schema(example = "INFINITY") + private DatasourceTypeDto type; + + @NotNull + @Schema(example = "0") + private Integer version; + +} diff --git a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/grafana/DatasourceTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/grafana/DatasourceTypeDto.java new file mode 100644 index 0000000000000000000000000000000000000000..e708ccf6a89809bbfa8cd7ca917a2f6a6769178d --- /dev/null +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/grafana/DatasourceTypeDto.java @@ -0,0 +1,24 @@ +package at.ac.tuwien.ifs.dbrepo.core.api.grafana; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; + +@Getter +@Schema +public enum DatasourceTypeDto { + + @JsonProperty("yesoreyeram-infinity-datasource") + INFINITY("yesoreyeram-infinity-datasource"); + + private final String name; + + DatasourceTypeDto(String name) { + this.name = name; + } + + @Override + public String toString() { + return this.name; + } +} diff --git a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/grafana/PermissionTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/grafana/PermissionTypeDto.java new file mode 100644 index 0000000000000000000000000000000000000000..f9561da03773946e9ad1a4f462f53219fcfe12a8 --- /dev/null +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/grafana/PermissionTypeDto.java @@ -0,0 +1,33 @@ +package at.ac.tuwien.ifs.dbrepo.core.api.grafana; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; + +@Getter +@Schema +public enum PermissionTypeDto { + + @JsonProperty("View") + VIEW("View"), + + @JsonProperty("Editor") + EDITOR("Editor"), + + @JsonProperty("Admin") + ADMIN("Admin"), + + @JsonProperty("") + NONE(""); + + private final String name; + + PermissionTypeDto(String name) { + this.name = name; + } + + @Override + public String toString() { + return this.name; + } +} diff --git a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/grafana/UpdateDashboardAccessDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/grafana/UpdateDashboardAccessDto.java new file mode 100644 index 0000000000000000000000000000000000000000..08d755e1115e15231e0be07e7f9e83b5ba4bbd26 --- /dev/null +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/grafana/UpdateDashboardAccessDto.java @@ -0,0 +1,21 @@ +package at.ac.tuwien.ifs.dbrepo.core.api.grafana; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.*; +import lombok.extern.jackson.Jacksonized; + +@Getter +@Setter +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Jacksonized +@ToString +public class UpdateDashboardAccessDto { + + @NotNull + @Schema(example = "View") + private PermissionTypeDto permission; +} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/AffiliationIdentifierSchemeTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/AffiliationIdentifierSchemeTypeDto.java similarity index 67% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/AffiliationIdentifierSchemeTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/AffiliationIdentifierSchemeTypeDto.java index 3c089e6454f0121bbea61fd17bbdd6a55e02c9b6..ba881921ac2b0e9f970d7a3f86751e46e4593f40 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/AffiliationIdentifierSchemeTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/AffiliationIdentifierSchemeTypeDto.java @@ -1,5 +1,5 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; import lombok.Getter; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/BibliographyTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/BibliographyTypeDto.java similarity index 83% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/BibliographyTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/BibliographyTypeDto.java index 9da9afbc0b1733fa75a710e035a67ec552287f97..d89935553cc580ce6a9c6da8a17c2330e6aff759 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/BibliographyTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/BibliographyTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; @@ -15,7 +15,7 @@ public enum BibliographyTypeDto { @JsonProperty("bibtex") BIBTEX("bibtex"); - private String name; + private final String name; BibliographyTypeDto(String name) { this.name = name; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreateIdentifierDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/CreateIdentifierDto.java similarity index 91% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreateIdentifierDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/CreateIdentifierDto.java index 5f2e73fc07badf436c3527fc8423b21d641967b7..286d04dc3b849264b79ad439742d2d70aa025f7f 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreateIdentifierDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/CreateIdentifierDto.java @@ -1,7 +1,7 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; -import at.tuwien.api.database.LanguageTypeDto; -import at.tuwien.api.database.LicenseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.LanguageTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.LicenseDto; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorBriefDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/CreatorBriefDto.java similarity index 96% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorBriefDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/CreatorBriefDto.java index 95b0d588f7bccc0c812c3bd823f94022d3da9d38..f5a1d9489780f1d359eab294aa6cb6727685f455 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorBriefDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/CreatorBriefDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/CreatorDto.java similarity index 95% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/CreatorDto.java index 1382baec51d8f3de1b048fafc8d8f564aecc6e4f..b98985c1c43f1b9b20d35f9391eb5460ef25ab32 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/CreatorDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; @@ -7,7 +7,6 @@ import lombok.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.extern.jackson.Jacksonized; -import org.springframework.data.annotation.Id; import java.util.UUID; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/DescriptionTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/DescriptionTypeDto.java similarity index 88% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/DescriptionTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/DescriptionTypeDto.java index c98c0a1f33e882b622e766b5db6f374641b75f7f..7ddab3278477c6c1c781dd867a45681a0c04dcc6 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/DescriptionTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/DescriptionTypeDto.java @@ -1,5 +1,5 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; @@ -25,7 +25,7 @@ public enum DescriptionTypeDto { @JsonProperty("Other") OTHER("Other"); - private String name; + private final String name; DescriptionTypeDto(String name) { this.name = name; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierBriefDto.java similarity index 96% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierBriefDto.java index 0434d1b21fe85c60b0596507e65e1bb7a67b3be9..74f60ab15374b1f9ea452e06390059be11c1e74b 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierBriefDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDescriptionDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierDescriptionDto.java similarity index 85% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDescriptionDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierDescriptionDto.java index 32ff2455ccde07b8d8ce39ad674245d65dd21174..e491fd674499b71de6e1a1dc9ccbdcadd7fb47f1 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDescriptionDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierDescriptionDto.java @@ -1,12 +1,11 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; -import at.tuwien.api.database.LanguageTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.LanguageTypeDto; 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 org.springframework.data.annotation.Id; import java.util.UUID; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierDto.java similarity index 92% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierDto.java index 0bc16d61cd9a1dc45c129184ec18cfb49ed0d754..35293a6d9e456522c9c9f366ad8f37c7b1dbbf1e 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierDto.java @@ -1,8 +1,8 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; -import at.tuwien.api.database.LanguageTypeDto; -import at.tuwien.api.database.LicenseDto; -import at.tuwien.api.user.UserBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.LanguageTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.LicenseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserBriefDto; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierFunderDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierFunderDto.java similarity index 93% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierFunderDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierFunderDto.java index 4184f2cf2afade6121711cca63a629b047156120..741e1ac1ac400d80bd7790f45bdcacfeacbaf87b 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierFunderDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierFunderDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; @@ -6,7 +6,6 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.*; import lombok.extern.jackson.Jacksonized; -import org.springframework.data.annotation.Id; import java.util.UUID; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierFunderTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierFunderTypeDto.java similarity index 86% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierFunderTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierFunderTypeDto.java index 70a6d36f26263ed02e1ae69a17b03d43094dd27d..6682bac43a0cfa8334ce37aaa68d9f89f468b831 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierFunderTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierFunderTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; @@ -21,7 +21,7 @@ public enum IdentifierFunderTypeDto { @JsonProperty("Other") OTHER("Other"); - private String name; + private final String name; IdentifierFunderTypeDto(String name) { this.name = name; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierSaveDto.java similarity index 91% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierSaveDto.java index f63c3ae79cdc84c9c4ec85edb62917282e06c815..2054e84012e3128dd46c7de15425e0c0758ac51b 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierSaveDto.java @@ -1,7 +1,7 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; -import at.tuwien.api.database.LanguageTypeDto; -import at.tuwien.api.database.LicenseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.LanguageTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.LicenseDto; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierStatusTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierStatusTypeDto.java similarity index 82% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierStatusTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierStatusTypeDto.java index 2c7f4527b1f06b2a591e91afff59b120d4b57cfb..655c670a359f8ef343140752f4892a0fa5cd0e3c 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierStatusTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierStatusTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; @@ -12,7 +12,7 @@ public enum IdentifierStatusTypeDto { @JsonProperty("published") PUBLISHED("published"); - private String name; + private final String name; IdentifierStatusTypeDto(String name) { this.name = name; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierTitleDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierTitleDto.java similarity index 84% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierTitleDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierTitleDto.java index d995527d88d281e22f96b220cd0566e05811dbbc..829454134d5fa112873b65bd0ac246d97f3400a0 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierTitleDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierTitleDto.java @@ -1,12 +1,11 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; -import at.tuwien.api.database.LanguageTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.LanguageTypeDto; 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 org.springframework.data.annotation.Id; import java.util.UUID; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierTypeDto.java similarity index 84% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierTypeDto.java index 19660e324d3f4e388135691662d74c048f684826..bca87f3cd81bf0b117edd239dbdd80be88e0d86f 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/IdentifierTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; @@ -18,7 +18,7 @@ public enum IdentifierTypeDto { @JsonProperty("view") VIEW("view"); - private String name; + private final String name; IdentifierTypeDto(String name) { this.name = name; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/LinksDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/LinksDto.java similarity index 77% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/LinksDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/LinksDto.java index fcef2a659750d9cf6b78bdc54b4a627dbcc0935d..9b3461ea47b05dd1bdc78d7cb54b051a9db649c8 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/LinksDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/LinksDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; @@ -29,4 +29,8 @@ public class LinksDto { @Schema(example = "http://example.com") private String data; + @JsonProperty("dashboard_html") + @Schema(example = "http://example.com/d/defi2baxqawaod") + private String dashboardHtml; + } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/NameIdentifierSchemeTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/NameIdentifierSchemeTypeDto.java similarity index 68% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/NameIdentifierSchemeTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/NameIdentifierSchemeTypeDto.java index 3ea4c2d7f843e57ee819322a667403b60db3751f..028abf15f264eb0daad80df42e7a2b98b239e6d7 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/NameIdentifierSchemeTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/NameIdentifierSchemeTypeDto.java @@ -1,5 +1,5 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; import lombok.Getter; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/NameTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/NameTypeDto.java similarity index 82% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/NameTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/NameTypeDto.java index d9f2a16bf5fedfcd58547710d033cf14ff423c92..6de88e1bb1e8df743f9b07879b0363a0b2389f2e 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/NameTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/NameTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; @@ -12,7 +12,7 @@ public enum NameTypeDto { @JsonProperty("Organizational") ORGANIZATIONAL("Organizational"); - private String name; + private final String name; NameTypeDto(String name) { this.name = name; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelatedIdentifierDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/RelatedIdentifierDto.java similarity index 69% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelatedIdentifierDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/RelatedIdentifierDto.java index 7205bc6e0b76e823bb3d2405aced77dd41b9adb5..5aec4780645d8bf084b60f3da803e466a7bdb2f2 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelatedIdentifierDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/RelatedIdentifierDto.java @@ -1,17 +1,11 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; -import at.tuwien.api.user.UserDto; -import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; import jakarta.validation.constraints.NotNull; import lombok.extern.jackson.Jacksonized; -import org.springframework.data.annotation.Id; -import java.time.Instant; import java.util.UUID; @Getter diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelatedTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/RelatedTypeDto.java similarity index 92% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelatedTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/RelatedTypeDto.java index 1e75513abc7639b23ce5ded2169b6e5c17f02163..76fabca0292b0b1df84a288ff2db71233e8744d7 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelatedTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/RelatedTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; @@ -60,7 +60,7 @@ public enum RelatedTypeDto { @JsonProperty("w3id") W3ID("w3id"); - private String name; + private final String name; RelatedTypeDto(String name) { this.name = name; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelationTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/RelationTypeDto.java similarity index 96% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelationTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/RelationTypeDto.java index fb43cc5b4617866d571690f83f14d7a75fafe248..bc43f0c81e9a0dca122e6b1d142f66fb961c0ec5 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelationTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/RelationTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; @@ -108,7 +108,7 @@ public enum RelationTypeDto { @JsonProperty("Obsoletes") OBSOLETES("Obsoletes"); - private String name; + private final String name; RelationTypeDto(String name) { this.name = name; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierCreatorDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/SaveIdentifierCreatorDto.java similarity index 96% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierCreatorDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/SaveIdentifierCreatorDto.java index 0866a5cb3b5dc36f7ad0484dddf860c7371816d9..ce3d92480b384f3d2eb324ee3fc8aed307d25258 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierCreatorDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/SaveIdentifierCreatorDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierDescriptionDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/SaveIdentifierDescriptionDto.java similarity index 87% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierDescriptionDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/SaveIdentifierDescriptionDto.java index bc1ad4f3dfd98fbbbd4c2edc1d73f562cc1f0d23..0abfa7312826430b4cb1fe63e83ee0861e222bdb 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierDescriptionDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/SaveIdentifierDescriptionDto.java @@ -1,6 +1,6 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; -import at.tuwien.api.database.LanguageTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.LanguageTypeDto; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierFunderDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/SaveIdentifierFunderDto.java similarity index 95% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierFunderDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/SaveIdentifierFunderDto.java index 1709c109b28a9aa3c57c10bcea1589d445d91c6c..f877f458295fd56ac015583ff1ac575a34d4a5bb 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierFunderDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/SaveIdentifierFunderDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierTitleDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/SaveIdentifierTitleDto.java similarity index 86% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierTitleDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/SaveIdentifierTitleDto.java index 07ebc35e2ca6ce2458746ee9253dbf9dc296a337..99a95c45d5fa341924940dd0a12b946557560ede 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierTitleDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/SaveIdentifierTitleDto.java @@ -1,6 +1,6 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; -import at.tuwien.api.database.LanguageTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.LanguageTypeDto; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveRelatedIdentifierDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/SaveRelatedIdentifierDto.java similarity index 92% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveRelatedIdentifierDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/SaveRelatedIdentifierDto.java index d22c8216e366d602e119abe824af6f543a5fac8f..ccb47cac439a093b8edb226f425d49fc18210544 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveRelatedIdentifierDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/SaveRelatedIdentifierDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/TitleTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/TitleTypeDto.java similarity index 86% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/TitleTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/TitleTypeDto.java index 72b30dd315da60a6051a2e7ecd0a87d23fd479ff..d1d5379a7eeac75ef5054f732dc5424866c8bc72 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/TitleTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/TitleTypeDto.java @@ -1,5 +1,5 @@ -package at.tuwien.api.identifier; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; @@ -19,7 +19,7 @@ public enum TitleTypeDto { @JsonProperty("Other") OTHER("Other"); - private String name; + private final String name; TitleTypeDto(String name) { this.name = name; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/ld/LdCreatorDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/ld/LdCreatorDto.java similarity index 89% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/ld/LdCreatorDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/ld/LdCreatorDto.java index 0bde2d2968b8bba6f6656056b31ddcf42f73753e..8d983afb3d7f5acd0aff89d5b0b64f214c60d6b9 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/ld/LdCreatorDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/ld/LdCreatorDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.identifier.ld; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier.ld; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/ld/LdDatasetDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/ld/LdDatasetDto.java similarity index 94% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/ld/LdDatasetDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/ld/LdDatasetDto.java index bab1deb2d16dfa005c2a08273afc6fb8d33b8841..e599f66d8ce6915661011bd9851e349d58492c4e 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/ld/LdDatasetDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/identifier/ld/LdDatasetDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.identifier.ld; +package at.ac.tuwien.ifs.dbrepo.core.api.identifier.ld; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/CredentialDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/CredentialDto.java similarity index 89% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/CredentialDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/CredentialDto.java index 172b844e1bf4e6b3fd77ab1530a9a8578255d2c6..71a279519d103651bf00d0a88d14e603beeaa18e 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/CredentialDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/CredentialDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.keycloak; +package at.ac.tuwien.ifs.dbrepo.core.api.keycloak; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/CredentialTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/CredentialTypeDto.java similarity index 79% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/CredentialTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/CredentialTypeDto.java index 4992f74cf96955ef10117a9de4663144fadb7bcb..71530c5edc770974e7dafed54ec16061abd257a7 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/CredentialTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/CredentialTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.keycloak; +package at.ac.tuwien.ifs.dbrepo.core.api.keycloak; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; @@ -9,7 +9,7 @@ public enum CredentialTypeDto { @JsonProperty("password") PASSWORD("password"); - private String name; + private final String name; CredentialTypeDto(String name) { this.name = name; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/ModifyUserDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/ModifyUserDto.java similarity index 90% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/ModifyUserDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/ModifyUserDto.java index 26d700e798e1517ae484dc60e9359bd8b5646965..8ad43b34c2533843183ec63fbd9cc055ad03a390 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/ModifyUserDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/ModifyUserDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.keycloak; +package at.ac.tuwien.ifs.dbrepo.core.api.keycloak; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/RoleRepresentationDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/RoleRepresentationDto.java similarity index 91% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/RoleRepresentationDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/RoleRepresentationDto.java index 8f7d795fdbb0a529fa4492c18f9028016e306d9e..bc3137d421a292d409e972d57ff32aca65d2a49e 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/RoleRepresentationDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/RoleRepresentationDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.keycloak; +package at.ac.tuwien.ifs.dbrepo.core.api.keycloak; import lombok.*; import lombok.extern.jackson.Jacksonized; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/TokenDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/TokenDto.java similarity index 92% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/TokenDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/TokenDto.java index dcd14c4d2a469b0bdfe88166aae9afba8048ba4c..8cde17a095dd955b6c4c62d96e23c973b2c5c7f0 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/TokenDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/TokenDto.java @@ -1,6 +1,6 @@ -package at.tuwien.api.keycloak; +package at.ac.tuwien.ifs.dbrepo.core.api.keycloak; -import at.tuwien.api.CacheableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.CacheableDto; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UpdateCredentialsDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/UpdateCredentialsDto.java similarity index 86% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UpdateCredentialsDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/UpdateCredentialsDto.java index c8bac04d455afa80bc061b7e391ed38e10f2edd1..3994b1aaab92eea9fc25fd9eab0256cc9ed824c7 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UpdateCredentialsDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/UpdateCredentialsDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.keycloak; +package at.ac.tuwien.ifs.dbrepo.core.api.keycloak; import jakarta.validation.constraints.NotNull; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserAttributesDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/UserAttributesDto.java similarity index 92% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserAttributesDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/UserAttributesDto.java index 50718bc8034d500c2d707abacac58acf2bb95012..0e7ab89f66297f8368aefe7ef8c3e9d39f38c57b 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserAttributesDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/UserAttributesDto.java @@ -1,12 +1,10 @@ -package at.tuwien.api.keycloak; +package at.ac.tuwien.ifs.dbrepo.core.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 diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserCreateAttributesDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/UserCreateAttributesDto.java similarity index 85% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserCreateAttributesDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/UserCreateAttributesDto.java index 6df8ce5e8f733313e9c9f2534e6cef03adb0d5e5..e2357a4e9434b2a71d8121635a7a1b5d01cb00d1 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserCreateAttributesDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/UserCreateAttributesDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.keycloak; +package at.ac.tuwien.ifs.dbrepo.core.api.keycloak; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserCreateDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/UserCreateDto.java similarity index 93% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserCreateDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/UserCreateDto.java index 2a80811b6247cd18fde5b3eadea1921b1ab2c3a9..b8879ae24e29daa163acfec9be93f485720858fd 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserCreateDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/UserCreateDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.keycloak; +package at.ac.tuwien.ifs.dbrepo.core.api.keycloak; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserIdAttributesDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/UserIdAttributesDto.java similarity index 90% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserIdAttributesDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/UserIdAttributesDto.java index 3155d75f027d2864f2a06ecf19376c13c9be7d35..0a34e5fe61bfaad96bed5535cf77a2dd9e782496 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserIdAttributesDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/keycloak/UserIdAttributesDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.keycloak; +package at.ac.tuwien.ifs.dbrepo.core.api.keycloak; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/ldap/UserDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/ldap/UserDto.java similarity index 89% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/ldap/UserDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/ldap/UserDto.java index e6aec082263ebe4ebe2789a683264d06df43cc9b..f06844ef7d865d27cab90dec9a9fc95ee21243fa 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/ldap/UserDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/ldap/UserDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.ldap; +package at.ac.tuwien.ifs.dbrepo.core.api.ldap; import jakarta.validation.constraints.NotNull; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/maintenance/BannerMessageBriefDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/maintenance/BannerMessageBriefDto.java similarity index 92% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/maintenance/BannerMessageBriefDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/maintenance/BannerMessageBriefDto.java index a11c70f6219d1bd362775c50fedbefa5a9aa07f4..72ca75913fa8e9d66e6439c75c9d29dba69893d4 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/maintenance/BannerMessageBriefDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/maintenance/BannerMessageBriefDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.maintenance; +package at.ac.tuwien.ifs.dbrepo.core.api.maintenance; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/maintenance/BannerMessageCreateDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/maintenance/BannerMessageCreateDto.java similarity index 95% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/maintenance/BannerMessageCreateDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/maintenance/BannerMessageCreateDto.java index f7466d3e2c1688756e61fd88364eba9373ec040d..3526258d80bef97bc1a79496ceb6b4af46440e60 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/maintenance/BannerMessageCreateDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/maintenance/BannerMessageCreateDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.maintenance; +package at.ac.tuwien.ifs.dbrepo.core.api.maintenance; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/maintenance/BannerMessageDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/maintenance/BannerMessageDto.java similarity index 96% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/maintenance/BannerMessageDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/maintenance/BannerMessageDto.java index d344ccd6b461460d77b7f865ab03e44d84fc6956..9e2f094b69c9abe55d3291fd798dc3381ff20bf7 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/maintenance/BannerMessageDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/maintenance/BannerMessageDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.maintenance; +package at.ac.tuwien.ifs.dbrepo.core.api.maintenance; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/maintenance/BannerMessageTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/maintenance/BannerMessageTypeDto.java similarity index 83% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/maintenance/BannerMessageTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/maintenance/BannerMessageTypeDto.java index 8a867f5ea4b06b44aff2efde9ee36c371718f374..16e9b8a81007a95e6cef7bd6f2a3ecb799dee0ad 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/maintenance/BannerMessageTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/maintenance/BannerMessageTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.maintenance; +package at.ac.tuwien.ifs.dbrepo.core.api.maintenance; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; @@ -15,7 +15,7 @@ public enum BannerMessageTypeDto { @JsonProperty("info") INFO("info"); - private String name; + private final String name; BannerMessageTypeDto(String name) { this.name = name; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/maintenance/BannerMessageUpdateDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/maintenance/BannerMessageUpdateDto.java similarity index 95% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/maintenance/BannerMessageUpdateDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/maintenance/BannerMessageUpdateDto.java index f6aad1989e3e5872b0edcc810878b8299cf7ce23..4551adaa40cc32e05aeedf635b22e56084fc18ef 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/maintenance/BannerMessageUpdateDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/maintenance/BannerMessageUpdateDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.maintenance; +package at.ac.tuwien.ifs.dbrepo.core.api.maintenance; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/OrcidDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/OrcidDto.java similarity index 66% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/OrcidDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/OrcidDto.java index c4ea89b005df0f5506e91b2bcc428c95a173bc7f..e25b7240fa36f58668aed64dd17fdbf2d2e680d8 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/OrcidDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/OrcidDto.java @@ -1,7 +1,7 @@ -package at.tuwien.api.orcid; +package at.ac.tuwien.ifs.dbrepo.core.api.orcid; -import at.tuwien.api.orcid.activities.OrcidActivitiesSummaryDto; -import at.tuwien.api.orcid.person.OrcidPersonDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.OrcidActivitiesSummaryDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.person.OrcidPersonDto; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; import lombok.extern.jackson.Jacksonized; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/OrcidActivitiesSummaryDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/OrcidActivitiesSummaryDto.java similarity index 65% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/OrcidActivitiesSummaryDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/OrcidActivitiesSummaryDto.java index 625611abd27a28864b310354936f9d167adee12f..3bd62fd915ee720099bf3fed170533d99a50a921 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/OrcidActivitiesSummaryDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/OrcidActivitiesSummaryDto.java @@ -1,6 +1,6 @@ -package at.tuwien.api.orcid.activities; +package at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities; -import at.tuwien.api.orcid.activities.employments.OrcidEmploymentsDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.OrcidEmploymentsDto; import lombok.*; import lombok.extern.jackson.Jacksonized; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/OrcidEmploymentsDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/employments/OrcidEmploymentsDto.java similarity index 66% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/OrcidEmploymentsDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/employments/OrcidEmploymentsDto.java index dea853b62bc3680e8bcefcedb50f85aa567b2c74..fee281294b1f0f15de263e736e24b04939c4fe14 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/OrcidEmploymentsDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/employments/OrcidEmploymentsDto.java @@ -1,6 +1,6 @@ -package at.tuwien.api.orcid.activities.employments; +package at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments; -import at.tuwien.api.orcid.activities.employments.affiliation.OrcidAffiliationGroupDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.OrcidAffiliationGroupDto; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; import lombok.extern.jackson.Jacksonized; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/OrcidAffiliationGroupDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/employments/affiliation/OrcidAffiliationGroupDto.java similarity index 57% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/OrcidAffiliationGroupDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/employments/affiliation/OrcidAffiliationGroupDto.java index a82a88869bb076791a85e8a9a51f45afb8e3a937..bbda576a4a337a908ca870bc53c6ce83b6a3b5d8 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/OrcidAffiliationGroupDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/employments/affiliation/OrcidAffiliationGroupDto.java @@ -1,6 +1,6 @@ -package at.tuwien.api.orcid.activities.employments.affiliation; +package at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation; -import at.tuwien.api.orcid.activities.employments.affiliation.group.OrcidEmploymentSummaryDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.group.OrcidEmploymentSummaryDto; import lombok.*; import lombok.extern.jackson.Jacksonized; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/OrcidEmploymentSummaryDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/employments/affiliation/group/OrcidEmploymentSummaryDto.java similarity index 63% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/OrcidEmploymentSummaryDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/employments/affiliation/group/OrcidEmploymentSummaryDto.java index 984dc8a6d07fe69b00a49636268e4334f3037678..159e83a3a5c9aee30e3fa1506b426157712e5603 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/OrcidEmploymentSummaryDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/employments/affiliation/group/OrcidEmploymentSummaryDto.java @@ -1,6 +1,6 @@ -package at.tuwien.api.orcid.activities.employments.affiliation.group; +package at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.group; -import at.tuwien.api.orcid.activities.employments.affiliation.group.summary.OrcidSummaryDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.group.summary.OrcidSummaryDto; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; import lombok.extern.jackson.Jacksonized; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/summary/OrcidSummaryDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/employments/affiliation/group/summary/OrcidSummaryDto.java similarity index 69% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/summary/OrcidSummaryDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/employments/affiliation/group/summary/OrcidSummaryDto.java index 1377a73dba186cab8fafcda307643ae62144a601..1dfd21700a7577f927115bcfc3538ba137d74b25 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/summary/OrcidSummaryDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/employments/affiliation/group/summary/OrcidSummaryDto.java @@ -1,6 +1,6 @@ -package at.tuwien.api.orcid.activities.employments.affiliation.group.summary; +package at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.group.summary; -import at.tuwien.api.orcid.activities.employments.affiliation.group.summary.organization.OrcidOrganizationDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.group.summary.organization.OrcidOrganizationDto; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; import lombok.extern.jackson.Jacksonized; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/summary/organization/OrcidOrganizationDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/employments/affiliation/group/summary/organization/OrcidOrganizationDto.java similarity index 60% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/summary/organization/OrcidOrganizationDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/employments/affiliation/group/summary/organization/OrcidOrganizationDto.java index 149af1b3e693c2bd2da2e2f3decb102ee878e2d0..7146bcf175b170d6bccc868b1515b4d8d675d70d 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/summary/organization/OrcidOrganizationDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/employments/affiliation/group/summary/organization/OrcidOrganizationDto.java @@ -1,6 +1,6 @@ -package at.tuwien.api.orcid.activities.employments.affiliation.group.summary.organization; +package at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.group.summary.organization; -import at.tuwien.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated.OrcidDisambiguatedDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated.OrcidDisambiguatedDto; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; import lombok.extern.jackson.Jacksonized; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/summary/organization/disambiguated/OrcidDisambiguatedDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/employments/affiliation/group/summary/organization/disambiguated/OrcidDisambiguatedDto.java similarity index 78% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/summary/organization/disambiguated/OrcidDisambiguatedDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/employments/affiliation/group/summary/organization/disambiguated/OrcidDisambiguatedDto.java index c5ed53e37ff2ddab6a79e76465578d306ce50952..e8ea1dba395eb82dd06737f93fcdab58a65a9a0d 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/summary/organization/disambiguated/OrcidDisambiguatedDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/employments/affiliation/group/summary/organization/disambiguated/OrcidDisambiguatedDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated; +package at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; diff --git a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/employments/affiliation/group/summary/organization/disambiguated/OrcidDisambiguatedSourceTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/employments/affiliation/group/summary/organization/disambiguated/OrcidDisambiguatedSourceTypeDto.java new file mode 100644 index 0000000000000000000000000000000000000000..83169ad79cf067edda2b6787c7c3c0480f7f2af6 --- /dev/null +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/activities/employments/affiliation/group/summary/organization/disambiguated/OrcidDisambiguatedSourceTypeDto.java @@ -0,0 +1,6 @@ +package at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated; + +public enum OrcidDisambiguatedSourceTypeDto { + RINGGOLD, + ROR +} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/person/OrcidPersonDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/person/OrcidPersonDto.java similarity index 64% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/person/OrcidPersonDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/person/OrcidPersonDto.java index f7de2794d721f283514562dfd8abecd687c229e5..afb1d6d80f4fac5e172b9b60238d6a435c3081ed 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/person/OrcidPersonDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/person/OrcidPersonDto.java @@ -1,6 +1,6 @@ -package at.tuwien.api.orcid.person; +package at.ac.tuwien.ifs.dbrepo.core.api.orcid.person; -import at.tuwien.api.orcid.person.name.OrcidNameDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.person.name.OrcidNameDto; import lombok.*; import lombok.extern.jackson.Jacksonized; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/person/name/OrcidNameDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/person/name/OrcidNameDto.java similarity index 87% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/person/name/OrcidNameDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/person/name/OrcidNameDto.java index 44c2ac0e6bdcc58229b0189709adc20729697669..2b638ff20ab3353f6d27b68d58d878d1c2427624 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/person/name/OrcidNameDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/person/name/OrcidNameDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.orcid.person.name; +package at.ac.tuwien.ifs.dbrepo.core.api.orcid.person.name; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/person/name/OrcidValueDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/person/name/OrcidValueDto.java similarity index 79% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/person/name/OrcidValueDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/person/name/OrcidValueDto.java index 251a39c23c3cd8d7dd4eb013461b530e76305647..bcfd0d3a16be598fd7a0a6a1632f6019d0e6ad6f 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/person/name/OrcidValueDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/orcid/person/name/OrcidValueDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.orcid.person.name; +package at.ac.tuwien.ifs.dbrepo.core.api.orcid.person.name; import lombok.*; import lombok.extern.jackson.Jacksonized; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/ror/RorDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/ror/RorDto.java similarity index 85% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/ror/RorDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/ror/RorDto.java index 8e9407885ca4f7e31994836a5664025ce7d499bb..19776bcf090f00766a1fbd9c03dbc0392d735b30 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/ror/RorDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/ror/RorDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.ror; +package at.ac.tuwien.ifs.dbrepo.core.api.ror; import lombok.*; import lombok.extern.jackson.Jacksonized; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/semantics/EntityDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/semantics/EntityDto.java similarity index 91% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/semantics/EntityDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/semantics/EntityDto.java index 5c1d6cc13a05b7a2c6887139bc88db6e9b314423..a9f31f97f00883dc54d61bd226199df23ed3e1a3 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/semantics/EntityDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/semantics/EntityDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.semantics; +package at.ac.tuwien.ifs.dbrepo.core.api.semantics; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/semantics/OntologyBriefDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/semantics/OntologyBriefDto.java similarity index 94% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/semantics/OntologyBriefDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/semantics/OntologyBriefDto.java index 29d5116a70bfe3b59c1223534616eebb80b9c57e..81caa34ad142db762e7ade6763ef86f0c31fa468 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/semantics/OntologyBriefDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/semantics/OntologyBriefDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.semantics; +package at.ac.tuwien.ifs.dbrepo.core.api.semantics; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/semantics/OntologyCreateDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/semantics/OntologyCreateDto.java similarity index 92% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/semantics/OntologyCreateDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/semantics/OntologyCreateDto.java index 1e2cf441674dc7a32ae608472e1e44247e3a0664..aa11b34e558bcd2e1bcb6afa426bd0fdce6467ca 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/semantics/OntologyCreateDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/semantics/OntologyCreateDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.semantics; +package at.ac.tuwien.ifs.dbrepo.core.api.semantics; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/semantics/OntologyDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/semantics/OntologyDto.java similarity index 88% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/semantics/OntologyDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/semantics/OntologyDto.java index a3e7c46d014d5de6c06ec5ed3608f51cb8700de3..afbb818e1b773b1a591703b63990c77f04153bea 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/semantics/OntologyDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/semantics/OntologyDto.java @@ -1,7 +1,5 @@ -package at.tuwien.api.semantics; +package at.ac.tuwien.ifs.dbrepo.core.api.semantics; -import at.tuwien.api.user.UserBriefDto; -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; @@ -9,7 +7,6 @@ import jakarta.validation.constraints.NotNull; import lombok.*; import lombok.extern.jackson.Jacksonized; -import java.time.Instant; import java.util.UUID; @Getter diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/semantics/OntologyModifyDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/semantics/OntologyModifyDto.java similarity index 93% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/semantics/OntologyModifyDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/semantics/OntologyModifyDto.java index f003790922ad28f5f583dfbf51303d545034be27..b73891b342ea0e0bb0ce2bfcfaf5a867bcf99332 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/semantics/OntologyModifyDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/semantics/OntologyModifyDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.semantics; +package at.ac.tuwien.ifs.dbrepo.core.api.semantics; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/semantics/TableColumnEntityDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/semantics/TableColumnEntityDto.java similarity index 95% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/semantics/TableColumnEntityDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/semantics/TableColumnEntityDto.java index f4a2147a29cbdb1f0ee7aa03a26fa500eb370d91..1bb401e5cac889f2d14b8693ff0774db8f31d1d0 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/semantics/TableColumnEntityDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/semantics/TableColumnEntityDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.semantics; +package at.ac.tuwien.ifs.dbrepo.core.api.semantics; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/ExchangeUpdatePermissionsDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/ExchangeUpdatePermissionsDto.java similarity index 91% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/ExchangeUpdatePermissionsDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/ExchangeUpdatePermissionsDto.java index f545f6204187a66a1c8942cb5e8a3eef9d73ae65..3b775a23186261ed2bb05971783e5dfc21458d20 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/ExchangeUpdatePermissionsDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/ExchangeUpdatePermissionsDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.user; +package at.ac.tuwien.ifs.dbrepo.core.api.user; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/GrantedAuthorityDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/GrantedAuthorityDto.java similarity index 87% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/GrantedAuthorityDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/GrantedAuthorityDto.java index 07e0029a716b1d4414b1c10c71b4ad6bcb11ae4a..cabc0b1d079e3b4e303c2a0e2691bfa566d69d46 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/GrantedAuthorityDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/GrantedAuthorityDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.user; +package at.ac.tuwien.ifs.dbrepo.core.api.user; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/RoleTypeDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/RoleTypeDto.java similarity index 85% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/RoleTypeDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/RoleTypeDto.java index 4b2c8774352edf2f6b6c31df14f3b7e0469f2785..30f2cc2b8b001d89e92a356429e8cd26f87dee45 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/RoleTypeDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/RoleTypeDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.user; +package at.ac.tuwien.ifs.dbrepo.core.api.user; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; @@ -15,7 +15,7 @@ public enum RoleTypeDto { @JsonProperty("data_steward") ROLE_DATA_STEWARD("data_steward"); - private String name; + private final String name; RoleTypeDto(String name) { this.name = name; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserAttributesDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserAttributesDto.java similarity index 94% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserAttributesDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserAttributesDto.java index ef9bae650c9c8615c9f7c43198dd61285aa2ce41..b365199cece5f4d21e13078eaf7df0cfaf550504 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserAttributesDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserAttributesDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.user; +package at.ac.tuwien.ifs.dbrepo.core.api.user; import com.fasterxml.jackson.annotation.JsonIgnore; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserBriefDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserBriefDto.java similarity index 95% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserBriefDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserBriefDto.java index d245bbaf4c46584b9f0cd93fa7b43c2b31ef6333..58a2aeab88416c5f95c72ac2e91c4b2aacefad56 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserBriefDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserBriefDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.user; +package at.ac.tuwien.ifs.dbrepo.core.api.user; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDetailsDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserDetailsDto.java similarity index 95% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDetailsDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserDetailsDto.java index 2ab170d616c75c40d4be36af42854d518d3ec7c5..8f4b3c3892d2ca2d94cd3943752020f193947d57 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDetailsDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserDetailsDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.user; +package at.ac.tuwien.ifs.dbrepo.core.api.user; import jakarta.validation.constraints.NotNull; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserDto.java similarity index 92% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserDto.java index e7367e2fb4e513a9681783dfdec89b55e57519e0..c5db9917257ad4cfe649c2d3bb9abffdb0e7215b 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserDto.java @@ -1,6 +1,6 @@ -package at.tuwien.api.user; +package at.ac.tuwien.ifs.dbrepo.core.api.user; -import at.tuwien.api.CacheableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.CacheableDto; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserEmailDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserEmailDto.java similarity index 90% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserEmailDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserEmailDto.java index caaf33249710f14c7c49540aa8dd2afe0a18e0c3..a8ccd56b8d9257ea0dd53252e04bdfee4f40bc69 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserEmailDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserEmailDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.user; +package at.ac.tuwien.ifs.dbrepo.core.api.user; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.Email; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserForgotDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserForgotDto.java similarity index 90% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserForgotDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserForgotDto.java index 5ebcbae7429c335c122c62e58644b739d8fc90ea..4895a04c70d2ad5322336462bbf5656357994fda 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserForgotDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserForgotDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.user; +package at.ac.tuwien.ifs.dbrepo.core.api.user; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.Email; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserModifyPasswordDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserModifyPasswordDto.java similarity index 90% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserModifyPasswordDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserModifyPasswordDto.java index 2b86672cc2704886a287912ff39c70eba63f1904..9b1e1a72cc42776d8502ba4ff46ba7839255e36a 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserModifyPasswordDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserModifyPasswordDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.user; +package at.ac.tuwien.ifs.dbrepo.core.api.user; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserPasswordDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserPasswordDto.java similarity index 86% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserPasswordDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserPasswordDto.java index dcf53932840057f6916b8ac281eae9031a40677e..f549047c4e277ed6f23315099ea2ab4378b7dd5e 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserPasswordDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserPasswordDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.user; +package at.ac.tuwien.ifs.dbrepo.core.api.user; import jakarta.validation.constraints.NotNull; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserResetDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserResetDto.java similarity index 87% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserResetDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserResetDto.java index 6cac59a904c529b1aa226b788bff427092e5bb1f..260b5f67ca7cf58f7eb998b23f19c1b7dc8ab709 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserResetDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserResetDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.user; +package at.ac.tuwien.ifs.dbrepo.core.api.user; import jakarta.validation.constraints.NotNull; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserRolesDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserRolesDto.java similarity index 87% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserRolesDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserRolesDto.java index 5667f38ec6c6f639981376292af5d16cda58b866..8ed18d5101f1b98593c6e4a54a90a627d5482567 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserRolesDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserRolesDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.user; +package at.ac.tuwien.ifs.dbrepo.core.api.user; import jakarta.validation.constraints.NotNull; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserThemeSetDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserThemeSetDto.java similarity index 88% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserThemeSetDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserThemeSetDto.java index 3f5b899df8777459e4df5faa86dccad01d6ac703..ebc7292edf278612aebf49458d48f673a7db5477 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserThemeSetDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserThemeSetDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.user; +package at.ac.tuwien.ifs.dbrepo.core.api.user; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserUpdateDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserUpdateDto.java similarity index 93% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserUpdateDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserUpdateDto.java index 68d674a7c2287dbd747969d3ad58cdf303cd2bf6..099d3e7b08d46b74312d1b4c1fbd31b3eb4c4e2b 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserUpdateDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserUpdateDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.user; +package at.ac.tuwien.ifs.dbrepo.core.api.user; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserUpdatePermissionsDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserUpdatePermissionsDto.java similarity index 89% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserUpdatePermissionsDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserUpdatePermissionsDto.java index 99f1eab30af6dc537ae767adb4e5e8cc8a1f5048..dd7742c2f5fe279ef27f2033b52bb5626206f65e 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserUpdatePermissionsDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/UserUpdatePermissionsDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.user; +package at.ac.tuwien.ifs.dbrepo.core.api.user; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/external/ExternalMetadataDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/external/ExternalMetadataDto.java similarity index 78% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/external/ExternalMetadataDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/external/ExternalMetadataDto.java index fb40af09487d8b65a2efabb0cb18d46e317484bb..c169e27fe52b9f5c767cd3d579456f5a2af2ab53 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/external/ExternalMetadataDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/external/ExternalMetadataDto.java @@ -1,6 +1,6 @@ -package at.tuwien.api.user.external; +package at.ac.tuwien.ifs.dbrepo.core.api.user.external; -import at.tuwien.api.user.external.affiliation.ExternalAffiliationDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.external.affiliation.ExternalAffiliationDto; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/external/ExternalResultType.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/external/ExternalResultType.java similarity index 82% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/external/ExternalResultType.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/external/ExternalResultType.java index e3eca17346ada216c77169e2d45dbc55ea4b04d6..e3cb61abf1fd31b39f311b29118a854021b9728e 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/external/ExternalResultType.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/external/ExternalResultType.java @@ -1,4 +1,4 @@ -package at.tuwien.api.user.external; +package at.ac.tuwien.ifs.dbrepo.core.api.user.external; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; @@ -12,7 +12,7 @@ public enum ExternalResultType { @JsonProperty("Organizational") ORGANIZATIONAL("Organizational"); - private String name; + private final String name; ExternalResultType(String name) { this.name = name; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/external/affiliation/ExternalAffiliationDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/external/affiliation/ExternalAffiliationDto.java similarity index 91% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/external/affiliation/ExternalAffiliationDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/external/affiliation/ExternalAffiliationDto.java index d8d30894bcb443a5bfb33426c01f3910bd4ee9b2..8a0a4935034f8688da4e9452ada9cf65b6d40148 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/external/affiliation/ExternalAffiliationDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/external/affiliation/ExternalAffiliationDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.user.external.affiliation; +package at.ac.tuwien.ifs.dbrepo.core.api.user.external.affiliation; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/internal/UpdateUserPasswordDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/internal/UpdateUserPasswordDto.java similarity index 85% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/internal/UpdateUserPasswordDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/internal/UpdateUserPasswordDto.java index c89e795bd367739c5b9d371e73c0191fa6758842..8f1cffdd62afa7afad0596f610afbf32a56207d5 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/internal/UpdateUserPasswordDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/api/user/internal/UpdateUserPasswordDto.java @@ -1,4 +1,4 @@ -package at.tuwien.api.user.internal; +package at.ac.tuwien.ifs.dbrepo.core.api.user.internal; import jakarta.validation.constraints.NotBlank; import lombok.*; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/Container.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/container/Container.java similarity index 88% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/Container.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/container/Container.java index 458dcec7ebb282ff5abc703668aa8010ca3e5d97..7390124cac8be6e519e60149277635b0b294f467 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/Container.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/container/Container.java @@ -1,7 +1,7 @@ -package at.tuwien.entities.container; +package at.ac.tuwien.ifs.dbrepo.core.entity.container; -import at.tuwien.entities.container.image.ContainerImage; -import at.tuwien.entities.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.image.ContainerImage; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.persistence.*; import lombok.*; @@ -84,6 +84,12 @@ public class Container { @Column private String privilegedPassword; + @Column + private String readonlyUsername; + + @Column + private String readonlyPassword; + @PrePersist public void prePersist() { if (this.id == null) { diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/ContainerImage.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/container/image/ContainerImage.java similarity index 95% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/ContainerImage.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/container/image/ContainerImage.java index 336a278d7d8ff6f2f4d2b56ebbde1f156e198659..7629976bf1a62d8a4dc92394c105a741271fd2cb 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/ContainerImage.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/container/image/ContainerImage.java @@ -1,6 +1,6 @@ -package at.tuwien.entities.container.image; +package at.ac.tuwien.ifs.dbrepo.core.entity.container.image; -import at.tuwien.entities.container.Container; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.Container; import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.persistence.*; import lombok.*; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/DataType.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/container/image/DataType.java similarity index 97% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/DataType.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/container/image/DataType.java index 347ca47e960e74f846eea32b3ddc166e3a0efc0e..502474bee249e6337cf5944d9a10bf6cf42a7358 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/DataType.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/container/image/DataType.java @@ -1,4 +1,4 @@ -package at.tuwien.entities.container.image; +package at.ac.tuwien.ifs.dbrepo.core.entity.container.image; import jakarta.persistence.*; import lombok.*; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/Operator.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/container/image/Operator.java similarity index 94% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/Operator.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/container/image/Operator.java index adeb6dd8ef7c977222021d3c1b0fdb54fb304a17..5e629d267311fcc9b821d5aa8c1dde66d594ea98 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/Operator.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/container/image/Operator.java @@ -1,4 +1,4 @@ -package at.tuwien.entities.container.image; +package at.ac.tuwien.ifs.dbrepo.core.entity.container.image; import jakarta.persistence.*; import lombok.*; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/AccessType.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/AccessType.java similarity index 63% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/AccessType.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/AccessType.java index 19a642ff965c7c1b930e67e31fa6b41decb59e67..c17ba90844c16588b49731986ef5f6535fcc76b9 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/AccessType.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/AccessType.java @@ -1,4 +1,4 @@ -package at.tuwien.entities.database; +package at.ac.tuwien.ifs.dbrepo.core.entity.database; import lombok.Getter; import lombok.ToString; @@ -8,5 +8,5 @@ import lombok.ToString; public enum AccessType { READ, WRITE_OWN, - WRITE_ALL; + WRITE_ALL } diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/Database.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/Database.java similarity index 86% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/Database.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/Database.java index b57f04066856d37fd35944b052e832bf0db4e4f6..2aefc232a30908654572a89b8a894abbc00d8c96 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/Database.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/Database.java @@ -1,9 +1,8 @@ -package at.tuwien.entities.database; +package at.ac.tuwien.ifs.dbrepo.core.entity.database; -import at.tuwien.entities.container.Container; -import at.tuwien.entities.database.table.Table; -import at.tuwien.entities.identifier.Identifier; -import at.tuwien.entities.user.User; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.Container; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.Identifier; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.persistence.*; import lombok.*; @@ -18,8 +17,6 @@ import java.time.Instant; import java.util.List; import java.util.UUID; -import static jakarta.persistence.GenerationType.IDENTITY; - @Data @Entity @Builder(toBuilder = true) @@ -32,13 +29,13 @@ import static jakarta.persistence.GenerationType.IDENTITY; @UniqueConstraint(columnNames = {"cid", "internalName"}) }) @NamedQueries({ - @NamedQuery(name = "Database.findAllDesc", query = "select distinct d from Database d order by d.id desc"), - @NamedQuery(name = "Database.findAllByInternalNameDesc", query = "select distinct d from Database d where d.internalName = ?1 order by d.id desc"), - @NamedQuery(name = "Database.findAllAtLestReadAccessDesc", query = "select distinct d from Database d where exists(select a.hdbid from DatabaseAccess a where a.huserid = ?1 and a.hdbid = d.id) order by d.id desc"), - @NamedQuery(name = "Database.findAllPublicOrSchemaPublicDesc", query = "select distinct d from Database d where d.isPublic = true or d.isSchemaPublic = true order by d.id desc"), - @NamedQuery(name = "Database.findAllPublicOrSchemaPublicOrReadAccessDesc", query = "select distinct d from Database d where d.isPublic = true or d.isSchemaPublic = true or exists(select a.hdbid from DatabaseAccess a where a.huserid = ?1 and a.hdbid = d.id) order by d.id desc"), - @NamedQuery(name = "Database.findAllPublicOrSchemaPublicOrReadAccessByInternalNameDesc", query = "select distinct d from Database d where (d.isPublic = true or d.isSchemaPublic = true) and d.internalName = ?2 or exists(select a.hdbid from DatabaseAccess a where a.huserid = ?1 and a.hdbid = d.id) order by d.id desc"), - @NamedQuery(name = "Database.findAllPublicOrSchemaPublicByInternalNameDesc", query = "select distinct d from Database d where (d.isPublic = true or d.isSchemaPublic = true) and d.internalName = ?1 order by d.id desc"), + @NamedQuery(name = "Database.findAllDesc", query = "select distinct d from Database d order by d.created desc"), + @NamedQuery(name = "Database.findAllByInternalNameDesc", query = "select distinct d from Database d where d.internalName = ?1 order by d.created desc"), + @NamedQuery(name = "Database.findAllAtLestReadAccessDesc", query = "select distinct d from Database d where exists(select a.hdbid from DatabaseAccess a where a.huserid = ?1 and a.hdbid = d.id) order by d.created desc"), + @NamedQuery(name = "Database.findAllPublicOrSchemaPublicDesc", query = "select distinct d from Database d where d.isPublic = true or d.isSchemaPublic = true order by d.created desc"), + @NamedQuery(name = "Database.findAllPublicOrSchemaPublicOrReadAccessDesc", query = "select distinct d from Database d where d.isPublic = true or d.isSchemaPublic = true or exists(select a.hdbid from DatabaseAccess a where a.huserid = ?1 and a.hdbid = d.id) order by d.created desc"), + @NamedQuery(name = "Database.findAllPublicOrSchemaPublicOrReadAccessByInternalNameDesc", query = "select distinct d from Database d where (d.isPublic = true or d.isSchemaPublic = true) and d.internalName = ?2 or exists(select a.hdbid from DatabaseAccess a where a.huserid = ?1 and a.hdbid = d.id) order by d.created desc"), + @NamedQuery(name = "Database.findAllPublicOrSchemaPublicByInternalNameDesc", query = "select distinct d from Database d where (d.isPublic = true or d.isSchemaPublic = true) and d.internalName = ?1 order by d.created desc"), }) public class Database implements Serializable { @@ -47,6 +44,9 @@ public class Database implements Serializable { @Column(columnDefinition = "VARCHAR(36)") private UUID id; + @Column(name = "grafana_dashboard_uid") + private String dashboardUid; + @JdbcTypeCode(java.sql.Types.VARCHAR) @Column(name = "owned_by", columnDefinition = "VARCHAR(36)") private UUID ownedBy; @@ -101,7 +101,7 @@ public class Database implements Serializable { @OrderBy("id DESC") @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL, CascadeType.PERSIST}, mappedBy = "database", orphanRemoval = true) - private List<Table> tables; + private List<at.ac.tuwien.ifs.dbrepo.core.entity.database.table.Table> tables; @OrderBy("id DESC") @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL, CascadeType.PERSIST}, mappedBy = "database", orphanRemoval = true) @@ -116,6 +116,9 @@ public class Database implements Serializable { @Column(nullable = false, columnDefinition = "boolean default true") private Boolean isSchemaPublic; + @Column(nullable = false, columnDefinition = "boolean default true") + private Boolean isDashboardEnabled; + @Lob @Basic(fetch = FetchType.LAZY) @Column(columnDefinition = "LONGBLOB") diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/DatabaseAccess.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/DatabaseAccess.java similarity index 89% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/DatabaseAccess.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/DatabaseAccess.java index e5f7dd3012d9d5b510f7e072dfadf255297e4a8e..b0e110a67643f45569380a7dbd56469edd5f1570 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/DatabaseAccess.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/DatabaseAccess.java @@ -1,14 +1,11 @@ -package at.tuwien.entities.database; +package at.ac.tuwien.ifs.dbrepo.core.entity.database; -import at.tuwien.entities.user.User; -import com.fasterxml.jackson.annotation.JsonFormat; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; import jakarta.persistence.*; import lombok.*; import org.hibernate.annotations.JdbcTypeCode; -import org.springframework.data.annotation.CreatedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import java.time.Instant; import java.util.UUID; @Data diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/DatabaseAccessKey.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/DatabaseAccessKey.java similarity index 80% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/DatabaseAccessKey.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/DatabaseAccessKey.java index b6963c290c38186fc7d78af149b07622804e7301..a1a55ab60e6257d05ee028f33f938e24a5793422 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/DatabaseAccessKey.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/DatabaseAccessKey.java @@ -1,4 +1,4 @@ -package at.tuwien.entities.database; +package at.ac.tuwien.ifs.dbrepo.core.entity.database; import lombok.EqualsAndHashCode; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/LanguageType.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/LanguageType.java similarity index 97% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/LanguageType.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/LanguageType.java index 35effb9cb8c28340922166956adb342c8c686ec0..b4e6ddb26117757b359f2541f69b09c49239a68b 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/LanguageType.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/LanguageType.java @@ -1,4 +1,4 @@ -package at.tuwien.entities.database; +package at.ac.tuwien.ifs.dbrepo.core.entity.database; import lombok.Getter; @@ -373,7 +373,7 @@ public enum LanguageType { ZU("zu"); - private String name; + private final String name; LanguageType(String name) { this.name = name; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/License.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/License.java similarity index 91% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/License.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/License.java index 4d43a3ba042c6fcffcc5ee52cf4f8fd884db49ff..ce449e61caff06efb8b673ad96135023f55c8d1d 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/License.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/License.java @@ -1,4 +1,4 @@ -package at.tuwien.entities.database; +package at.ac.tuwien.ifs.dbrepo.core.entity.database; import lombok.*; import org.springframework.data.jpa.domain.support.AuditingEntityListener; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/View.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/View.java similarity index 96% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/View.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/View.java index 8f84a8f066d577e6ba009f6ffbc4ff144d671fc8..d84b75530b1b5dd2b27a896461f6d86671588ea1 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/View.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/View.java @@ -1,7 +1,7 @@ -package at.tuwien.entities.database; +package at.ac.tuwien.ifs.dbrepo.core.entity.database; -import at.tuwien.entities.identifier.Identifier; -import at.tuwien.entities.user.User; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.Identifier; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.persistence.*; import lombok.*; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/ViewColumn.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/ViewColumn.java similarity index 92% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/ViewColumn.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/ViewColumn.java index 2b18132e8cca75d05ee203143a5dbba40eabf21f..aa2cfcd84512e76e0df7c6c1d60aa71505c98abc 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/ViewColumn.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/ViewColumn.java @@ -1,6 +1,6 @@ -package at.tuwien.entities.database; +package at.ac.tuwien.ifs.dbrepo.core.entity.database; -import at.tuwien.entities.database.table.columns.TableColumnType; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumnType; import jakarta.persistence.*; import lombok.*; import org.hibernate.annotations.JdbcTypeCode; @@ -8,8 +8,6 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener; import java.util.UUID; -import static jakarta.persistence.GenerationType.IDENTITY; - @Data @Entity @Builder(toBuilder = true) diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/Table.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/Table.java similarity index 91% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/Table.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/Table.java index 1e2aa72b924cdd6c1a37aa5c98f64728ba92fc20..42faf301ca49b73bfc4bcded087b9c005a5c764a 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/Table.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/Table.java @@ -1,10 +1,10 @@ -package at.tuwien.entities.database.table; +package at.ac.tuwien.ifs.dbrepo.core.entity.database.table; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.database.table.columns.TableColumn; -import at.tuwien.entities.database.table.constraints.Constraints; -import at.tuwien.entities.identifier.Identifier; -import at.tuwien.entities.user.User; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumn; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.Constraints; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.Identifier; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.persistence.*; import lombok.*; @@ -21,8 +21,6 @@ import java.time.Instant; import java.util.List; import java.util.UUID; -import static jakarta.persistence.GenerationType.IDENTITY; - @Data @Entity @Builder diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/ColumnEnum.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/columns/ColumnEnum.java similarity index 89% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/ColumnEnum.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/columns/ColumnEnum.java index 99002c812970c355b27ead84e2f6ad3626ec2132..dddf3fd5019c2853b1d5c77658f0a3b705097a23 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/ColumnEnum.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/columns/ColumnEnum.java @@ -1,4 +1,4 @@ -package at.tuwien.entities.database.table.columns; +package at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns; import jakarta.persistence.*; import lombok.*; @@ -6,8 +6,6 @@ import org.hibernate.annotations.JdbcTypeCode; import java.util.UUID; -import static jakarta.persistence.GenerationType.IDENTITY; - @Data @Entity @Builder(toBuilder = true) diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/ColumnSet.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/columns/ColumnSet.java similarity index 89% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/ColumnSet.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/columns/ColumnSet.java index 036c0202db40719227b90e6be6f30a8157a5e0fd..a5925f9c2e9c7011c4bac5488f53cbf28b9db968 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/ColumnSet.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/columns/ColumnSet.java @@ -1,4 +1,4 @@ -package at.tuwien.entities.database.table.columns; +package at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns; import jakarta.persistence.*; import lombok.*; @@ -6,8 +6,6 @@ import org.hibernate.annotations.JdbcTypeCode; import java.util.UUID; -import static jakarta.persistence.GenerationType.IDENTITY; - @Data @Entity @Builder(toBuilder = true) diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/columns/TableColumn.java similarity index 96% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/columns/TableColumn.java index eefa648dfd2aea752e1fd8a5944ea3fe51c234c3..010c919f05de881e40a6d3138e0f1191bde71e46 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/columns/TableColumn.java @@ -1,6 +1,6 @@ -package at.tuwien.entities.database.table.columns; +package at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns; -import at.tuwien.entities.database.table.Table; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.Table; import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.persistence.*; import lombok.*; @@ -16,8 +16,6 @@ import java.time.Instant; import java.util.List; import java.util.UUID; -import static jakarta.persistence.GenerationType.IDENTITY; - @Data @Entity @Builder(toBuilder = true) diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnConcept.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/columns/TableColumnConcept.java similarity index 95% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnConcept.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/columns/TableColumnConcept.java index edf39d84e36a41fdf9d783fb3c5fdaea4fd920cf..7b576cf792c54f3a064d0f9b65a455cdf954d5d9 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnConcept.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/columns/TableColumnConcept.java @@ -1,4 +1,4 @@ -package at.tuwien.entities.database.table.columns; +package at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns; import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.persistence.*; @@ -11,8 +11,6 @@ import java.time.Instant; import java.util.List; import java.util.UUID; -import static jakarta.persistence.GenerationType.IDENTITY; - @Data @Entity @Builder diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnType.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/columns/TableColumnType.java similarity index 85% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnType.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/columns/TableColumnType.java index 7f95c476ddf2d80aa78f773ff5db67aee751b86c..9562193a2d909beb62a50fdad9f6b6397d0aa438 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnType.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/columns/TableColumnType.java @@ -1,4 +1,4 @@ -package at.tuwien.entities.database.table.columns; +package at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns; import lombok.Getter; import lombok.ToString; @@ -35,5 +35,5 @@ public enum TableColumnType { DATETIME, TIMESTAMP, TIME, - YEAR; + YEAR } \ No newline at end of file diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnUnit.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/columns/TableColumnUnit.java similarity index 95% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnUnit.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/columns/TableColumnUnit.java index 9d48062d33a3489892fee857b0c06440336e362c..39341261ff92de778ef253d3935dcaa8269b3c18 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnUnit.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/columns/TableColumnUnit.java @@ -1,4 +1,4 @@ -package at.tuwien.entities.database.table.columns; +package at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns; import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.persistence.*; @@ -11,8 +11,6 @@ import java.time.Instant; import java.util.List; import java.util.UUID; -import static jakarta.persistence.GenerationType.IDENTITY; - @Data @Entity @Builder diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/Constraints.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/constraints/Constraints.java similarity index 71% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/Constraints.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/constraints/Constraints.java index 2676eaf3e1843c395c2d4e08b24020661398d5ce..f009c69f7f4789d050d930ba45ea745a1ce0b558 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/Constraints.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/constraints/Constraints.java @@ -1,8 +1,8 @@ -package at.tuwien.entities.database.table.constraints; +package at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints; -import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKey; -import at.tuwien.entities.database.table.constraints.primaryKey.PrimaryKey; -import at.tuwien.entities.database.table.constraints.unique.Unique; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.foreignKey.ForeignKey; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.primaryKey.PrimaryKey; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.unique.Unique; import lombok.*; import jakarta.persistence.*; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ForeignKey.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/constraints/foreignKey/ForeignKey.java similarity index 92% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ForeignKey.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/constraints/foreignKey/ForeignKey.java index 92271b32328ed66215311389de57413b722d5ebe..c7414e3c1d7c42cdb66ce51d1c781217906969c7 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ForeignKey.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/constraints/foreignKey/ForeignKey.java @@ -1,6 +1,6 @@ -package at.tuwien.entities.database.table.constraints.foreignKey; +package at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.foreignKey; -import at.tuwien.entities.database.table.Table; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.Table; import jakarta.persistence.*; import lombok.*; import org.hibernate.annotations.JdbcTypeCode; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ForeignKeyReference.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/constraints/foreignKey/ForeignKeyReference.java similarity index 89% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ForeignKeyReference.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/constraints/foreignKey/ForeignKeyReference.java index 850b25ac5ca3d156600c5c0b5be92663c33f2cca..8ac36e4fa8c91d1de20c1c59717eaf36b6d7a301 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ForeignKeyReference.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/constraints/foreignKey/ForeignKeyReference.java @@ -1,6 +1,6 @@ -package at.tuwien.entities.database.table.constraints.foreignKey; +package at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.foreignKey; -import at.tuwien.entities.database.table.columns.TableColumn; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumn; import jakarta.persistence.*; import lombok.*; import org.hibernate.annotations.JdbcTypeCode; @@ -8,8 +8,6 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener; import java.util.UUID; -import static jakarta.persistence.GenerationType.IDENTITY; - @Data @Entity @Builder diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ReferenceType.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/constraints/foreignKey/ReferenceType.java similarity index 67% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ReferenceType.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/constraints/foreignKey/ReferenceType.java index 88be5c81aa918ec6c310bb5ed98eaec3842483f6..5e5aacb0bd76ae380da8079fd55eb21ef2a5b09d 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ReferenceType.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/constraints/foreignKey/ReferenceType.java @@ -1,4 +1,4 @@ -package at.tuwien.entities.database.table.constraints.foreignKey; +package at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.foreignKey; import lombok.Getter; import lombok.ToString; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/primaryKey/PrimaryKey.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/constraints/primaryKey/PrimaryKey.java similarity index 85% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/primaryKey/PrimaryKey.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/constraints/primaryKey/PrimaryKey.java index 26e0f132991a5b8bf7a1b2f572575f8f6a48820f..ddf3abdf9a611c90dd18b3614bde097344ba4b2c 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/primaryKey/PrimaryKey.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/constraints/primaryKey/PrimaryKey.java @@ -1,7 +1,7 @@ -package at.tuwien.entities.database.table.constraints.primaryKey; +package at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.primaryKey; -import at.tuwien.entities.database.table.Table; -import at.tuwien.entities.database.table.columns.TableColumn; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.Table; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumn; import jakarta.persistence.*; import lombok.*; import org.hibernate.annotations.JdbcTypeCode; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/unique/Unique.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/constraints/unique/Unique.java similarity index 87% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/unique/Unique.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/constraints/unique/Unique.java index e1ad4c4c4d167bf5ccf21b33d5a22e67d424d988..8dcf9ccbfd1e19a3a901aae4f3338549f35b294a 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/unique/Unique.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/database/table/constraints/unique/Unique.java @@ -1,7 +1,7 @@ -package at.tuwien.entities.database.table.constraints.unique; +package at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.unique; -import at.tuwien.entities.database.table.Table; -import at.tuwien.entities.database.table.columns.TableColumn; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.Table; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumn; import jakarta.persistence.*; import lombok.*; import org.hibernate.annotations.JdbcTypeCode; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/AffiliationIdentifierSchemeType.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/AffiliationIdentifierSchemeType.java similarity index 66% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/AffiliationIdentifierSchemeType.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/AffiliationIdentifierSchemeType.java index 0d794ff431005a17a34294b19816ea84cc6e3ab6..8660ce193619e35b4d20b44c215491eafac3cf2c 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/AffiliationIdentifierSchemeType.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/AffiliationIdentifierSchemeType.java @@ -1,5 +1,5 @@ -package at.tuwien.entities.identifier; +package at.ac.tuwien.ifs.dbrepo.core.entity.identifier; import lombok.Getter; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/Creator.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/Creator.java similarity index 96% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/Creator.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/Creator.java index cdbcf797773cc2d7e9d7dbdecb6dc0fcb0d6afae..8a2bcf25e2e0a7bfc4add70406bc84503cb959d2 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/Creator.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/Creator.java @@ -1,4 +1,4 @@ -package at.tuwien.entities.identifier; +package at.ac.tuwien.ifs.dbrepo.core.entity.identifier; import jakarta.persistence.*; import lombok.*; @@ -7,8 +7,6 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener; import java.util.UUID; -import static jakarta.persistence.GenerationType.IDENTITY; - @Data @Entity @Builder diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/DescriptionType.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/DescriptionType.java similarity index 82% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/DescriptionType.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/DescriptionType.java index 1d9ab52d784a2619239dbf78fbee5679a008d538..ef85f04e72bde17c4a05f768ff05c2c5b32e701b 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/DescriptionType.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/DescriptionType.java @@ -1,5 +1,5 @@ -package at.tuwien.entities.identifier; +package at.ac.tuwien.ifs.dbrepo.core.entity.identifier; import lombok.Getter; @@ -18,7 +18,7 @@ public enum DescriptionType { OTHER("Other"); - private String name; + private final String name; DescriptionType(String name) { this.name = name; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/Identifier.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/Identifier.java similarity index 95% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/Identifier.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/Identifier.java index 43dbb849e341c7aba5dbfc4a3097115ef1ce378b..04471509c6cd711b745f1a9060227d869f2dcb33 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/Identifier.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/Identifier.java @@ -1,9 +1,9 @@ -package at.tuwien.entities.identifier; +package at.ac.tuwien.ifs.dbrepo.core.entity.identifier; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.database.LanguageType; -import at.tuwien.entities.database.License; -import at.tuwien.entities.user.User; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.Database; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.LanguageType; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.License; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.persistence.*; import lombok.*; @@ -17,8 +17,6 @@ import java.time.Instant; import java.util.List; import java.util.UUID; -import static jakarta.persistence.GenerationType.IDENTITY; - @Data @Entity @Builder(toBuilder = true) diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/IdentifierDescription.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/IdentifierDescription.java similarity index 93% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/IdentifierDescription.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/IdentifierDescription.java index 32adddccfc7c73750a1fd516edc6c4638d150739..ab73de406ee607253f14a182a4c9af9f748666dc 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/IdentifierDescription.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/IdentifierDescription.java @@ -1,6 +1,6 @@ -package at.tuwien.entities.identifier; +package at.ac.tuwien.ifs.dbrepo.core.entity.identifier; -import at.tuwien.entities.database.LanguageType; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.LanguageType; import jakarta.persistence.*; import lombok.*; import org.hibernate.annotations.JdbcTypeCode; @@ -9,8 +9,6 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener; import java.io.Serializable; import java.util.UUID; -import static jakarta.persistence.GenerationType.IDENTITY; - @Data @Entity @Builder diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/IdentifierFunder.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/IdentifierFunder.java similarity index 93% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/IdentifierFunder.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/IdentifierFunder.java index 5b69b2e8f70a947dad40460609b0ee5ffc530dfa..eb3c21e61794726e53cabfcfe8e32e58072789d9 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/IdentifierFunder.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/IdentifierFunder.java @@ -1,4 +1,4 @@ -package at.tuwien.entities.identifier; +package at.ac.tuwien.ifs.dbrepo.core.entity.identifier; import jakarta.persistence.*; import lombok.*; @@ -8,8 +8,6 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener; import java.io.Serializable; import java.util.UUID; -import static jakarta.persistence.GenerationType.IDENTITY; - @Data @Entity @Builder diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/IdentifierFunderType.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/IdentifierFunderType.java similarity index 64% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/IdentifierFunderType.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/IdentifierFunderType.java index ea538dcbfbc062884c19cfc4998e33c114f189d9..d805d7e7a269ef33312beb8f982755dbe4236d8d 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/IdentifierFunderType.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/IdentifierFunderType.java @@ -1,4 +1,4 @@ -package at.tuwien.entities.identifier; +package at.ac.tuwien.ifs.dbrepo.core.entity.identifier; public enum IdentifierFunderType { CROSSREF_FUNDER_ID, diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/IdentifierStatusType.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/IdentifierStatusType.java similarity index 53% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/IdentifierStatusType.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/IdentifierStatusType.java index 6dd545a73265e533f37e4bd8966167bb6cb2eae8..242a41e4a7c8e35e7abfb75d2b132a3a0bcb1fc2 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/IdentifierStatusType.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/IdentifierStatusType.java @@ -1,9 +1,9 @@ -package at.tuwien.entities.identifier; +package at.ac.tuwien.ifs.dbrepo.core.entity.identifier; import lombok.Getter; @Getter public enum IdentifierStatusType { DRAFT, - PUBLISHED; + PUBLISHED } diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/IdentifierTitle.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/IdentifierTitle.java similarity index 93% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/IdentifierTitle.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/IdentifierTitle.java index 769ff12a678a9f18d10f877e29461585f5cd2b59..8dbbdac0a9dd7804f61315892201c5df53857403 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/IdentifierTitle.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/IdentifierTitle.java @@ -1,6 +1,6 @@ -package at.tuwien.entities.identifier; +package at.ac.tuwien.ifs.dbrepo.core.entity.identifier; -import at.tuwien.entities.database.LanguageType; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.LanguageType; import jakarta.persistence.*; import lombok.*; import org.hibernate.annotations.JdbcTypeCode; @@ -9,8 +9,6 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener; import java.io.Serializable; import java.util.UUID; -import static jakarta.persistence.GenerationType.IDENTITY; - @Data @Entity @Builder diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/IdentifierType.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/IdentifierType.java similarity index 60% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/IdentifierType.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/IdentifierType.java index 51e2f01ef63a62feea3a6d77e12c42776393d6c7..85fb127d98a247873f24825f65e9ca4afc960c9f 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/IdentifierType.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/IdentifierType.java @@ -1,4 +1,4 @@ -package at.tuwien.entities.identifier; +package at.ac.tuwien.ifs.dbrepo.core.entity.identifier; import lombok.Getter; @@ -7,5 +7,5 @@ public enum IdentifierType { DATABASE, SUBSET, TABLE, - VIEW; + VIEW } diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/NameIdentifierSchemeType.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/NameIdentifierSchemeType.java similarity index 66% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/NameIdentifierSchemeType.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/NameIdentifierSchemeType.java index 6a7eb73a12a15cfd7360cfe7e3034349caa0b75f..645ec69d897678154474377adfd51d65924b9585 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/NameIdentifierSchemeType.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/NameIdentifierSchemeType.java @@ -1,5 +1,5 @@ -package at.tuwien.entities.identifier; +package at.ac.tuwien.ifs.dbrepo.core.entity.identifier; import lombok.Getter; diff --git a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/NameType.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/NameType.java new file mode 100644 index 0000000000000000000000000000000000000000..ce2f1585e438d8f5e5784cd7c73b2daa7d0c2ca8 --- /dev/null +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/NameType.java @@ -0,0 +1,9 @@ +package at.ac.tuwien.ifs.dbrepo.core.entity.identifier; + +import lombok.Getter; + +@Getter +public enum NameType { + PERSONAL, + ORGANIZATIONAL +} diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/RelatedIdentifier.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/RelatedIdentifier.java similarity index 97% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/RelatedIdentifier.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/RelatedIdentifier.java index 24ac7adb1fe1fabd49491a320b29256f8178a0de..e0eb28d11b7c68753c2f99564d28bb59be7fbf17 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/RelatedIdentifier.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/RelatedIdentifier.java @@ -1,4 +1,4 @@ -package at.tuwien.entities.identifier; +package at.ac.tuwien.ifs.dbrepo.core.entity.identifier; import jakarta.persistence.*; import lombok.*; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/RelatedType.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/RelatedType.java similarity index 85% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/RelatedType.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/RelatedType.java index 34f98ef59116e35115a8324262b417b85862d9fc..7310ff455b5ceb1e7ae83ef5bc6547c1f5466a59 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/RelatedType.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/RelatedType.java @@ -1,4 +1,4 @@ -package at.tuwien.entities.identifier; +package at.ac.tuwien.ifs.dbrepo.core.entity.identifier; public enum RelatedType { @@ -38,7 +38,7 @@ public enum RelatedType { W3ID("w3id"); - private String name; + private final String name; RelatedType(String name) { this.name = name; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/RelationType.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/RelationType.java similarity index 94% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/RelationType.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/RelationType.java index 65fc23fddbdbe3dca3dedf0669ad4bdb9a2feb7e..94bebb011799245cf265b95a0a7eb0940dcd5288 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/RelationType.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/RelationType.java @@ -1,4 +1,4 @@ -package at.tuwien.entities.identifier; +package at.ac.tuwien.ifs.dbrepo.core.entity.identifier; public enum RelationType { @@ -70,7 +70,7 @@ public enum RelationType { OBSOLETES("Obsoletes"); - private String name; + private final String name; RelationType(String name) { this.name = name; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/TitleType.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/TitleType.java similarity index 79% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/TitleType.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/TitleType.java index 5dce16f7716483419fdc3c0848faacac0d2c7b57..a4b5f36b67c47d76a92f98c61aa04abe01012471 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/identifier/TitleType.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/identifier/TitleType.java @@ -1,5 +1,5 @@ -package at.tuwien.entities.identifier; +package at.ac.tuwien.ifs.dbrepo.core.entity.identifier; import lombok.Getter; @@ -14,7 +14,7 @@ public enum TitleType { OTHER("Other"); - private String name; + private final String name; TitleType(String name) { this.name = name; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/maintenance/BannerMessage.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/maintenance/BannerMessage.java similarity index 93% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/maintenance/BannerMessage.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/maintenance/BannerMessage.java index 8a5f2d76a3d4b73f89d7223af8df88c7ac7efdb9..ef6f3533e9dc464230b688cf373ff966824937c0 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/maintenance/BannerMessage.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/maintenance/BannerMessage.java @@ -1,4 +1,4 @@ -package at.tuwien.entities.maintenance; +package at.ac.tuwien.ifs.dbrepo.core.entity.maintenance; import jakarta.persistence.*; import lombok.*; @@ -8,8 +8,6 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener; import java.time.Instant; import java.util.UUID; -import static jakarta.persistence.GenerationType.IDENTITY; - @Data @Entity @Builder diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/maintenance/BannerMessageType.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/maintenance/BannerMessageType.java similarity index 65% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/maintenance/BannerMessageType.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/maintenance/BannerMessageType.java index ca838657419292d646c7aaf1349504181cb18224..34cf2bc6d4d75b4b727c1973bf5b97f865c5d1ad 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/maintenance/BannerMessageType.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/maintenance/BannerMessageType.java @@ -1,4 +1,4 @@ -package at.tuwien.entities.maintenance; +package at.ac.tuwien.ifs.dbrepo.core.entity.maintenance; import lombok.Getter; import lombok.ToString; @@ -8,5 +8,5 @@ import lombok.ToString; public enum BannerMessageType { WARNING, ERROR, - INFO; + INFO } \ No newline at end of file diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/semantics/Ontology.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/semantics/Ontology.java similarity index 94% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/semantics/Ontology.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/semantics/Ontology.java index 664b284c3d087250fee1623a624f77305e19c1eb..8cf3250a048654a085c5628e1c12c65083fb4aec 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/semantics/Ontology.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/semantics/Ontology.java @@ -1,4 +1,4 @@ -package at.tuwien.entities.semantics; +package at.ac.tuwien.ifs.dbrepo.core.entity.semantics; import jakarta.persistence.*; import lombok.*; @@ -10,8 +10,6 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener; import java.time.Instant; import java.util.UUID; -import static jakarta.persistence.GenerationType.IDENTITY; - @Data @Entity @Builder diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/user/User.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/user/User.java similarity index 93% rename from dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/user/User.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/user/User.java index 44d36e5e03c1e38a3fd9ecd807abce21116eb768..f3a65f1de5c0a2ca468f1e57a269d71bb5962bb3 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/user/User.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/entity/user/User.java @@ -1,6 +1,6 @@ -package at.tuwien.entities.user; +package at.ac.tuwien.ifs.dbrepo.core.entity.user; -import at.tuwien.entities.database.DatabaseAccess; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.DatabaseAccess; import jakarta.persistence.*; import lombok.*; import lombok.extern.log4j.Log4j2; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AccessNotFoundException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/AccessNotFoundException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AccessNotFoundException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/AccessNotFoundException.java index d308361ae1be8b203212fe460a7098234ccc1e87..9cac5ca8f8fdef6606bd5b5906d7b3660e8db148 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AccessNotFoundException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/AccessNotFoundException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AccountNotSetupException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/AccountNotSetupException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AccountNotSetupException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/AccountNotSetupException.java index 395e63d4239337b4dc58e3ad1ee3945b46900f4f..ed00129ca906373d9c85b66f9076815949086cbc 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AccountNotSetupException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/AccountNotSetupException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AnalyseServiceException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/AnalyseServiceException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AnalyseServiceException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/AnalyseServiceException.java index 44cd0d3dc812b8ac2ff2aa8e19ea022a6c93113e..d86344bc86d95347e9795a9970fd14766766b70d 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AnalyseServiceException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/AnalyseServiceException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AuthServiceConnectionException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/AuthServiceConnectionException.java similarity index 92% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AuthServiceConnectionException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/AuthServiceConnectionException.java index 08cb54f9de186033e1513c270e4461c5638db9d0..abca69a27bf1c2c2ab79b4d7879f5ada47693535 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AuthServiceConnectionException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/AuthServiceConnectionException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AuthServiceException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/AuthServiceException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AuthServiceException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/AuthServiceException.java index de43ce1cbefab60f6e56d4aa942d107c921f7291..de5969c4a8a753ca8fda596505144c1c66710c26 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AuthServiceException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/AuthServiceException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerServiceConnectionException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/BrokerServiceConnectionException.java similarity index 92% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerServiceConnectionException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/BrokerServiceConnectionException.java index 6efa16fa8757fbfcf218f09f0750a500d40161b3..7a5f17d0edbc7f0d5ad6c2d75474dd717a7da1f5 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerServiceConnectionException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/BrokerServiceConnectionException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerServiceException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/BrokerServiceException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerServiceException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/BrokerServiceException.java index 86201c5d691bdede33bca6bef2606125b29775de..c0ca429d66ea789f4278e8075d06ad0f6724e081 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerServiceException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/BrokerServiceException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ConceptNotFoundException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ConceptNotFoundException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ConceptNotFoundException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ConceptNotFoundException.java index 33e093ae5af1a12fe642934139ac23fc50a8d133..6be6c9dd8f64c31c451b071ac857a54d75ee6a39 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ConceptNotFoundException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ConceptNotFoundException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ContainerAlreadyExistsException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ContainerAlreadyExistsException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ContainerAlreadyExistsException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ContainerAlreadyExistsException.java index f27ea0aa19bc91e324ec783e819b52fa2a9c188c..348bcf51f31bac5dfc321fba4cfecd307752b467 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ContainerAlreadyExistsException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ContainerAlreadyExistsException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ContainerNotFoundException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ContainerNotFoundException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ContainerNotFoundException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ContainerNotFoundException.java index 0d17faafab86f9591a573a337b1d598a03cc7f7d..a81b036e26f9cb23a4f08cb5940549e4717afa00 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ContainerNotFoundException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ContainerNotFoundException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ContainerQuotaException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ContainerQuotaException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ContainerQuotaException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ContainerQuotaException.java index 6679775f00473632a2e2e28cd17f3d3303edd0a6..9d01a336071afca41c6d3673a4db7e1a15ecd97e 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ContainerQuotaException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ContainerQuotaException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/CredentialsInvalidException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/CredentialsInvalidException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/CredentialsInvalidException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/CredentialsInvalidException.java index 984c70f4857262c158a7fc15075376aa8e425186..afe130463f44e7fb66901a48c7ff868e93fa88d7 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/CredentialsInvalidException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/CredentialsInvalidException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DashboardServiceConnectionException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DashboardServiceConnectionException.java new file mode 100644 index 0000000000000000000000000000000000000000..cbac75cfff00df627e0815f33171dad246de4bb0 --- /dev/null +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DashboardServiceConnectionException.java @@ -0,0 +1,21 @@ +package at.ac.tuwien.ifs.dbrepo.core.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.BAD_GATEWAY, reason = "error.dashboard.connection") +public class DashboardServiceConnectionException extends Exception { + + public DashboardServiceConnectionException(String msg) { + super(msg); + } + + public DashboardServiceConnectionException(String msg, Throwable thr) { + super(msg + ": " + thr.getLocalizedMessage(), thr); + } + + public DashboardServiceConnectionException(Throwable thr) { + super(thr); + } + +} diff --git a/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DashboardServiceException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DashboardServiceException.java new file mode 100644 index 0000000000000000000000000000000000000000..8ab1d1ef233233df9e8d0998237cee1ebb7d9435 --- /dev/null +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DashboardServiceException.java @@ -0,0 +1,21 @@ +package at.ac.tuwien.ifs.dbrepo.core.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.SERVICE_UNAVAILABLE, reason = "error.dashboard.invalid") +public class DashboardServiceException extends Exception { + + public DashboardServiceException(String message) { + super(message); + } + + public DashboardServiceException(String message, Throwable thr) { + super(message, thr); + } + + public DashboardServiceException(Throwable thr) { + super(thr); + } + +} diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DataServiceConnectionException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DataServiceConnectionException.java similarity index 92% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DataServiceConnectionException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DataServiceConnectionException.java index 0125a781add4e384e43ec87690b0f8afaeb30c92..156d8be72916e4763c9b54f1f3c6f5cf8a882fa2 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DataServiceConnectionException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DataServiceConnectionException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DataServiceException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DataServiceException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DataServiceException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DataServiceException.java index f76e662a655593ffe5991ec84da207b58df052b2..66ea9a4e9bd94b6e9d728c04f00bc3093c2f83eb 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DataServiceException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DataServiceException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseMalformedException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DatabaseMalformedException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseMalformedException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DatabaseMalformedException.java index 4bdc362256cc6a8778649a3a22f0aa2ca72761ae..797341970523d486f28c1b739a461ed657c085e0 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseMalformedException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DatabaseMalformedException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseNotFoundException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DatabaseNotFoundException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseNotFoundException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DatabaseNotFoundException.java index c50349f33bd3f5df80f163ecddd9b9e43569416f..41cdcc8d4b2b67b86cccbb5351bfabb0e2b405cb 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseNotFoundException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DatabaseNotFoundException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseUnavailableException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DatabaseUnavailableException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseUnavailableException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DatabaseUnavailableException.java index 12c13d0754070f7b8eb425442e6dbc7e53023e51..1f40dd083245df171722b29b370e708bed157f53 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseUnavailableException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DatabaseUnavailableException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DoiNotFoundException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DoiNotFoundException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DoiNotFoundException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DoiNotFoundException.java index 3b8e1732cce6b8b7e8f1c2f8e9a138f074bb1682..790c43f28de7fcf9286582c2ce7d9eed90d7a2aa 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DoiNotFoundException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/DoiNotFoundException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/EmailExistsException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/EmailExistsException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/EmailExistsException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/EmailExistsException.java index 4ce6c9b0ba51cfbd9f438069266785eb123bdf1b..c82f6438bd964d144f6d0b88bf027004c2345e5a 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/EmailExistsException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/EmailExistsException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ExchangeNotFoundException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ExchangeNotFoundException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ExchangeNotFoundException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ExchangeNotFoundException.java index 251f09081e6ea9fc0ed09c14dfbe01eb60a4d69a..f6e32e047a33eb45a48d4228633d9809b27acf7d 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ExchangeNotFoundException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ExchangeNotFoundException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ExternalServiceException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ExternalServiceException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ExternalServiceException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ExternalServiceException.java index d5f399c40205b886607f5fc1c22d17d9b159f6e4..0866ee86d1ea2d70fe066ed4cd2e093695cd742c 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ExternalServiceException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ExternalServiceException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/FilterBadRequestException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/FilterBadRequestException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/FilterBadRequestException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/FilterBadRequestException.java index 88689409aebad584a02b69db0639379788ee9536..0c584430a64a53e42b2f6ed8024b03c2de6c64ff 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/FilterBadRequestException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/FilterBadRequestException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/FormatNotAvailableException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/FormatNotAvailableException.java similarity index 90% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/FormatNotAvailableException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/FormatNotAvailableException.java index 2681e8d442cf873eef9d07497f4b18cfb6a4c5fe..f977c087cbdc4f1917e5e8e77237531e19d404ed 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/FormatNotAvailableException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/FormatNotAvailableException.java @@ -1,10 +1,8 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; -import java.io.IOException; - @ResponseStatus(code = HttpStatus.NOT_ACCEPTABLE, reason = "error.identifier.format") public class FormatNotAvailableException extends Exception { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierNotFoundException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/IdentifierNotFoundException.java similarity index 92% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierNotFoundException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/IdentifierNotFoundException.java index dee6a000352dd6c501f539b38bb5be34b50ede7a..a17825aed335e0b746a3f003d0a2e90769c35a79 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierNotFoundException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/IdentifierNotFoundException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierNotSupportedException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/IdentifierNotSupportedException.java similarity index 92% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierNotSupportedException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/IdentifierNotSupportedException.java index 23b26ac6d674b2e0e306787f5cebd2e91c01904d..07d090a2a3750a6fd601628710d668a0cb0aacfa 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierNotSupportedException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/IdentifierNotSupportedException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ImageAlreadyExistsException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ImageAlreadyExistsException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ImageAlreadyExistsException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ImageAlreadyExistsException.java index 2db757ed21db3a0d022f1e85a23762c280974a39..98e854ca18c38efe05d65f1a876e06299f4a325d 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ImageAlreadyExistsException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ImageAlreadyExistsException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ImageInvalidException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ImageInvalidException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ImageInvalidException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ImageInvalidException.java index 401b587aedf5b5665315e76c7a4615ea65a19f82..4b4eeef07cea154bc389a117f247c479a58ea30f 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ImageInvalidException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ImageInvalidException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ImageNotFoundException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ImageNotFoundException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ImageNotFoundException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ImageNotFoundException.java index a0235cc7536c3e23a25093bb638c1eee64fd543d..4e0bcf905ca274dd17b30e796c7d73a3b6836cff 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ImageNotFoundException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ImageNotFoundException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/LicenseNotFoundException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/LicenseNotFoundException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/LicenseNotFoundException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/LicenseNotFoundException.java index fec3ad4128788ea8bd6700d979eada0afbb837e7..1b4ad4f10e343332e3b631ed54e5690557f9a85c 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/LicenseNotFoundException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/LicenseNotFoundException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/MalformedException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/MalformedException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/MalformedException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/MalformedException.java index 974c2dadd6563cdf84799fbe661978ccf89a1c7c..f358709de7fe24483fa1e4d71092cc0b087c1503 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/MalformedException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/MalformedException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/MessageNotFoundException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/MessageNotFoundException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/MessageNotFoundException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/MessageNotFoundException.java index 90905905514396c90a6c64b1131269d8660ca56b..53294e85d21c64766f1852b1c2592ea3a2ceacd5 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/MessageNotFoundException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/MessageNotFoundException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/MetadataServiceConnectionException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/MetadataServiceConnectionException.java similarity index 92% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/MetadataServiceConnectionException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/MetadataServiceConnectionException.java index 329de6ffc4b82b859da0ea41aca7ed99a3b1802c..10599ab33967ad90115a600200c305dd558089a8 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/MetadataServiceConnectionException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/MetadataServiceConnectionException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/MetadataServiceException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/MetadataServiceException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/MetadataServiceException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/MetadataServiceException.java index a6784d6dd01ed0c60379246373b26d3c49a8875d..ec86fd55f22494884c795856b9308d6336828ba4 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/MetadataServiceException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/MetadataServiceException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/NotAllowedException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/NotAllowedException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/NotAllowedException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/NotAllowedException.java index 52a2867b017fa3a141b7dc573e47e9d0c010de53..79332fe74aad93f45d2915645a8690750c7839a0 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/NotAllowedException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/NotAllowedException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/OntologyNotFoundException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/OntologyNotFoundException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/OntologyNotFoundException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/OntologyNotFoundException.java index 5f15403d67a48d7ed28d04f4f80776d9e3c3ce4d..283219e7809e9e193f3f5a83318a6396b2511b43 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/OntologyNotFoundException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/OntologyNotFoundException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/OrcidNotFoundException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/OrcidNotFoundException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/OrcidNotFoundException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/OrcidNotFoundException.java index cf1ad7c067dcd8e9423507df45b0dc78458fa4ae..2ad3560a8e6a677eda125c06f71ff24173e6a9fb 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/OrcidNotFoundException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/OrcidNotFoundException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/PaginationException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/PaginationException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/PaginationException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/PaginationException.java index 5d71d0c4046b2cf8b29800efb41c0d0d6dfef1aa..4eae0a8bc600bdfa365277bac69496a86fd72277 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/PaginationException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/PaginationException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryMalformedException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueryMalformedException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryMalformedException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueryMalformedException.java index 0782bc3269d3e3457d0d54215a5699db360fc2d3..571ae5e31393dc0651f62c133431f5674fc6e028 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryMalformedException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueryMalformedException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryNotFoundException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueryNotFoundException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryNotFoundException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueryNotFoundException.java index 631fb1f0d832d22d2966f3e44c1db05c18166fea..0bdba4634eaccd1e20b27c6e29770f02eb84cfd3 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryNotFoundException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueryNotFoundException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryNotSupportedException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueryNotSupportedException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryNotSupportedException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueryNotSupportedException.java index e5894f0fdde0617634b99b59d436d13c656d449f..6a5df4f9e10d1e6cc5ec32f417c901b73bee1027 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryNotSupportedException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueryNotSupportedException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStoreCreateException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueryStoreCreateException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStoreCreateException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueryStoreCreateException.java index 27ddb85e2c7eb6746eedf3e6e4e0c137a5a55227..d69c7757c52898de3048e07ccf938df037012eea 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStoreCreateException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueryStoreCreateException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStoreGCException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueryStoreGCException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStoreGCException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueryStoreGCException.java index 00302c55eab047c7b565413a0d0a0a7e50383596..d4f40910bc83cdc1a3cc6bd0c6995d6545579775 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStoreGCException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueryStoreGCException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStoreInsertException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueryStoreInsertException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStoreInsertException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueryStoreInsertException.java index 564383c844ee31ad55f383df81e5c1c783dc310f..0b7713d2ed0aebad22f43a09335267cf0717ac1b 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStoreInsertException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueryStoreInsertException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStorePersistException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueryStorePersistException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStorePersistException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueryStorePersistException.java index 5b17442a3a804504755a9c16675b3f30258d0ea2..4cf73af90be1d7a41f2cfa07653bd18ce51fb729 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStorePersistException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueryStorePersistException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueueNotFoundException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueueNotFoundException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueueNotFoundException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueueNotFoundException.java index d06eca74382987d0ab855d3637b38a2f9bbd4c3c..69e1550046a08ebe240f730bc92e6712d5f87697 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueueNotFoundException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/QueueNotFoundException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RemoteUnavailableException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/RemoteUnavailableException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RemoteUnavailableException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/RemoteUnavailableException.java index 6c2b14bb9bb0005689d820170c2dc1901f16810e..0ab1bb158db100916071b4b547084cc55128a214 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RemoteUnavailableException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/RemoteUnavailableException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RorNotFoundException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/RorNotFoundException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RorNotFoundException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/RorNotFoundException.java index afee080b5edc983ab157977560555536ad1c2298..12a9e3ce069edcadfcc86739673c515d7662c408 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RorNotFoundException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/RorNotFoundException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SearchServiceConnectionException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/SearchServiceConnectionException.java similarity index 92% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SearchServiceConnectionException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/SearchServiceConnectionException.java index d68185102a00e33419ae8cf2c4250c0775082a23..ee6b4ab5ba0cf2c1fa70d15b8cf30d7a5ce5d5ab 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SearchServiceConnectionException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/SearchServiceConnectionException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SearchServiceException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/SearchServiceException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SearchServiceException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/SearchServiceException.java index aef3ae7f7cd75db6ec7ed59f95980f2c8e021c2b..a2ca63f200ae6ea27cc546d5538b788b90bc8b7d 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SearchServiceException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/SearchServiceException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SemanticEntityNotFoundException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/SemanticEntityNotFoundException.java similarity index 92% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SemanticEntityNotFoundException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/SemanticEntityNotFoundException.java index 83c2f07f57d709f410c1a7b44b9aab07e167a322..78540ac51c152081b8fe0069dbdb19351c9edc3e 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SemanticEntityNotFoundException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/SemanticEntityNotFoundException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SortException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/SortException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SortException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/SortException.java index f70f0fbef996d4e7032ecf6dc73b5037223c7b20..bf9f1dd2b74decf353e1bb4e024db99bdd1afe5c 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SortException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/SortException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/StorageNotFoundException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/StorageNotFoundException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/StorageNotFoundException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/StorageNotFoundException.java index bbb780ea919d33c64c34f719f99c5ed30eae326a..2bef9e7a75fe24896e9d37830a36fe42f33877b7 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/StorageNotFoundException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/StorageNotFoundException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/StorageUnavailableException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/StorageUnavailableException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/StorageUnavailableException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/StorageUnavailableException.java index 08e49ada9ed210046c755c04eb6e4a07c224020c..813cbd58ad1bf5b32096936d7ab84c9d45f4015f 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/StorageUnavailableException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/StorageUnavailableException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableExistsException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/TableExistsException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableExistsException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/TableExistsException.java index 252c1b0fa67e57f73e17a971cbcec1ccca6f1caf..7eca5f85e0a556c2668a9ae936ae17105cd6b439 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableExistsException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/TableExistsException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableMalformedException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/TableMalformedException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableMalformedException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/TableMalformedException.java index 0878f3607070f2a18976454714f6e6e64a23ce7d..0440a939bffbc6fa6255f37c541195c5fc45a587 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableMalformedException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/TableMalformedException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableNotFoundException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/TableNotFoundException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableNotFoundException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/TableNotFoundException.java index 5380be1e60058b51d0832f69fbc875449f3d0bf1..e40bf35f76a095e8eecd2ca7d5fc2823330b3a82 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableNotFoundException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/TableNotFoundException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableSchemaException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/TableSchemaException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableSchemaException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/TableSchemaException.java index 539e39897e52c3447378aa46112b96d654cdb7d1..47d0456aa53c4334fd62254773c014568ec0a4d9 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableSchemaException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/TableSchemaException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UnitNotFoundException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/UnitNotFoundException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UnitNotFoundException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/UnitNotFoundException.java index 1cc030875525cef47f135821f2827cc8aca6c2a9..b8204c40e750cb4e692f8f7133a3d7cad52391cc 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UnitNotFoundException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/UnitNotFoundException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UriMalformedException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/UriMalformedException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UriMalformedException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/UriMalformedException.java index 05d10c1323d84cbeaef3d9a29122fc04c6ec9cf1..fa4317280ae321041098707cf60395f8c8240f21 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UriMalformedException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/UriMalformedException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UserExistsException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/UserExistsException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UserExistsException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/UserExistsException.java index 712e79fa26fb768c7c25dbc6aa971a4269396de6..e2640b3039c4c8ec45fb9bb7b64f7c7c61355063 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UserExistsException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/UserExistsException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UserNotFoundException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/UserNotFoundException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UserNotFoundException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/UserNotFoundException.java index 1aa6adafecb5fbe86ab0307efec87c3a2ea6cc0b..47c78d0b08c5e8f6bbe42dd5ab330c13d9aa586f 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UserNotFoundException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/UserNotFoundException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ViewExistsException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ViewExistsException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ViewExistsException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ViewExistsException.java index 265974db55184f6f770190068c79596b39281b6d..c45e0022f0d25b2086b97b021f25df05a2982dd7 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ViewExistsException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ViewExistsException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ViewMalformedException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ViewMalformedException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ViewMalformedException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ViewMalformedException.java index 0f8d5bef5520a5b1f93f3ec7aa5cf77051c85378..e8158644facc497b035eb67787ac137caed3bfde 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ViewMalformedException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ViewMalformedException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ViewNotFoundException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ViewNotFoundException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ViewNotFoundException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ViewNotFoundException.java index 2c8cf52e0e60e9375a1c91e01912b631388bfe0a..fea56d5edd4f7f19d1769e057e3a27e608307f95 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ViewNotFoundException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ViewNotFoundException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ViewSchemaException.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ViewSchemaException.java similarity index 91% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ViewSchemaException.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ViewSchemaException.java index 4761b6e964a1db84de55fbd2a70006c1cc15a54c..035842aab71af5896be1e12f2dc802c391bbd30e 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ViewSchemaException.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/exception/ViewSchemaException.java @@ -1,4 +1,4 @@ -package at.tuwien.exception; +package at.ac.tuwien.ifs.dbrepo.core.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/mapper/MetadataMapper.java similarity index 79% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/mapper/MetadataMapper.java index 74284789247ee20deac7df99c49a4f60e8cfa765..e6c354e35ed31de22300fecb2a6b8abcefdd8101 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/mapper/MetadataMapper.java @@ -1,79 +1,87 @@ -package at.tuwien.mapper; - -import at.tuwien.api.container.ContainerBriefDto; -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.table.TableBriefDto; -import at.tuwien.api.database.table.TableDto; -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.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; -import at.tuwien.api.database.table.constraints.foreign.ReferenceTypeDto; -import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto; -import at.tuwien.api.database.table.constraints.unique.UniqueDto; -import at.tuwien.api.datacite.doi.*; -import at.tuwien.api.identifier.*; -import at.tuwien.api.identifier.ld.LdCreatorDto; -import at.tuwien.api.identifier.ld.LdDatasetDto; -import at.tuwien.api.keycloak.TokenDto; -import at.tuwien.api.keycloak.UserCreateDto; -import at.tuwien.api.maintenance.BannerMessageBriefDto; -import at.tuwien.api.maintenance.BannerMessageCreateDto; -import at.tuwien.api.maintenance.BannerMessageDto; -import at.tuwien.api.maintenance.BannerMessageTypeDto; -import at.tuwien.api.orcid.OrcidDto; -import at.tuwien.api.orcid.activities.employments.affiliation.OrcidAffiliationGroupDto; -import at.tuwien.api.orcid.activities.employments.affiliation.group.OrcidEmploymentSummaryDto; -import at.tuwien.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated.OrcidDisambiguatedDto; -import at.tuwien.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated.OrcidDisambiguatedSourceTypeDto; -import at.tuwien.api.ror.RorDto; -import at.tuwien.api.semantics.EntityDto; -import at.tuwien.api.semantics.OntologyBriefDto; -import at.tuwien.api.semantics.OntologyCreateDto; -import at.tuwien.api.semantics.OntologyDto; -import at.tuwien.api.user.UserBriefDto; -import at.tuwien.api.user.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; -import at.tuwien.entities.container.Container; -import at.tuwien.entities.container.image.ContainerImage; -import at.tuwien.entities.container.image.DataType; -import at.tuwien.entities.database.*; -import at.tuwien.entities.database.table.Table; -import at.tuwien.entities.database.table.columns.TableColumn; -import at.tuwien.entities.database.table.columns.TableColumnConcept; -import at.tuwien.entities.database.table.columns.TableColumnUnit; -import at.tuwien.entities.database.table.constraints.Constraints; -import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKey; -import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKeyReference; -import at.tuwien.entities.database.table.constraints.foreignKey.ReferenceType; -import at.tuwien.entities.database.table.constraints.primaryKey.PrimaryKey; -import at.tuwien.entities.database.table.constraints.unique.Unique; -import at.tuwien.entities.identifier.*; -import at.tuwien.entities.maintenance.BannerMessage; -import at.tuwien.entities.maintenance.BannerMessageType; -import at.tuwien.entities.semantics.Ontology; -import at.tuwien.entities.user.User; +package at.ac.tuwien.ifs.dbrepo.core.mapper; + +import at.ac.tuwien.ifs.dbrepo.core.api.container.ContainerBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.ContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.CreateContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.DataTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.ImageDto; +import at.ac.tuwien.ifs.dbrepo.core.api.crossref.CrossRefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.TableDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.ColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.CreateTableColumnDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.concepts.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.ConstraintsDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.CreateTableConstraintsDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign.ForeignKeyBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign.ForeignKeyDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign.ForeignKeyReferenceDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign.ReferenceTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.primary.PrimaryKeyDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.unique.UniqueDto; +import at.ac.tuwien.ifs.dbrepo.core.api.datacite.doi.*; +import at.ac.tuwien.ifs.dbrepo.core.api.grafana.CreateDashboardDto; +import at.ac.tuwien.ifs.dbrepo.core.api.grafana.PermissionTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.*; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.ld.LdCreatorDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.ld.LdDatasetDto; +import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.TokenDto; +import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.UserCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageDto; +import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.OrcidDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.OrcidActivitiesSummaryDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.OrcidEmploymentsDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.OrcidAffiliationGroupDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.group.OrcidEmploymentSummaryDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.group.summary.OrcidSummaryDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.group.summary.organization.OrcidOrganizationDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated.OrcidDisambiguatedDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated.OrcidDisambiguatedSourceTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.person.OrcidPersonDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.person.name.OrcidNameDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.person.name.OrcidValueDto; +import at.ac.tuwien.ifs.dbrepo.core.api.ror.RorDto; +import at.ac.tuwien.ifs.dbrepo.core.api.semantics.EntityDto; +import at.ac.tuwien.ifs.dbrepo.core.api.semantics.OntologyBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.semantics.OntologyCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.semantics.OntologyDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.external.ExternalMetadataDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.external.ExternalResultType; +import at.ac.tuwien.ifs.dbrepo.core.api.user.external.affiliation.ExternalAffiliationDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.Container; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.image.ContainerImage; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.image.DataType; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.*; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.Table; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumn; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumnConcept; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumnUnit; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.Constraints; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.foreignKey.ForeignKey; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.foreignKey.ForeignKeyReference; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.foreignKey.ReferenceType; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.primaryKey.PrimaryKey; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.unique.Unique; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.*; +import at.ac.tuwien.ifs.dbrepo.core.entity.maintenance.BannerMessage; +import at.ac.tuwien.ifs.dbrepo.core.entity.maintenance.BannerMessageType; +import at.ac.tuwien.ifs.dbrepo.core.entity.semantics.Ontology; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; import org.keycloak.representations.AccessTokenResponse; import org.keycloak.representations.idm.UserRepresentation; import org.mapstruct.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.text.Normalizer; import java.time.Instant; @@ -86,7 +94,7 @@ import java.util.stream.Collectors; @Mapper(componentModel = "spring", imports = {LinkedList.class, ExternalResultType.class}) public interface MetadataMapper { - org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MetadataMapper.class); + Logger log = LoggerFactory.getLogger(MetadataMapper.class); @Mappings({ @Mapping(target = "dMin", source = "DMin"), @@ -96,6 +104,12 @@ public interface MetadataMapper { }) DataTypeDto dataTypeToDataTypeDto(DataType data); + @Mappings({ + @Mapping(target = "databaseName", source = "internalName"), + @Mapping(target = "ownerUsername", source = "owner.username") + }) + CreateDashboardDto databaseToCreateDashboardDto(Database database); + @Mappings({ @Mapping(target = "id", ignore = true), /* id attribute is ignored by the library anyway, just making it explicit */ @Mapping(target = "attributes", ignore = true) @@ -267,6 +281,38 @@ public interface MetadataMapper { }) ExternalMetadataDto orcidDtoToExternalMetadataDto(OrcidDto data); + default OrcidDto userToOrcidDto(User data) { + return OrcidDto.builder() + .person(OrcidPersonDto.builder() + .name(OrcidNameDto.builder() + .givenNames(OrcidValueDto.builder() + .value(data.getFirstname()) + .build()) + .familyName(OrcidValueDto.builder() + .value(data.getLastname()) + .build()) + .build()) + .build()) + .activitiesSummary(OrcidActivitiesSummaryDto.builder() + .employments(OrcidEmploymentsDto.builder() + .affiliationGroup(new OrcidAffiliationGroupDto[]{ + OrcidAffiliationGroupDto.builder() + .summaries(new OrcidEmploymentSummaryDto[]{ + OrcidEmploymentSummaryDto.builder() + .employmentSummary(OrcidSummaryDto.builder() + .organization(OrcidOrganizationDto.builder() + .name(data.getAffiliation()) + .build()) + .build()) + .build() + }) + .build() + }) + .build()) + .build()) + .build(); + } + @Mappings({ @Mapping(target = "organizationName", source = "employmentSummary.organization.name"), @Mapping(target = "ringgoldId", expression = "java(disambiguatedOrganizationToRinggoldId(data.getEmploymentSummary().getOrganization().getDisambiguatedOrganization()))"), @@ -289,6 +335,16 @@ public interface MetadataMapper { return null; } + default PermissionTypeDto accessTypeDtoToPermissionTypeDto(AccessTypeDto data) { + if (data == null) { + return PermissionTypeDto.NONE; + } + return switch (data) { + case READ -> PermissionTypeDto.VIEW; + case WRITE_OWN, WRITE_ALL -> PermissionTypeDto.EDITOR; + }; + } + default ExternalMetadataDto rorDtoToExternalMetadataDto(RorDto data) { return ExternalMetadataDto.builder() .affiliations(new ExternalAffiliationDto[]{ @@ -299,7 +355,7 @@ public interface MetadataMapper { .build(); } - default ExternalMetadataDto crossrefDtoToExternalMetadataDto(CrossrefDto data) { + default ExternalMetadataDto crossrefDtoToExternalMetadataDto(CrossRefDto data) { return ExternalMetadataDto.builder() .affiliations(new ExternalAffiliationDto[]{ ExternalAffiliationDto.builder() @@ -336,6 +392,9 @@ public interface MetadataMapper { case SUBSET -> links.setData("/api/database/" + data.getDatabase().getId() + "/subset/" + data.getQueryId() + "/data"); } + if (data.getDatabase().getIsDashboardEnabled()) { + links.setDashboardHtml("/d/" + data.getDatabase().getDashboardUid()); + } return links; } @@ -400,12 +459,18 @@ public interface MetadataMapper { .build(); } - Identifier identifierCreateDtoToIdentifier(CreateIdentifierDto data); + Identifier createIdentifierDtoToIdentifier(CreateIdentifierDto data); - Identifier identifierUpdateDtoToIdentifier(IdentifierSaveDto data); + Identifier identifierSaveDtoToIdentifier(IdentifierSaveDto data); + + IdentifierSaveDto identifierToIdentifierSaveDto(Identifier data); + + CreateIdentifierDto identifierToCreateIdentifierDto(Identifier data); License licenseDtoToLicense(LicenseDto data); + ImageCreateDto containerImageToImageCreateDto(ContainerImage data); + IdentifierTitle identifierCreateTitleDtoToIdentifierTitle(SaveIdentifierTitleDto data); IdentifierDescription identifierCreateDescriptionDtoToIdentifierDescription(SaveIdentifierDescriptionDto data); @@ -512,8 +577,12 @@ public interface MetadataMapper { ConceptDto tableColumnConceptToConceptDto(TableColumnConcept data); + ConceptBriefDto tableColumnConceptToConceptBriefDto(TableColumnConcept data); + UnitDto tableColumnUnitToUnitDto(TableColumnUnit data); + UnitBriefDto tableColumnUnitToUnitBriefDto(TableColumnUnit data); + TableColumnUnit unitSaveDtoToTableColumnUnit(UnitSaveDto data); TableColumnUnit entityDtoToTableColumnUnit(EntityDto data); @@ -588,6 +657,7 @@ public interface MetadataMapper { .identifiers(new LinkedList<>()) .columns(new LinkedList<>()) .constraints(constraintsToConstraintsDto(data.getConstraints())) + .created(data.getCreated()) .build(); if (data.getIdentifiers() != null) { table.setIdentifiers(new LinkedList<>(data.getIdentifiers() @@ -866,10 +936,8 @@ public interface MetadataMapper { String nowhitespace = WHITESPACE.matcher(data).replaceAll("_"); String normalized = Normalizer.normalize(nowhitespace, Normalizer.Form.NFD); String slug = NONLATIN.matcher(normalized).replaceAll("_"); - final String name = slug.toLowerCase(Locale.ENGLISH) + return slug.toLowerCase(Locale.ENGLISH) .replaceAll("-", "_"); - log.debug("mapping name {} to internal name {}", data, name); - return name; } LanguageType languageTypeDtoToLanguageType(LanguageTypeDto data); diff --git a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/test/BaseTest.java similarity index 69% rename from dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/test/BaseTest.java index 490c902295d9c50977caa0ab2b66a462ba6d514b..5209b40ce42e0675cf3c94570444f184f382b3e6 100644 --- a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/test/BaseTest.java @@ -1,73 +1,76 @@ -package at.tuwien.test; - -import at.tuwien.ExportResourceDto; -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.container.ContainerBriefDto; -import at.tuwien.api.container.ContainerDto; -import at.tuwien.api.container.image.*; -import at.tuwien.api.database.*; -import at.tuwien.api.database.query.*; -import at.tuwien.api.database.table.*; -import at.tuwien.api.database.table.columns.*; -import at.tuwien.api.database.table.columns.concepts.*; -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.datacite.DataCiteBody; -import at.tuwien.api.datacite.DataCiteData; -import at.tuwien.api.datacite.doi.DataCiteDoi; -import at.tuwien.api.identifier.*; -import at.tuwien.api.keycloak.*; -import at.tuwien.api.maintenance.BannerMessageCreateDto; -import at.tuwien.api.maintenance.BannerMessageDto; -import at.tuwien.api.maintenance.BannerMessageTypeDto; -import at.tuwien.api.maintenance.BannerMessageUpdateDto; -import at.tuwien.api.orcid.OrcidDto; -import at.tuwien.api.orcid.activities.OrcidActivitiesSummaryDto; -import at.tuwien.api.orcid.activities.employments.OrcidEmploymentsDto; -import at.tuwien.api.orcid.activities.employments.affiliation.OrcidAffiliationGroupDto; -import at.tuwien.api.orcid.activities.employments.affiliation.group.OrcidEmploymentSummaryDto; -import at.tuwien.api.orcid.activities.employments.affiliation.group.summary.OrcidSummaryDto; -import at.tuwien.api.orcid.activities.employments.affiliation.group.summary.organization.OrcidOrganizationDto; -import at.tuwien.api.orcid.person.OrcidPersonDto; -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.*; -import at.tuwien.api.user.internal.UpdateUserPasswordDto; -import at.tuwien.entities.container.Container; -import at.tuwien.entities.container.image.ContainerImage; -import at.tuwien.entities.container.image.Operator; -import at.tuwien.entities.database.*; -import at.tuwien.entities.database.table.Table; -import at.tuwien.entities.database.table.columns.TableColumn; -import at.tuwien.entities.database.table.columns.TableColumnConcept; -import at.tuwien.entities.database.table.columns.TableColumnType; -import at.tuwien.entities.database.table.columns.TableColumnUnit; -import at.tuwien.entities.database.table.constraints.Constraints; -import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKey; -import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKeyReference; -import at.tuwien.entities.database.table.constraints.foreignKey.ReferenceType; -import at.tuwien.entities.database.table.constraints.primaryKey.PrimaryKey; -import at.tuwien.entities.database.table.constraints.unique.Unique; -import at.tuwien.entities.identifier.*; -import at.tuwien.entities.maintenance.BannerMessage; -import at.tuwien.entities.maintenance.BannerMessageType; -import at.tuwien.entities.semantics.Ontology; -import at.tuwien.entities.user.User; -import at.tuwien.test.utils.ArrayUtils; +package at.ac.tuwien.ifs.dbrepo.core.test; + +import at.ac.tuwien.ifs.dbrepo.core.api.ExportResourceDto; +import at.ac.tuwien.ifs.dbrepo.core.api.amqp.CreateVirtualHostDto; +import at.ac.tuwien.ifs.dbrepo.core.api.amqp.ExchangeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.amqp.GrantVirtualHostPermissionsDto; +import at.ac.tuwien.ifs.dbrepo.core.api.amqp.QueueDto; +import at.ac.tuwien.ifs.dbrepo.core.api.auth.CreateUserDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.ContainerBriefDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.ContainerDto; +import at.ac.tuwien.ifs.dbrepo.core.api.container.image.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.query.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.columns.concepts.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.ConstraintsDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.CreateTableConstraintsDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.foreign.*; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.primary.PrimaryKeyDto; +import at.ac.tuwien.ifs.dbrepo.core.api.database.table.constraints.unique.UniqueDto; +import at.ac.tuwien.ifs.dbrepo.core.api.datacite.DataCiteBody; +import at.ac.tuwien.ifs.dbrepo.core.api.datacite.DataCiteData; +import at.ac.tuwien.ifs.dbrepo.core.api.datacite.doi.DataCiteDoi; +import at.ac.tuwien.ifs.dbrepo.core.api.grafana.CreateDashboardDto; +import at.ac.tuwien.ifs.dbrepo.core.api.grafana.CreateDashboardResponseDto; +import at.ac.tuwien.ifs.dbrepo.core.api.identifier.*; +import at.ac.tuwien.ifs.dbrepo.core.api.keycloak.*; +import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageCreateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageDto; +import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageTypeDto; +import at.ac.tuwien.ifs.dbrepo.core.api.maintenance.BannerMessageUpdateDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.OrcidDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.OrcidActivitiesSummaryDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.OrcidEmploymentsDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.OrcidAffiliationGroupDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.group.OrcidEmploymentSummaryDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.group.summary.OrcidSummaryDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.activities.employments.affiliation.group.summary.organization.OrcidOrganizationDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.person.OrcidPersonDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.person.name.OrcidNameDto; +import at.ac.tuwien.ifs.dbrepo.core.api.orcid.person.name.OrcidValueDto; +import at.ac.tuwien.ifs.dbrepo.core.api.semantics.*; +import at.ac.tuwien.ifs.dbrepo.core.api.user.*; +import at.ac.tuwien.ifs.dbrepo.core.api.user.UserAttributesDto; +import at.ac.tuwien.ifs.dbrepo.core.api.user.internal.UpdateUserPasswordDto; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.Container; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.image.ContainerImage; +import at.ac.tuwien.ifs.dbrepo.core.entity.container.image.Operator; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.*; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.Table; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumn; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumnConcept; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumnType; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.columns.TableColumnUnit; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.Constraints; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.foreignKey.ForeignKey; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.foreignKey.ForeignKeyReference; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.foreignKey.ReferenceType; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.primaryKey.PrimaryKey; +import at.ac.tuwien.ifs.dbrepo.core.entity.database.table.constraints.unique.Unique; +import at.ac.tuwien.ifs.dbrepo.core.entity.identifier.*; +import at.ac.tuwien.ifs.dbrepo.core.entity.maintenance.BannerMessage; +import at.ac.tuwien.ifs.dbrepo.core.entity.maintenance.BannerMessageType; +import at.ac.tuwien.ifs.dbrepo.core.entity.semantics.Ontology; +import at.ac.tuwien.ifs.dbrepo.core.entity.user.User; +import at.ac.tuwien.ifs.dbrepo.core.test.utils.ArrayUtils; import org.springframework.core.io.InputStreamResource; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.test.context.TestPropertySource; import java.io.InputStream; import java.math.BigDecimal; @@ -77,7 +80,6 @@ import java.time.Instant; import java.time.LocalDate; import java.time.ZoneOffset; import java.util.*; -import java.util.stream.Collectors; import static java.time.temporal.ChronoUnit.HOURS; import static java.time.temporal.ChronoUnit.MINUTES; @@ -121,183 +123,180 @@ import static java.time.temporal.ChronoUnit.MINUTES; * </ul> * <p> * Database 4 (Public Data, Public Schema, User 4) -> Container 4 + * <ul> * <li>Table 9</li> * <li>Identifier 7</li> * <li>Query 7</li> - * <ul> * </ul> - * <br /> - * User 1 (read) - * <br /> - * User 2 (write-own) - * <br /> - * User 3 (write-all) */ -public abstract class BaseTest { - - public static final String MINIO_IMAGE = "minio/minio:RELEASE.2024-06-06T09-36-42Z"; - - public static final String MARIADB_IMAGE = "mariadb:11.3.2"; +@TestPropertySource(locations = "classpath:application.properties") +public class BaseTest { - public static final String RABBITMQ_IMAGE = "rabbitmq:3.13.7"; + public final static String MINIO_IMAGE = "minio/minio:RELEASE.2024-06-06T09-36-42Z"; + public final static String MARIADB_IMAGE = "mariadb:11.3.2"; + public final static String RABBITMQ_IMAGE = "rabbitmq:3.13.7"; + public final static String KEYCLOAK_IMAGE = "quay.io/keycloak/keycloak:26.0.4"; - public static final String KEYCLOAK_IMAGE = "quay.io/keycloak/keycloak:26.0.4"; + public final static String REALM_DBREPO_NAME = "dbrepo"; - public static final String[] DEFAULT_SEMANTICS_HANDLING = new String[]{"default-semantics-handling", + public final static String[] DEFAULT_SEMANTICS_HANDLING = new String[]{"default-semantics-handling", "create-semantic-unit", "execute-semantic-query", "table-semantic-analyse", "create-semantic-concept"}; - public static final String[] DEFAULT_VIEW_HANDLING = new String[]{"update-database-view", "create-database-view", + public final static String[] DEFAULT_VIEW_HANDLING = new String[]{"update-database-view", "create-database-view", "delete-database-view", "list-database-views", "modify-view-visibility", "find-database-view"}; - public static final String[] ESCALATED_SEMANTICS_HANDLING = new String[]{"escalated-semantics-handling", + public final static String[] ESCALATED_SEMANTICS_HANDLING = new String[]{"escalated-semantics-handling", "update-semantic-concept", "modify-foreign-table-column-semantics", "delete-ontology", "list-ontologies", "update-semantic-unit", "create-ontology", "update-ontology"}; - public static final String[] DEFAULT_CONTAINER_HANDLING = new String[]{"default-container-handling", + public final static String[] DEFAULT_CONTAINER_HANDLING = new String[]{"default-container-handling", "create-container", "list-containers", "modify-container-state"}; - public static final String[] ESCALATED_CONTAINER_HANDLING = new String[]{"escalated-container-handling", + public final static String[] ESCALATED_CONTAINER_HANDLING = new String[]{"escalated-container-handling", "modify-foreign-container-state", "delete-container"}; - public static final String[] DEFAULT_DATABASE_HANDLING = new String[]{"default-database-handling", + public final static String[] DEFAULT_DATABASE_HANDLING = new String[]{"default-database-handling", "update-database-access", "modify-database-visibility", "create-database", "modify-database-owner", "delete-database-access", "check-database-access", "list-databases", "modify-database-image", "create-database-access", "find-database", "import-database-data"}; - public static final String[] ESCALATED_DATABASE_HANDLING = new String[]{"escalated-database-handling", + public final static String[] ESCALATED_DATABASE_HANDLING = new String[]{"escalated-database-handling", "delete-database"}; - public static final String[] DEFAULT_IDENTIFIER_HANDLING = new String[]{"default-identifier-handling", + public final static String[] DEFAULT_IDENTIFIER_HANDLING = new String[]{"default-identifier-handling", "create-identifier", "find-identifier", "list-identifiers", "publish-identifier", "delete-identifier"}; - public static final String[] ESCALATED_IDENTIFIER_HANDLING = new String[]{"escalated-identifier-handling", + public final static String[] ESCALATED_IDENTIFIER_HANDLING = new String[]{"escalated-identifier-handling", "modify-identifier-metadata", "update-foreign-identifier", "create-foreign-identifier"}; - public static final String[] DEFAULT_QUERY_HANDLING = new String[]{"default-query-handling", "view-table-data", + public final static String[] DEFAULT_QUERY_HANDLING = new String[]{"default-query-handling", "view-table-data", "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 static final String[] ESCALATED_QUERY_HANDLING = new String[]{"escalated-query-handling"}; + public final static String[] ESCALATED_QUERY_HANDLING = new String[]{"escalated-query-handling"}; - public static final String[] DEFAULT_TABLE_HANDLING = new String[]{"default-table-handling", - "list-tables", "create-table", "modify-table-column-semantics", "find-table", "delete-table", - "update-table-statistic", "update-table"}; + public final static String[] DEFAULT_TABLE_HANDLING = new String[]{"default-table-handling", "list-tables", + "create-table", "modify-table-column-semantics", "find-table", "delete-table", "update-table-statistic", + "update-table"}; - public static final String[] ESCALATED_TABLE_HANDLING = new String[]{"escalated-table-handling", + public final static String[] ESCALATED_TABLE_HANDLING = new String[]{"escalated-table-handling", "delete-foreign-table"}; - public static final String[] DEFAULT_USER_HANDLING = new String[]{"default-user-handling", "modify-user-theme", + public final static String[] DEFAULT_USER_HANDLING = new String[]{"default-user-handling", "modify-user-theme", "modify-user-information"}; - public static final String[] ESCALATED_USER_HANDLING = new String[]{"escalated-user-handling", "find-user"}; - - public static final String[] DEFAULT_RESEARCHER_ROLES = ArrayUtils.merge(List.of(new String[]{"default-researcher-roles"}, - DEFAULT_CONTAINER_HANDLING, DEFAULT_DATABASE_HANDLING, DEFAULT_IDENTIFIER_HANDLING, DEFAULT_QUERY_HANDLING, - DEFAULT_TABLE_HANDLING, DEFAULT_USER_HANDLING, DEFAULT_SEMANTICS_HANDLING, DEFAULT_VIEW_HANDLING)); - - public static final String[] DEFAULT_DEVELOPER_ROLES = ArrayUtils.merge(List.of(new String[]{"default-developer-roles"}, - DEFAULT_CONTAINER_HANDLING, DEFAULT_DATABASE_HANDLING, DEFAULT_IDENTIFIER_HANDLING, DEFAULT_QUERY_HANDLING, - DEFAULT_TABLE_HANDLING, DEFAULT_USER_HANDLING, ESCALATED_USER_HANDLING, ESCALATED_CONTAINER_HANDLING, - ESCALATED_DATABASE_HANDLING, ESCALATED_IDENTIFIER_HANDLING, ESCALATED_QUERY_HANDLING, - ESCALATED_TABLE_HANDLING, DEFAULT_VIEW_HANDLING)); - - public static final 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 static final String[] DEFAULT_LOCAL_ADMIN_ROLES = new String[]{"system"}; - - public static final List<GrantedAuthorityDto> AUTHORITY_LOCAL_ADMIN_ROLES = Arrays.stream(DEFAULT_LOCAL_ADMIN_ROLES) - .map(GrantedAuthorityDto::new) - .collect(Collectors.toList()); - - public static final List<GrantedAuthorityDto> AUTHORITY_DEFAULT_RESEARCHER_ROLES = Arrays.stream(DEFAULT_RESEARCHER_ROLES) - .map(GrantedAuthorityDto::new) - .collect(Collectors.toList()); - - public static final List<GrantedAuthorityDto> AUTHORITY_DEFAULT_DEVELOPER_ROLES = Arrays.stream(DEFAULT_DEVELOPER_ROLES) - .map(GrantedAuthorityDto::new) - .collect(Collectors.toList()); - - public static final List<GrantedAuthorityDto> AUTHORITY_DEFAULT_DATA_STEWARD_ROLES = Arrays.stream(DEFAULT_DATA_STEWARD_ROLES) - .map(GrantedAuthorityDto::new) - .collect(Collectors.toList()); - - public static final List<GrantedAuthority> AUTHORITY_DEFAULT_LOCAL_ADMIN_AUTHORITIES = AUTHORITY_LOCAL_ADMIN_ROLES.stream() - .map(a -> new SimpleGrantedAuthority(a.getAuthority())) - .collect(Collectors.toList()); - - public static final List<GrantedAuthority> AUTHORITY_DEFAULT_RESEARCHER_AUTHORITIES = AUTHORITY_DEFAULT_RESEARCHER_ROLES.stream() - .map(a -> new SimpleGrantedAuthority(a.getAuthority())) - .collect(Collectors.toList()); - - public static final List<GrantedAuthority> AUTHORITY_DEFAULT_DEVELOPER_AUTHORITIES = AUTHORITY_DEFAULT_DEVELOPER_ROLES.stream() - .map(a -> new SimpleGrantedAuthority(a.getAuthority())) - .collect(Collectors.toList()); - - public static final List<GrantedAuthority> AUTHORITY_DEFAULT_DATA_STEWARD_AUTHORITIES = AUTHORITY_DEFAULT_DATA_STEWARD_ROLES.stream() - .map(a -> new SimpleGrantedAuthority(a.getAuthority())) - .collect(Collectors.toList()); - - public static final UUID REALM_DBREPO_ID = UUID.fromString("6264bf7b-d1d3-4562-9c07-ce4364a8f9d3"); - public static final String REALM_DBREPO_NAME = "dbrepo"; - public static final Boolean REALM_DBREPO_ENABLED = true; - - public static final UUID ROLE_DEFAULT_REALM_DBREPO_ROLES_ID = UUID.fromString("c74cbbe7-3ab1-4472-9211-cc904567268"); - public static final String ROLE_DEFAULT_REALM_DBREPO_ROLES_NAME = "default-dbrepo-roles"; - public static final UUID ROLE_DEFAULT_REALM_DBREPO_ROLES_REALM_ID = REALM_DBREPO_ID; - - public static final UUID ROLE_DEFAULT_RESEARCHER_ROLES_ID = UUID.fromString("c74cbbe7-3ab1-4472-9211-cc9045672682"); - public static final String ROLE_DEFAULT_RESEARCHER_ROLES_NAME = "default-researcher-roles"; - public static final UUID ROLE_DEFAULT_RESEARCHER_ROLES_REALM_ID = REALM_DBREPO_ID; - - public static final CreateAccessDto UPDATE_DATABASE_ACCESS_READ_DTO = CreateAccessDto.builder() + public final static String[] ESCALATED_USER_HANDLING = new String[]{"escalated-user-handling", "find-user"}; + + public final static String[] DEFAULT_RESEARCHER_ROLES = ArrayUtils.merge(List.of( + new String[]{"default-researcher-roles"}, DEFAULT_CONTAINER_HANDLING, DEFAULT_DATABASE_HANDLING, + DEFAULT_IDENTIFIER_HANDLING, DEFAULT_QUERY_HANDLING, DEFAULT_TABLE_HANDLING, DEFAULT_USER_HANDLING, + DEFAULT_SEMANTICS_HANDLING, DEFAULT_VIEW_HANDLING)); + + public final static String[] DEFAULT_DEVELOPER_ROLES = ArrayUtils.merge(List.of( + new String[]{"default-developer-roles"}, DEFAULT_CONTAINER_HANDLING, DEFAULT_DATABASE_HANDLING, + DEFAULT_IDENTIFIER_HANDLING, DEFAULT_QUERY_HANDLING, DEFAULT_TABLE_HANDLING, DEFAULT_USER_HANDLING, + ESCALATED_USER_HANDLING, ESCALATED_CONTAINER_HANDLING, ESCALATED_DATABASE_HANDLING, + ESCALATED_IDENTIFIER_HANDLING, ESCALATED_QUERY_HANDLING, ESCALATED_TABLE_HANDLING, DEFAULT_VIEW_HANDLING)); + + 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 = ArrayUtils.merge(List.of(new String[]{"system"}, + DEFAULT_RESEARCHER_ROLES)); + + public final List<GrantedAuthorityDto> AUTHORITY_LOCAL_ADMIN_ROLES = + Arrays.stream(DEFAULT_LOCAL_ADMIN_ROLES) + .map(GrantedAuthorityDto::new) + .toList(); + + public final List<GrantedAuthorityDto> AUTHORITY_DEFAULT_RESEARCHER_ROLES = + Arrays.stream(DEFAULT_RESEARCHER_ROLES) + .map(GrantedAuthorityDto::new) + .toList(); + + public final List<GrantedAuthorityDto> AUTHORITY_DEFAULT_DEVELOPER_ROLES = + Arrays.stream(DEFAULT_DEVELOPER_ROLES) + .map(GrantedAuthorityDto::new) + .toList(); + + public final List<GrantedAuthorityDto> AUTHORITY_DEFAULT_DATA_STEWARD_ROLES = + Arrays.stream(DEFAULT_DATA_STEWARD_ROLES) + .map(GrantedAuthorityDto::new) + .toList(); + + public final List<GrantedAuthority> AUTHORITY_DEFAULT_LOCAL_ADMIN_AUTHORITIES = + AUTHORITY_LOCAL_ADMIN_ROLES + .stream() + .map(a -> (GrantedAuthority) new SimpleGrantedAuthority(a.getAuthority())) + .toList(); + + public final List<GrantedAuthority> AUTHORITY_DEFAULT_RESEARCHER_AUTHORITIES = + AUTHORITY_DEFAULT_RESEARCHER_ROLES + .stream() + .map(a -> (GrantedAuthority) new SimpleGrantedAuthority(a.getAuthority())) + .toList(); + + public final List<GrantedAuthority> AUTHORITY_DEFAULT_DEVELOPER_AUTHORITIES = + AUTHORITY_DEFAULT_DEVELOPER_ROLES + .stream() + .map(a -> (GrantedAuthority) new SimpleGrantedAuthority(a.getAuthority())) + .toList(); + + public final List<GrantedAuthority> AUTHORITY_DEFAULT_DATA_STEWARD_AUTHORITIES = + AUTHORITY_DEFAULT_DATA_STEWARD_ROLES + .stream() + .map(a -> (GrantedAuthority) new SimpleGrantedAuthority(a.getAuthority())) + .toList(); + + public final CreateAccessDto UPDATE_DATABASE_ACCESS_READ_DTO = CreateAccessDto.builder() .type(AccessTypeDto.READ) .build(); - public static final CreateAccessDto UPDATE_DATABASE_ACCESS_WRITE_OWN_DTO = CreateAccessDto.builder() + public final CreateAccessDto UPDATE_DATABASE_ACCESS_WRITE_OWN_DTO = CreateAccessDto.builder() .type(AccessTypeDto.WRITE_OWN) .build(); - public static final CreateAccessDto UPDATE_DATABASE_ACCESS_WRITE_ALL_DTO = CreateAccessDto.builder() + public final CreateAccessDto UPDATE_DATABASE_ACCESS_WRITE_ALL_DTO = CreateAccessDto.builder() .type(AccessTypeDto.WRITE_ALL) .build(); - public static final String TOKEN_ACCESS_TOKEN = "ey.yee.skrr"; - public static final String TOKEN_ACCESS_SCOPE = "openid"; + public final static String TOKEN_ACCESS_TOKEN = "ey.yee.skrr"; + public final static String TOKEN_ACCESS_SCOPE = "openid"; - public static final TokenDto TOKEN_DTO = TokenDto.builder() + public final TokenDto TOKEN_DTO = TokenDto.builder() .accessToken(TOKEN_ACCESS_TOKEN) .scope(TOKEN_ACCESS_SCOPE) .build(); - public static final UUID CONCEPT_1_ID = UUID.fromString("8cabc011-4bdf-44d4-9d33-b2648e2ddbf1"); - public static final String CONCEPT_1_NAME = "precipitation"; - public static final String CONCEPT_1_URI = "http://www.wikidata.org/entity/Q25257"; - public static final String CONCEPT_1_DESCRIPTION = null; - public static final Instant CONCEPT_1_CREATED = Instant.ofEpochSecond(1701976048L) /* 2023-12-07 19:07:27 (UTC) */; + public final static UUID CONCEPT_1_ID = UUID.fromString("8cabc011-4bdf-44d4-9d33-b2648e2ddbf1"); + public final static String CONCEPT_1_NAME = "precipitation"; + public final static String CONCEPT_1_URI = "http://www.wikidata.org/entity/Q25257"; + public final static String CONCEPT_1_DESCRIPTION = null; + public final static Instant CONCEPT_1_CREATED = Instant.ofEpochSecond(1701976048L) /* 2023-12-07 19:07:27 (UTC) */; - public static final ConceptSaveDto CONCEPT_1_SAVE_DTO = ConceptSaveDto.builder() + public final ConceptSaveDto CONCEPT_1_SAVE_DTO = ConceptSaveDto.builder() .uri(CONCEPT_1_URI) .name(CONCEPT_1_NAME) .description(CONCEPT_1_DESCRIPTION) .build(); - public static final ConceptDto CONCEPT_1_DTO = ConceptDto.builder() + public final ConceptDto CONCEPT_1_DTO = ConceptDto.builder() .id(CONCEPT_1_ID) .uri(CONCEPT_1_URI) .name(CONCEPT_1_NAME) .description(CONCEPT_1_DESCRIPTION) .build(); - public static final ConceptBriefDto CONCEPT_1_BRIEF_DTO = ConceptBriefDto.builder() + public final ConceptBriefDto CONCEPT_1_BRIEF_DTO = ConceptBriefDto.builder() .id(CONCEPT_1_ID) .uri(CONCEPT_1_URI) .name(CONCEPT_1_NAME) .description(CONCEPT_1_DESCRIPTION) .build(); - public static final TableColumnConcept CONCEPT_1 = TableColumnConcept.builder() + public final TableColumnConcept CONCEPT_1 = TableColumnConcept.builder() .id(CONCEPT_1_ID) .uri(CONCEPT_1_URI) .name(CONCEPT_1_NAME) @@ -305,39 +304,39 @@ public abstract class BaseTest { .created(CONCEPT_1_CREATED) .build(); - public static final EntityDto CONCEPT_1_ENTITY_DTO = EntityDto.builder() + public final EntityDto CONCEPT_1_ENTITY_DTO = EntityDto.builder() .uri(CONCEPT_1_URI) .description(CONCEPT_1_DESCRIPTION) .label(CONCEPT_1_NAME) .build(); - public static final UUID CONCEPT_2_ID = UUID.fromString("c5cf9914-15c1-4813-af11-eb2a070d59a9"); - public static final String CONCEPT_2_NAME = "FAIR data"; - public static final String CONCEPT_2_URI = "http://www.wikidata.org/entity/Q29032648"; - public static final String CONCEPT_2_DESCRIPTION = "data compliant with the terms of the FAIR Data Principles"; - public static final Instant CONCEPT_2_CREATED = Instant.now(); + public final static UUID CONCEPT_2_ID = UUID.fromString("c5cf9914-15c1-4813-af11-eb2a070d59a9"); + public final static String CONCEPT_2_NAME = "FAIR data"; + public final static String CONCEPT_2_URI = "http://www.wikidata.org/entity/Q29032648"; + public final static String CONCEPT_2_DESCRIPTION = "data compliant with the terms of the FAIR Data Principles"; + public final static Instant CONCEPT_2_CREATED = Instant.ofEpochSecond(1701976049L) /* 2023-12-07 19:07:28 (UTC) */; - public static final ConceptSaveDto CONCEPT_2_SAVE_DTO = ConceptSaveDto.builder() + public final ConceptSaveDto CONCEPT_2_SAVE_DTO = ConceptSaveDto.builder() .uri(CONCEPT_2_URI) .name(CONCEPT_2_NAME) .description(CONCEPT_2_DESCRIPTION) .build(); - public static final ConceptDto CONCEPT_2_DTO = ConceptDto.builder() + public final ConceptDto CONCEPT_2_DTO = ConceptDto.builder() .id(CONCEPT_2_ID) .uri(CONCEPT_2_URI) .name(CONCEPT_2_NAME) .description(CONCEPT_2_DESCRIPTION) .build(); - public static final ConceptBriefDto CONCEPT_2_BRIEF_DTO = ConceptBriefDto.builder() + public final ConceptBriefDto CONCEPT_2_BRIEF_DTO = ConceptBriefDto.builder() .id(CONCEPT_2_ID) .uri(CONCEPT_2_URI) .name(CONCEPT_2_NAME) .description(CONCEPT_2_DESCRIPTION) .build(); - public static final TableColumnConcept CONCEPT_2 = TableColumnConcept.builder() + public final TableColumnConcept CONCEPT_2 = TableColumnConcept.builder() .id(CONCEPT_2_ID) .uri(CONCEPT_2_URI) .name(CONCEPT_2_NAME) @@ -345,33 +344,33 @@ public abstract class BaseTest { .created(CONCEPT_2_CREATED) .build(); - public static final UUID UNIT_1_ID = UUID.fromString("1fee60e4-42f8-4883-85a8-e282fddf6a62"); - public static final String UNIT_1_NAME = "millimetre"; - public static final String UNIT_1_URI = "http://www.ontology-of-units-of-measure.org/resource/om-2/millimetre"; - public static final String UNIT_1_DESCRIPTION = "The millimetre is a unit of length defined as 1.0e-3 metre."; - public static final Instant UNIT_1_CREATED = Instant.ofEpochSecond(1701976282L) /* 2023-12-07 19:11:22 */; + public final static UUID UNIT_1_ID = UUID.fromString("1fee60e4-42f8-4883-85a8-e282fddf6a62"); + public final static String UNIT_1_NAME = "millimetre"; + public final static String UNIT_1_URI = "http://www.ontology-of-units-of-measure.org/resource/om-2/millimetre"; + public final static String UNIT_1_DESCRIPTION = "The millimetre is a unit of length defined as 1.0e-3 metre."; + public final static Instant UNIT_1_CREATED = Instant.ofEpochSecond(1701976282L) /* 2023-12-07 19:11:22 */; - public static final UnitSaveDto UNIT_1_SAVE_DTO = UnitSaveDto.builder() + public final UnitSaveDto UNIT_1_SAVE_DTO = UnitSaveDto.builder() .uri(UNIT_1_URI) .name(UNIT_1_NAME) .description(UNIT_1_DESCRIPTION) .build(); - public static final UnitDto UNIT_1_DTO = UnitDto.builder() + public final UnitDto UNIT_1_DTO = UnitDto.builder() .id(UNIT_1_ID) .uri(UNIT_1_URI) .name(UNIT_1_NAME) .description(UNIT_1_DESCRIPTION) .build(); - public static final UnitBriefDto UNIT_1_BRIEF_DTO = UnitBriefDto.builder() + public final UnitBriefDto UNIT_1_BRIEF_DTO = UnitBriefDto.builder() .id(UNIT_1_ID) .uri(UNIT_1_URI) .name(UNIT_1_NAME) .description(UNIT_1_DESCRIPTION) .build(); - public static final TableColumnUnit UNIT_1 = TableColumnUnit.builder() + public final TableColumnUnit UNIT_1 = TableColumnUnit.builder() .id(UNIT_1_ID) .uri(UNIT_1_URI) .name(UNIT_1_NAME) @@ -379,39 +378,39 @@ public abstract class BaseTest { .created(UNIT_1_CREATED) .build(); - public static final EntityDto UNIT_1_ENTITY_DTO = EntityDto.builder() + public final EntityDto UNIT_1_ENTITY_DTO = EntityDto.builder() .uri(UNIT_1_URI) .description(UNIT_1_DESCRIPTION) .label(UNIT_1_NAME) .build(); - public static final UUID UNIT_2_ID = UUID.fromString("d88591a9-5171-4b12-8381-bcff1cfe7442"); - public static final String UNIT_2_NAME = "tonne"; - public static final String UNIT_2_URI = "http://www.ontology-of-units-of-measure.org/resource/om-2/tonne"; - public static final String UNIT_2_DESCRIPTION = "The tonne is a unit of mass defined as 1000 kilogram."; - public static final Instant UNIT_2_CREATED = Instant.ofEpochSecond(1701976462L) /* 2023-12-07 19:14:22 */; + public final static UUID UNIT_2_ID = UUID.fromString("d88591a9-5171-4b12-8381-bcff1cfe7442"); + public final static String UNIT_2_NAME = "tonne"; + public final static String UNIT_2_URI = "http://www.ontology-of-units-of-measure.org/resource/om-2/tonne"; + public final static String UNIT_2_DESCRIPTION = "The tonne is a unit of mass defined as 1000 kilogram."; + public final static Instant UNIT_2_CREATED = Instant.ofEpochSecond(1701976462L) /* 2023-12-07 19:14:22 */; - public static final UnitSaveDto UNIT_2_SAVE_DTO = UnitSaveDto.builder() + public final UnitSaveDto UNIT_2_SAVE_DTO = UnitSaveDto.builder() .uri(UNIT_2_URI) .name(UNIT_2_NAME) .description(UNIT_2_DESCRIPTION) .build(); - public static final UnitDto UNIT_2_DTO = UnitDto.builder() + public final UnitDto UNIT_2_DTO = UnitDto.builder() .id(UNIT_2_ID) .uri(UNIT_2_URI) .name(UNIT_2_NAME) .description(UNIT_2_DESCRIPTION) .build(); - public static final UnitBriefDto UNIT_2_BRIEF_DTO = UnitBriefDto.builder() + public final UnitBriefDto UNIT_2_BRIEF_DTO = UnitBriefDto.builder() .id(UNIT_2_ID) .uri(UNIT_2_URI) .name(UNIT_2_NAME) .description(UNIT_2_DESCRIPTION) .build(); - public static final TableColumnUnit UNIT_2 = TableColumnUnit.builder() + public final TableColumnUnit UNIT_2 = TableColumnUnit.builder() .id(UNIT_2_ID) .uri(UNIT_2_URI) .name(UNIT_2_NAME) @@ -419,29 +418,29 @@ public abstract class BaseTest { .created(UNIT_2_CREATED) .build(); - public static final String USER_BROKER_USERNAME = "guest"; + public final static String USER_BROKER_USERNAME = "guest"; @SuppressWarnings("java:S2068") - public static final String USER_BROKER_PASSWORD = "guest"; + public final static String USER_BROKER_PASSWORD = "guest"; - public static final UUID USER_LOCAL_ADMIN_ID = UUID.fromString("a54dcb2e-a644-4e82-87e7-05a96413983d"); - public static final UUID USER_LOCAL_ADMIN_KEYCLOAK_ID = UUID.fromString("703c2ca0-8fc3-4c03-9bc5-4dae6b211e78"); - public static final String USER_LOCAL_ADMIN_USERNAME = "admin"; + 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 static final String USER_LOCAL_ADMIN_PASSWORD = "admin"; - public static final String USER_LOCAL_ADMIN_THEME = "dark"; - public static final Boolean USER_LOCAL_ADMIN_IS_INTERNAL = true; - public static final Boolean USER_LOCAL_ADMIN_ENABLED = true; + 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; @SuppressWarnings("java:S2068") - public static final String USER_LOCAL_ADMIN_MARIADB_PASSWORD = "*440BA4FD1A87A0999647DB67C0EE258198B247BA"; + public final static String USER_LOCAL_ADMIN_MARIADB_PASSWORD = "*440BA4FD1A87A0999647DB67C0EE258198B247BA"; - public static final UserDetails USER_LOCAL_ADMIN_DETAILS = UserDetailsDto.builder() + public final UserDetails USER_LOCAL_ADMIN_DETAILS = UserDetailsDto.builder() .id(USER_LOCAL_ADMIN_ID.toString()) .username(USER_LOCAL_ADMIN_USERNAME) .password(USER_LOCAL_ADMIN_PASSWORD) .authorities(AUTHORITY_DEFAULT_LOCAL_ADMIN_AUTHORITIES) .build(); - public static final User USER_LOCAL = User.builder() + public final User USER_LOCAL = User.builder() .id(USER_LOCAL_ADMIN_ID) .keycloakId(USER_LOCAL_ADMIN_KEYCLOAK_ID) .username(USER_LOCAL_ADMIN_USERNAME) @@ -450,34 +449,34 @@ public abstract class BaseTest { .isInternal(USER_LOCAL_ADMIN_IS_INTERNAL) .build(); - public static final Principal USER_LOCAL_ADMIN_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_LOCAL_ADMIN_DETAILS, - USER_LOCAL_ADMIN_PASSWORD, USER_LOCAL_ADMIN_DETAILS.getAuthorities()); + public final Principal USER_LOCAL_ADMIN_PRINCIPAL = new UsernamePasswordAuthenticationToken( + USER_LOCAL_ADMIN_DETAILS, USER_LOCAL_ADMIN_PASSWORD, USER_LOCAL_ADMIN_DETAILS.getAuthorities()); - public static final UUID USER_1_ID = UUID.fromString("cd5bab0d-7799-4069-85fb-c5d738572a0b"); - public static final UUID USER_1_KEYCLOAK_ID = UUID.fromString("cd5bab0d-7799-4069-85fb-c5d738572a0b"); - public static final String USER_1_USERNAME = "junit1"; + public final static UUID USER_1_ID = UUID.fromString("cd5bab0d-7799-4069-85fb-c5d738572a0b"); + 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 static final String USER_1_PASSWORD = "junit1"; + public final static String USER_1_PASSWORD = "junit1"; @SuppressWarnings("java:S2068") - public static final String USER_1_DATABASE_PASSWORD = "*440BA4FD1A87A0999647DB67C0EE258198B247BA" /* junit1 */; - public static final String USER_1_FIRSTNAME = "John"; - public static final String USER_1_LASTNAME = "Doe"; - public static final String USER_1_QUALIFIED_NAME = USER_1_FIRSTNAME + " " + USER_1_LASTNAME + " — @" + USER_1_USERNAME; - public static final String USER_1_NAME = "John Doe"; - public static final String USER_1_AFFILIATION = "TU Graz"; - public static final String USER_1_ORCID_URL = "https://orcid.org/0000-0003-4216-302X"; - public static final Boolean USER_1_ENABLED = true; - public static final Boolean USER_1_IS_INTERNAL = false; - public static final String USER_1_THEME = "light"; - public static final String USER_1_LANGUAGE = "en"; - public static final Instant USER_1_CREATED = Instant.ofEpochSecond(1677399441L) /* 2023-02-26 08:17:21 (UTC) */; - - public static final UpdateUserPasswordDto USER_1_UPDATE_PASSWORD_DTO = UpdateUserPasswordDto.builder() + public final static String USER_1_DATABASE_PASSWORD = "*440BA4FD1A87A0999647DB67C0EE258198B247BA" /* junit1 */; + public final static String USER_1_FIRSTNAME = "John"; + public final static String USER_1_LASTNAME = "Doe"; + public final static String USER_1_QUALIFIED_NAME = USER_1_FIRSTNAME + " " + USER_1_LASTNAME + " — @" + USER_1_USERNAME; + public final static String USER_1_NAME = "John Doe"; + public final static String USER_1_AFFILIATION = "TU Graz"; + public final static String USER_1_ORCID_URL = "https://orcid.org/0000-0003-4216-302X"; + public final static Boolean USER_1_ENABLED = true; + public final static Boolean USER_1_IS_INTERNAL = false; + public final static String USER_1_THEME = "light"; + public final static String USER_1_LANGUAGE = "en"; + public final static Instant USER_1_CREATED = Instant.ofEpochSecond(1677399441L) /* 2023-02-26 08:17:21 (UTC) */; + + public final UpdateUserPasswordDto USER_1_UPDATE_PASSWORD_DTO = UpdateUserPasswordDto.builder() .username(USER_1_USERNAME) .password(USER_1_PASSWORD) .build(); - public static final UserAttributesDto USER_1_ATTRIBUTES_DTO = UserAttributesDto.builder() + public final UserAttributesDto USER_1_ATTRIBUTES_DTO = UserAttributesDto.builder() .theme(USER_1_THEME) .orcid(USER_1_ORCID_URL) .affiliation(USER_1_AFFILIATION) @@ -485,19 +484,19 @@ public abstract class BaseTest { .language(USER_1_LANGUAGE) .build(); - public static final CredentialDto USER_1_KEYCLOAK_CREDENTIAL_1 = CredentialDto.builder() + public final CredentialDto USER_1_KEYCLOAK_CREDENTIAL_1 = CredentialDto.builder() .type(CredentialTypeDto.PASSWORD) .temporary(false) .value(USER_1_PASSWORD) .build(); - public static final CredentialDto USER_LOCAL_KEYCLOAK_CREDENTIAL_1 = CredentialDto.builder() + public final CredentialDto USER_LOCAL_KEYCLOAK_CREDENTIAL_1 = CredentialDto.builder() .type(CredentialTypeDto.PASSWORD) .temporary(false) .value(USER_LOCAL_ADMIN_PASSWORD) .build(); - public static final UserCreateDto USER_1_KEYCLOAK_SIGNUP_REQUEST = UserCreateDto.builder() + public final UserCreateDto USER_1_KEYCLOAK_SIGNUP_REQUEST = UserCreateDto.builder() .username(USER_1_USERNAME) .enabled(USER_1_ENABLED) .credentials(new LinkedList<>(List.of(USER_1_KEYCLOAK_CREDENTIAL_1))) @@ -506,7 +505,7 @@ public abstract class BaseTest { .build()) .build(); - public static final UserCreateDto USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST = UserCreateDto.builder() + public final UserCreateDto USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST = UserCreateDto.builder() .username(USER_LOCAL_ADMIN_USERNAME) .enabled(USER_LOCAL_ADMIN_ENABLED) .credentials(new LinkedList<>(List.of(USER_LOCAL_KEYCLOAK_CREDENTIAL_1))) @@ -516,7 +515,7 @@ public abstract class BaseTest { .build()) .build(); - public static final User USER_1 = User.builder() + public final User USER_1 = User.builder() .id(USER_1_ID) .keycloakId(USER_1_KEYCLOAK_ID) .username(USER_1_USERNAME) @@ -528,9 +527,10 @@ public abstract class BaseTest { .mariadbPassword(USER_1_DATABASE_PASSWORD) .language(USER_1_LANGUAGE) .isInternal(USER_1_IS_INTERNAL) + .accesses(new LinkedList<>()) .build(); - public static final UserDto USER_1_DTO = UserDto.builder() + public final UserDto USER_1_DTO = UserDto.builder() .id(USER_1_ID) .username(USER_1_USERNAME) .firstname(USER_1_FIRSTNAME) @@ -540,7 +540,7 @@ public abstract class BaseTest { .qualifiedName(USER_1_QUALIFIED_NAME) .build(); - public static final CreateUserDto USER_1_CREATE_USER_DTO = CreateUserDto.builder() + public final CreateUserDto USER_1_CREATE_USER_DTO = CreateUserDto.builder() .id(USER_1_KEYCLOAK_ID) .ldapId(USER_1_ID) .givenName(USER_1_FIRSTNAME) @@ -548,7 +548,7 @@ public abstract class BaseTest { .username(USER_1_USERNAME) .build(); - public static final UserUpdateDto USER_1_UPDATE_DTO = UserUpdateDto.builder() + public final UserUpdateDto USER_1_UPDATE_DTO = UserUpdateDto.builder() .firstname(USER_1_FIRSTNAME) .lastname(USER_1_LASTNAME) .affiliation(USER_1_AFFILIATION) @@ -557,11 +557,11 @@ public abstract class BaseTest { .language(USER_1_LANGUAGE) .build(); - public static final UserPasswordDto USER_1_PASSWORD_DTO = UserPasswordDto.builder() + public final UserPasswordDto USER_1_PASSWORD_DTO = UserPasswordDto.builder() .password(USER_1_PASSWORD) .build(); - public static final UserBriefDto USER_1_BRIEF_DTO = UserBriefDto.builder() + public final UserBriefDto USER_1_BRIEF_DTO = UserBriefDto.builder() .id(USER_1_ID) .username(USER_1_USERNAME) .firstname(USER_1_FIRSTNAME) @@ -571,34 +571,34 @@ public abstract class BaseTest { .orcid(USER_1_ORCID_URL) .build(); - public static final UserDetails USER_1_DETAILS = UserDetailsDto.builder() + public final UserDetails USER_1_DETAILS = UserDetailsDto.builder() .id(USER_1_ID.toString()) .username(USER_1_USERNAME) .password(USER_1_PASSWORD) .authorities(AUTHORITY_DEFAULT_RESEARCHER_AUTHORITIES) .build(); - public static final Principal USER_1_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_1_DETAILS, + public final Principal USER_1_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_1_DETAILS, USER_1_PASSWORD, USER_1_DETAILS.getAuthorities()); - public static final UUID USER_2_ID = UUID.fromString("eeb9a51b-4cd8-4039-90bf-e24f17372f7c"); - public static final UUID USER_2_KEYCLOAK_ID = UUID.fromString("eeb9a51b-4cd8-4039-90bf-e24f17372f7c"); - public static final String USER_2_USERNAME = "junit2"; - public static final String USER_2_FIRSTNAME = "Jane"; - public static final String USER_2_LASTNAME = "Doe"; - public static final String USER_2_NAME = "Jane Doe"; - public static final String USER_2_AFFILIATION = "TU Wien"; - public static final String USER_2_ORCID_URL = "https://orcid.org/0000-0002-9272-6225"; + public final static UUID USER_2_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_USERNAME = "junit2"; + public final static String USER_2_FIRSTNAME = "Jane"; + public final static String USER_2_LASTNAME = "Doe"; + public final static String USER_2_NAME = "Jane Doe"; + public final static String USER_2_AFFILIATION = "TU Wien"; + public final static String USER_2_ORCID_URL = "https://orcid.org/0000-0002-9272-6225"; @SuppressWarnings("java:S2068") - public static final String USER_2_PASSWORD = "junit2"; + public final static String USER_2_PASSWORD = "junit2"; @SuppressWarnings("java:S2068") - public static final String USER_2_DATABASE_PASSWORD = "*9AA70A8B0EEFAFCB5BED5BDEF6EE264D5DA915AE" /* junit2 */; - public static final String USER_2_QUALIFIED_NAME = USER_2_FIRSTNAME + " " + USER_2_LASTNAME + " — @" + USER_2_USERNAME; - public static final Boolean USER_2_IS_INTERNAL = false; - public static final String USER_2_THEME = "light"; - public static final String USER_2_LANGUAGE = "de"; + public final static String USER_2_DATABASE_PASSWORD = "*9AA70A8B0EEFAFCB5BED5BDEF6EE264D5DA915AE" /* junit2 */; + public final static String USER_2_QUALIFIED_NAME = USER_2_FIRSTNAME + " " + USER_2_LASTNAME + " — @" + USER_2_USERNAME; + public final static Boolean USER_2_IS_INTERNAL = false; + public final static String USER_2_THEME = "light"; + public final static String USER_2_LANGUAGE = "de"; - public static final UserAttributesDto USER_2_ATTRIBUTES_DTO = UserAttributesDto.builder() + public final UserAttributesDto USER_2_ATTRIBUTES_DTO = UserAttributesDto.builder() .theme(USER_2_THEME) .orcid(USER_2_ORCID_URL) .affiliation(USER_2_AFFILIATION) @@ -606,7 +606,7 @@ public abstract class BaseTest { .language(USER_2_LANGUAGE) .build(); - public static final User USER_2 = User.builder() + public final User USER_2 = User.builder() .id(USER_2_ID) .keycloakId(USER_2_KEYCLOAK_ID) .username(USER_2_USERNAME) @@ -618,9 +618,10 @@ public abstract class BaseTest { .mariadbPassword(USER_2_DATABASE_PASSWORD) .language(USER_2_LANGUAGE) .isInternal(USER_2_IS_INTERNAL) + .accesses(new LinkedList<>()) .build(); - public static final UserDto USER_2_DTO = UserDto.builder() + public final UserDto USER_2_DTO = UserDto.builder() .id(USER_2_ID) .username(USER_2_USERNAME) .firstname(USER_2_FIRSTNAME) @@ -630,7 +631,7 @@ public abstract class BaseTest { .attributes(USER_2_ATTRIBUTES_DTO) .build(); - public static final UserBriefDto USER_2_BRIEF_DTO = UserBriefDto.builder() + public final UserBriefDto USER_2_BRIEF_DTO = UserBriefDto.builder() .id(USER_2_ID) .username(USER_2_USERNAME) .firstname(USER_2_FIRSTNAME) @@ -640,46 +641,46 @@ public abstract class BaseTest { .qualifiedName(USER_2_QUALIFIED_NAME) .build(); - public static final UserDetails USER_2_DETAILS = UserDetailsDto.builder() + public final UserDetails USER_2_DETAILS = UserDetailsDto.builder() .id(USER_2_ID.toString()) .username(USER_2_USERNAME) .password(USER_2_PASSWORD) .authorities(AUTHORITY_DEFAULT_RESEARCHER_AUTHORITIES) .build(); - public static final 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 at.ac.tuwien.ifs.dbrepo.core.api.amqp.UserDetailsDto USER_2_DETAILS_DTO = + at.ac.tuwien.ifs.dbrepo.core.api.amqp.UserDetailsDto.builder() + .name(USER_2_USERNAME) + .tags(new String[]{}) + .build(); - public static final Principal USER_2_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_2_DETAILS, + public final Principal USER_2_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_2_DETAILS, USER_2_PASSWORD, USER_2_DETAILS.getAuthorities()); - public static final UUID USER_3_ID = UUID.fromString("7b080e33-d8db-4276-9d53-47208e657006"); - public static final UUID USER_3_KEYCLOAK_ID = UUID.fromString("b0108bc3-95aa-4a3f-8868-dc301286aeca"); - public static final String USER_3_USERNAME = "junit3"; - public static final String USER_3_FIRSTNAME = "System"; - public static final String USER_3_LASTNAME = "System"; - public static final String USER_3_NAME = "System System"; - public static final String USER_3_AFFILIATION = "TU Wien"; - public static final String USER_3_ORCID_URL = null; - public static final String USER_3_ORCID_UNCOMPRESSED = null; + public final static UUID USER_3_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"; + public final static String USER_3_NAME = "System System"; + public final static String USER_3_AFFILIATION = "TU Wien"; + public final static String USER_3_ORCID_URL = null; @SuppressWarnings("java:S2068") - public static final String USER_3_PASSWORD = "password"; + public final static String USER_3_PASSWORD = "password"; @SuppressWarnings("java:S2068") - public static final String USER_3_DATABASE_PASSWORD = "*D65FCA043964B63E849DD6334699ECB065905DA4" /* junit3 */; - public static final String USER_3_QUALIFIED_NAME = USER_3_FIRSTNAME + " " + USER_3_LASTNAME + " — @" + USER_3_USERNAME; - public static final Boolean USER_3_IS_INTERNAL = false; - public static final String USER_3_THEME = "light"; + public final static String USER_3_DATABASE_PASSWORD = "*D65FCA043964B63E849DD6334699ECB065905DA4" /* junit3 */; + public final static String USER_3_QUALIFIED_NAME = USER_3_FIRSTNAME + " " + USER_3_LASTNAME + " — @" + USER_3_USERNAME; + public final static Boolean USER_3_IS_INTERNAL = false; + public final static String USER_3_THEME = "light"; - public static final UserAttributesDto USER_3_ATTRIBUTES_DTO = UserAttributesDto.builder() + public final UserAttributesDto USER_3_ATTRIBUTES_DTO = UserAttributesDto.builder() .theme(USER_3_THEME) - .orcid(USER_3_ORCID_UNCOMPRESSED) + .orcid(USER_3_ORCID_URL) .affiliation(USER_3_AFFILIATION) .mariadbPassword(USER_3_DATABASE_PASSWORD) .build(); - public static final User USER_3 = User.builder() + public final User USER_3 = User.builder() .id(USER_3_ID) .keycloakId(USER_3_KEYCLOAK_ID) .username(USER_3_USERNAME) @@ -690,9 +691,10 @@ public abstract class BaseTest { .theme(USER_3_THEME) .mariadbPassword(USER_3_DATABASE_PASSWORD) .isInternal(USER_3_IS_INTERNAL) + .accesses(new LinkedList<>()) .build(); - public static final UserDto USER_3_DTO = UserDto.builder() + public final UserDto USER_3_DTO = UserDto.builder() .id(USER_3_ID) .username(USER_3_USERNAME) .firstname(USER_3_FIRSTNAME) @@ -702,7 +704,7 @@ public abstract class BaseTest { .attributes(USER_3_ATTRIBUTES_DTO) .build(); - public static final UserBriefDto USER_3_BRIEF_DTO = UserBriefDto.builder() + public final UserBriefDto USER_3_BRIEF_DTO = UserBriefDto.builder() .id(USER_3_ID) .username(USER_3_USERNAME) .firstname(USER_3_FIRSTNAME) @@ -711,45 +713,46 @@ public abstract class BaseTest { .qualifiedName(USER_3_QUALIFIED_NAME) .build(); - public static final UserDetails USER_3_DETAILS = UserDetailsDto.builder() + public final UserDetails USER_3_DETAILS = UserDetailsDto.builder() .id(USER_3_ID.toString()) .username(USER_3_USERNAME) .password(USER_3_PASSWORD) .authorities(AUTHORITY_DEFAULT_RESEARCHER_AUTHORITIES) .build(); - public static final Principal USER_3_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_3_DETAILS, + public final Principal USER_3_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_3_DETAILS, USER_3_PASSWORD, USER_3_DETAILS.getAuthorities()); - public static final at.tuwien.api.amqp.UserDetailsDto USER_3_DETAILS_DTO = at.tuwien.api.amqp.UserDetailsDto.builder() - .name(USER_3_USERNAME) - .tags(new String[]{}) - .build(); - - public static final UUID USER_4_ID = UUID.fromString("791d58c5-bfab-4520-b4fc-b44d4ab9feb0"); - public static final UUID USER_4_KEYCLOAK_ID = UUID.fromString("25040ad3-6d57-4052-b357-6b4c8a6e7f4d"); - public static final String USER_4_USERNAME = "junit4"; - public static final String USER_4_FIRSTNAME = "JUnit"; - public static final String USER_4_LASTNAME = "4"; - public static final String USER_4_NAME = "JUnit 4"; - public static final String USER_4_AFFILIATION = "TU Wien"; - public static final String USER_4_ORCID_URL = null; + public final at.ac.tuwien.ifs.dbrepo.core.api.amqp.UserDetailsDto USER_3_DETAILS_DTO = + at.ac.tuwien.ifs.dbrepo.core.api.amqp.UserDetailsDto.builder() + .name(USER_3_USERNAME) + .tags(new String[]{}) + .build(); + + public final static UUID USER_4_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"; + public final static String USER_4_NAME = "JUnit 4"; + public final static String USER_4_AFFILIATION = "TU Wien"; + public final static String USER_4_ORCID_URL = null; @SuppressWarnings("java:S2068") - public static final String USER_4_PASSWORD = "junit4"; + public final static String USER_4_PASSWORD = "junit4"; @SuppressWarnings("java:S2068") - public static final String USER_4_DATABASE_PASSWORD = "*C20EF5C6875857DEFA9BE6E9B62DD76AAAE51882" /* junit4 */; - public static final String USER_4_QUALIFIED_NAME = USER_4_FIRSTNAME + " " + USER_4_LASTNAME + " — @" + USER_4_USERNAME; - public static final Boolean USER_4_IS_INTERNAL = false; - public static final String USER_4_THEME = "light"; + 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 Boolean USER_4_IS_INTERNAL = false; + public final static String USER_4_THEME = "light"; - public static final UserAttributesDto USER_4_ATTRIBUTES_DTO = UserAttributesDto.builder() + public final UserAttributesDto USER_4_ATTRIBUTES_DTO = UserAttributesDto.builder() .theme(USER_4_THEME) .orcid(USER_4_ORCID_URL) .affiliation(USER_4_AFFILIATION) .mariadbPassword(USER_4_DATABASE_PASSWORD) .build(); - public static final User USER_4 = User.builder() + public final User USER_4 = User.builder() .id(USER_4_ID) .keycloakId(USER_4_KEYCLOAK_ID) .username(USER_4_USERNAME) @@ -760,9 +763,10 @@ public abstract class BaseTest { .theme(USER_4_THEME) .mariadbPassword(USER_4_DATABASE_PASSWORD) .isInternal(USER_4_IS_INTERNAL) + .accesses(new LinkedList<>()) .build(); - public static final UserDto USER_4_DTO = UserDto.builder() + public final UserDto USER_4_DTO = UserDto.builder() .id(USER_4_ID) .username(USER_4_USERNAME) .firstname(USER_4_FIRSTNAME) @@ -772,7 +776,7 @@ public abstract class BaseTest { .qualifiedName(USER_4_QUALIFIED_NAME) .build(); - public static final UserBriefDto USER_4_BRIEF_DTO = UserBriefDto.builder() + public final UserBriefDto USER_4_BRIEF_DTO = UserBriefDto.builder() .id(USER_4_ID) .username(USER_4_USERNAME) .firstname(USER_4_FIRSTNAME) @@ -781,38 +785,38 @@ public abstract class BaseTest { .qualifiedName(USER_4_QUALIFIED_NAME) .build(); - public static final UserDetails USER_4_DETAILS = UserDetailsDto.builder() + public final UserDetails USER_4_DETAILS = UserDetailsDto.builder() .id(USER_4_ID.toString()) .username(USER_4_USERNAME) .password(USER_4_PASSWORD) .authorities(new LinkedList<>()) .build(); - public static final Principal USER_4_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_4_DETAILS, + public final Principal USER_4_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_4_DETAILS, USER_4_PASSWORD, USER_4_DETAILS.getAuthorities()); - public static final UUID USER_5_ID = UUID.fromString("28ff851d-d7bc-4422-959c-edd7a5b15630"); - public static final UUID USER_5_KEYCLOAK_ID = UUID.fromString("28ff851d-d7bc-4422-959c-edd7a5b15630"); - public static final String USER_5_USERNAME = "nobody"; - public static final String USER_5_FIRSTNAME = "No"; - public static final String USER_5_LASTNAME = "Body"; - public static final String USER_5_NAME = "No Body"; - public static final String USER_5_AFFILIATION = "TU Wien"; + public final static UUID USER_5_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"; + public final static String USER_5_NAME = "No Body"; + public final static String USER_5_AFFILIATION = "TU Wien"; @SuppressWarnings("java:S2068") - public static final String USER_5_PASSWORD = "junit5"; + public final static String USER_5_PASSWORD = "junit5"; @SuppressWarnings("java:S2068") - public static final String USER_5_DATABASE_PASSWORD = "*C20EF5C6875857DEFA9BE6E9B62DD76AAAE51882" /* junit5 */; - public static final String USER_5_QUALIFIED_NAME = USER_5_FIRSTNAME + " " + USER_5_LASTNAME + " — @" + USER_5_USERNAME; - public static final Boolean USER_5_IS_INTERNAL = false; - public static final String USER_5_THEME = "dark"; + 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 Boolean USER_5_IS_INTERNAL = false; + public final static String USER_5_THEME = "dark"; - public static final UserAttributesDto USER_5_ATTRIBUTES_DTO = UserAttributesDto.builder() + public final UserAttributesDto USER_5_ATTRIBUTES_DTO = UserAttributesDto.builder() .theme(USER_5_THEME) .affiliation(USER_5_AFFILIATION) .mariadbPassword(USER_5_DATABASE_PASSWORD) .build(); - public static final UserDto USER_5_DTO = UserDto.builder() + public final UserDto USER_5_DTO = UserDto.builder() .id(USER_5_ID) .username(USER_5_USERNAME) .firstname(USER_5_FIRSTNAME) @@ -822,7 +826,7 @@ public abstract class BaseTest { .attributes(USER_5_ATTRIBUTES_DTO) .build(); - public static final UserBriefDto USER_5_BRIEF_DTO = UserBriefDto.builder() + public final UserBriefDto USER_5_BRIEF_DTO = UserBriefDto.builder() .id(USER_5_ID) .username(USER_5_USERNAME) .firstname(USER_5_FIRSTNAME) @@ -830,17 +834,17 @@ public abstract class BaseTest { .qualifiedName(USER_5_QUALIFIED_NAME) .build(); - public static final UserDetails USER_5_DETAILS = UserDetailsDto.builder() + public final UserDetails USER_5_DETAILS = UserDetailsDto.builder() .id(USER_5_ID.toString()) .username(USER_5_USERNAME) .password(USER_5_PASSWORD) .authorities(AUTHORITY_DEFAULT_DEVELOPER_AUTHORITIES) .build(); - public static final Principal USER_5_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_5_DETAILS, + public final Principal USER_5_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_5_DETAILS, USER_5_PASSWORD, USER_5_DETAILS.getAuthorities()); - public static final User USER_5 = User.builder() + public final User USER_5 = User.builder() .id(USER_5_ID) .keycloakId(USER_5_KEYCLOAK_ID) .username(USER_5_USERNAME) @@ -850,111 +854,124 @@ public abstract class BaseTest { .theme(USER_5_THEME) .mariadbPassword(USER_5_DATABASE_PASSWORD) .isInternal(USER_5_IS_INTERNAL) + .accesses(new LinkedList<>()) .build(); - public static final UUID USER_6_ID = UUID.fromString("28ff851d-d7bc-4422-959c-edd7a5b15630"); - public static final String USER_6_USERNAME = "system"; - public static final String USER_6_FIRSTNAME = "System"; - public static final String USER_6_LASTNAME = "System"; - public static final String USER_6_NAME = "System System"; - public static final String USER_6_AFFILIATION = "TU Wien"; - public static final String USER_6_ORCID = null; + public final static UUID USER_6_ID = UUID.fromString("28ff851d-d7bc-4422-959c-edd7a5b15630"); + public final static UUID USER_6_KEYCLOAK_ID = UUID.fromString("0fddf102-8958-4223-8653-5d4dc51b3a18"); + public final static String USER_6_USERNAME = "system"; + public final static String USER_6_FIRSTNAME = "System"; + public final static String USER_6_LASTNAME = "System"; + public final static String USER_6_NAME = "System System"; + public final static String USER_6_AFFILIATION = "TU Wien"; + public final static String USER_6_ORCID = null; @SuppressWarnings("java:S2068") - public static final String USER_6_PASSWORD = "junit5"; + public final static String USER_6_PASSWORD = "junit5"; @SuppressWarnings("java:S2068") - public static final String USER_6_DATABASE_PASSWORD = "*C20EF5C6875857DEFA9BE6E9B62DD76AAAE51882" /* junit5 */; - public static final Boolean USER_6_VERIFIED = true; - public static final Boolean USER_6_ENABLED = true; - public static final Boolean USER_6_IS_INTERNAL = false; - public static final Boolean USER_6_THEME_DARK = false; - public static final Instant USER_6_CREATED = Instant.ofEpochSecond(1677399592L) /* 2023-02-26 08:19:52 (UTC) */; - public static final UUID USER_6_REALM_ID = REALM_DBREPO_ID; - - public static final UserDto USER_6_DTO = UserDto.builder() + public final static String USER_6_DATABASE_PASSWORD = "*C20EF5C6875857DEFA9BE6E9B62DD76AAAE51882" /* junit5 */; + 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; + public final static String USER_6_THEME = "light"; + public final static Instant USER_6_CREATED = Instant.ofEpochSecond(1677399592L) /* 2023-02-26 08:19:52 (UTC) */; + + public final User USER_6 = User.builder() + .id(USER_6_ID) + .keycloakId(USER_6_KEYCLOAK_ID) + .username(USER_6_USERNAME) + .firstname(USER_6_FIRSTNAME) + .lastname(USER_6_LASTNAME) + .affiliation(USER_6_AFFILIATION) + .theme(USER_6_THEME) + .mariadbPassword(USER_6_DATABASE_PASSWORD) + .isInternal(USER_6_IS_INTERNAL) + .accesses(new LinkedList<>()) + .build(); + + public final UserDto USER_6_DTO = UserDto.builder() .id(USER_6_ID) .username(USER_6_USERNAME) .firstname(USER_6_FIRSTNAME) .lastname(USER_6_LASTNAME) .build(); - public static final UserDetails USER_6_DETAILS = UserDetailsDto.builder() + public final UserDetails USER_6_DETAILS = UserDetailsDto.builder() .id(USER_6_ID.toString()) .username(USER_6_USERNAME) .password(USER_6_PASSWORD) .authorities(AUTHORITY_DEFAULT_RESEARCHER_AUTHORITIES) .build(); - public static final Principal USER_6_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_6_DETAILS, + public final Principal USER_6_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_6_DETAILS, USER_6_PASSWORD, USER_6_DETAILS.getAuthorities()); - public static final UUID IMAGE_1_ID = UUID.fromString("e5449ade-acc1-4ba4-8858-e3496cdecd9c"); - public static final String IMAGE_1_REGISTRY = "docker.io"; - public static final String IMAGE_1_NAME = "mariadb"; - public static final String IMAGE_1_VERSION = "11.1.3"; - public static final String IMAGE_1_DIALECT = "org.hibernate.dialect.MariaDBDialect"; - public static final String IMAGE_1_DRIVER = "org.mariadb.jdbc.Driver"; - public static final String IMAGE_1_JDBC = "mariadb"; - public static final Integer IMAGE_1_PORT = 3306; - public static final Boolean IMAGE_1_IS_DEFAULT = true; - - public static final ImageCreateDto IMAGE_1_CREATE_DTO = ImageCreateDto.builder() + public final static UUID IMAGE_1_ID = UUID.fromString("e5449ade-acc1-4ba4-8858-e3496cdecd9c"); + public final static String IMAGE_1_REGISTRY = "docker.io"; + public final static String IMAGE_1_NAME = "mariadb"; + public final static String IMAGE_1_VERSION = "11.1.3"; + public final static String IMAGE_1_DIALECT = "org.hibernate.dialect.MariaDBDialect"; + public final static String IMAGE_1_DRIVER = "org.mariadb.jdbc.Driver"; + public final static String IMAGE_1_JDBC_METHOD = "mariadb"; + public final static Integer IMAGE_1_DEFAULT_PORT = 3306; + public final static Boolean IMAGE_1_IS_DEFAULT = true; + + public final ImageCreateDto IMAGE_1_CREATE_DTO = ImageCreateDto.builder() .registry(IMAGE_1_REGISTRY) .name(IMAGE_1_NAME) .version(IMAGE_1_VERSION) .dialect(IMAGE_1_DIALECT) - .jdbcMethod(IMAGE_1_JDBC) + .jdbcMethod(IMAGE_1_JDBC_METHOD) .driverClass(IMAGE_1_DRIVER) - .defaultPort(IMAGE_1_PORT) + .defaultPort(IMAGE_1_DEFAULT_PORT) .build(); - public static final ImageChangeDto IMAGE_1_CHANGE_DTO = ImageChangeDto.builder() + public final ImageChangeDto IMAGE_1_CHANGE_DTO = ImageChangeDto.builder() .registry(IMAGE_1_REGISTRY) .dialect(IMAGE_1_DIALECT) - .jdbcMethod(IMAGE_1_JDBC) + .jdbcMethod(IMAGE_1_JDBC_METHOD) .driverClass(IMAGE_1_DRIVER) - .defaultPort(IMAGE_1_PORT) + .defaultPort(IMAGE_1_DEFAULT_PORT) .build(); - public static final ContainerImage IMAGE_1 = ContainerImage.builder() + public final ContainerImage IMAGE_1 = ContainerImage.builder() .id(IMAGE_1_ID) .name(IMAGE_1_NAME) .registry(IMAGE_1_REGISTRY) .version(IMAGE_1_VERSION) .dialect(IMAGE_1_DIALECT) - .jdbcMethod(IMAGE_1_JDBC) + .jdbcMethod(IMAGE_1_JDBC_METHOD) .driverClass(IMAGE_1_DRIVER) - .defaultPort(IMAGE_1_PORT) + .defaultPort(IMAGE_1_DEFAULT_PORT) .isDefault(IMAGE_1_IS_DEFAULT) - .operators(new LinkedList<>()) /* IMAGE_1_OPERATORS */ + .operators(null) .build(); - public static final ImageDto IMAGE_1_DTO = ImageDto.builder() + public final ImageDto IMAGE_1_DTO = ImageDto.builder() .id(IMAGE_1_ID) .name(IMAGE_1_NAME) .version(IMAGE_1_VERSION) .isDefault(IMAGE_1_IS_DEFAULT) - .jdbcMethod(IMAGE_1_JDBC) + .jdbcMethod(IMAGE_1_JDBC_METHOD) .operators(null) /* IMAGE_1_OPERATORS_DTO */ .build(); - public static final ImageBriefDto IMAGE_1_BRIEF_DTO = ImageBriefDto.builder() + public final ImageBriefDto IMAGE_1_BRIEF_DTO = ImageBriefDto.builder() .id(IMAGE_1_ID) .name(IMAGE_1_NAME) .version(IMAGE_1_VERSION) .isDefault(IMAGE_1_IS_DEFAULT) .build(); - public static final UUID IMAGE_1_OPERATORS_1_ID = UUID.fromString("42a56348-38bd-4aba-b0f2-ac813d5d2da1"); - public static final String IMAGE_1_OPERATORS_1_DISPLAY_NAME = "XOR"; - public static final String IMAGE_1_OPERATORS_1_VALUE = "XOR"; - public static final String IMAGE_1_OPERATORS_1_DOCUMENTATION = "https://mariadb.com/kb/en/xor/"; + public final static UUID IMAGE_1_OPERATORS_1_ID = UUID.fromString("42a56348-38bd-4aba-b0f2-ac813d5d2da1"); + public final static String IMAGE_1_OPERATORS_1_DISPLAY_NAME = "XOR"; + public final static String IMAGE_1_OPERATORS_1_VALUE = "XOR"; + public final static String IMAGE_1_OPERATORS_1_DOCUMENTATION = "https://mariadb.com/kb/en/xor/"; + public final static UUID IMAGE_1_OPERATORS_2_ID = UUID.fromString("42a56348-38bd-4aba-b0f2-ac813d5d2da2"); + public final static String IMAGE_1_OPERATORS_2_DISPLAY_NAME = "="; + public final static String IMAGE_1_OPERATORS_2_VALUE = "="; + public final static String IMAGE_1_OPERATORS_2_DOCUMENTATION = "https://mariadb.com/kb/en/equal/"; - public static final UUID IMAGE_1_OPERATORS_2_ID = UUID.fromString("42a56348-38bd-4aba-b0f2-ac813d5d2da2"); - public static final String IMAGE_1_OPERATORS_2_DISPLAY_NAME = "="; - public static final String IMAGE_1_OPERATORS_2_VALUE = "="; - public static final String IMAGE_1_OPERATORS_2_DOCUMENTATION = "https://mariadb.com/kb/en/equal/"; - - public static final List<Operator> IMAGE_1_OPERATORS = new LinkedList<>(List.of( + public final List<Operator> IMAGE_1_OPERATORS = new LinkedList<>(List.of( Operator.builder() .id(IMAGE_1_OPERATORS_1_ID) .image(IMAGE_1) @@ -970,7 +987,7 @@ public abstract class BaseTest { .documentation(IMAGE_1_OPERATORS_2_DOCUMENTATION) .build())); - public static final List<OperatorDto> IMAGE_1_OPERATORS_DTO = new LinkedList<>(List.of( + public final List<OperatorDto> IMAGE_1_OPERATORS_DTO = new LinkedList<>(List.of( OperatorDto.builder() .id(IMAGE_1_OPERATORS_1_ID) .displayName(IMAGE_1_OPERATORS_1_DISPLAY_NAME) @@ -984,25 +1001,25 @@ public abstract class BaseTest { .documentation(IMAGE_1_OPERATORS_2_DOCUMENTATION) .build())); - public static final UUID CONTAINER_1_ID = UUID.fromString("7ddb7e87-b965-43a2-9a24-4fa406d998f4"); - public static final String CONTAINER_1_NAME = "u01"; - public static final String CONTAINER_1_INTERNALNAME = "dbrepo-userdb-u01"; - public static final String CONTAINER_1_UI_HOST = "localhost"; - public static final Integer CONTAINER_1_UI_PORT = 3306; - public static final String CONTAINER_1_UI_ADDITIONAL_FLAGS = "?sslMode=disable"; - public static final Integer CONTAINER_1_QUOTA = 4; - public static final Integer CONTAINER_1_COUNT = 3; - public static final String CONTAINER_1_HOST = "localhost"; - public static final Integer CONTAINER_1_PORT = 3308; - public static final String CONTAINER_1_PRIVILEGED_USERNAME = "root"; + public final static UUID CONTAINER_1_ID = UUID.fromString("7ddb7e87-b965-43a2-9a24-4fa406d998f4"); + public final static String CONTAINER_1_NAME = "u01"; + public final static String CONTAINER_1_INTERNAL_NAME = "dbrepo-userdb-u01"; + public final static String CONTAINER_1_UI_HOST = "localhost"; + public final static Integer CONTAINER_1_UI_PORT = 3306; + public final static String CONTAINER_1_UI_ADDITIONAL_FLAGS = "?sslMode=disable"; + public final static Integer CONTAINER_1_QUOTA = 4; + public final static Integer CONTAINER_1_COUNT = 3; + public final static String CONTAINER_1_HOST = "localhost"; + public final static Integer CONTAINER_1_PORT = 3308; + public final static String CONTAINER_1_PRIVILEGED_USERNAME = "root"; @SuppressWarnings("java:S2068") - public static final String CONTAINER_1_PRIVILEGED_PASSWORD = "dbrepo"; - public static final Instant CONTAINER_1_CREATED = Instant.ofEpochSecond(1677399629L) /* 2023-02-26 08:20:29 (UTC) */; + public final static String CONTAINER_1_PRIVILEGED_PASSWORD = "dbrepo"; + public final static Instant CONTAINER_1_CREATED = Instant.ofEpochSecond(1677399629L) /* 2023-02-26 08:20:29 (UTC) */; - public static final Container CONTAINER_1 = Container.builder() + public final Container CONTAINER_1 = Container.builder() .id(CONTAINER_1_ID) .name(CONTAINER_1_NAME) - .internalName(CONTAINER_1_INTERNALNAME) + .internalName(CONTAINER_1_INTERNAL_NAME) .image(IMAGE_1) .created(CONTAINER_1_CREATED) .host(CONTAINER_1_HOST) @@ -1013,31 +1030,31 @@ public abstract class BaseTest { .uiAdditionalFlags(CONTAINER_1_UI_ADDITIONAL_FLAGS) .privilegedUsername(CONTAINER_1_PRIVILEGED_USERNAME) .privilegedPassword(CONTAINER_1_PRIVILEGED_PASSWORD) - .databases(null) /* DATABASE_1, DATABASE_2, DATABASE_3 */ + .databases(new LinkedList<>()) .build(); - public static final ContainerDto CONTAINER_1_DTO = ContainerDto.builder() + public final ContainerDto CONTAINER_1_DTO = ContainerDto.builder() .id(CONTAINER_1_ID) .name(CONTAINER_1_NAME) - .internalName(CONTAINER_1_INTERNALNAME) + .internalName(CONTAINER_1_INTERNAL_NAME) .image(IMAGE_1_DTO) .host(CONTAINER_1_HOST) .port(CONTAINER_1_PORT) .build(); - public static final ContainerBriefDto CONTAINER_1_BRIEF_DTO = ContainerBriefDto.builder() + public final ContainerBriefDto CONTAINER_1_BRIEF_DTO = ContainerBriefDto.builder() .id(CONTAINER_1_ID) .name(CONTAINER_1_NAME) - .internalName(CONTAINER_1_INTERNALNAME) + .internalName(CONTAINER_1_INTERNAL_NAME) .quota(CONTAINER_1_QUOTA) .count(CONTAINER_1_COUNT) .image(IMAGE_1_BRIEF_DTO) .build(); - public static final ContainerDto CONTAINER_1_PRIVILEGED_DTO = ContainerDto.builder() + public final ContainerDto CONTAINER_1_PRIVILEGED_DTO = ContainerDto.builder() .id(CONTAINER_1_ID) .name(CONTAINER_1_NAME) - .internalName(CONTAINER_1_INTERNALNAME) + .internalName(CONTAINER_1_INTERNAL_NAME) .image(IMAGE_1_DTO) .host(CONTAINER_1_HOST) .port(CONTAINER_1_PORT) @@ -1046,25 +1063,23 @@ public abstract class BaseTest { .password(CONTAINER_1_PRIVILEGED_PASSWORD) .build(); - public static final UUID CONTAINER_2_ID = UUID.fromString("c2ec601e-2bfb-4be8-8891-0cb804a08d4a"); - public static final ContainerImage CONTAINER_2_IMAGE = IMAGE_1; - public static final ImageDto CONTAINER_2_IMAGE_DTO = IMAGE_1_DTO; - public static final String CONTAINER_2_NAME = "u02"; - public static final String CONTAINER_2_INTERNALNAME = "dbrepo-userdb-u02"; - public static final String CONTAINER_2_HOST = "localhost"; - public static final Integer CONTAINER_2_PORT = 3309; - public static final Integer CONTAINER_2_QUOTA = 3; - public static final Integer CONTAINER_2_COUNT = 3; - public static final String CONTAINER_2_PRIVILEGED_USERNAME = "root"; + public final static UUID CONTAINER_2_ID = UUID.fromString("c2ec601e-2bfb-4be8-8891-0cb804a08d4a"); + public final static String CONTAINER_2_NAME = "u02"; + public final static String CONTAINER_2_INTERNAL_NAME = "dbrepo-userdb-u02"; + public final static String CONTAINER_2_HOST = "localhost"; + public final static Integer CONTAINER_2_PORT = 3309; + public final static Integer CONTAINER_2_QUOTA = 3; + public final static Integer CONTAINER_2_COUNT = 3; + public final static String CONTAINER_2_PRIVILEGED_USERNAME = "root"; @SuppressWarnings("java:S2068") - public static final String CONTAINER_2_PRIVILEGED_PASSWORD = "dbrepo"; - public static final Instant CONTAINER_2_CREATED = Instant.ofEpochSecond(1677399655L) /* 2023-02-26 08:20:55 (UTC) */; + public final static String CONTAINER_2_PRIVILEGED_PASSWORD = "dbrepo"; + public final static Instant CONTAINER_2_CREATED = Instant.ofEpochSecond(1677399655L) /* 2023-02-26 08:20:55 (UTC) */; - public static final Container CONTAINER_2 = Container.builder() + public final Container CONTAINER_2 = Container.builder() .id(CONTAINER_2_ID) .name(CONTAINER_2_NAME) - .internalName(CONTAINER_2_INTERNALNAME) - .image(CONTAINER_2_IMAGE) + .internalName(CONTAINER_2_INTERNAL_NAME) + .image(IMAGE_1) .created(CONTAINER_2_CREATED) .host(CONTAINER_2_HOST) .port(CONTAINER_2_PORT) @@ -1074,27 +1089,27 @@ public abstract class BaseTest { .privilegedPassword(CONTAINER_2_PRIVILEGED_PASSWORD) .build(); - public static final ContainerDto CONTAINER_2_DTO = ContainerDto.builder() + public final ContainerDto CONTAINER_2_DTO = ContainerDto.builder() .id(CONTAINER_2_ID) .name(CONTAINER_2_NAME) - .internalName(CONTAINER_2_INTERNALNAME) - .image(CONTAINER_2_IMAGE_DTO) + .internalName(CONTAINER_2_INTERNAL_NAME) + .image(IMAGE_1_DTO) .host(CONTAINER_2_HOST) .port(CONTAINER_2_PORT) .build(); - public static final ContainerBriefDto CONTAINER_2_DTO_BRIEF = ContainerBriefDto.builder() + public final ContainerBriefDto CONTAINER_2_DTO_BRIEF = ContainerBriefDto.builder() .id(CONTAINER_2_ID) .name(CONTAINER_2_NAME) - .internalName(CONTAINER_2_INTERNALNAME) + .internalName(CONTAINER_2_INTERNAL_NAME) .quota(CONTAINER_2_QUOTA) .build(); - public static final ContainerDto CONTAINER_2_PRIVILEGED_DTO = ContainerDto.builder() + public final ContainerDto CONTAINER_2_PRIVILEGED_DTO = ContainerDto.builder() .id(CONTAINER_2_ID) .name(CONTAINER_2_NAME) - .internalName(CONTAINER_2_INTERNALNAME) - .image(CONTAINER_2_IMAGE_DTO) + .internalName(CONTAINER_2_INTERNAL_NAME) + .image(IMAGE_1_DTO) .host(CONTAINER_2_HOST) .port(CONTAINER_2_PORT) .lastRetrieved(Instant.now()) @@ -1102,49 +1117,47 @@ public abstract class BaseTest { .password(CONTAINER_2_PRIVILEGED_PASSWORD) .build(); - public static final UUID CONTAINER_3_ID = UUID.fromString("1731c7d2-8bd1-4392-85bc-18a3be99e01d"); - public static final ContainerImage CONTAINER_3_IMAGE = IMAGE_1; - public static final String CONTAINER_3_NAME = "u03"; - public static final String CONTAINER_3_INTERNALNAME = "dbrepo-userdb-u03"; - public static final String CONTAINER_3_HOST = "localhost"; - public static final Integer CONTAINER_3_PORT = 3310; - public static final Integer CONTAINER_3_QUOTA = 20; - public static final String CONTAINER_3_PRIVILEGED_USERNAME = "root"; + public final static UUID CONTAINER_3_ID = UUID.fromString("1731c7d2-8bd1-4392-85bc-18a3be99e01d"); + public final static String CONTAINER_3_NAME = "u03"; + public final static String CONTAINER_3_INTERNAL_NAME = "dbrepo-userdb-u03"; + public final static String CONTAINER_3_HOST = "localhost"; + public final static Integer CONTAINER_3_PORT = 3310; + public final static Integer CONTAINER_3_QUOTA = 20; + public final static String CONTAINER_3_PRIVILEGED_USERNAME = "root"; @SuppressWarnings("java:S2068") - public static final String CONTAINER_3_PRIVILEGED_PASSWORD = "dbrepo"; - public static final Instant CONTAINER_3_CREATED = Instant.ofEpochSecond(1677399672L) /* 2023-02-26 08:21:12 (UTC) */; + public final static String CONTAINER_3_PRIVILEGED_PASSWORD = "dbrepo"; + public final static Instant CONTAINER_3_CREATED = Instant.ofEpochSecond(1677399672L) /* 2023-02-26 08:21:12 (UTC) */; - public static final Container CONTAINER_3 = Container.builder() + public final Container CONTAINER_3 = Container.builder() .id(CONTAINER_3_ID) .name(CONTAINER_3_NAME) - .internalName(CONTAINER_3_INTERNALNAME) - .image(CONTAINER_3_IMAGE) + .internalName(CONTAINER_3_INTERNAL_NAME) + .image(IMAGE_1) .created(CONTAINER_3_CREATED) .host(CONTAINER_3_HOST) .port(CONTAINER_3_PORT) .quota(CONTAINER_3_QUOTA) - .databases(new LinkedList<>(List.of())) + .databases(new LinkedList<>()) .privilegedUsername(CONTAINER_3_PRIVILEGED_USERNAME) .privilegedPassword(CONTAINER_3_PRIVILEGED_PASSWORD) .build(); - public static final UUID CONTAINER_4_ID = UUID.fromString("67aee75c-791c-410b-abbb-175c11ddd252"); - public static final ContainerImage CONTAINER_4_IMAGE = IMAGE_1; - public static final String CONTAINER_4_NAME = "u04"; - public static final String CONTAINER_4_INTERNALNAME = "dbrepo-userdb-u04"; - public static final String CONTAINER_4_HOST = "localhost"; - public static final Integer CONTAINER_4_PORT = 3311; - public static final Integer CONTAINER_4_QUOTA = 0; - public static final String CONTAINER_4_PRIVILEGED_USERNAME = "root"; + public final static UUID CONTAINER_4_ID = UUID.fromString("67aee75c-791c-410b-abbb-175c11ddd252"); + public final static String CONTAINER_4_NAME = "u04"; + public final static String CONTAINER_4_INTERNAL_NAME = "dbrepo-userdb-u04"; + public final static String CONTAINER_4_HOST = "localhost"; + public final static Integer CONTAINER_4_PORT = 3311; + public final static Integer CONTAINER_4_QUOTA = 0; + public final static String CONTAINER_4_PRIVILEGED_USERNAME = "root"; @SuppressWarnings("java:S2068") - public static final String CONTAINER_4_PRIVILEGED_PASSWORD = "dbrepo"; - public static final Instant CONTAINER_4_CREATED = Instant.ofEpochSecond(1677399688L) /* 2023-02-26 08:21:28 (UTC) */; + public final static String CONTAINER_4_PRIVILEGED_PASSWORD = "dbrepo"; + public final static Instant CONTAINER_4_CREATED = Instant.ofEpochSecond(1677399688L) /* 2023-02-26 08:21:28 (UTC) */; - public static final Container CONTAINER_4 = Container.builder() + public final Container CONTAINER_4 = Container.builder() .id(CONTAINER_4_ID) .name(CONTAINER_4_NAME) - .internalName(CONTAINER_4_INTERNALNAME) - .image(CONTAINER_4_IMAGE) + .internalName(CONTAINER_4_INTERNAL_NAME) + .image(IMAGE_1) .created(CONTAINER_4_CREATED) .host(CONTAINER_4_HOST) .port(CONTAINER_4_PORT) @@ -1154,14 +1167,14 @@ public abstract class BaseTest { .databases(null) /* DATABASE_4 */ .build(); - public static final String EXCHANGE_DBREPO_NAME = "dbrepo"; - public static final Boolean EXCHANGE_DBREPO_AUTO_DELETE = true; - public static final Boolean EXCHANGE_DBREPO_DURABLE = true; - public static final Boolean EXCHANGE_DBREPO_INTERNAL = true; - public static final String EXCHANGE_DBREPO_TYPE = "topic"; - public static final String EXCHANGE_DBREPO_VHOST = "dbrepo"; + public final static String EXCHANGE_DBREPO_NAME = "dbrepo"; + public final static Boolean EXCHANGE_DBREPO_AUTO_DELETE = true; + public final static Boolean EXCHANGE_DBREPO_DURABLE = true; + public final static Boolean EXCHANGE_DBREPO_INTERNAL = true; + public final static String EXCHANGE_DBREPO_TYPE = "topic"; + public final static String EXCHANGE_DBREPO_VHOST = "dbrepo"; - public static final ExchangeDto EXCHANGE_DBREPO_DTO = ExchangeDto.builder() + public final ExchangeDto EXCHANGE_DBREPO_DTO = ExchangeDto.builder() .autoDelete(EXCHANGE_DBREPO_AUTO_DELETE) .type(EXCHANGE_DBREPO_TYPE) .name(EXCHANGE_DBREPO_NAME) @@ -1170,25 +1183,26 @@ public abstract class BaseTest { .internal(EXCHANGE_DBREPO_INTERNAL) .build(); - public static final UUID DATABASE_1_ID = UUID.fromString("b3bcb5bf-4f88-40e2-9726-9b0d2ee2b425"); - public static final String DATABASE_1_NAME = "Weather"; - public static final String DATABASE_1_DESCRIPTION = "Weather in Australia"; - public static final String DATABASE_1_INTERNALNAME = "weather"; - public static final Boolean DATABASE_1_PUBLIC = false; - public static final Boolean DATABASE_1_SCHEMA_PUBLIC = false; - public static final String DATABASE_1_EXCHANGE = "dbrepo"; - public static final Instant DATABASE_1_CREATED = Instant.ofEpochSecond(1677399741L) /* 2023-02-26 08:22:21 (UTC) */; - public static final Instant DATABASE_1_LAST_MODIFIED = Instant.ofEpochSecond(1677399741L) /* 2023-02-26 08:22:21 (UTC) */; - public static final UUID DATABASE_1_CREATED_BY = USER_1_ID; + public final static UUID DATABASE_1_ID = UUID.fromString("b3bcb5bf-4f88-40e2-9726-9b0d2ee2b425"); + public final static String DATABASE_1_NAME = "Weather"; + public final static String DATABASE_1_DESCRIPTION = "Weather in Australia"; + public final static String DATABASE_1_INTERNAL_NAME = "weather"; + public final static Boolean DATABASE_1_PUBLIC = false; + public final static Boolean DATABASE_1_SCHEMA_PUBLIC = false; + public final static Boolean DATABASE_1_DASHBOARD_ENABLED = false; + public final static String DATABASE_1_DASHBOARD_UID = "730f0bdde6cf1b"; + 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 static final CreateDatabaseDto DATABASE_1_CREATE = CreateDatabaseDto.builder() + public final CreateDatabaseDto DATABASE_1_CREATE = CreateDatabaseDto.builder() .name(DATABASE_1_NAME) .isPublic(DATABASE_1_PUBLIC) .cid(CONTAINER_1_ID) .build(); - public static final at.tuwien.api.database.internal.CreateDatabaseDto DATABASE_1_CREATE_INTERNAL = at.tuwien.api.database.internal.CreateDatabaseDto.builder() - .internalName(DATABASE_1_INTERNALNAME) + public final at.ac.tuwien.ifs.dbrepo.core.api.database.internal.CreateDatabaseDto DATABASE_1_CREATE_INTERNAL = at.ac.tuwien.ifs.dbrepo.core.api.database.internal.CreateDatabaseDto.builder() + .internalName(DATABASE_1_INTERNAL_NAME) .containerId(CONTAINER_1_ID) .username(USER_1_USERNAME) .password(USER_1_PASSWORD) @@ -1197,41 +1211,44 @@ public abstract class BaseTest { .privilegedPassword(CONTAINER_1_PRIVILEGED_PASSWORD) .build(); - public static final UUID DATABASE_2_ID = UUID.fromString("dd9dfee2-9fbd-46b0-92d5-98f0f8866ffe"); - public static final String DATABASE_2_NAME = "Zoo"; - public static final String DATABASE_2_DESCRIPTION = "Zoo data"; - public static final String DATABASE_2_INTERNALNAME = "zoo"; - public static final Boolean DATABASE_2_PUBLIC = false; - public static final Boolean DATABASE_2_SCHEMA_PUBLIC = true; - public static final String DATABASE_2_EXCHANGE = "dbrepo"; - public static final Instant DATABASE_2_CREATED = Instant.ofEpochSecond(1677399772L) /* 2023-02-26 08:22:52 (UTC) */; - public static final Instant DATABASE_2_LAST_MODIFIED = Instant.ofEpochSecond(1677399772L) /* 2023-02-26 08:22:52 (UTC) */; - public static final UUID DATABASE_2_OWNER = USER_2_ID; - public static final UUID DATABASE_2_CREATOR = USER_2_ID; + public final static UUID DATABASE_2_ID = UUID.fromString("dd9dfee2-9fbd-46b0-92d5-98f0f8866ffe"); + public final static String DATABASE_2_NAME = "Zoo"; + public final static String DATABASE_2_DESCRIPTION = "Zoo data"; + public final static String DATABASE_2_INTERNAL_NAME = "zoo"; + public final static Boolean DATABASE_2_PUBLIC = false; + public final static Boolean DATABASE_2_SCHEMA_PUBLIC = true; + public final static Boolean DATABASE_2_DASHBOARD_ENABLED = true; + public final static String DATABASE_2_DASHBOARD_UID = "c6ab10f377148c"; + public final static String DATABASE_2_EXCHANGE = "dbrepo"; + public final static Instant DATABASE_2_CREATED = Instant.ofEpochSecond(1677399772L) /* 2023-02-26 08:22:52 (UTC) */; + public final static Instant DATABASE_2_LAST_MODIFIED = Instant.ofEpochSecond(1677399772L) /* 2023-02-26 08:22:52 (UTC) */; - public static final CreateDatabaseDto DATABASE_2_CREATE = CreateDatabaseDto.builder() + public final CreateDatabaseDto DATABASE_2_CREATE = CreateDatabaseDto.builder() .name(DATABASE_2_NAME) .isPublic(DATABASE_2_PUBLIC) .cid(CONTAINER_1_ID) .build(); - public static final UUID DATABASE_3_ID = UUID.fromString("9d8cb9a9-9468-4801-a2e0-2dac8bc67c31"); - public static final String DATABASE_3_NAME = "Musicology"; - public static final String DATABASE_3_DESCRIPTION = "Musicology data"; - public static final String DATABASE_3_INTERNALNAME = "musicology"; - public static final Boolean DATABASE_3_PUBLIC = true; - public static final Boolean DATABASE_3_SCHEMA_PUBLIC = false; - public static final String DATABASE_3_EXCHANGE = "dbrepo"; - public static final Instant DATABASE_3_CREATED = Instant.ofEpochSecond(1677399792L) /* 2023-02-26 08:23:12 (UTC) */; - public static final Instant DATABASE_3_LAST_MODIFIED = Instant.ofEpochSecond(1677399792L) /* 2023-02-26 08:23:12 (UTC) */; - public static final UUID DATABASE_3_OWNER = USER_3_ID; + public final static UUID DATABASE_3_ID = UUID.fromString("9d8cb9a9-9468-4801-a2e0-2dac8bc67c31"); + public final static String DATABASE_3_NAME = "Musicology"; + public final static String DATABASE_3_DESCRIPTION = "Musicology data"; + public final static String DATABASE_3_INTERNAL_NAME = "musicology"; + public final static Boolean DATABASE_3_PUBLIC = true; + public final static Boolean DATABASE_3_SCHEMA_PUBLIC = false; + public final static String DATABASE_3_DASHBOARD_UID = "96ef37d5d1b0d1"; + public final static Boolean DATABASE_3_DASHBOARD_ENABLED = true; + public final static String DATABASE_3_EXCHANGE = "dbrepo"; + public final static Instant DATABASE_3_CREATED = Instant.ofEpochSecond(1677399792L) /* 2023-02-26 08:23:12 (UTC) */; + public final static Instant DATABASE_3_LAST_MODIFIED = Instant.ofEpochSecond(1677399792L) /* 2023-02-26 08:23:12 (UTC) */; - public static final DatabaseDto DATABASE_3_DTO = DatabaseDto.builder() + public final DatabaseDto DATABASE_3_DTO = DatabaseDto.builder() .id(DATABASE_3_ID) .isPublic(DATABASE_3_PUBLIC) .isSchemaPublic(DATABASE_3_SCHEMA_PUBLIC) + .isDashboardEnabled(DATABASE_3_DASHBOARD_ENABLED) + .dashboardUid(DATABASE_3_DASHBOARD_UID) .name(DATABASE_3_NAME) - .internalName(DATABASE_3_INTERNALNAME) + .internalName(DATABASE_3_INTERNAL_NAME) .owner(USER_3_BRIEF_DTO) .container(CONTAINER_1_DTO) .exchangeName(DATABASE_3_EXCHANGE) @@ -1240,12 +1257,12 @@ public abstract class BaseTest { .identifiers(new LinkedList<>()) /* IDENTIFIER_6_DTO */ .build(); - public static final DatabaseDto DATABASE_3_PRIVILEGED_DTO = DatabaseDto.builder() + public final 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) + .internalName(DATABASE_3_INTERNAL_NAME) .owner(USER_3_BRIEF_DTO) .container(CONTAINER_1_PRIVILEGED_DTO) .exchangeName(DATABASE_3_EXCHANGE) @@ -1255,63 +1272,63 @@ public abstract class BaseTest { .lastRetrieved(Instant.now()) .build(); - public static final DatabaseBriefDto DATABASE_3_PRIVILEGED_BRIEF_DTO = DatabaseBriefDto.builder() + public final DatabaseBriefDto DATABASE_3_PRIVILEGED_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) + .internalName(DATABASE_3_INTERNAL_NAME) .ownerId(USER_3_ID) .identifiers(new LinkedList<>()) /* IDENTIFIER_6_DTO */ .build(); - public static final DatabaseBriefDto DATABASE_3_BRIEF_DTO = DatabaseBriefDto.builder() + public final 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) + .internalName(DATABASE_3_INTERNAL_NAME) .ownerId(USER_3_ID) .identifiers(new LinkedList<>()) .build(); - public static final CreateDatabaseDto DATABASE_3_CREATE = CreateDatabaseDto.builder() + public final CreateDatabaseDto DATABASE_3_CREATE = CreateDatabaseDto.builder() .name(DATABASE_3_NAME) .isPublic(DATABASE_3_PUBLIC) .cid(CONTAINER_1_ID) .build(); - public static final UUID DATABASE_4_ID = UUID.fromString("c503d7f3-5952-4d97-b26a-da86bea4c20d"); - public static final String DATABASE_4_NAME = "Weather AT"; - public static final String DATABASE_4_DESCRIPTION = "Weather data"; - public static final Boolean DATABASE_4_PUBLIC = true; - public static final Boolean DATABASE_4_SCHEMA_PUBLIC = true; - public static final String DATABASE_4_INTERNALNAME = "weather_at"; - public static final String DATABASE_4_EXCHANGE = "dbrepo"; - public static final Instant DATABASE_4_CREATED = Instant.ofEpochSecond(1677399813L) /* 2023-02-26 08:23:33 (UTC) */; - public static final Instant DATABASE_4_LAST_MODIFIED = Instant.ofEpochSecond(1677399813L) /* 2023-02-26 08:23:33 (UTC) */; - public static final UUID DATABASE_4_OWNER = USER_4_ID; - public static final UUID DATABASE_4_CREATOR = USER_4_ID; + public final static UUID DATABASE_4_ID = UUID.fromString("c503d7f3-5952-4d97-b26a-da86bea4c20d"); + public final static String DATABASE_4_NAME = "Weather AT"; + public final static String DATABASE_4_DESCRIPTION = "Weather data"; + public final static Boolean DATABASE_4_PUBLIC = true; + public final static Boolean DATABASE_4_SCHEMA_PUBLIC = true; + public final static Boolean DATABASE_4_DASHBOARD_ENABLED = true; + public final static String DATABASE_4_DASHBOARD_UID = "045e44890411ef"; + public final static String DATABASE_4_INTERNAL_NAME = "weather_at"; + public final static String DATABASE_4_EXCHANGE = "dbrepo"; + public final static Instant DATABASE_4_CREATED = Instant.ofEpochSecond(1677399813L) /* 2023-02-26 08:23:33 (UTC) */; + public final static Instant DATABASE_4_LAST_MODIFIED = Instant.ofEpochSecond(1677399813L) /* 2023-02-26 08:23:33 (UTC) */; - public static final DatabaseBriefDto DATABASE_4_BRIEF_DTO = DatabaseBriefDto.builder() + public final 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) + .internalName(DATABASE_4_INTERNAL_NAME) .ownerId(USER_4_ID) .identifiers(new LinkedList<>()) .build(); - public static final DatabaseDto DATABASE_4_DTO = DatabaseDto.builder() + public final 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) + .internalName(DATABASE_4_INTERNAL_NAME) .exchangeName(DATABASE_4_EXCHANGE) .owner(USER_4_BRIEF_DTO) .tables(new LinkedList<>()) /* TABLE_9_DTO */ @@ -1319,14 +1336,14 @@ public abstract class BaseTest { .identifiers(new LinkedList<>()) /* IDENTIFIER_7_DTO */ .build(); - public static final DatabaseDto DATABASE_4_PRIVILEGED_DTO = DatabaseDto.builder() + public final 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) + .internalName(DATABASE_4_INTERNAL_NAME) .exchangeName(DATABASE_4_EXCHANGE) .owner(USER_4_BRIEF_DTO) .tables(new LinkedList<>()) /* TABLE_9_DTO */ @@ -1335,13 +1352,15 @@ public abstract class BaseTest { .lastRetrieved(Instant.now()) .build(); - public static final CreateTableDto TABLE_0_CREATE_DTO = CreateTableDto.builder() + public final CreateTableConstraintsDto TABLE_1_CREATE_CONSTRAINTS_DTO = CreateTableConstraintsDto.builder() + .uniques(new LinkedList<>()) + .foreignKeys(new LinkedList<>()) + .build(); + + public final CreateTableDto TABLE_0_CREATE_DTO = CreateTableDto.builder() .name("full") .description("full example") - .constraints(CreateTableConstraintsDto.builder() - .uniques(new LinkedList<>()) - .foreignKeys(new LinkedList<>()) - .build()) + .constraints(TABLE_1_CREATE_CONSTRAINTS_DTO) .columns(List.of(CreateTableColumnDto.builder() .name("col1a") .type(ColumnTypeDto.CHAR) @@ -1504,24 +1523,23 @@ public abstract class BaseTest { .build())) .build(); - public static final UUID TABLE_1_ID = UUID.fromString("666d0b6b-f017-4f7c-80d8-a47174d8b539"); - public static final String TABLE_1_NAME = "Weather AUS"; - public static final String TABLE_1_INTERNAL_NAME = "weather_aus"; - public static final Boolean TABLE_1_VERSIONED = true; - public static final Boolean TABLE_1_IS_PUBLIC = false; - public static final Boolean TABLE_1_SCHEMA_PUBLIC = false; - public static final Boolean TABLE_1_PROCESSED_CONSTRAINTS = true; - public static final String TABLE_1_DESCRIPTION = "Weather in Australia"; - public static final String TABLE_1_QUEUE_NAME = TABLE_1_INTERNAL_NAME; - public static final String TABLE_1_ROUTING_KEY = "dbrepo." + DATABASE_1_ID + "." + TABLE_1_ID; - public static final Long TABLE_1_AVG_ROW_LENGTH = 3L; - public static final Long TABLE_1_NUM_ROWS = 3L; - public static final Long TABLE_1_DATA_LENGTH = 2000L; - public static final Long TABLE_1_MAX_DATA_LENGTH = Long.MAX_VALUE; - public static final Instant TABLE_1_CREATED = Instant.ofEpochSecond(1677399975L) /* 2023-02-26 08:26:15 (UTC) */; - public static final Instant TABLE_1_LAST_MODIFIED = Instant.ofEpochSecond(1677399975L) /* 2023-02-26 08:26:15 (UTC) */; - - public static final Table TABLE_1 = Table.builder() + public final static UUID TABLE_1_ID = UUID.fromString("666d0b6b-f017-4f7c-80d8-a47174d8b539"); + public final static String TABLE_1_NAME = "Weather AUS"; + public final static String TABLE_1_INTERNAL_NAME = "weather_aus"; + public final static Boolean TABLE_1_VERSIONED = true; + public final static Boolean TABLE_1_IS_PUBLIC = false; + public final static Boolean TABLE_1_SCHEMA_PUBLIC = false; + public final static String TABLE_1_DESCRIPTION = "Weather in Australia"; + public final static String TABLE_1_QUEUE_NAME = TABLE_1_INTERNAL_NAME; + public final static String TABLE_1_ROUTING_KEY = "dbrepo." + DATABASE_1_ID + "." + TABLE_1_ID; + public final static Long TABLE_1_AVG_ROW_LENGTH = 3L; + public final static Long TABLE_1_NUM_ROWS = 3L; + public final static Long TABLE_1_DATA_LENGTH = 2000L; + public final static Long TABLE_1_MAX_DATA_LENGTH = Long.MAX_VALUE; + public final static Instant TABLE_1_CREATED = Instant.ofEpochSecond(1677399975L) /* 2023-02-26 08:26:15 (UTC) */; + public final static Instant TABLE_1_LAST_MODIFIED = Instant.ofEpochSecond(1677399975L) /* 2023-02-26 08:26:15 (UTC) */; + + public final Table TABLE_1 = Table.builder() .id(TABLE_1_ID) .tdbid(DATABASE_1_ID) .database(null /* DATABASE_1 */) @@ -1534,7 +1552,7 @@ public abstract class BaseTest { .name(TABLE_1_NAME) .queueName(TABLE_1_QUEUE_NAME) .identifiers(new LinkedList<>()) - .columns(new LinkedList<>() /* TABLE_1_COLUMNS */) + .columns(new LinkedList<>()) /* TABLE_1_COLUMNS */ .constraints(null) /* TABLE_1_CONSTRAINTS */ .ownedBy(USER_1_ID) .owner(USER_1) @@ -1545,38 +1563,13 @@ public abstract class BaseTest { .maxDataLength(TABLE_1_MAX_DATA_LENGTH) .build(); - public static final TableDto TABLE_1_DTO = TableDto.builder() - .id(TABLE_1_ID) - .databaseId(DATABASE_1_ID) - .internalName(TABLE_1_INTERNAL_NAME) - .isVersioned(TABLE_1_VERSIONED) - .isPublic(TABLE_1_IS_PUBLIC) - .isSchemaPublic(TABLE_1_SCHEMA_PUBLIC) - .description(TABLE_1_DESCRIPTION) - .name(TABLE_1_NAME) - .queueName(TABLE_1_QUEUE_NAME) - .routingKey(TABLE_1_ROUTING_KEY) - .identifiers(new LinkedList<>()) - .columns(new LinkedList<>() /* TABLE_1_COLUMNS_DTO */) - .constraints(null) /* TABLE_1_CONSTRAINTS_DTO */ - .owner(USER_1_BRIEF_DTO) - .avgRowLength(TABLE_1_AVG_ROW_LENGTH) - .numRows(TABLE_1_NUM_ROWS) - .dataLength(TABLE_1_DATA_LENGTH) - .maxDataLength(TABLE_1_MAX_DATA_LENGTH) - .build(); - - public static final UUID COLUMN_1_1_ID = UUID.fromString("377c0a6e-938e-458c-ad2b-bbbd75d46412"); - - public static final UUID COLUMN_1_2_ID = UUID.fromString("dbca4821-3023-479b-a25a-c08eb0ec02ce"); - - public static final UUID COLUMN_1_3_ID = UUID.fromString("8ff0351e-4882-4948-94af-598e4b264b25"); + public final static UUID COLUMN_1_1_ID = UUID.fromString("377c0a6e-938e-458c-ad2b-bbbd75d46412"); + public final static UUID COLUMN_1_2_ID = UUID.fromString("dbca4821-3023-479b-a25a-c08eb0ec02ce"); + public final static UUID COLUMN_1_3_ID = UUID.fromString("8ff0351e-4882-4948-94af-598e4b264b25"); + public final static UUID COLUMN_1_4_ID = UUID.fromString("9ab256eb-3324-4e76-af3b-e3e2a58ce161"); + public final static UUID COLUMN_1_5_ID = UUID.fromString("619e9355-51aa-438f-8579-80cec30f35cb"); - public static final UUID COLUMN_1_4_ID = UUID.fromString("9ab256eb-3324-4e76-af3b-e3e2a58ce161"); - - public static final UUID COLUMN_1_5_ID = UUID.fromString("619e9355-51aa-438f-8579-80cec30f35cb"); - - public static final List<ColumnDto> TABLE_1_COLUMNS_DTO = List.of(ColumnDto.builder() + public final List<ColumnDto> TABLE_1_COLUMNS_DTO = List.of(ColumnDto.builder() .id(COLUMN_1_1_ID) .tableId(TABLE_1_ID) .databaseId(DATABASE_1_ID) @@ -1644,7 +1637,36 @@ public abstract class BaseTest { .sets(null) .build()); - public static final TableBriefDto TABLE_1_BRIEF_DTO = TableBriefDto.builder() + public final CreateTableConstraintsDto TABLE_1_CREATE_TABLE_CONSTRAINTS_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 TableDto TABLE_1_DTO = TableDto.builder() + .id(TABLE_1_ID) + .databaseId(DATABASE_1_ID) + .internalName(TABLE_1_INTERNAL_NAME) + .isVersioned(TABLE_1_VERSIONED) + .isPublic(TABLE_1_IS_PUBLIC) + .isSchemaPublic(TABLE_1_SCHEMA_PUBLIC) + .description(TABLE_1_DESCRIPTION) + .name(TABLE_1_NAME) + .queueName(TABLE_1_QUEUE_NAME) + .routingKey(TABLE_1_ROUTING_KEY) + .identifiers(new LinkedList<>()) + .columns(new LinkedList<>()) + .constraints(null) + .owner(USER_1_BRIEF_DTO) + .avgRowLength(TABLE_1_AVG_ROW_LENGTH) + .numRows(TABLE_1_NUM_ROWS) + .dataLength(TABLE_1_DATA_LENGTH) + .maxDataLength(TABLE_1_MAX_DATA_LENGTH) + .build(); + + public final TableBriefDto TABLE_1_BRIEF_DTO = TableBriefDto.builder() .id(TABLE_1_ID) .databaseId(DATABASE_1_ID) .internalName(TABLE_1_INTERNAL_NAME) @@ -1656,9 +1678,10 @@ public abstract class BaseTest { .ownedBy(USER_1_ID) .build(); - public static final Long TABLE_1_DATA_COUNT = 3L; + public final static Long TABLE_1_DATA_COUNT = 3L; + @SuppressWarnings("java:S3599") - public static final List<Map<String, Object>> TABLE_1_DATA_DTO = new LinkedList<>(List.of( + public final List<Map<String, Object>> TABLE_1_DATA_DTO = new LinkedList<>(List.of( new HashMap<>() {{ put("id", BigInteger.valueOf(1L)); put("date", LocalDate.of(2008, 12, 1).atStartOfDay().toInstant(ZoneOffset.UTC)); @@ -1682,29 +1705,28 @@ public abstract class BaseTest { }} )); - public static final UUID TABLE_2_ID = UUID.fromString("0cc067b6-4e81-4871-b47e-17a38228a574"); - public static final String TABLE_2_NAME = "Weather Location"; - public static final String TABLE_2_INTERNALNAME = "weather_location"; - public static final Boolean TABLE_2_VERSIONED = true; - public static final Boolean TABLE_2_IS_PUBLIC = false; - public static final Boolean TABLE_2_SCHEMA_PUBLIC = true; - public static final Boolean TABLE_2_PROCESSED_CONSTRAINTS = true; - public static final String TABLE_2_DESCRIPTION = "Weather location"; - public static final String TABLE_2_QUEUE_NAME = TABLE_2_INTERNALNAME; - public static final String TABLE_2_ROUTING_KEY = "dbrepo." + DATABASE_1_ID + "." + TABLE_2_ID; - public static final Instant TABLE_2_CREATED = Instant.ofEpochSecond(1677400007L) /* 2023-02-26 08:26:47 (UTC) */; - public static final Instant TABLE_2_LAST_MODIFIED = Instant.ofEpochSecond(1677400007L) /* 2023-02-26 08:26:47 (UTC) */; - public static final Long TABLE_2_AVG_ROW_LENGTH = 3L; - public static final Long TABLE_2_NUM_ROWS = 3L; - public static final Long TABLE_2_DATA_LENGTH = 2000L; - public static final Long TABLE_2_MAX_DATA_LENGTH = Long.MAX_VALUE; - - public static final Table TABLE_2 = Table.builder() + public final static UUID TABLE_2_ID = UUID.fromString("0cc067b6-4e81-4871-b47e-17a38228a574"); + public final static String TABLE_2_NAME = "Weather Location"; + public final static String TABLE_2_INTERNAL_NAME = "weather_location"; + public final static Boolean TABLE_2_VERSIONED = true; + public final static Boolean TABLE_2_IS_PUBLIC = false; + public final static Boolean TABLE_2_SCHEMA_PUBLIC = true; + public final static String TABLE_2_DESCRIPTION = "Weather location"; + public final static String TABLE_2_QUEUE_NAME = TABLE_2_INTERNAL_NAME; + public final static String TABLE_2_ROUTING_KEY = "dbrepo." + DATABASE_1_ID + "." + TABLE_2_ID; + public final static Instant TABLE_2_CREATED = Instant.ofEpochSecond(1677400007L) /* 2023-02-26 08:26:47 (UTC) */; + public final static Instant TABLE_2_LAST_MODIFIED = Instant.ofEpochSecond(1677400007L) /* 2023-02-26 08:26:47 (UTC) */; + public final static Long TABLE_2_AVG_ROW_LENGTH = 3L; + public final static Long TABLE_2_NUM_ROWS = 3L; + public final static Long TABLE_2_DATA_LENGTH = 2000L; + public final static Long TABLE_2_MAX_DATA_LENGTH = Long.MAX_VALUE; + + public final Table TABLE_2 = Table.builder() .id(TABLE_2_ID) .tdbid(DATABASE_1_ID) .database(null /* DATABASE_1 */) .created(TABLE_2_CREATED) - .internalName(TABLE_2_INTERNALNAME) + .internalName(TABLE_2_INTERNAL_NAME) .isVersioned(TABLE_2_VERSIONED) .isPublic(TABLE_2_IS_PUBLIC) .isSchemaPublic(TABLE_2_SCHEMA_PUBLIC) @@ -1712,7 +1734,7 @@ public abstract class BaseTest { .name(TABLE_2_NAME) .lastModified(TABLE_2_LAST_MODIFIED) .queueName(TABLE_2_QUEUE_NAME) - .columns(new LinkedList<>() /* TABLE_2_COLUMNS */) + .columns(new LinkedList<>()) /* TABLE_2_COLUMNS */ .constraints(null) /* TABLE_2_CONSTRAINTS */ .owner(USER_2) .ownedBy(USER_2_ID) @@ -1722,61 +1744,177 @@ public abstract class BaseTest { .maxDataLength(TABLE_2_MAX_DATA_LENGTH) .build(); - public static final TableDto TABLE_2_DTO = TableDto.builder() + public final TableBriefDto TABLE_2_BRIEF_DTO = TableBriefDto.builder() .id(TABLE_2_ID) .databaseId(DATABASE_1_ID) - .internalName(TABLE_2_INTERNALNAME) + .internalName(TABLE_2_INTERNAL_NAME) .isVersioned(TABLE_2_VERSIONED) .isPublic(TABLE_2_IS_PUBLIC) .isSchemaPublic(TABLE_2_SCHEMA_PUBLIC) .description(TABLE_2_DESCRIPTION) .name(TABLE_2_NAME) - .queueName(TABLE_2_QUEUE_NAME) - .routingKey(TABLE_2_ROUTING_KEY) - .columns(new LinkedList<>() /* TABLE_2_COLUMNS_DTO */) - .constraints(null) /* TABLE_2_CONSTRAINTS_DTO */ - .owner(USER_2_BRIEF_DTO) - .avgRowLength(TABLE_2_AVG_ROW_LENGTH) - .numRows(TABLE_2_NUM_ROWS) - .dataLength(TABLE_2_DATA_LENGTH) - .maxDataLength(TABLE_2_MAX_DATA_LENGTH) + .ownedBy(USER_2_ID) + .build(); + + public final static UUID COLUMN_2_1_ID = UUID.fromString("795faa78-7ebb-4dd5-9eb1-e54a9192d0b5"); + public final static UUID COLUMN_2_2_ID = UUID.fromString("f316ced5-7774-4656-aa7f-a874622d99b3"); + public final static UUID COLUMN_2_3_ID = UUID.fromString("11cb1aa2-8582-45ef-a3bb-7056aa94cdf1"); + + public final ColumnBriefDto TABLE_1_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() + .id(COLUMN_1_1_ID) + .name("id") + .internalName("id") + .columnType(ColumnTypeDto.BIGINT) + .build(); + + public final List<ColumnDto> TABLE_2_COLUMNS_DTO = List.of(ColumnDto.builder() + .id(COLUMN_2_1_ID) + .tableId(TABLE_2_ID) + .databaseId(DATABASE_1_ID) + .ordinalPosition(0) + .name("location") + .internalName("location") + .columnType(ColumnTypeDto.VARCHAR) + .size(255L) + .isNullAllowed(false) + .enums(null) + .sets(null) + .build(), + ColumnDto.builder() + .id(COLUMN_2_2_ID) + .tableId(TABLE_2_ID) + .databaseId(DATABASE_1_ID) + .ordinalPosition(1) + .name("lat") + .internalName("lat") + .columnType(ColumnTypeDto.DOUBLE) + .size(22L) + .isNullAllowed(true) + .enums(null) + .sets(null) + .build(), + ColumnDto.builder() + .id(COLUMN_2_3_ID) + .tableId(TABLE_2_ID) + .databaseId(DATABASE_1_ID) + .ordinalPosition(2) + .name("lng") + .internalName("lng") + .columnType(ColumnTypeDto.DOUBLE) + .size(22L) + .isNullAllowed(true) + .enums(null) + .sets(null) + .build()); + + public final ColumnBriefDto TABLE_2_COLUMNS_BRIEF_2_DTO = ColumnBriefDto.builder() + .id(COLUMN_2_3_ID) + .name("lng") + .internalName("lng") + .columnType(ColumnTypeDto.DECIMAL) + .build(); + + public final 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 ColumnBriefDto TABLE_2_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() + .id(COLUMN_2_1_ID) + .name("location") + .internalName("location") + .columnType(ColumnTypeDto.VARCHAR) .build(); - public static final TableBriefDto TABLE_2_BRIEF_DTO = TableBriefDto.builder() + public final TableDto TABLE_2_DTO = TableDto.builder() .id(TABLE_2_ID) .databaseId(DATABASE_1_ID) - .internalName(TABLE_2_INTERNALNAME) + .internalName(TABLE_2_INTERNAL_NAME) .isVersioned(TABLE_2_VERSIONED) .isPublic(TABLE_2_IS_PUBLIC) .isSchemaPublic(TABLE_2_SCHEMA_PUBLIC) .description(TABLE_2_DESCRIPTION) .name(TABLE_2_NAME) - .ownedBy(USER_2_ID) + .queueName(TABLE_2_QUEUE_NAME) + .routingKey(TABLE_2_ROUTING_KEY) + .columns(new LinkedList<>()) + .constraints(ConstraintsDto.builder() + .checks(new LinkedHashSet<>(List.of("`mintemp` > 0"))) + .foreignKeys(new LinkedList<>(List.of(ForeignKeyDto.builder() + .id(UUID.fromString("ca833111-1e9a-48a3-bb16-ad6f90196f96")) + .name("fk_location") + .onDelete(ReferenceTypeDto.NO_ACTION) + .references(new LinkedList<>(List.of(ForeignKeyReferenceDto.builder() + .id(UUID.fromString("8552f282-0403-424d-b2ba-4ed0f760197c")) + .column(TABLE_2_COLUMNS_BRIEF_2_DTO) + .referencedColumn(TABLE_1_COLUMNS_BRIEF_0_DTO) + .foreignKey(null) + .build()))) + .table(TABLE_1_BRIEF_DTO) + .referencedTable(TABLE_2_BRIEF_DTO) + .onUpdate(ReferenceTypeDto.NO_ACTION) + .build()))) + .uniques(new LinkedList<>(List.of(UniqueDto.builder() + .id(UUID.fromString("b9aba807-dd9c-43a3-9614-2493cb4b26bd")) + .table(TABLE_2_BRIEF_DTO) + .name("uk_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) + .column(TABLE_2_COLUMNS_BRIEF_0_DTO) + .id(COLUMN_2_1_ID) + .build()))) + .build()) + .owner(USER_2_BRIEF_DTO) + .avgRowLength(TABLE_2_AVG_ROW_LENGTH) + .numRows(TABLE_2_NUM_ROWS) + .dataLength(TABLE_2_DATA_LENGTH) + .maxDataLength(TABLE_2_MAX_DATA_LENGTH) .build(); - public static final UUID TABLE_3_ID = UUID.fromString("a94ee518-c235-496b-8613-b0c643bc1b11"); - public static final String TABLE_3_NAME = "Sensor"; - public static final String TABLE_3_INTERNALNAME = "sensor"; - public static final Boolean TABLE_3_VERSIONED = true; - public static final Boolean TABLE_3_IS_PUBLIC = false; - public static final Boolean TABLE_3_SCHEMA_PUBLIC = false; - public static final Boolean TABLE_3_PROCESSED_CONSTRAINTS = true; - public static final String TABLE_3_DESCRIPTION = "Some sensor data"; - public static final String TABLE_3_QUEUE_NAME = TABLE_3_INTERNALNAME; - public static final String TABLE_3_ROUTING_KEY = "dbrepo." + DATABASE_1_ID + "." + TABLE_3_ID; - public static final Instant TABLE_3_CREATED = Instant.ofEpochSecond(1677400031L) /* 2023-02-26 08:27:11 (UTC) */; - public static final Instant TABLE_3_LAST_MODIFIED = Instant.ofEpochSecond(1677400031L) /* 2023-02-26 08:27:11 (UTC) */; - public static final Long TABLE_3_AVG_ROW_LENGTH = 6L; - public static final Long TABLE_3_NUM_ROWS = 6L; - public static final Long TABLE_3_DATA_LENGTH = 1800L; - public static final Long TABLE_3_MAX_DATA_LENGTH = Long.MAX_VALUE; - - public static final Table TABLE_3 = Table.builder() + public final static UUID TABLE_3_ID = UUID.fromString("a94ee518-c235-496b-8613-b0c643bc1b11"); + public final static String TABLE_3_NAME = "Sensor"; + public final static String TABLE_3_INTERNAL_NAME = "sensor"; + public final static Boolean TABLE_3_VERSIONED = true; + public final static Boolean TABLE_3_IS_PUBLIC = false; + public final static Boolean TABLE_3_SCHEMA_PUBLIC = false; + public final static String TABLE_3_DESCRIPTION = "Some sensor data"; + public final static String TABLE_3_QUEUE_NAME = TABLE_3_INTERNAL_NAME; + public final static String TABLE_3_ROUTING_KEY = "dbrepo." + DATABASE_1_ID + "." + TABLE_3_ID; + public final static Instant TABLE_3_CREATED = Instant.ofEpochSecond(1677400031L) /* 2023-02-26 08:27:11 (UTC) */; + public final static Instant TABLE_3_LAST_MODIFIED = Instant.ofEpochSecond(1677400031L) /* 2023-02-26 08:27:11 (UTC) */; + public final static Long TABLE_3_AVG_ROW_LENGTH = 6L; + public final static Long TABLE_3_NUM_ROWS = 6L; + public final static Long TABLE_3_DATA_LENGTH = 1800L; + public final static Long TABLE_3_MAX_DATA_LENGTH = Long.MAX_VALUE; + + public final Table TABLE_3 = Table.builder() .id(TABLE_3_ID) .tdbid(DATABASE_1_ID) - .database(null /* DATABASE_1 */) + .database(null) /* DATABASE_1 */ .created(TABLE_3_CREATED) - .internalName(TABLE_3_INTERNALNAME) + .internalName(TABLE_3_INTERNAL_NAME) .isVersioned(TABLE_3_VERSIONED) .isPublic(TABLE_3_IS_PUBLIC) .isSchemaPublic(TABLE_3_SCHEMA_PUBLIC) @@ -1784,7 +1922,7 @@ public abstract class BaseTest { .name(TABLE_3_NAME) .lastModified(TABLE_3_LAST_MODIFIED) .queueName(TABLE_3_QUEUE_NAME) - .columns(new LinkedList<>() /* TABLE_3_COLUMNS */) + .columns(new LinkedList<>()) /* TABLE_3_COLUMNS */ .constraints(null) /* TABLE_3_CONSTRAINTS */ .owner(USER_3) .ownedBy(USER_3_ID) @@ -1794,10 +1932,10 @@ public abstract class BaseTest { .maxDataLength(TABLE_3_MAX_DATA_LENGTH) .build(); - public static final TableDto TABLE_3_DTO = TableDto.builder() + public final TableDto TABLE_3_DTO = TableDto.builder() .id(TABLE_3_ID) .databaseId(DATABASE_1_ID) - .internalName(TABLE_3_INTERNALNAME) + .internalName(TABLE_3_INTERNAL_NAME) .isVersioned(TABLE_3_VERSIONED) .isPublic(TABLE_3_IS_PUBLIC) .isSchemaPublic(TABLE_3_SCHEMA_PUBLIC) @@ -1814,10 +1952,10 @@ public abstract class BaseTest { .maxDataLength(TABLE_3_MAX_DATA_LENGTH) .build(); - public static final TableBriefDto TABLE_3_BRIEF_DTO = TableBriefDto.builder() + public final TableBriefDto TABLE_3_BRIEF_DTO = TableBriefDto.builder() .id(TABLE_3_ID) .databaseId(DATABASE_1_ID) - .internalName(TABLE_3_INTERNALNAME) + .internalName(TABLE_3_INTERNAL_NAME) .isVersioned(TABLE_3_VERSIONED) .isPublic(TABLE_3_IS_PUBLIC) .isSchemaPublic(TABLE_3_SCHEMA_PUBLIC) @@ -1826,14 +1964,14 @@ public abstract class BaseTest { .ownedBy(USER_3_ID) .build(); - public static final CreateTableConstraintsDto TABLE_3_CONSTRAINTS_CREATE_DTO = CreateTableConstraintsDto.builder() + public final CreateTableConstraintsDto TABLE_3_CONSTRAINTS_CREATE_DTO = CreateTableConstraintsDto.builder() .checks(new LinkedHashSet<>()) .primaryKey(new LinkedHashSet<>()) .foreignKeys(new LinkedList<>()) .uniques(new LinkedList<>()) .build(); - public static final CreateTableConstraintsDto TABLE_3_CONSTRAINTS_INVALID_CREATE_DTO = CreateTableConstraintsDto.builder() + public final CreateTableConstraintsDto TABLE_3_CONSTRAINTS_INVALID_CREATE_DTO = CreateTableConstraintsDto.builder() .checks(new LinkedHashSet<>()) .primaryKey(new LinkedHashSet<>()) // <<<< .uniques(new LinkedList<>()) @@ -1844,42 +1982,41 @@ public abstract class BaseTest { .build())) .build(); - public static final CreateTableDto TABLE_3_CREATE_DTO = CreateTableDto.builder() + public final 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 static final CreateTableDto TABLE_3_INVALID_CREATE_DTO = CreateTableDto.builder() + public final CreateTableDto TABLE_3_INVALID_CREATE_DTO = CreateTableDto.builder() .name(TABLE_3_NAME) .description(TABLE_3_DESCRIPTION) .columns(new LinkedList<>()) .constraints(TABLE_3_CONSTRAINTS_INVALID_CREATE_DTO) .build(); - public static final UUID TABLE_5_ID = UUID.fromString("91306cbd-c51f-47d3-8722-debfdbd8a77e"); - public static final String TABLE_5_NAME = "zoo"; - public static final String TABLE_5_INTERNALNAME = "zoo"; - public static final Boolean TABLE_5_VERSIONED = true; - public static final Boolean TABLE_5_IS_PUBLIC = true; - public static final Boolean TABLE_5_SCHEMA_PUBLIC = true; - public static final Boolean TABLE_5_PROCESSED_CONSTRAINTS = true; - public static final String TABLE_5_DESCRIPTION = "Some Kaggle dataset"; - public static final String TABLE_5_QUEUE_NAME = TABLE_5_INTERNALNAME; - public static final String TABLE_5_ROUTING_KEY = "dbrepo." + DATABASE_2_ID + "." + TABLE_5_ID; - public static final Instant TABLE_5_CREATED = Instant.ofEpochSecond(1677400067L) /* 2023-02-26 08:27:47 (UTC) */; - public static final Instant TABLE_5_LAST_MODIFIED = Instant.ofEpochSecond(1677400067L) /* 2023-02-26 08:27:47 (UTC) */; - public static final Long TABLE_5_AVG_ROW_LENGTH = 1080L; - public static final Long TABLE_5_NUM_ROWS = 101L; - public static final Long TABLE_5_DATA_LENGTH = 15200L; - public static final Long TABLE_5_MAX_DATA_LENGTH = Long.MAX_VALUE; - - public static final Table TABLE_5 = Table.builder() + public final static UUID TABLE_5_ID = UUID.fromString("91306cbd-c51f-47d3-8722-debfdbd8a77e"); + public final static String TABLE_5_NAME = "zoo"; + public final static String TABLE_5_INTERNAL_NAME = "zoo"; + public final static Boolean TABLE_5_VERSIONED = true; + public final static Boolean TABLE_5_IS_PUBLIC = true; + public final static Boolean TABLE_5_SCHEMA_PUBLIC = true; + public final static String TABLE_5_DESCRIPTION = "Some Kaggle dataset"; + public final static String TABLE_5_QUEUE_NAME = TABLE_5_INTERNAL_NAME; + public final static String TABLE_5_ROUTING_KEY = "dbrepo." + DATABASE_2_ID + "." + TABLE_5_ID; + public final static Instant TABLE_5_CREATED = Instant.ofEpochSecond(1677400067L) /* 2023-02-26 08:27:47 (UTC) */; + public final static Instant TABLE_5_LAST_MODIFIED = Instant.ofEpochSecond(1677400067L) /* 2023-02-26 08:27:47 (UTC) */; + public final static Long TABLE_5_AVG_ROW_LENGTH = 1080L; + public final static Long TABLE_5_NUM_ROWS = 101L; + public final static Long TABLE_5_DATA_LENGTH = 15200L; + public final static Long TABLE_5_MAX_DATA_LENGTH = Long.MAX_VALUE; + + public final Table TABLE_5 = Table.builder() .id(TABLE_5_ID) .tdbid(DATABASE_2_ID) .created(Instant.now()) - .internalName(TABLE_5_INTERNALNAME) + .internalName(TABLE_5_INTERNAL_NAME) .isVersioned(TABLE_5_VERSIONED) .isPublic(TABLE_5_IS_PUBLIC) .isSchemaPublic(TABLE_5_SCHEMA_PUBLIC) @@ -1893,10 +2030,10 @@ public abstract class BaseTest { .owner(USER_1) .build(); - public static final TableDto TABLE_5_DTO = TableDto.builder() + public final TableDto TABLE_5_DTO = TableDto.builder() .id(TABLE_5_ID) .databaseId(DATABASE_2_ID) - .internalName(TABLE_5_INTERNALNAME) + .internalName(TABLE_5_INTERNAL_NAME) .isVersioned(TABLE_5_VERSIONED) .isPublic(TABLE_5_IS_PUBLIC) .isSchemaPublic(TABLE_5_SCHEMA_PUBLIC) @@ -1909,10 +2046,10 @@ public abstract class BaseTest { .owner(USER_1_BRIEF_DTO) .build(); - public static final TableBriefDto TABLE_5_BRIEF_DTO = TableBriefDto.builder() + public final TableBriefDto TABLE_5_BRIEF_DTO = TableBriefDto.builder() .id(TABLE_5_ID) .databaseId(DATABASE_2_ID) - .internalName(TABLE_5_INTERNALNAME) + .internalName(TABLE_5_INTERNAL_NAME) .isVersioned(TABLE_5_VERSIONED) .isPublic(TABLE_5_IS_PUBLIC) .isSchemaPublic(TABLE_5_SCHEMA_PUBLIC) @@ -1921,24 +2058,23 @@ public abstract class BaseTest { .ownedBy(USER_1_ID) .build(); - public static final UUID TABLE_6_ID = UUID.fromString("ae84d169-d36c-4f5a-a390-153d090f9574"); - public static final String TABLE_6_NAME = "names"; - public static final String TABLE_6_INTERNALNAME = "names"; - public static final Boolean TABLE_6_VERSIONED = true; - public static final Boolean TABLE_6_IS_PUBLIC = true; - public static final Boolean TABLE_6_SCHEMA_PUBLIC = false; - public static final Boolean TABLE_6_PROCESSED_CONSTRAINTS = true; - public static final String TABLE_6_DESCRIPTION = "Some names dataset"; - public static final String TABLE_6_QUEUE_NAME = TABLE_6_INTERNALNAME; - public static final String TABLE_6_ROUTING_KEY = "dbrepo." + DATABASE_2_ID + "." + TABLE_6_ID; - public static final Instant TABLE_6_CREATED = Instant.ofEpochSecond(1677400117L) /* 2023-02-26 08:28:37 (UTC) */; - public static final Instant TABLE_6_LAST_MODIFIED = Instant.ofEpochSecond(1677400117L) /* 2023-02-26 08:28:37 (UTC) */; - - public static final Table TABLE_6 = Table.builder() + public final static UUID TABLE_6_ID = UUID.fromString("ae84d169-d36c-4f5a-a390-153d090f9574"); + public final static String TABLE_6_NAME = "names"; + public final static String TABLE_6_INTERNAL_NAME = "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 = false; + public final static String TABLE_6_DESCRIPTION = "Some names dataset"; + public final static String TABLE_6_QUEUE_NAME = TABLE_6_INTERNAL_NAME; + public final static String TABLE_6_ROUTING_KEY = "dbrepo." + DATABASE_2_ID + "." + TABLE_6_ID; + public final static Instant TABLE_6_CREATED = Instant.ofEpochSecond(1677400117L) /* 2023-02-26 08:28:37 (UTC) */; + public final static Instant TABLE_6_LAST_MODIFIED = Instant.ofEpochSecond(1677400117L) /* 2023-02-26 08:28:37 (UTC) */; + + public final Table TABLE_6 = Table.builder() .id(TABLE_6_ID) .tdbid(DATABASE_2_ID) .created(TABLE_6_CREATED) - .internalName(TABLE_6_INTERNALNAME) + .internalName(TABLE_6_INTERNAL_NAME) .isVersioned(TABLE_6_VERSIONED) .isPublic(TABLE_6_IS_PUBLIC) .isSchemaPublic(TABLE_6_SCHEMA_PUBLIC) @@ -1953,10 +2089,10 @@ public abstract class BaseTest { .created(TABLE_6_CREATED) .build(); - public static final TableDto TABLE_6_DTO = TableDto.builder() + public final TableDto TABLE_6_DTO = TableDto.builder() .id(TABLE_6_ID) .databaseId(DATABASE_2_ID) - .internalName(TABLE_6_INTERNALNAME) + .internalName(TABLE_6_INTERNAL_NAME) .isVersioned(TABLE_6_VERSIONED) .isPublic(TABLE_6_IS_PUBLIC) .isSchemaPublic(TABLE_6_SCHEMA_PUBLIC) @@ -1969,10 +2105,10 @@ public abstract class BaseTest { .owner(USER_1_BRIEF_DTO) .build(); - public static final TableBriefDto TABLE_6_BRIEF_DTO = TableBriefDto.builder() + public final TableBriefDto TABLE_6_BRIEF_DTO = TableBriefDto.builder() .id(TABLE_6_ID) .databaseId(DATABASE_2_ID) - .internalName(TABLE_6_INTERNALNAME) + .internalName(TABLE_6_INTERNAL_NAME) .isVersioned(TABLE_6_VERSIONED) .isPublic(TABLE_6_IS_PUBLIC) .isSchemaPublic(TABLE_6_SCHEMA_PUBLIC) @@ -1981,20 +2117,19 @@ public abstract class BaseTest { .ownedBy(USER_1_ID) .build(); - public static final UUID TABLE_7_ID = UUID.fromString("e5d10200-3e4f-45f4-9f36-ff3ca39c6c29"); - public static final String TABLE_7_NAME = "likes"; - public static final String TABLE_7_INTERNAL_NAME = "likes"; - public static final Boolean TABLE_7_VERSIONED = true; - public static final Boolean TABLE_7_IS_PUBLIC = true; - public static final Boolean TABLE_7_SCHEMA_PUBLIC = true; - public static final Boolean TABLE_7_PROCESSED_CONSTRAINTS = true; - public static final String TABLE_7_DESCRIPTION = "Some likes dataset"; - public static final String TABLE_7_QUEUE_NAME = TABLE_7_INTERNAL_NAME; - public static final String TABLE_7_ROUTING_KEY = "dbrepo." + DATABASE_2_ID + "." + TABLE_7_ID; - public static final Instant TABLE_7_CREATED = Instant.ofEpochSecond(1677400147L) /* 2023-02-26 08:29:07 (UTC) */; - public static final Instant TABLE_7_LAST_MODIFIED = Instant.ofEpochSecond(1677400147L) /* 2023-02-26 08:29:07 (UTC) */; - - public static final Table TABLE_7 = Table.builder() + public final static UUID TABLE_7_ID = UUID.fromString("e5d10200-3e4f-45f4-9f36-ff3ca39c6c29"); + public final static String TABLE_7_NAME = "likes"; + public final static String TABLE_7_INTERNAL_NAME = "likes"; + public final static Boolean TABLE_7_VERSIONED = true; + public final static Boolean TABLE_7_IS_PUBLIC = true; + public final static Boolean TABLE_7_SCHEMA_PUBLIC = true; + public final static String TABLE_7_DESCRIPTION = "Some likes dataset"; + public final static String TABLE_7_QUEUE_NAME = TABLE_7_INTERNAL_NAME; + public final static String TABLE_7_ROUTING_KEY = "dbrepo." + DATABASE_2_ID + "." + TABLE_7_ID; + public final static Instant TABLE_7_CREATED = Instant.ofEpochSecond(1677400147L) /* 2023-02-26 08:29:07 (UTC) */; + public final static Instant TABLE_7_LAST_MODIFIED = Instant.ofEpochSecond(1677400147L) /* 2023-02-26 08:29:07 (UTC) */; + + public final Table TABLE_7 = Table.builder() .id(TABLE_7_ID) .tdbid(DATABASE_2_ID) .created(TABLE_7_CREATED) @@ -2013,7 +2148,7 @@ public abstract class BaseTest { .created(TABLE_7_CREATED) .build(); - public static final TableDto TABLE_7_DTO = TableDto.builder() + public final TableDto TABLE_7_DTO = TableDto.builder() .id(TABLE_7_ID) .databaseId(DATABASE_2_ID) .internalName(TABLE_7_INTERNAL_NAME) @@ -2029,7 +2164,7 @@ public abstract class BaseTest { .owner(USER_1_BRIEF_DTO) .build(); - public static final TableBriefDto TABLE_7_BRIEF_DTO = TableBriefDto.builder() + public final TableBriefDto TABLE_7_BRIEF_DTO = TableBriefDto.builder() .id(TABLE_7_ID) .databaseId(DATABASE_2_ID) .internalName(TABLE_7_INTERNAL_NAME) @@ -2041,26 +2176,26 @@ public abstract class BaseTest { .ownedBy(USER_1_ID) .build(); - public static final UUID TABLE_4_ID = UUID.fromString("6c87cbcf-5043-404f-9bf1-b09ddbac25a2"); - public static final String TABLE_4_NAME = "Sensor 2"; - public static final String TABLE_4_INTERNALNAME = "sensor_2"; - public static final Boolean TABLE_4_VERSIONED = true; - public static final Boolean TABLE_4_IS_PUBLIC = true; - public static final Boolean TABLE_4_SCHEMA_PUBLIC = false; - public static final String TABLE_4_DESCRIPTION = "Hello sensor"; - public static final String TABLE_4_QUEUE_NAME = TABLE_4_INTERNALNAME; - public static final String TABLE_4_ROUTING_KEY = "dbrepo." + DATABASE_1_ID + "." + TABLE_4_ID; - public static final Instant TABLE_4_CREATED = Instant.ofEpochSecond(1677400175L) /* 2023-02-26 08:29:35 (UTC) */; - public static final Instant TABLE_4_LAST_MODIFIED = Instant.ofEpochSecond(1677400175L) /* 2023-02-26 08:29:35 (UTC) */; - public static final Long TABLE_4_AVG_ROW_LENGTH = 0L; - public static final Long TABLE_4_NUM_ROWS = 0L; - public static final Long TABLE_4_DATA_LENGTH = 1000L; - public static final Long TABLE_4_MAX_DATA_LENGTH = Long.MAX_VALUE; - - public static final Table TABLE_4 = Table.builder() + public final static UUID TABLE_4_ID = UUID.fromString("6c87cbcf-5043-404f-9bf1-b09ddbac25a2"); + public final static String TABLE_4_NAME = "Sensor 2"; + public final static String TABLE_4_INTERNAL_NAME = "sensor_2"; + public final static Boolean TABLE_4_VERSIONED = true; + public final static Boolean TABLE_4_IS_PUBLIC = true; + public final static Boolean TABLE_4_SCHEMA_PUBLIC = false; + public final static String TABLE_4_DESCRIPTION = "Hello sensor"; + public final static String TABLE_4_QUEUE_NAME = TABLE_4_INTERNAL_NAME; + public final static String TABLE_4_ROUTING_KEY = "dbrepo." + DATABASE_1_ID + "." + TABLE_4_ID; + public final static Instant TABLE_4_CREATED = Instant.ofEpochSecond(1677400175L) /* 2023-02-26 08:29:35 (UTC) */; + public final static Instant TABLE_4_LAST_MODIFIED = Instant.ofEpochSecond(1677400175L) /* 2023-02-26 08:29:35 (UTC) */; + public final static Long TABLE_4_AVG_ROW_LENGTH = 0L; + public final static Long TABLE_4_NUM_ROWS = 0L; + public final static Long TABLE_4_DATA_LENGTH = 1000L; + public final static Long TABLE_4_MAX_DATA_LENGTH = Long.MAX_VALUE; + + public final Table TABLE_4 = Table.builder() .id(TABLE_4_ID) .tdbid(DATABASE_1_ID) - .internalName(TABLE_4_INTERNALNAME) + .internalName(TABLE_4_INTERNAL_NAME) .description(TABLE_4_DESCRIPTION) .database(null /* DATABASE_1 */) .name(TABLE_4_NAME) @@ -2080,10 +2215,10 @@ public abstract class BaseTest { .maxDataLength(TABLE_4_MAX_DATA_LENGTH) .build(); - public static final TableDto TABLE_4_DTO = TableDto.builder() + public final TableDto TABLE_4_DTO = TableDto.builder() .id(TABLE_4_ID) .databaseId(DATABASE_1_ID) - .internalName(TABLE_4_INTERNALNAME) + .internalName(TABLE_4_INTERNAL_NAME) .description(TABLE_4_DESCRIPTION) .name(TABLE_4_NAME) .queueName(TABLE_4_QUEUE_NAME) @@ -2100,10 +2235,10 @@ public abstract class BaseTest { .maxDataLength(TABLE_4_MAX_DATA_LENGTH) .build(); - public static final TableBriefDto TABLE_4_BRIEF_DTO = TableBriefDto.builder() + public final TableBriefDto TABLE_4_BRIEF_DTO = TableBriefDto.builder() .id(TABLE_4_ID) .databaseId(DATABASE_1_ID) - .internalName(TABLE_4_INTERNALNAME) + .internalName(TABLE_4_INTERNAL_NAME) .description(TABLE_4_DESCRIPTION) .name(TABLE_4_NAME) .isVersioned(TABLE_4_VERSIONED) @@ -2112,18 +2247,17 @@ public abstract class BaseTest { .ownedBy(USER_1_ID) .build(); - public static final ColumnBriefDto TABLE_4_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() + public final ColumnBriefDto TABLE_4_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() .id(UUID.fromString("360f02be-6dfb-48ea-9d1e-1da488b0e324")) .name("Timestamp") .internalName("timestamp") .columnType(ColumnTypeDto.TIMESTAMP) .build(); - public static final UUID COLUMN_4_1_ID = UUID.fromString("c8ec8a56-dea1-4316-895f-56e6d289cbf7"); - - public static final UUID COLUMN_4_2_ID = UUID.fromString("d06956ae-aabd-474f-a47d-47af1ba043d1"); + public final static UUID COLUMN_4_1_ID = UUID.fromString("c8ec8a56-dea1-4316-895f-56e6d289cbf7"); + public final static UUID COLUMN_4_2_ID = UUID.fromString("d06956ae-aabd-474f-a47d-47af1ba043d1"); - public static final List<TableColumn> TABLE_4_COLUMNS = List.of(TableColumn.builder() + public final List<TableColumn> TABLE_4_COLUMNS = List.of(TableColumn.builder() .id(COLUMN_4_1_ID) .ordinalPosition(0) .table(TABLE_4) @@ -2142,7 +2276,7 @@ public abstract class BaseTest { .isNullAllowed(true) .build()); - public static final List<CreateTableColumnDto> TABLE_4_COLUMNS_CREATE_DTO = List.of(CreateTableColumnDto.builder() + public final List<CreateTableColumnDto> TABLE_4_COLUMNS_CREATE_DTO = List.of(CreateTableColumnDto.builder() .name("Timestamp") .type(ColumnTypeDto.TIMESTAMP) .nullAllowed(false) @@ -2155,28 +2289,29 @@ public abstract class BaseTest { .d(10L) .build()); - public static final CreateTableConstraintsDto TABLE_4_CONSTRAINTS_CREATE_DTO = CreateTableConstraintsDto.builder() + public final 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 static final CreateTableDto TABLE_4_CREATE_DTO = CreateTableDto.builder() + public final CreateTableDto TABLE_4_CREATE_DTO = CreateTableDto.builder() .name(TABLE_4_NAME) .description(TABLE_4_DESCRIPTION) .columns(TABLE_4_COLUMNS_CREATE_DTO) .constraints(TABLE_4_CONSTRAINTS_CREATE_DTO) .build(); - public static final at.tuwien.api.database.table.internal.TableCreateDto TABLE_4_CREATE_INTERNAL_DTO = at.tuwien.api.database.table.internal.TableCreateDto.builder() - .name(TABLE_4_NAME) - .description(TABLE_4_DESCRIPTION) - .columns(TABLE_4_COLUMNS_CREATE_DTO) - .constraints(TABLE_4_CONSTRAINTS_CREATE_DTO) - .build(); + public final at.ac.tuwien.ifs.dbrepo.core.api.database.table.internal.TableCreateDto TABLE_4_CREATE_INTERNAL_DTO = + at.ac.tuwien.ifs.dbrepo.core.api.database.table.internal.TableCreateDto.builder() + .name(TABLE_4_NAME) + .description(TABLE_4_DESCRIPTION) + .columns(TABLE_4_COLUMNS_CREATE_DTO) + .constraints(TABLE_4_CONSTRAINTS_CREATE_DTO) + .build(); - public static final List<ColumnDto> TABLE_4_COLUMNS_DTO = List.of(ColumnDto.builder() + public final List<ColumnDto> TABLE_4_COLUMNS_DTO = List.of(ColumnDto.builder() .id(COLUMN_4_1_ID) .databaseId(DATABASE_1_ID) .tableId(TABLE_4_ID) @@ -2195,19 +2330,19 @@ public abstract class BaseTest { .isNullAllowed(true) .build()); - public static final UUID TABLE_8_ID = UUID.fromString("2e039d0d-3257-4083-8b32-76d7cfa1f7fd"); - public static final String TABLE_8_NAME = "location"; - public static final String TABLE_8_INTERNAL_NAME = "mfcc"; - public static final Boolean TABLE_8_VERSIONED = true; - public static final Boolean TABLE_8_IS_PUBLIC = false; - public static final Boolean TABLE_8_SCHEMA_PUBLIC = false; - public static final String TABLE_8_DESCRIPTION = "Hello mfcc"; - public static final String TABLE_8_QUEUE_NAME = TABLE_8_INTERNAL_NAME; - public static final String TABLE_8_ROUTING_KEY = "dbrepo." + DATABASE_3_ID + "." + TABLE_8_ID; - public static final Instant TABLE_8_CREATED = Instant.ofEpochSecond(1688400185L) /* 2023-02-26 08:29:35 (UTC) */; - public static final Instant TABLE_8_LAST_MODIFIED = Instant.ofEpochSecond(1688400185L) /* 2023-02-26 08:29:35 (UTC) */; - - public static final Table TABLE_8 = Table.builder() + public final static UUID TABLE_8_ID = UUID.fromString("2e039d0d-3257-4083-8b32-76d7cfa1f7fd"); + public final static String TABLE_8_NAME = "location"; + public final static String TABLE_8_INTERNAL_NAME = "mfcc"; + 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 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; + public final static Instant TABLE_8_CREATED = Instant.ofEpochSecond(1688400185L) /* 2023-02-26 08:29:35 (UTC) */; + public final static Instant TABLE_8_LAST_MODIFIED = Instant.ofEpochSecond(1688400185L) /* 2023-02-26 08:29:35 (UTC) */; + + public final Table TABLE_8 = Table.builder() .id(TABLE_8_ID) .tdbid(DATABASE_3_ID) .internalName(TABLE_8_INTERNAL_NAME) @@ -2226,7 +2361,7 @@ public abstract class BaseTest { .lastModified(TABLE_8_LAST_MODIFIED) .build(); - public static final TableDto TABLE_8_DTO = TableDto.builder() + public final TableDto TABLE_8_DTO = TableDto.builder() .id(TABLE_8_ID) .databaseId(DATABASE_3_ID) .internalName(TABLE_8_INTERNAL_NAME) @@ -2241,13 +2376,13 @@ public abstract class BaseTest { .owner(USER_1_BRIEF_DTO) .build(); - public static final TableUpdateDto TABLE_8_UPDATE_DTO = TableUpdateDto.builder() + public final TableUpdateDto TABLE_8_UPDATE_DTO = TableUpdateDto.builder() .description(null) .isPublic(true) .isSchemaPublic(true) .build(); - public static final TableBriefDto TABLE_8_BRIEF_DTO = TableBriefDto.builder() + public final TableBriefDto TABLE_8_BRIEF_DTO = TableBriefDto.builder() .id(TABLE_8_ID) .databaseId(DATABASE_3_ID) .internalName(TABLE_8_INTERNAL_NAME) @@ -2259,20 +2394,19 @@ public abstract class BaseTest { .ownedBy(USER_1_ID) .build(); - public static final UUID TABLE_9_ID = UUID.fromString("9314294f-04fc-4354-8b1f-2a8aeb566453"); - public static final String TABLE_9_NAME = "Weather Location"; - public static final String TABLE_9_INTERNAL_NAME = "weather_location"; - public static final Boolean TABLE_9_VERSIONED = true; - public static final Boolean TABLE_9_IS_PUBLIC = false; - public static final Boolean TABLE_9_SCHEMA_PUBLIC = true; - public static final Boolean TABLE_9_PROCESSED_CONSTRAINTS = true; - public static final String TABLE_9_DESCRIPTION = "Location"; - public static final String TABLE_9_QUEUE_NAME = TABLE_9_INTERNAL_NAME; - public static final String TABLE_9_ROUTING_KEY = "dbrepo." + DATABASE_4_ID + "." + TABLE_9_ID; - public static final Instant TABLE_9_CREATED = Instant.ofEpochSecond(1688400185L) /* 2023-02-26 08:29:35 (UTC) */; - public static final Instant TABLE_9_LAST_MODIFIED = Instant.ofEpochSecond(1688400185L) /* 2023-02-26 08:29:35 (UTC) */; - - public static final Table TABLE_9 = Table.builder() + public final static UUID TABLE_9_ID = UUID.fromString("9314294f-04fc-4354-8b1f-2a8aeb566453"); + public final static String TABLE_9_NAME = "Weather Location"; + public final static String TABLE_9_INTERNAL_NAME = "weather_location"; + public final static Boolean TABLE_9_VERSIONED = true; + public final static Boolean TABLE_9_IS_PUBLIC = false; + public final static Boolean TABLE_9_SCHEMA_PUBLIC = true; + public final static String TABLE_9_DESCRIPTION = "Location"; + public final static String TABLE_9_QUEUE_NAME = TABLE_9_INTERNAL_NAME; + public final static String TABLE_9_ROUTING_KEY = "dbrepo." + DATABASE_4_ID + "." + TABLE_9_ID; + public final static Instant TABLE_9_CREATED = Instant.ofEpochSecond(1688400185L) /* 2023-02-26 08:29:35 (UTC) */; + public final static Instant TABLE_9_LAST_MODIFIED = Instant.ofEpochSecond(1688400185L) /* 2023-02-26 08:29:35 (UTC) */; + + public final Table TABLE_9 = Table.builder() .id(TABLE_9_ID) .tdbid(DATABASE_4_ID) .internalName(TABLE_9_INTERNAL_NAME) @@ -2291,7 +2425,7 @@ public abstract class BaseTest { .lastModified(TABLE_9_LAST_MODIFIED) .build(); - public static final TableDto TABLE_9_DTO = TableDto.builder() + public final TableDto TABLE_9_DTO = TableDto.builder() .id(TABLE_9_ID) .databaseId(DATABASE_4_ID) .internalName(TABLE_9_INTERNAL_NAME) @@ -2306,7 +2440,7 @@ public abstract class BaseTest { .owner(USER_1_BRIEF_DTO) .build(); - public static final TableBriefDto TABLE_9_BRIEF_DTO = TableBriefDto.builder() + public final TableBriefDto TABLE_9_BRIEF_DTO = TableBriefDto.builder() .id(TABLE_9_ID) .databaseId(DATABASE_4_ID) .internalName(TABLE_9_INTERNAL_NAME) @@ -2318,22 +2452,21 @@ public abstract class BaseTest { .ownedBy(USER_1_ID) .build(); - public static final UUID COLUMN_9_1_ID = UUID.fromString("e03c7578-2d1a-4599-9b11-7174f40efc0a"); - public static final String COLUMN_9_1_NAME = "location"; - public static final String COLUMN_9_1_INTERNAL_NAME = "location"; + public final static UUID COLUMN_9_1_ID = UUID.fromString("e03c7578-2d1a-4599-9b11-7174f40efc0a"); + public final static String COLUMN_9_1_NAME = "location"; + public final static String COLUMN_9_1_INTERNAL_NAME = "location"; - public static final ColumnBriefDto TABLE_9_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() + public final ColumnBriefDto TABLE_9_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() .id(COLUMN_9_1_ID) .name(COLUMN_9_1_NAME) .internalName(COLUMN_9_1_INTERNAL_NAME) .columnType(ColumnTypeDto.BIGINT) .build(); - public static final UUID COLUMN_9_2_ID = UUID.fromString("03c07223-17e1-4af5-b1ae-ef9ab434fe2d"); - - public static final UUID COLUMN_9_3_ID = UUID.fromString("ee6590db-923b-4234-beb8-3120da055cf6"); + public final static UUID COLUMN_9_2_ID = UUID.fromString("03c07223-17e1-4af5-b1ae-ef9ab434fe2d"); + public final static UUID COLUMN_9_3_ID = UUID.fromString("ee6590db-923b-4234-beb8-3120da055cf6"); - public static final List<TableColumn> TABLE_9_COLUMNS = List.of(TableColumn.builder() + public final List<TableColumn> TABLE_9_COLUMNS = List.of(TableColumn.builder() .id(COLUMN_9_1_ID) .ordinalPosition(0) .table(TABLE_9) @@ -2372,7 +2505,7 @@ public abstract class BaseTest { .sets(null) .build()); - public static final List<ColumnDto> TABLE_9_COLUMNS_DTO = List.of(ColumnDto.builder() + public final List<ColumnDto> TABLE_9_COLUMNS_DTO = List.of(ColumnDto.builder() .id(COLUMN_9_1_ID) .ordinalPosition(0) .name(COLUMN_9_1_NAME) @@ -2408,7 +2541,7 @@ public abstract class BaseTest { .sets(null) .build()); - public static final Constraints TABLE_9_CONSTRAINTS = Constraints.builder() + public final Constraints TABLE_9_CONSTRAINTS = Constraints.builder() .checks(new LinkedHashSet<>()) .foreignKeys(new LinkedList<>()) .uniques(new LinkedList<>()) @@ -2419,7 +2552,7 @@ public abstract class BaseTest { .build()))) .build(); - public static final ConstraintsDto TABLE_9_CONSTRAINTS_DTO = ConstraintsDto.builder() + public final ConstraintsDto TABLE_9_CONSTRAINTS_DTO = ConstraintsDto.builder() .checks(new LinkedHashSet<>()) .foreignKeys(new LinkedList<>()) .uniques(new LinkedList<>()) @@ -2430,17 +2563,17 @@ public abstract class BaseTest { .build()))) .build(); - public static final UUID QUERY_9_ID = UUID.fromString("df34f0b9-b64c-406c-9109-7a031f4a7f27"); - public static final String QUERY_9_STATEMENT = "SELECT `lat`, `lng` FROM `mfcc` WHERE `location` = 'Fuji'"; - public static final String QUERY_9_QUERY_HASH = "dfcdec827b2ea74d89415f8d1ce39354f59ef304444ba4e12e4f3d9d3f35abe3"; - public static final String QUERY_9_RESULT_HASH = "f0aba070a1fd29e96230d12d7c0b4d08b89820b3cc2dda0575680492010016e7"; - public static final Instant QUERY_9_CREATED = Instant.now().minus(5, MINUTES); - public static final Instant QUERY_9_EXECUTION = Instant.now().minus(1, MINUTES); - public static final Instant QUERY_9_LAST_MODIFIED = Instant.ofEpochSecond(1551588555L); - public static final Long QUERY_9_RESULT_NUMBER = 6L; - public static final Boolean QUERY_9_PERSISTED = true; + public final static UUID QUERY_9_ID = UUID.fromString("df34f0b9-b64c-406c-9109-7a031f4a7f27"); + public final static String QUERY_9_STATEMENT = "SELECT `lat`, `lng` FROM `mfcc` WHERE `location` = 'Fuji'"; + public final static String QUERY_9_QUERY_HASH = "dfcdec827b2ea74d89415f8d1ce39354f59ef304444ba4e12e4f3d9d3f35abe3"; + public final static String QUERY_9_RESULT_HASH = "f0aba070a1fd29e96230d12d7c0b4d08b89820b3cc2dda0575680492010016e7"; + public final static Instant QUERY_9_CREATED = Instant.now().minus(5, MINUTES); + public final static Instant QUERY_9_EXECUTION = Instant.now().minus(1, MINUTES); + public final static Instant QUERY_9_LAST_MODIFIED = Instant.ofEpochSecond(1551588555L); + public final static Long QUERY_9_RESULT_NUMBER = 6L; + public final static Boolean QUERY_9_PERSISTED = true; - public static final QueryDto QUERY_9_DTO = QueryDto.builder() + public final QueryDto QUERY_9_DTO = QueryDto.builder() .id(QUERY_9_ID) .databaseId(DATABASE_3_ID) .query(QUERY_9_STATEMENT) @@ -2453,8 +2586,9 @@ public abstract class BaseTest { .owner(USER_1_BRIEF_DTO) .build(); - public static final SubsetDto QUERY_9_SUBSET_DTO = SubsetDto.builder() - .tableId(TABLE_9_ID) + public final SubsetDto QUERY_9_SUBSET_DTO = SubsetDto.builder() + .datasourceId(TABLE_9_ID) + .datasourceType(DatasourceType.TABLE) .columns(new LinkedList<>(List.of(COLUMN_9_2_ID, COLUMN_9_3_ID))) .filter(new LinkedList<>(List.of(FilterDto.builder() .columnId(COLUMN_9_1_ID) @@ -2464,7 +2598,7 @@ public abstract class BaseTest { .build()))) .build(); - public static final ViewDto QUERY_9_VIEW_DTO = ViewDto.builder() + public final ViewDto QUERY_9_VIEW_DTO = ViewDto.builder() .query(QUERY_9_STATEMENT) .queryHash(QUERY_9_QUERY_HASH) .owner(USER_1_BRIEF_DTO) @@ -2478,14 +2612,14 @@ public abstract class BaseTest { .build()))) .build(); - public static final String QUEUE_NAME = "dbrepo"; - public static final String QUEUE_VHOST = "dbrepo"; - public static final Boolean QUEUE_AUTO_DELETE = false; - public static final Boolean QUEUE_DURABLE = true; - public static final Boolean QUEUE_EXCLUSIVE = false; - public static final String QUEUE_TYPE = "quorum"; + public final static String QUEUE_NAME = "dbrepo"; + public final static String QUEUE_VHOST = "dbrepo"; + public final static Boolean QUEUE_AUTO_DELETE = false; + public final static Boolean QUEUE_DURABLE = true; + public final static Boolean QUEUE_EXCLUSIVE = false; + public final static String QUEUE_TYPE = "quorum"; - public static final QueueDto QUEUE_DTO = QueueDto.builder() + public final QueueDto QUEUE_DTO = QueueDto.builder() .name(QUEUE_NAME) .vhost(QUEUE_VHOST) .autoDelete(QUEUE_AUTO_DELETE) @@ -2494,18 +2628,17 @@ public abstract class BaseTest { .type(QUEUE_TYPE) .build(); - public static final UUID ONTOLOGY_1_ID = UUID.fromString("dc195d01-0a45-4583-aa83-fd270b874353"); - public static final String ONTOLOGY_1_PREFIX = "om2"; - public static final String ONTOLOGY_1_NEW_PREFIX = "om-2"; - public static final String ONTOLOGY_1_URI = "http://www.ontology-of-units-of-measure.org/resource/om-2/"; - public static final String ONTOLOGY_1_URI_PATTERN = "http://www.ontology-of-units-of-measure.org/resource/om-2/.*"; - public static final String ONTOLOGY_1_SPARQL_ENDPOINT = null; - public static final Boolean ONTOLOGY_1_SPARQL = false; - public static final String ONTOLOGY_1_RDF_PATH = "rdf/om-2.0.rdf"; - public static final Boolean ONTOLOGY_1_RDF = true; - public static final UUID ONTOLOGY_1_CREATED_BY = USER_1_ID; + public final static UUID ONTOLOGY_1_ID = UUID.fromString("dc195d01-0a45-4583-aa83-fd270b874353"); + public final static String ONTOLOGY_1_PREFIX = "om2"; + public final static String ONTOLOGY_1_NEW_PREFIX = "om-2"; + public final static String ONTOLOGY_1_URI = "http://www.ontology-of-units-of-measure.org/resource/om-2/"; + public final static String ONTOLOGY_1_URI_PATTERN = "http://www.ontology-of-units-of-measure.org/resource/om-2/.*"; + public final static String ONTOLOGY_1_SPARQL_ENDPOINT = null; + public final static Boolean ONTOLOGY_1_SPARQL = false; + public final static String ONTOLOGY_1_RDF_PATH = "rdf/om-2.0.rdf"; + public final static Boolean ONTOLOGY_1_RDF = true; - public static final Ontology ONTOLOGY_1 = Ontology.builder() + public final Ontology ONTOLOGY_1 = Ontology.builder() .id(ONTOLOGY_1_ID) .prefix(ONTOLOGY_1_PREFIX) .uri(ONTOLOGY_1_URI) @@ -2514,7 +2647,7 @@ public abstract class BaseTest { .rdfPath(ONTOLOGY_1_RDF_PATH) .build(); - public static final OntologyDto ONTOLOGY_1_DTO = OntologyDto.builder() + public final OntologyDto ONTOLOGY_1_DTO = OntologyDto.builder() .id(ONTOLOGY_1_ID) .prefix(ONTOLOGY_1_PREFIX) .uri(ONTOLOGY_1_URI) @@ -2525,7 +2658,7 @@ public abstract class BaseTest { .rdf(ONTOLOGY_1_RDF) .build(); - public static final OntologyBriefDto ONTOLOGY_1_BRIEF_DTO = OntologyBriefDto.builder() + public final OntologyBriefDto ONTOLOGY_1_BRIEF_DTO = OntologyBriefDto.builder() .id(ONTOLOGY_1_ID) .prefix(ONTOLOGY_1_PREFIX) .uri(ONTOLOGY_1_URI) @@ -2534,131 +2667,124 @@ public abstract class BaseTest { .rdf(ONTOLOGY_1_RDF) .build(); - public static final OntologyCreateDto ONTOLOGY_1_CREATE_DTO = OntologyCreateDto.builder() + public final OntologyCreateDto ONTOLOGY_1_CREATE_DTO = OntologyCreateDto.builder() .prefix(ONTOLOGY_1_PREFIX) .uri(ONTOLOGY_1_URI) .sparqlEndpoint(ONTOLOGY_1_SPARQL_ENDPOINT) .build(); - public static final OntologyModifyDto ONTOLOGY_1_MODIFY_DTO = OntologyModifyDto.builder() + public final OntologyModifyDto ONTOLOGY_1_MODIFY_DTO = OntologyModifyDto.builder() .prefix(ONTOLOGY_1_NEW_PREFIX) .uri(ONTOLOGY_1_URI) .sparqlEndpoint(ONTOLOGY_1_SPARQL_ENDPOINT) .build(); - public static final UUID ONTOLOGY_2_ID = UUID.fromString("41d902a1-f9f8-4d51-ad64-618b72acf5ed"); - public static final String ONTOLOGY_2_PREFIX = "wd"; - public static final String ONTOLOGY_2_URI = "http://www.wikidata.org/"; - public static final String ONTOLOGY_2_SPARQL_ENDPOINT = "https://query.wikidata.org/sparql"; - public static final UUID ONTOLOGY_2_CREATED_BY = USER_1_ID; + public final static UUID ONTOLOGY_2_ID = UUID.fromString("41d902a1-f9f8-4d51-ad64-618b72acf5ed"); + public final static String ONTOLOGY_2_PREFIX = "wd"; + public final static String ONTOLOGY_2_URI = "http://www.wikidata.org/"; + public final static String ONTOLOGY_2_SPARQL_ENDPOINT = "https://query.wikidata.org/sparql"; - public static final Ontology ONTOLOGY_2 = Ontology.builder() + public final Ontology ONTOLOGY_2 = Ontology.builder() .id(ONTOLOGY_2_ID) .prefix(ONTOLOGY_2_PREFIX) .uri(ONTOLOGY_2_URI) .sparqlEndpoint(ONTOLOGY_2_SPARQL_ENDPOINT) .build(); - public static final OntologyCreateDto ONTOLOGY_2_CREATE_DTO = OntologyCreateDto.builder() + public final OntologyCreateDto ONTOLOGY_2_CREATE_DTO = OntologyCreateDto.builder() .prefix(ONTOLOGY_2_PREFIX) .uri(ONTOLOGY_2_URI) .sparqlEndpoint(ONTOLOGY_2_SPARQL_ENDPOINT) .build(); - public static final UUID ONTOLOGY_3_ID = UUID.fromString("5b41390b-d2d2-45c6-8038-1258c4b2725f"); - public static final String ONTOLOGY_3_PREFIX = "rdfs"; - public static final String ONTOLOGY_3_URI = "http://www.w3.org/2000/01/rdf-schema#"; - public static final String ONTOLOGY_3_SPARQL_ENDPOINT = null; - public static final UUID ONTOLOGY_3_CREATED_BY = USER_1_ID; + public final static UUID ONTOLOGY_3_ID = UUID.fromString("5b41390b-d2d2-45c6-8038-1258c4b2725f"); + public final static String ONTOLOGY_3_PREFIX = "rdfs"; + public final static String ONTOLOGY_3_URI = "http://www.w3.org/2000/01/rdf-schema#"; + public final static String ONTOLOGY_3_SPARQL_ENDPOINT = null; - public static final Ontology ONTOLOGY_3 = Ontology.builder() + public final Ontology ONTOLOGY_3 = Ontology.builder() .id(ONTOLOGY_3_ID) .prefix(ONTOLOGY_3_PREFIX) .uri(ONTOLOGY_3_URI) .sparqlEndpoint(ONTOLOGY_3_SPARQL_ENDPOINT) .build(); - public static final OntologyCreateDto ONTOLOGY_3_CREATE_DTO = OntologyCreateDto.builder() + public final OntologyCreateDto ONTOLOGY_3_CREATE_DTO = OntologyCreateDto.builder() .prefix(ONTOLOGY_3_PREFIX) .uri(ONTOLOGY_3_URI) .sparqlEndpoint(ONTOLOGY_3_SPARQL_ENDPOINT) .build(); - public static final UUID ONTOLOGY_4_ID = UUID.fromString("d6992475-9b71-4a4a-a6eb-bc1fe6a34443"); - public static final String ONTOLOGY_4_PREFIX = "schema"; - public static final String ONTOLOGY_4_URI = "http://schema.org/"; - public static final String ONTOLOGY_4_SPARQL_ENDPOINT = null; - public static final UUID ONTOLOGY_4_CREATED_BY = USER_1_ID; + public final static UUID ONTOLOGY_4_ID = UUID.fromString("d6992475-9b71-4a4a-a6eb-bc1fe6a34443"); + public final static String ONTOLOGY_4_PREFIX = "schema"; + public final static String ONTOLOGY_4_URI = "http://schema.org/"; + public final static String ONTOLOGY_4_SPARQL_ENDPOINT = null; - public static final Ontology ONTOLOGY_4 = Ontology.builder() + public final Ontology ONTOLOGY_4 = Ontology.builder() .id(ONTOLOGY_4_ID) .prefix(ONTOLOGY_4_PREFIX) .uri(ONTOLOGY_4_URI) .sparqlEndpoint(ONTOLOGY_4_SPARQL_ENDPOINT) .build(); - public static final OntologyCreateDto ONTOLOGY_4_CREATE_DTO = OntologyCreateDto.builder() + public final OntologyCreateDto ONTOLOGY_4_CREATE_DTO = OntologyCreateDto.builder() .prefix(ONTOLOGY_4_PREFIX) .uri(ONTOLOGY_4_URI) .sparqlEndpoint(ONTOLOGY_4_SPARQL_ENDPOINT) .build(); - public static final UUID ONTOLOGY_5_ID = UUID.fromString("f95d1330-762e-4f5a-875a-3c64da5808a1"); - public static final String ONTOLOGY_5_PREFIX = "db"; - public static final String ONTOLOGY_5_URI = "http://dbpedia.org"; - public static final String ONTOLOGY_5_SPARQL_ENDPOINT = "http://dbpedia.org/sparql"; - public static final UUID ONTOLOGY_5_CREATED_BY = USER_1_ID; + public final static UUID ONTOLOGY_5_ID = UUID.fromString("f95d1330-762e-4f5a-875a-3c64da5808a1"); + public final static String ONTOLOGY_5_PREFIX = "db"; + public final static String ONTOLOGY_5_URI = "http://dbpedia.org"; + public final static String ONTOLOGY_5_SPARQL_ENDPOINT = "http://dbpedia.org/sparql"; - public static final Ontology ONTOLOGY_5 = Ontology.builder() + public final Ontology ONTOLOGY_5 = Ontology.builder() .id(ONTOLOGY_5_ID) .prefix(ONTOLOGY_5_PREFIX) .uri(ONTOLOGY_5_URI) .sparqlEndpoint(ONTOLOGY_5_SPARQL_ENDPOINT) .build(); - public static final OntologyCreateDto ONTOLOGY_5_CREATE_DTO = OntologyCreateDto.builder() + public final OntologyCreateDto ONTOLOGY_5_CREATE_DTO = OntologyCreateDto.builder() .prefix(ONTOLOGY_5_PREFIX) .uri(ONTOLOGY_5_URI) .sparqlEndpoint(ONTOLOGY_5_SPARQL_ENDPOINT) .build(); - public static final UUID COLUMN_8_1_ID = UUID.fromString("af362ac6-5dbb-4ede-83ea-5d94b39641c8"); - public static final Integer COLUMN_8_1_ORDINALPOS = 0; - public static final String COLUMN_8_1_NAME = "ID"; - public static final String COLUMN_8_1_INTERNAL_NAME = "id"; - public static final TableColumnType COLUMN_8_1_TYPE = TableColumnType.BIGINT; - public static final ColumnTypeDto COLUMN_8_1_TYPE_DTO = ColumnTypeDto.BIGINT; - public static final Boolean COLUMN_8_1_NULL = false; - public static final Boolean COLUMN_8_1_AUTO_GENERATED = true; - - public static final UUID COLUMN_8_2_ID = UUID.fromString("7ada597b-0766-4612-9ace-67eeee94e2da"); - public static final Integer COLUMN_8_2_ORDINALPOS = 1; - public static final String COLUMN_8_2_NAME = "Value"; - public static final String COLUMN_8_2_INTERNAL_NAME = "value"; - public static final TableColumnType COLUMN_8_2_TYPE = TableColumnType.DECIMAL; - public static final ColumnTypeDto COLUMN_8_2_TYPE_DTO = ColumnTypeDto.DECIMAL; - public static final Long COLUMN_8_2_SIZE = 10L; - public static final Long COLUMN_8_2_D = 10L; - public static final Boolean COLUMN_8_2_NULL = false; - public static final Boolean COLUMN_8_2_AUTO_GENERATED = false; - - public static final UUID COLUMN_8_3_ID = UUID.fromString("8bcd9ef8-f7b8-4730-acc1-a3d43ba69a56"); - public static final Integer COLUMN_8_3_ORDINALPOS = 2; - public static final String COLUMN_8_3_NAME = "raw"; - public static final String COLUMN_8_3_INTERNAL_NAME = "raw"; - public static final TableColumnType COLUMN_8_3_TYPE = TableColumnType.LONGBLOB; - public static final ColumnTypeDto COLUMN_8_3_TYPE_DTO = ColumnTypeDto.LONGBLOB; - public static final Boolean COLUMN_8_3_NULL = true; - public static final Boolean COLUMN_8_3_AUTO_GENERATED = false; - - public static final ColumnBriefDto TABLE_8_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() + public final static UUID COLUMN_8_1_ID = UUID.fromString("af362ac6-5dbb-4ede-83ea-5d94b39641c8"); + public final static Integer COLUMN_8_1_ORDINALPOS = 0; + public final static String COLUMN_8_1_NAME = "ID"; + public final static String COLUMN_8_1_INTERNAL_NAME = "id"; + public final static TableColumnType COLUMN_8_1_TYPE = TableColumnType.BIGINT; + public final static ColumnTypeDto COLUMN_8_1_TYPE_DTO = ColumnTypeDto.BIGINT; + public final static Boolean COLUMN_8_1_NULL = false; + + public final static UUID COLUMN_8_2_ID = UUID.fromString("7ada597b-0766-4612-9ace-67eeee94e2da"); + public final static Integer COLUMN_8_2_ORDINALPOS = 1; + public final static String COLUMN_8_2_NAME = "Value"; + public final static String COLUMN_8_2_INTERNAL_NAME = "value"; + public final static TableColumnType COLUMN_8_2_TYPE = TableColumnType.DECIMAL; + public final static ColumnTypeDto COLUMN_8_2_TYPE_DTO = ColumnTypeDto.DECIMAL; + public final static Long COLUMN_8_2_SIZE = 10L; + public final static Long COLUMN_8_2_D = 10L; + public final static Boolean COLUMN_8_2_NULL = true; + + public final static UUID COLUMN_8_3_ID = UUID.fromString("8bcd9ef8-f7b8-4730-acc1-a3d43ba69a56"); + public final static Integer COLUMN_8_3_ORDINALPOS = 2; + public final static String COLUMN_8_3_NAME = "raw"; + public final static String COLUMN_8_3_INTERNAL_NAME = "raw"; + public final static TableColumnType COLUMN_8_3_TYPE = TableColumnType.LONGBLOB; + public final static ColumnTypeDto COLUMN_8_3_TYPE_DTO = ColumnTypeDto.LONGBLOB; + public final static Boolean COLUMN_8_3_NULL = true; + + public final ColumnBriefDto TABLE_8_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() .id(COLUMN_8_1_ID) .name(COLUMN_8_1_NAME) .internalName(COLUMN_8_1_INTERNAL_NAME) .columnType(ColumnTypeDto.BIGINT) .build(); - public static final List<TableColumn> TABLE_8_COLUMNS = List.of(TableColumn.builder() + public final List<TableColumn> TABLE_8_COLUMNS = List.of(TableColumn.builder() .id(COLUMN_8_1_ID) .ordinalPosition(COLUMN_8_1_ORDINALPOS) .table(TABLE_8) @@ -2688,7 +2814,7 @@ public abstract class BaseTest { .isNullAllowed(COLUMN_8_3_NULL) .build()); - public static final List<ColumnDto> TABLE_8_COLUMNS_DTO = List.of(ColumnDto.builder() + public final List<ColumnDto> TABLE_8_COLUMNS_DTO = List.of(ColumnDto.builder() .id(COLUMN_8_1_ID) .ordinalPosition(COLUMN_8_1_ORDINALPOS) .name(COLUMN_8_1_NAME) @@ -2713,9 +2839,9 @@ public abstract class BaseTest { .isNullAllowed(COLUMN_8_3_NULL) .build()); - public static final Long TABLE_8_DATA_COUNT = 6L; + public final static Long TABLE_8_DATA_COUNT = 6L; @SuppressWarnings("java:S3599") - public static final List<Map<String, Object>> TABLE_8_DATA_DTO = new LinkedList<>(List.of( + public final List<Map<String, Object>> TABLE_8_DATA_DTO = new LinkedList<>(List.of( new HashMap<>() {{ put(COLUMN_8_1_INTERNAL_NAME, BigInteger.valueOf(1L)); put(COLUMN_8_2_INTERNAL_NAME, 11.2); @@ -2749,30 +2875,29 @@ public abstract class BaseTest { )); @SuppressWarnings("java:S3599") - public static final TableStatisticDto TABLE_8_STATISTIC_DTO = TableStatisticDto.builder() - .columns(new HashMap<>() {{ - put(COLUMN_8_1_INTERNAL_NAME, ColumnStatisticDto.builder() - .min(BigDecimal.valueOf(11.2)) - .max(BigDecimal.valueOf(23.1)) - .mean(BigDecimal.valueOf(13.5333)) - .median(BigDecimal.valueOf(11.4)) - .stdDev(BigDecimal.valueOf(4.2952)) - .build()); - }}) - .build(); - - public static final UUID QUERY_1_ID = UUID.fromString("60494137-f000-459e-acd3-4fcadbdf14ca"); - public static final String QUERY_1_STATEMENT = "SELECT `id`, `date`, `location`, `mintemp`, `rainfall` FROM `weather_aus` ORDER BY id ASC"; - public static final String QUERY_1_DOI = null; - public static final Long QUERY_1_RESULT_NUMBER = 2L; - public static final String QUERY_1_QUERY_HASH = "a3b8ac39e38167d14cf3a9c20a69e4b6954d049525390b973a2c23064953a992"; - public static final String QUERY_1_RESULT_HASH = "8358c8ade4849d2094ab5bb29127afdae57e6bb5acb1db7af603813d406c467a"; - public static final Instant QUERY_1_CREATED = Instant.ofEpochSecond(1677648377L); - public static final Instant QUERY_1_EXECUTION = Instant.now(); - public static final Boolean QUERY_1_PERSISTED = true; - - public static final SubsetDto QUERY_1_SUBSET_DTO = SubsetDto.builder() - .tableId(TABLE_1_ID) + public final TableStatisticDto TABLE_8_STATISTIC_DTO = TableStatisticDto.builder() + .columns(new LinkedList<>(List.of(ColumnStatisticDto.builder() + .name(COLUMN_8_1_INTERNAL_NAME) + .min(BigDecimal.valueOf(11.2)) + .max(BigDecimal.valueOf(23.1)) + .mean(BigDecimal.valueOf(13.5333)) + .median(BigDecimal.valueOf(11.4)) + .stdDev(BigDecimal.valueOf(4.2952)) + .build()))) + .build(); + + public final static UUID QUERY_1_ID = UUID.fromString("60494137-f000-459e-acd3-4fcadbdf14ca"); + public final static String QUERY_1_STATEMENT = "SELECT `id`, `date`, `location`, `mintemp`, `rainfall` FROM `weather_aus` ORDER BY id ASC"; + public final static Long QUERY_1_RESULT_NUMBER = 2L; + public final static String QUERY_1_QUERY_HASH = "a3b8ac39e38167d14cf3a9c20a69e4b6954d049525390b973a2c23064953a992"; + public final static String QUERY_1_RESULT_HASH = "8358c8ade4849d2094ab5bb29127afdae57e6bb5acb1db7af603813d406c467a"; + public final static Instant QUERY_1_CREATED = Instant.ofEpochSecond(1677648377L); + public final static Instant QUERY_1_EXECUTION = Instant.now(); + public final static Boolean QUERY_1_PERSISTED = true; + + public final SubsetDto QUERY_1_SUBSET_DTO = SubsetDto.builder() + .datasourceId(TABLE_1_ID) + .datasourceType(DatasourceType.TABLE) .columns(new LinkedList<UUID>(List.of(COLUMN_1_1_ID, COLUMN_1_2_ID, COLUMN_1_3_ID, COLUMN_1_4_ID, COLUMN_1_5_ID))) .order(new LinkedList<OrderDto>(List.of(OrderDto.builder() .columnId(COLUMN_1_1_ID) @@ -2780,7 +2905,7 @@ public abstract class BaseTest { .build()))) .build(); - public static final ViewDto QUERY_1_VIEW_DTO = ViewDto.builder() + public final ViewDto QUERY_1_VIEW_DTO = ViewDto.builder() .query(QUERY_1_STATEMENT) .queryHash(QUERY_1_QUERY_HASH) .owner(USER_1_BRIEF_DTO) @@ -2806,7 +2931,7 @@ public abstract class BaseTest { .build()))) .build(); - public static final QueryBriefDto QUERY_1_BRIEF_DTO = QueryBriefDto.builder() + public final QueryBriefDto QUERY_1_BRIEF_DTO = QueryBriefDto.builder() .id(QUERY_1_ID) .databaseId(DATABASE_1_ID) .query(QUERY_1_STATEMENT) @@ -2818,49 +2943,32 @@ public abstract class BaseTest { .resultNumber(3L) .build(); - public static final UUID QUERY_2_ID = UUID.fromString("4e0ac92a-7cb3-4222-9b85-0498c73e0afd"); - public static final String QUERY_2_STATEMENT = "SELECT `location` FROM `weather_aus`"; - public static final String QUERY_2_QUERY_HASH = "a2d2dd94ebc7653bb5a3b55dd8ed5e91d3d13c225c6855a1eb4eb7ca14c36ced"; - public static final Long QUERY_2_RESULT_NUMBER = 2L; - public static final String QUERY_2_RESULT_HASH = "ff3f7cbe1b96d296957f6e39e55b8b1b577fa3d205d4795af99594cfd20cb80d"; - public static final Instant QUERY_2_CREATED = Instant.now().minus(2, MINUTES); - public static final Instant QUERY_2_EXECUTION = Instant.now().minus(1, MINUTES); - public static final Instant QUERY_2_LAST_MODIFIED = Instant.ofEpochSecond(1541588352L); - public static final Boolean QUERY_2_PERSISTED = false; - - public static final UUID QUERY_3_ID = UUID.fromString("a9849020-45a7-40a8-9a19-d4ae2b28dd46"); - public static final String QUERY_3_STATEMENT = "SELECT `location`, `mintemp` FROM `weather_aus` WHERE `mintemp` > 10"; - public static final String QUERY_3_QUERY_HASH = "a3d3dd94ebc7653bb5a3b55dd8ed5e91d3d13c335c6855a1eb4eb7ca14c36ced"; - public static final String QUERY_3_RESULT_HASH = "ff3f7cbe1b96d396957f6e39e55b8b1b577fa3d305d4795af99594cfd30cb80d"; - public static final Instant QUERY_3_CREATED = Instant.now().minus(3, MINUTES); - public static final Instant QUERY_3_EXECUTION = Instant.now().minus(1, MINUTES); - public static final Instant QUERY_3_LAST_MODIFIED = Instant.ofEpochSecond(1541588353L); - public static final Long QUERY_3_RESULT_NUMBER = 2L; - public static final Boolean QUERY_3_PERSISTED = true; - - public static final UUID QUERY_7_ID = UUID.fromString("fe73a325-30a0-444c-b74f-23ce1533e55f"); - public static final 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 static final String QUERY_7_QUERY_HASH = "df7da3801dfb5c191ff6711d79ce6455f3c09ec8323ce1ff7208ab85387263f5"; - public static final String QUERY_7_RESULT_HASH = "ff4f7cbe1b96d496957f6e49e55b8b1b577fa4d405d4795af99594cfd40cb80d"; - public static final Instant QUERY_7_CREATED = Instant.now().minus(4, MINUTES); - public static final Instant QUERY_7_EXECUTION = Instant.now().minus(1, MINUTES); - public static final Instant QUERY_7_LAST_MODIFIED = Instant.ofEpochSecond(1541588454L); - public static final Long QUERY_7_RESULT_NUMBER = 6L; - public static final Long QUERY_7_RESULT_ID = 4L; - public static final Boolean QUERY_7_PERSISTED = false; - - public static final UUID QUERY_4_ID = UUID.fromString("18a98197-51ff-4011-9f40-914a11675a6d"); - public static final String QUERY_4_STATEMENT = "SELECT `id`, `value` FROM `mfcc`"; - public static final String QUERY_4_QUERY_HASH = "df7da3801dfb5c191ff6711d79ce6455f3c09ec8323ce1ff7208ab85387263f5"; - public static final String QUERY_4_RESULT_HASH = "ff4f7cbe1b96d496957f6e49e55b8b1b577fa4d405d4795af99594cfd40cb80d"; - public static final Instant QUERY_4_CREATED = Instant.now().minus(4, MINUTES); - public static final Instant QUERY_4_EXECUTION = Instant.now().minus(1, MINUTES); - public static final Instant QUERY_4_LAST_MODIFIED = Instant.ofEpochSecond(1541588454L); - public static final Long QUERY_4_RESULT_NUMBER = 6L; - public static final Long QUERY_4_RESULT_ID = 4L; - public static final Boolean QUERY_4_PERSISTED = false; - - public static final List<Map<String, Object>> QUERY_4_RESULT_DTO = new LinkedList<>(List.of( + public final static UUID QUERY_2_ID = UUID.fromString("4e0ac92a-7cb3-4222-9b85-0498c73e0afd"); + public final static String QUERY_2_STATEMENT = "SELECT `location` FROM `weather_aus`"; + public final static String QUERY_2_QUERY_HASH = "a2d2dd94ebc7653bb5a3b55dd8ed5e91d3d13c225c6855a1eb4eb7ca14c36ced"; + public final static Long QUERY_2_RESULT_NUMBER = 2L; + public final static String QUERY_2_RESULT_HASH = "ff3f7cbe1b96d296957f6e39e55b8b1b577fa3d205d4795af99594cfd20cb80d"; + public final static Instant QUERY_2_EXECUTION = Instant.now().minus(1, MINUTES); + public final static Boolean QUERY_2_PERSISTED = false; + + public final static UUID QUERY_3_ID = UUID.fromString("a9849020-45a7-40a8-9a19-d4ae2b28dd46"); + public final static String QUERY_3_STATEMENT = "SELECT `location`, `mintemp` FROM `weather_aus` WHERE `mintemp` > 10"; + public final static String QUERY_3_QUERY_HASH = "a3d3dd94ebc7653bb5a3b55dd8ed5e91d3d13c335c6855a1eb4eb7ca14c36ced"; + public final static String QUERY_3_RESULT_HASH = "ff3f7cbe1b96d396957f6e39e55b8b1b577fa3d305d4795af99594cfd30cb80d"; + public final static Instant QUERY_3_EXECUTION = Instant.now().minus(1, MINUTES); + public final static Long QUERY_3_RESULT_NUMBER = 2L; + public final static Boolean QUERY_3_PERSISTED = true; + + public final static UUID QUERY_4_ID = UUID.fromString("18a98197-51ff-4011-9f40-914a11675a6d"); + public final static String QUERY_4_STATEMENT = "SELECT `id`, `value` FROM `mfcc`"; + public final static String QUERY_4_QUERY_HASH = "df7da3801dfb5c191ff6711d79ce6455f3c09ec8323ce1ff7208ab85387263f5"; + public final static String QUERY_4_RESULT_HASH = "ff4f7cbe1b96d496957f6e49e55b8b1b577fa4d405d4795af99594cfd40cb80d"; + public final static Instant QUERY_4_EXECUTION = Instant.now().minus(1, MINUTES); + public final static Long QUERY_4_RESULT_NUMBER = 6L; + public final static Long QUERY_4_RESULT_ID = 4L; + public final static Boolean QUERY_4_PERSISTED = false; + + public final List<Map<String, Object>> QUERY_4_RESULT_DTO = new LinkedList<>(List.of( new HashMap<>() {{ put("id", BigInteger.valueOf(1L)); put("value", 11.2); @@ -2881,7 +2989,7 @@ public abstract class BaseTest { put("value", 23.1); }})); - public static final QueryDto QUERY_4_DTO = QueryDto.builder() + public final QueryDto QUERY_4_DTO = QueryDto.builder() .id(QUERY_4_ID) .databaseId(DATABASE_3_ID) .query(QUERY_4_STATEMENT) @@ -2894,17 +3002,15 @@ public abstract class BaseTest { .owner(USER_1_BRIEF_DTO) .build(); - public static final UUID QUERY_5_ID = UUID.fromString("1a39f775-e3d5-4865-b4f5-dbbb5693b637"); - public static final String QUERY_5_STATEMENT = "SELECT `id`, `value` FROM `mfcc` WHERE `value` > 0"; - public static final String QUERY_5_QUERY_HASH = "6d6dc48b12cdfd959d39a62887334a6bbd529b93eed4f211f3f671bd9e7d6225"; - public static final String QUERY_5_RESULT_HASH = "ff5f7cbe1b96d596957f6e59e55b8b1b577fa5d505d5795af99595cfd50cb80d"; - public static final Instant QUERY_5_CREATED = Instant.now().minus(5, MINUTES); - public static final Instant QUERY_5_EXECUTION = Instant.now().minus(1, MINUTES); - public static final Instant QUERY_5_LAST_MODIFIED = Instant.ofEpochSecond(1551588555L); - public static final Long QUERY_5_RESULT_NUMBER = 6L; - public static final Boolean QUERY_5_PERSISTED = true; + public final static UUID QUERY_5_ID = UUID.fromString("1a39f775-e3d5-4865-b4f5-dbbb5693b637"); + public final static String QUERY_5_STATEMENT = "SELECT `id`, `value` FROM `mfcc` WHERE `value` > 0"; + public final static String QUERY_5_QUERY_HASH = "6d6dc48b12cdfd959d39a62887334a6bbd529b93eed4f211f3f671bd9e7d6225"; + public final static String QUERY_5_RESULT_HASH = "ff5f7cbe1b96d596957f6e59e55b8b1b577fa5d505d5795af99595cfd50cb80d"; + public final static Instant QUERY_5_EXECUTION = Instant.now().minus(1, MINUTES); + public final static Long QUERY_5_RESULT_NUMBER = 6L; + public final static Boolean QUERY_5_PERSISTED = true; - public static final QueryDto QUERY_5_DTO = QueryDto.builder() + public final QueryDto QUERY_5_DTO = QueryDto.builder() .id(QUERY_5_ID) .databaseId(DATABASE_3_ID) .query(QUERY_5_STATEMENT) @@ -2917,8 +3023,9 @@ public abstract class BaseTest { .owner(USER_1_BRIEF_DTO) .build(); - public static final SubsetDto QUERY_5_SUBSET_DTO = SubsetDto.builder() - .tableId(TABLE_8_ID) + public final SubsetDto QUERY_5_SUBSET_DTO = SubsetDto.builder() + .datasourceId(TABLE_8_ID) + .datasourceType(DatasourceType.TABLE) .columns(new LinkedList<>(List.of(COLUMN_8_1_ID, COLUMN_8_2_ID))) .filter(new LinkedList<>(List.of(FilterDto.builder() .columnId(COLUMN_8_2_ID) @@ -2928,7 +3035,7 @@ public abstract class BaseTest { .build()))) .build(); - public static final ViewDto QUERY_5_VIEW_DTO = ViewDto.builder() + public final ViewDto QUERY_5_VIEW_DTO = ViewDto.builder() .query(QUERY_5_STATEMENT) .queryHash(QUERY_5_QUERY_HASH) .owner(USER_1_BRIEF_DTO) @@ -2942,7 +3049,7 @@ public abstract class BaseTest { .build()))) .build(); - public static final List<Map<String, Object>> QUERY_5_RESULT_DTO = new LinkedList<>(List.of( + public final 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), Map.of("id", BigInteger.valueOf(3L), "value", 11.4), @@ -2951,17 +3058,15 @@ public abstract class BaseTest { Map.of("id", BigInteger.valueOf(6L), "value", 23.1) )); - public static final UUID QUERY_6_ID = UUID.fromString("7463412a-20c4-4fc1-8a33-948aea026f49"); - public static final String QUERY_6_STATEMENT = "SELECT `location` FROM `weather_aus` WHERE `id` = 1"; - public static final String QUERY_6_QUERY_HASH = "6d6dc48b12cdfd959d39a62887334a6bbd529b93eed4f211f3f671bd9e7d6225"; - public static final String QUERY_6_RESULT_HASH = "ff5f7cbe1b96d596957f6e59e55b8b1b577fa5d505d5795af99595cfd50cb80d"; - public static final Instant QUERY_6_CREATED = Instant.now().minus(5, MINUTES); - public static final Instant QUERY_6_EXECUTION = Instant.now().minus(1, MINUTES); - public static final Instant QUERY_6_LAST_MODIFIED = Instant.ofEpochSecond(1551588555L); - public static final Long QUERY_6_RESULT_NUMBER = 1L; - public static final Boolean QUERY_6_PERSISTED = true; - - public static final List<TableColumn> TABLE_1_COLUMNS = List.of(TableColumn.builder() + public final static UUID QUERY_6_ID = UUID.fromString("7463412a-20c4-4fc1-8a33-948aea026f49"); + public final static String QUERY_6_STATEMENT = "SELECT `location` FROM `weather_aus` WHERE `id` = 1"; + public final static String QUERY_6_QUERY_HASH = "6d6dc48b12cdfd959d39a62887334a6bbd529b93eed4f211f3f671bd9e7d6225"; + public final static String QUERY_6_RESULT_HASH = "ff5f7cbe1b96d596957f6e59e55b8b1b577fa5d505d5795af99595cfd50cb80d"; + public final static Instant QUERY_6_EXECUTION = Instant.now().minus(1, MINUTES); + public final static Long QUERY_6_RESULT_NUMBER = 1L; + public final static Boolean QUERY_6_PERSISTED = true; + + public final List<TableColumn> TABLE_1_COLUMNS = List.of(TableColumn.builder() .id(COLUMN_1_1_ID) .ordinalPosition(0) .table(TABLE_1) @@ -3014,14 +3119,16 @@ public abstract class BaseTest { .isNullAllowed(true) .build()); - public static final ColumnBriefDto TABLE_1_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() - .id(COLUMN_1_1_ID) - .name("id") - .internalName("id") - .columnType(ColumnTypeDto.BIGINT) - .build(); + public final static UUID QUERY_7_ID = UUID.fromString("fe73a325-30a0-444c-b74f-23ce1533e55f"); + 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"; + public final static String QUERY_7_RESULT_HASH = "ff4f7cbe1b96d496957f6e49e55b8b1b577fa4d405d4795af99594cfd40cb80d"; + public final static Instant QUERY_7_EXECUTION = Instant.now().minus(1, MINUTES); + public final static Long QUERY_7_RESULT_NUMBER = 6L; + public final static Long QUERY_7_RESULT_ID = 4L; + public final static Boolean QUERY_7_PERSISTED = false; - public static final List<CreateTableColumnDto> TABLE_1_COLUMNS_CREATE_DTO = List.of(CreateTableColumnDto.builder() + public final List<CreateTableColumnDto> TABLE_1_COLUMNS_CREATE_DTO = List.of(CreateTableColumnDto.builder() .name("id") .type(ColumnTypeDto.BIGINT) .nullAllowed(false) @@ -3056,48 +3163,37 @@ public abstract class BaseTest { .unitUri(UNIT_1_URI) .build()); - public static final 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 static final CreateTableConstraintsDto TABLE_1_CONSTRAINTS_CREATE_INVALID_DTO = CreateTableConstraintsDto.builder() + public final 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 static final CreateTableDto TABLE_1_CREATE_DTO = CreateTableDto.builder() - .name(TABLE_1_NAME) - .description(TABLE_1_DESCRIPTION) - .columns(TABLE_1_COLUMNS_CREATE_DTO) - .constraints(TABLE_1_CONSTRAINTS_CREATE_DTO) - .build(); - - public static final at.tuwien.api.database.table.internal.TableCreateDto TABLE_1_CREATE_INTERNAL_DTO = at.tuwien.api.database.table.internal.TableCreateDto.builder() - .name(TABLE_1_NAME) - .description(TABLE_1_DESCRIPTION) - .columns(TABLE_1_COLUMNS_CREATE_DTO) - .constraints(TABLE_1_CONSTRAINTS_CREATE_DTO) - .build(); - - public static final at.tuwien.api.database.table.internal.TableCreateDto TABLE_1_CREATE_INTERNAL_INVALID_DTO = at.tuwien.api.database.table.internal.TableCreateDto.builder() + public final CreateTableDto TABLE_1_CREATE_DTO = CreateTableDto.builder() .name(TABLE_1_NAME) .description(TABLE_1_DESCRIPTION) .columns(TABLE_1_COLUMNS_CREATE_DTO) - .constraints(TABLE_1_CONSTRAINTS_CREATE_INVALID_DTO) - .build(); - - public static final UUID COLUMN_2_1_ID = UUID.fromString("795faa78-7ebb-4dd5-9eb1-e54a9192d0b5"); - - public static final UUID COLUMN_2_2_ID = UUID.fromString("f316ced5-7774-4656-aa7f-a874622d99b3"); - - public static final UUID COLUMN_2_3_ID = UUID.fromString("11cb1aa2-8582-45ef-a3bb-7056aa94cdf1"); - - public static final List<TableColumn> TABLE_2_COLUMNS = List.of(TableColumn.builder() + .constraints(TABLE_1_CREATE_CONSTRAINTS_DTO) + .build(); + + public final at.ac.tuwien.ifs.dbrepo.core.api.database.table.internal.TableCreateDto TABLE_1_CREATE_INTERNAL_DTO = + at.ac.tuwien.ifs.dbrepo.core.api.database.table.internal.TableCreateDto.builder() + .name(TABLE_1_NAME) + .description(TABLE_1_DESCRIPTION) + .columns(TABLE_1_COLUMNS_CREATE_DTO) + .constraints(TABLE_1_CREATE_CONSTRAINTS_DTO) + .build(); + + public final at.ac.tuwien.ifs.dbrepo.core.api.database.table.internal.TableCreateDto TABLE_1_CREATE_INTERNAL_INVALID_DTO = + at.ac.tuwien.ifs.dbrepo.core.api.database.table.internal.TableCreateDto.builder() + .name(TABLE_1_NAME) + .description(TABLE_1_DESCRIPTION) + .columns(TABLE_1_COLUMNS_CREATE_DTO) + .constraints(TABLE_1_CONSTRAINTS_CREATE_INVALID_DTO) + .build(); + + public final List<TableColumn> TABLE_2_COLUMNS = List.of(TableColumn.builder() .id(COLUMN_2_1_ID) .ordinalPosition(0) .table(TABLE_2) @@ -3136,163 +3232,50 @@ public abstract class BaseTest { .sets(null) .build()); - public static final ColumnBriefDto TABLE_2_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() - .id(COLUMN_2_1_ID) - .name("location") - .internalName("location") - .columnType(ColumnTypeDto.VARCHAR) - .build(); - - public static final ColumnBriefDto TABLE_2_COLUMNS_BRIEF_2_DTO = ColumnBriefDto.builder() - .id(COLUMN_2_3_ID) - .name("lng") - .internalName("lng") - .columnType(ColumnTypeDto.DECIMAL) - .build(); - - public static final List<ColumnDto> TABLE_2_COLUMNS_DTO = List.of(ColumnDto.builder() - .id(COLUMN_2_1_ID) - .tableId(TABLE_2_ID) - .databaseId(DATABASE_1_ID) - .ordinalPosition(0) - .name("location") - .internalName("location") - .columnType(ColumnTypeDto.VARCHAR) - .size(255L) - .isNullAllowed(false) - .enums(null) - .sets(null) - .build(), - ColumnDto.builder() - .id(COLUMN_2_2_ID) - .tableId(TABLE_2_ID) - .databaseId(DATABASE_1_ID) - .ordinalPosition(1) - .name("lat") - .internalName("lat") - .columnType(ColumnTypeDto.DOUBLE) - .size(22L) - .isNullAllowed(true) - .enums(null) - .sets(null) - .build(), - ColumnDto.builder() - .id(COLUMN_2_3_ID) - .tableId(TABLE_2_ID) - .databaseId(DATABASE_1_ID) - .ordinalPosition(2) - .name("lng") - .internalName("lng") - .columnType(ColumnTypeDto.DOUBLE) - .size(22L) - .isNullAllowed(true) - .enums(null) - .sets(null) - .build()); - - public static final 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 static final UUID COLUMN_3_1_ID = UUID.fromString("49cc2735-ba75-4e12-8ac7-8aec87ed7724"); - - public static final UUID COLUMN_3_2_ID = UUID.fromString("2c240d64-3052-4a74-b696-e7490fdff3ea"); - - public static final UUID COLUMN_3_3_ID = UUID.fromString("6fbb0a56-f23a-4aa4-b158-c614a0a30f86"); - - public static final UUID COLUMN_3_4_ID = UUID.fromString("9b01f925-93ee-4f28-bf31-9902900a7099"); - - public static final UUID COLUMN_3_5_ID = UUID.fromString("9bbd66f1-0d94-401c-b7f7-6e329bb9ee21"); - - public static final UUID COLUMN_3_6_ID = UUID.fromString("19ad93d7-b298-495b-9678-9aac80678ff9"); - - public static final UUID COLUMN_3_7_ID = UUID.fromString("4d27d9f4-645f-4222-b5a8-4a91fa6e4275"); - - public static final UUID COLUMN_3_8_ID = UUID.fromString("b4f8fcf8-5824-45ec-8c58-43f20e6dffc5"); - - public static final UUID COLUMN_3_9_ID = UUID.fromString("87247218-369e-484a-9a8f-d758478d8dfc"); - - public static final UUID COLUMN_3_10_ID = UUID.fromString("6e191b97-189a-4d88-901e-888ca889e280"); - - public static final UUID COLUMN_3_11_ID = UUID.fromString("6ac356ff-9be5-4259-9b62-83b6707be7fe"); - - public static final UUID COLUMN_3_12_ID = UUID.fromString("0665b384-c824-4358-b6c5-f17706d46ea4"); - - public static final UUID COLUMN_3_13_ID = UUID.fromString("22d3676e-d28e-4075-b223-91a7ac767bcf"); - - public static final UUID COLUMN_3_14_ID = UUID.fromString("673326e3-ee2b-4c2f-902f-982e2abce1c2"); - - public static final UUID COLUMN_3_15_ID = UUID.fromString("8dcacf4a-736b-4e67-9618-74998cba8940"); - - public static final UUID COLUMN_3_16_ID = UUID.fromString("2b2f5359-76d3-4763-a53f-d18ca6b793fb"); - - public static final UUID COLUMN_3_17_ID = UUID.fromString("674b6120-06cf-4624-b006-1ed48898bd69"); - - public static final UUID COLUMN_3_18_ID = UUID.fromString("13edd7c9-6c88-44d7-b206-34774e49c5af"); - - public static final UUID COLUMN_3_19_ID = UUID.fromString("6977bb3f-4ae2-43ea-bb82-c7f68454c538"); - - public static final UUID COLUMN_3_20_ID = UUID.fromString("c03d2429-53e1-42eb-a1f5-ce342fa23336"); - - public static final UUID COLUMN_3_21_ID = UUID.fromString("06edd332-750e-4aa1-b61b-e757fb2312c3"); - - public static final UUID COLUMN_3_22_ID = UUID.fromString("b6b8631d-f283-49da-8d5e-4bb24def2a40"); - - public static final UUID COLUMN_3_23_ID = UUID.fromString("0393ee00-31ba-44ab-9e82-1f5034a9f57b"); - - public static final UUID COLUMN_3_24_ID = UUID.fromString("a63784ea-f70d-4bda-ace6-1c6a88edf831"); - - public static final UUID COLUMN_3_25_ID = UUID.fromString("720fe829-802c-420b-8e41-bdbb636db43c"); - - public static final UUID COLUMN_3_26_ID = UUID.fromString("5bce38ef-7d49-43b5-9054-068750684b5f"); - - public static final UUID COLUMN_3_27_ID = UUID.fromString("92097c02-3dd3-40ea-bd03-a9135f45a557"); - - public static final UUID COLUMN_3_28_ID = UUID.fromString("7361a38a-828b-495e-8a57-b36cca17d7db"); - - public static final UUID COLUMN_3_29_ID = UUID.fromString("a06812db-03b7-484c-92a6-45d94eef3bb9"); - - public static final UUID COLUMN_3_30_ID = UUID.fromString("05614d89-9216-47ea-96f0-acffc4674acf"); - - public static final UUID COLUMN_3_31_ID = UUID.fromString("05ada13d-361a-48e7-9a0f-1191499509f1"); - - public static final UUID COLUMN_3_32_ID = UUID.fromString("b3f259f6-700a-4b60-8eac-dceaa0dcda9d"); - - public static final UUID COLUMN_3_33_ID = UUID.fromString("9160af06-e168-4b10-a7f9-520f41ae7955"); - - public static final UUID COLUMN_3_34_ID = UUID.fromString("fde20c99-ed9c-4a60-8c18-f46e8603ebb5"); - - public static final UUID COLUMN_3_35_ID = UUID.fromString("071c7f27-1cdd-4af9-b4d6-f932c27c7287"); - - public static final ColumnBriefDto TABLE_3_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() + public final static UUID COLUMN_3_1_ID = UUID.fromString("49cc2735-ba75-4e12-8ac7-8aec87ed7724"); + public final static UUID COLUMN_3_2_ID = UUID.fromString("2c240d64-3052-4a74-b696-e7490fdff3ea"); + public final static UUID COLUMN_3_3_ID = UUID.fromString("6fbb0a56-f23a-4aa4-b158-c614a0a30f86"); + public final static UUID COLUMN_3_4_ID = UUID.fromString("9b01f925-93ee-4f28-bf31-9902900a7099"); + public final static UUID COLUMN_3_5_ID = UUID.fromString("9bbd66f1-0d94-401c-b7f7-6e329bb9ee21"); + public final static UUID COLUMN_3_6_ID = UUID.fromString("19ad93d7-b298-495b-9678-9aac80678ff9"); + public final static UUID COLUMN_3_7_ID = UUID.fromString("4d27d9f4-645f-4222-b5a8-4a91fa6e4275"); + public final static UUID COLUMN_3_8_ID = UUID.fromString("b4f8fcf8-5824-45ec-8c58-43f20e6dffc5"); + public final static UUID COLUMN_3_9_ID = UUID.fromString("87247218-369e-484a-9a8f-d758478d8dfc"); + public final static UUID COLUMN_3_10_ID = UUID.fromString("6e191b97-189a-4d88-901e-888ca889e280"); + public final static UUID COLUMN_3_11_ID = UUID.fromString("6ac356ff-9be5-4259-9b62-83b6707be7fe"); + public final static UUID COLUMN_3_12_ID = UUID.fromString("0665b384-c824-4358-b6c5-f17706d46ea4"); + public final static UUID COLUMN_3_13_ID = UUID.fromString("22d3676e-d28e-4075-b223-91a7ac767bcf"); + public final static UUID COLUMN_3_14_ID = UUID.fromString("673326e3-ee2b-4c2f-902f-982e2abce1c2"); + public final static UUID COLUMN_3_15_ID = UUID.fromString("8dcacf4a-736b-4e67-9618-74998cba8940"); + public final static UUID COLUMN_3_16_ID = UUID.fromString("2b2f5359-76d3-4763-a53f-d18ca6b793fb"); + public final static UUID COLUMN_3_17_ID = UUID.fromString("674b6120-06cf-4624-b006-1ed48898bd69"); + public final static UUID COLUMN_3_18_ID = UUID.fromString("13edd7c9-6c88-44d7-b206-34774e49c5af"); + public final static UUID COLUMN_3_19_ID = UUID.fromString("6977bb3f-4ae2-43ea-bb82-c7f68454c538"); + public final static UUID COLUMN_3_20_ID = UUID.fromString("c03d2429-53e1-42eb-a1f5-ce342fa23336"); + public final static UUID COLUMN_3_21_ID = UUID.fromString("06edd332-750e-4aa1-b61b-e757fb2312c3"); + public final static UUID COLUMN_3_22_ID = UUID.fromString("b6b8631d-f283-49da-8d5e-4bb24def2a40"); + public final static UUID COLUMN_3_23_ID = UUID.fromString("0393ee00-31ba-44ab-9e82-1f5034a9f57b"); + public final static UUID COLUMN_3_24_ID = UUID.fromString("a63784ea-f70d-4bda-ace6-1c6a88edf831"); + public final static UUID COLUMN_3_25_ID = UUID.fromString("720fe829-802c-420b-8e41-bdbb636db43c"); + public final static UUID COLUMN_3_26_ID = UUID.fromString("5bce38ef-7d49-43b5-9054-068750684b5f"); + public final static UUID COLUMN_3_27_ID = UUID.fromString("92097c02-3dd3-40ea-bd03-a9135f45a557"); + public final static UUID COLUMN_3_28_ID = UUID.fromString("7361a38a-828b-495e-8a57-b36cca17d7db"); + public final static UUID COLUMN_3_29_ID = UUID.fromString("a06812db-03b7-484c-92a6-45d94eef3bb9"); + public final static UUID COLUMN_3_30_ID = UUID.fromString("05614d89-9216-47ea-96f0-acffc4674acf"); + public final static UUID COLUMN_3_31_ID = UUID.fromString("05ada13d-361a-48e7-9a0f-1191499509f1"); + public final static UUID COLUMN_3_32_ID = UUID.fromString("b3f259f6-700a-4b60-8eac-dceaa0dcda9d"); + public final static UUID COLUMN_3_33_ID = UUID.fromString("9160af06-e168-4b10-a7f9-520f41ae7955"); + public final static UUID COLUMN_3_34_ID = UUID.fromString("fde20c99-ed9c-4a60-8c18-f46e8603ebb5"); + public final static UUID COLUMN_3_35_ID = UUID.fromString("071c7f27-1cdd-4af9-b4d6-f932c27c7287"); + + public final ColumnBriefDto TABLE_3_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() .id(COLUMN_3_1_ID) .columnType(ColumnTypeDto.BIGINT) .name("id") .internalName("id") .build(); - public static final List<TableColumn> TABLE_3_COLUMNS = List.of(TableColumn.builder() + public final List<TableColumn> TABLE_3_COLUMNS = List.of(TableColumn.builder() .id(COLUMN_3_1_ID) .table(TABLE_3) .ordinalPosition(0) @@ -3678,7 +3661,7 @@ public abstract class BaseTest { .sets(new LinkedList<>()) .build()); - public static final List<ColumnDto> TABLE_3_COLUMNS_DTO = List.of(ColumnDto.builder() + public final List<ColumnDto> TABLE_3_COLUMNS_DTO = List.of(ColumnDto.builder() .id(COLUMN_3_1_ID) .tableId(TABLE_3_ID) .databaseId(DATABASE_1_ID) @@ -4064,56 +4047,36 @@ public abstract class BaseTest { .sets(new LinkedList<>()) .build()); - public static final UUID COLUMN_5_1_ID = UUID.fromString("4efd4cbb-ca2e-48e2-8f40-37514956aa67"); - - public static final UUID COLUMN_5_2_ID = UUID.fromString("53061685-c1db-4df6-ad4e-8f384a200104"); - - public static final UUID COLUMN_5_3_ID = UUID.fromString("643f9cda-8db1-47a4-bb08-c10e78e54c10"); - - public static final UUID COLUMN_5_4_ID = UUID.fromString("efeacc15-3b31-4a9f-9dba-f07d62dcddd6"); - - public static final UUID COLUMN_5_5_ID = UUID.fromString("0319db31-473a-47bc-bb9d-fa1edf82fcd5"); - - public static final UUID COLUMN_5_6_ID = UUID.fromString("9ba789ca-59cf-4480-b9f6-3b957b1d7f5c"); - - public static final UUID COLUMN_5_7_ID = UUID.fromString("81c42954-fd1a-4fef-adb1-bc4945469e26"); - - public static final UUID COLUMN_5_8_ID = UUID.fromString("49a38905-52a2-4a9b-b7b9-5e1dcf799b2a"); - - public static final UUID COLUMN_5_9_ID = UUID.fromString("1e1a9b6b-5aee-4773-b52d-ea56a5d1e2c8"); - - public static final UUID COLUMN_5_10_ID = UUID.fromString("42ede62a-ae98-4a14-ba54-76b8ba1c580f"); - - public static final UUID COLUMN_5_11_ID = UUID.fromString("0af0f84a-5a58-418a-8bbc-bde29ed0cda0"); - - public static final UUID COLUMN_5_12_ID = UUID.fromString("d9cb30a2-1566-4bd1-899d-060a8ba47722"); - - public static final UUID COLUMN_5_13_ID = UUID.fromString("e69f7f75-3731-4706-8193-0393aa0c08a7"); - - public static final UUID COLUMN_5_14_ID = UUID.fromString("4441630e-7dfa-4046-8bc2-929860f1c66e"); - - public static final UUID COLUMN_5_15_ID = UUID.fromString("f0a12be0-0b26-4686-bf7e-539cdc7e71b4"); - - public static final UUID COLUMN_5_16_ID = UUID.fromString("b60abdcc-5786-40f8-a309-e4467f7d963c"); - - public static final UUID COLUMN_5_17_ID = UUID.fromString("6d5877e2-daef-43d6-a1b6-1aff3ab1a9a2"); - - public static final UUID COLUMN_5_18_ID = UUID.fromString("bb45455f-d449-496e-94f8-eac4d46ba9c0"); - - public static final UUID COLUMN_5_19_ID = UUID.fromString("44c5484b-b57d-48a4-8f24-d2074de98e1a"); - - public static final UUID COLUMN_5_20_ID = UUID.fromString("6475b937-71fc-4331-bc85-8ee71fa68d99"); - - public static final UUID COLUMN_5_21_ID = UUID.fromString("92ff472f-e203-4c8e-b243-81640229ca19"); - - public static final ColumnBriefDto TABLE_5_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() + public final static UUID COLUMN_5_1_ID = UUID.fromString("4efd4cbb-ca2e-48e2-8f40-37514956aa67"); + public final static UUID COLUMN_5_2_ID = UUID.fromString("53061685-c1db-4df6-ad4e-8f384a200104"); + public final static UUID COLUMN_5_3_ID = UUID.fromString("643f9cda-8db1-47a4-bb08-c10e78e54c10"); + public final static UUID COLUMN_5_4_ID = UUID.fromString("efeacc15-3b31-4a9f-9dba-f07d62dcddd6"); + public final static UUID COLUMN_5_5_ID = UUID.fromString("0319db31-473a-47bc-bb9d-fa1edf82fcd5"); + public final static UUID COLUMN_5_6_ID = UUID.fromString("9ba789ca-59cf-4480-b9f6-3b957b1d7f5c"); + public final static UUID COLUMN_5_7_ID = UUID.fromString("81c42954-fd1a-4fef-adb1-bc4945469e26"); + public final static UUID COLUMN_5_8_ID = UUID.fromString("49a38905-52a2-4a9b-b7b9-5e1dcf799b2a"); + public final static UUID COLUMN_5_9_ID = UUID.fromString("1e1a9b6b-5aee-4773-b52d-ea56a5d1e2c8"); + public final static UUID COLUMN_5_10_ID = UUID.fromString("42ede62a-ae98-4a14-ba54-76b8ba1c580f"); + public final static UUID COLUMN_5_11_ID = UUID.fromString("0af0f84a-5a58-418a-8bbc-bde29ed0cda0"); + public final static UUID COLUMN_5_12_ID = UUID.fromString("d9cb30a2-1566-4bd1-899d-060a8ba47722"); + public final static UUID COLUMN_5_13_ID = UUID.fromString("e69f7f75-3731-4706-8193-0393aa0c08a7"); + public final static UUID COLUMN_5_14_ID = UUID.fromString("4441630e-7dfa-4046-8bc2-929860f1c66e"); + public final static UUID COLUMN_5_15_ID = UUID.fromString("f0a12be0-0b26-4686-bf7e-539cdc7e71b4"); + public final static UUID COLUMN_5_16_ID = UUID.fromString("b60abdcc-5786-40f8-a309-e4467f7d963c"); + public final static UUID COLUMN_5_17_ID = UUID.fromString("6d5877e2-daef-43d6-a1b6-1aff3ab1a9a2"); + public final static UUID COLUMN_5_18_ID = UUID.fromString("bb45455f-d449-496e-94f8-eac4d46ba9c0"); + public final static UUID COLUMN_5_19_ID = UUID.fromString("44c5484b-b57d-48a4-8f24-d2074de98e1a"); + public final static UUID COLUMN_5_20_ID = UUID.fromString("6475b937-71fc-4331-bc85-8ee71fa68d99"); + public final static UUID COLUMN_5_21_ID = UUID.fromString("92ff472f-e203-4c8e-b243-81640229ca19"); + + public final ColumnBriefDto TABLE_5_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() .id(COLUMN_5_1_ID) .name("id") .internalName("id") .columnType(ColumnTypeDto.BIGINT) .build(); - public static final List<TableColumn> TABLE_5_COLUMNS = List.of(TableColumn.builder() + public final List<TableColumn> TABLE_5_COLUMNS = List.of(TableColumn.builder() .id(COLUMN_5_1_ID) .ordinalPosition(0) .table(TABLE_5) @@ -4302,8 +4265,7 @@ public abstract class BaseTest { .columnType(TableColumnType.DECIMAL) .isNullAllowed(true) .build()); - - public static final List<ColumnDto> TABLE_5_COLUMNS_DTO = List.of(ColumnDto.builder() + public final List<ColumnDto> TABLE_5_COLUMNS_DTO = List.of(ColumnDto.builder() .id(COLUMN_5_1_ID) .ordinalPosition(0) .tableId(TABLE_5_ID) @@ -4493,17 +4455,17 @@ public abstract class BaseTest { .isNullAllowed(true) .build()); - public static final List<CreateForeignKeyDto> TABLE_5_FOREIGN_KEYS_INVALID_CREATE = List.of(CreateForeignKeyDto.builder() + public final 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 static final CreateTableConstraintsDto TABLE_5_CONSTRAINTS_INVALID_CREATE = CreateTableConstraintsDto.builder() + public final CreateTableConstraintsDto TABLE_5_CONSTRAINTS_INVALID_CREATE = CreateTableConstraintsDto.builder() .foreignKeys(TABLE_5_FOREIGN_KEYS_INVALID_CREATE) .build(); - public static final List<CreateTableColumnDto> TABLE_5_COLUMNS_CREATE = List.of(CreateTableColumnDto.builder() + public final List<CreateTableColumnDto> TABLE_5_COLUMNS_CREATE = List.of(CreateTableColumnDto.builder() .name("id") .type(ColumnTypeDto.BIGINT) .nullAllowed(false) @@ -4609,37 +4571,38 @@ public abstract class BaseTest { .nullAllowed(true) .build()); - public static final CreateTableConstraintsDto TABLE_5_CREATE_CONSTRAINTS_DTO = CreateTableConstraintsDto.builder() + public final 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 static final CreateTableDto TABLE_5_CREATE_DTO = CreateTableDto.builder() + public final 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 static final CreateTableDto TABLE_5_INVALID_CREATE_DTO = CreateTableDto.builder() + public final CreateTableDto TABLE_5_INVALID_CREATE_DTO = CreateTableDto.builder() .name(TABLE_5_NAME) .description(TABLE_5_DESCRIPTION) .columns(TABLE_5_COLUMNS_CREATE) .constraints(TABLE_5_CONSTRAINTS_INVALID_CREATE) .build(); - public static final UUID QUERY_8_ID = UUID.fromString("1c466eee-d551-4ef9-a7e0-b5a2d1b15473"); - public static final String QUERY_8_STATEMENT = "SELECT `id`, `animal_name` FROM `zoo` WHERE `hair` = TRUE AND `feathers` = FALSE;"; - public static final String QUERY_8_QUERY_HASH = "f0ee0d6dd45e092fca120c4f0eab089f91ed26ccf8dc34a03c6b9c6bb4141271"; - public static final Long QUERY_8_RESULT_NUMBER = 5L; - public static final String QUERY_8_RESULT_HASH = "b5f9cae916d32deff81c5f2e9f8ff43904034bc084b12320730953d120698bed"; - public static final Instant QUERY_8_EXECUTION = Instant.now().minus(1, MINUTES); - public static final Boolean QUERY_8_PERSISTED = true; + public final static UUID QUERY_8_ID = UUID.fromString("1c466eee-d551-4ef9-a7e0-b5a2d1b15473"); + public final static String QUERY_8_STATEMENT = "SELECT `id`, `animal_name` FROM `zoo` WHERE `hair` = TRUE AND `feathers` = false;"; + public final static String QUERY_8_QUERY_HASH = "f0ee0d6dd45e092fca120c4f0eab089f91ed26ccf8dc34a03c6b9c6bb4141271"; + public final static Long QUERY_8_RESULT_NUMBER = 5L; + public final static String QUERY_8_RESULT_HASH = "b5f9cae916d32deff81c5f2e9f8ff43904034bc084b12320730953d120698bed"; + public final static Instant QUERY_8_EXECUTION = Instant.now().minus(1, MINUTES); + public final static Boolean QUERY_8_PERSISTED = true; - public static final SubsetDto QUERY_8_SUBSET_DTO = SubsetDto.builder() - .tableId(TABLE_5_ID) + public final SubsetDto QUERY_8_SUBSET_DTO = SubsetDto.builder() + .datasourceId(TABLE_5_ID) + .datasourceType(DatasourceType.TABLE) .columns(new LinkedList<>(List.of(COLUMN_5_1_ID, COLUMN_5_2_ID))) .filter(new LinkedList<>(List.of(FilterDto.builder() .type(FilterTypeDto.WHERE) @@ -4658,19 +4621,14 @@ public abstract class BaseTest { .build()))) .build(); - public static final UUID COLUMN_6_1_ID = UUID.fromString("27b04a64-2849-4fae-b295-858c3e50361f"); - - public static final UUID COLUMN_6_2_ID = UUID.fromString("1ea62e32-5719-4152-94da-45d37eb88b6f"); - - public static final UUID COLUMN_6_3_ID = UUID.fromString("f523f9f5-42f7-4695-841e-a5fd30fa6879"); - - public static final UUID COLUMN_6_4_ID = UUID.fromString("f57ea880-f917-4127-bcbb-202a34831383"); + public final static UUID COLUMN_6_1_ID = UUID.fromString("27b04a64-2849-4fae-b295-858c3e50361f"); + public final static UUID COLUMN_6_2_ID = UUID.fromString("1ea62e32-5719-4152-94da-45d37eb88b6f"); + public final static UUID COLUMN_6_3_ID = UUID.fromString("f523f9f5-42f7-4695-841e-a5fd30fa6879"); + public final static UUID COLUMN_6_4_ID = UUID.fromString("f57ea880-f917-4127-bcbb-202a34831383"); + public final static UUID COLUMN_6_5_ID = UUID.fromString("38aaeb63-b94b-4d90-8eae-a626dfb1f092"); + public final static UUID COLUMN_6_6_ID = UUID.fromString("f788cf6f-66ed-4f28-8b24-d9d173c4d340"); - public static final UUID COLUMN_6_5_ID = UUID.fromString("38aaeb63-b94b-4d90-8eae-a626dfb1f092"); - - public static final UUID COLUMN_6_6_ID = UUID.fromString("f788cf6f-66ed-4f28-8b24-d9d173c4d340"); - - public static final List<TableColumn> TABLE_6_COLUMNS = List.of(TableColumn.builder() + public final List<TableColumn> TABLE_6_COLUMNS = List.of(TableColumn.builder() .id(COLUMN_6_1_ID) .ordinalPosition(0) .table(TABLE_6) @@ -4725,14 +4683,14 @@ public abstract class BaseTest { .isNullAllowed(true) .build()); - public static final ColumnBriefDto TABLE_6_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() + public final ColumnBriefDto TABLE_6_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() .id(COLUMN_6_1_ID) .name("id") .internalName("id") .columnType(ColumnTypeDto.BIGINT) .build(); - public static final List<ColumnDto> TABLE_6_COLUMNS_DTO = List.of(ColumnDto.builder() + public final List<ColumnDto> TABLE_6_COLUMNS_DTO = List.of(ColumnDto.builder() .id(COLUMN_6_1_ID) .ordinalPosition(0) .tableId(TABLE_6_ID) @@ -4787,25 +4745,23 @@ public abstract class BaseTest { .isNullAllowed(true) .build()); - public static final List<List<String>> TABLE_6_UNIQUES_CREATE = List.of( + public final List<List<String>> TABLE_6_UNIQUES_CREATE = List.of( List.of("firstname", "lastname")); - public static final List<CreateForeignKeyDto> TABLE_6_FOREIGN_KEYS_CREATE = List.of(CreateForeignKeyDto.builder() + public final 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"))) .build()); - public static final Set<String> TABLE_6_CHECKS_CREATE = Set.of("firstname != lastname"); - - public static final CreateTableConstraintsDto TABLE_6_CONSTRAINTS_CREATE = CreateTableConstraintsDto.builder() + public final CreateTableConstraintsDto TABLE_6_CONSTRAINTS_CREATE = CreateTableConstraintsDto.builder() .uniques(TABLE_6_UNIQUES_CREATE) .foreignKeys(TABLE_6_FOREIGN_KEYS_CREATE) - .checks(TABLE_6_CHECKS_CREATE) + .checks(Set.of("firstname != lastname")) .primaryKey(Set.of("id")) .build(); - public static final List<CreateTableColumnDto> TABLE_6_COLUMNS_CREATE = List.of( + public final List<CreateTableColumnDto> TABLE_6_COLUMNS_CREATE = List.of( CreateTableColumnDto.builder() .name("name_id") .type(ColumnTypeDto.BIGINT) @@ -4818,32 +4774,31 @@ public abstract class BaseTest { .nullAllowed(false) .build()); - public static final CreateTableDto TABLE_6_CREATE_DTO = CreateTableDto.builder() + public final CreateTableDto TABLE_6_CREATE_DTO = CreateTableDto.builder() .name(TABLE_6_NAME) .description(TABLE_6_DESCRIPTION) .columns(TABLE_6_COLUMNS_CREATE) .constraints(TABLE_6_CONSTRAINTS_CREATE) .build(); - public static final UUID COLUMN_7_1_ID = UUID.fromString("395b44a4-0e31-41ea-94ad-c4f2d5e912c6"); + public final static UUID COLUMN_7_1_ID = UUID.fromString("395b44a4-0e31-41ea-94ad-c4f2d5e912c6"); + public final static UUID COLUMN_7_2_ID = UUID.fromString("5713333b-872a-44c5-ab94-4d0ab62f5663"); - public static final UUID COLUMN_7_2_ID = UUID.fromString("5713333b-872a-44c5-ab94-4d0ab62f5663"); - - public static final ColumnBriefDto TABLE_7_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() + public final ColumnBriefDto TABLE_7_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() .id(COLUMN_7_1_ID) .name("name_id") .internalName("name_id") .columnType(ColumnTypeDto.BIGINT) .build(); - public static final ColumnBriefDto TABLE_7_COLUMNS_BRIEF_1_DTO = ColumnBriefDto.builder() + public final ColumnBriefDto TABLE_7_COLUMNS_BRIEF_1_DTO = ColumnBriefDto.builder() .id(COLUMN_7_2_ID) .name("zoo_id") .internalName("zoo_id") .columnType(ColumnTypeDto.BIGINT) .build(); - public static final List<TableColumn> TABLE_7_COLUMNS = List.of(TableColumn.builder() + public final List<TableColumn> TABLE_7_COLUMNS = List.of(TableColumn.builder() .id(COLUMN_7_1_ID) .ordinalPosition(0) .table(TABLE_7) @@ -4862,7 +4817,7 @@ public abstract class BaseTest { .isNullAllowed(false) .build()); - public static final List<ColumnDto> TABLE_7_COLUMNS_DTO = List.of(ColumnDto.builder() + public final List<ColumnDto> TABLE_7_COLUMNS_DTO = List.of(ColumnDto.builder() .id(COLUMN_7_1_ID) .ordinalPosition(0) .tableId(TABLE_7_ID) @@ -4881,27 +4836,25 @@ public abstract class BaseTest { .isNullAllowed(false) .build()); - public static final UUID VIEW_1_ID = UUID.fromString("7d712cf7-78c7-4a47-90b0-d6b9f7f19b70"); - public static final Boolean VIEW_1_INITIAL_VIEW = false; - public static final String VIEW_1_NAME = "JUnit"; - public static final String VIEW_1_INTERNAL_NAME = "junit"; - public static final Boolean VIEW_1_PUBLIC = false; - public static final Boolean VIEW_1_SCHEMA_PUBLIC = false; - public static final String VIEW_1_QUERY = "SELECT `location`, `lat`, `lng` FROM `weather_location`"; - public static final String VIEW_1_QUERY_HASH = "dc81a6877c7c51a6a6f406e1fc2a255e44a0d49a20548596e0d583c3eb849c23"; - - public static final UUID VIEW_COLUMN_1_1_ID = UUID.fromString("ebf2c5ce-4deb-4cc6-b6f6-61f5d3f6fc98"); - - public static final UUID VIEW_COLUMN_1_2_ID = UUID.fromString("d6ba3475-cefa-4771-aaa1-9274f16335ee"); - - public static final UUID VIEW_COLUMN_1_3_ID = UUID.fromString("4f189a5f-c9ca-4518-9758-1a0730f6276b"); - - public static final SubsetDto VIEW_1_SUBSET_DTO = SubsetDto.builder() - .tableId(TABLE_2_ID) + public final static UUID VIEW_1_ID = UUID.fromString("7d712cf7-78c7-4a47-90b0-d6b9f7f19b70"); + public final static Boolean VIEW_1_INITIAL_VIEW = false; + public final static String VIEW_1_NAME = "JUnit"; + public final static String VIEW_1_INTERNAL_NAME = "junit"; + 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"; + public final static UUID VIEW_COLUMN_1_1_ID = UUID.fromString("ebf2c5ce-4deb-4cc6-b6f6-61f5d3f6fc98"); + public final static UUID VIEW_COLUMN_1_2_ID = UUID.fromString("d6ba3475-cefa-4771-aaa1-9274f16335ee"); + public final static UUID VIEW_COLUMN_1_3_ID = UUID.fromString("4f189a5f-c9ca-4518-9758-1a0730f6276b"); + + public final SubsetDto VIEW_1_SUBSET_DTO = SubsetDto.builder() + .datasourceId(TABLE_2_ID) + .datasourceType(DatasourceType.TABLE) .columns(new LinkedList<>(List.of(COLUMN_2_1_ID, COLUMN_2_2_ID, COLUMN_2_3_ID))) .build(); - public static final List<ViewColumnDto> VIEW_1_COLUMNS_DTO = List.of( + public final List<ViewColumnDto> VIEW_1_COLUMNS_DTO = List.of( ViewColumnDto.builder() .id(VIEW_COLUMN_1_1_ID) .ordinalPosition(0) @@ -4933,10 +4886,9 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .build() - ); + .build()); - public static final View VIEW_1 = View.builder() + public final View VIEW_1 = View.builder() .id(VIEW_1_ID) .isInitialView(VIEW_1_INITIAL_VIEW) .name(VIEW_1_NAME) @@ -4952,8 +4904,8 @@ public abstract class BaseTest { .database(null) /* DATABASE_1 */ .build(); - public static final Long VIEW_1_DATA_COUNT = 3L; - public static final List<Map<String, Object>> VIEW_1_DATA_DTO = new LinkedList<>(List.of( + public final static Long VIEW_1_DATA_COUNT = 3L; + public final List<Map<String, Object>> VIEW_1_DATA_DTO = new LinkedList<>(List.of( new HashMap<>() {{ put("location", "Albury"); put("lat", -36.0653583); @@ -4971,7 +4923,7 @@ public abstract class BaseTest { }} )); - public static final List<ViewColumn> VIEW_1_COLUMNS = List.of( + public final List<ViewColumn> VIEW_1_COLUMNS = List.of( ViewColumn.builder() .id(VIEW_COLUMN_1_1_ID) .ordinalPosition(0) @@ -5003,10 +4955,9 @@ public abstract class BaseTest { .d(0L) .isNullAllowed(true) .view(VIEW_1) - .build() - ); + .build()); - public static final ViewDto VIEW_1_DTO = ViewDto.builder() + public final ViewDto VIEW_1_DTO = ViewDto.builder() .id(VIEW_1_ID) .databaseId(DATABASE_1_ID) .isInitialView(VIEW_1_INITIAL_VIEW) @@ -5021,7 +4972,7 @@ public abstract class BaseTest { .columns(VIEW_1_COLUMNS_DTO) .build(); - public static final ViewBriefDto VIEW_1_BRIEF_DTO = ViewBriefDto.builder() + public final ViewBriefDto VIEW_1_BRIEF_DTO = ViewBriefDto.builder() .id(VIEW_1_ID) .isInitialView(VIEW_1_INITIAL_VIEW) .name(VIEW_1_NAME) @@ -5034,30 +4985,26 @@ public abstract class BaseTest { .queryHash(VIEW_1_QUERY_HASH) .build(); - public static final CreateViewDto VIEW_1_CREATE_DTO = CreateViewDto.builder() + public final CreateViewDto VIEW_1_CREATE_DTO = CreateViewDto.builder() .isPublic(VIEW_1_PUBLIC) .name(VIEW_1_NAME) .query(VIEW_1_SUBSET_DTO) .build(); - public static final UUID VIEW_2_ID = UUID.fromString("1921a0a0-e4b0-4d12-a05f-be920af9b5ce"); - public static final Boolean VIEW_2_INITIAL_VIEW = false; - public static final String VIEW_2_NAME = "JUnit2"; - public static final String VIEW_2_INTERNAL_NAME = "junit2"; - public static final Boolean VIEW_2_PUBLIC = true; - public static final Boolean VIEW_2_SCHEMA_PUBLIC = true; - public static final String VIEW_2_QUERY = "select `date`, `location` as loc, `mintemp`, `rainfall` from `weather_aus` where `location` = 'Albury'"; - public static final String VIEW_2_QUERY_HASH = "987fc946772ffb6d85060262dcb5df419692a1f6772ea995e3dedb53c191e984"; - - public static final UUID VIEW_COLUMN_2_1_ID = UUID.fromString("8fb30bce-04a8-4e9a-9c6b-0776eda3aab8"); - - public static final UUID VIEW_COLUMN_2_2_ID = UUID.fromString("d43f9940-ae27-4d81-b17b-ccbaf578186c"); - - public static final UUID VIEW_COLUMN_2_3_ID = UUID.fromString("b47733bb-aeea-414d-811e-405c64463730"); - - public static final UUID VIEW_COLUMN_2_4_ID = UUID.fromString("2b467e3a-acef-4944-be19-b4b0680874c2"); - - public static final List<ViewColumnDto> VIEW_2_COLUMNS_DTO = List.of( + public final static UUID VIEW_2_ID = UUID.fromString("1921a0a0-e4b0-4d12-a05f-be920af9b5ce"); + public final static Boolean VIEW_2_INITIAL_VIEW = false; + public final static String VIEW_2_NAME = "JUnit2"; + public final static String VIEW_2_INTERNAL_NAME = "junit2"; + public final static Boolean VIEW_2_PUBLIC = true; + public final static Boolean VIEW_2_SCHEMA_PUBLIC = true; + public final static String VIEW_2_QUERY = "select `date`, `location` as loc, `mintemp`, `rainfall` from `weather_aus` where `location` = 'Albury'"; + public final static String VIEW_2_QUERY_HASH = "987fc946772ffb6d85060262dcb5df419692a1f6772ea995e3dedb53c191e984"; + public final static UUID VIEW_COLUMN_2_1_ID = UUID.fromString("8fb30bce-04a8-4e9a-9c6b-0776eda3aab8"); + public final static UUID VIEW_COLUMN_2_2_ID = UUID.fromString("d43f9940-ae27-4d81-b17b-ccbaf578186c"); + public final static UUID VIEW_COLUMN_2_3_ID = UUID.fromString("b47733bb-aeea-414d-811e-405c64463730"); + public final static UUID VIEW_COLUMN_2_4_ID = UUID.fromString("2b467e3a-acef-4944-be19-b4b0680874c2"); + + public final List<ViewColumnDto> VIEW_2_COLUMNS_DTO = List.of( ViewColumnDto.builder() .id(VIEW_COLUMN_2_1_ID) .databaseId(DATABASE_1_ID) @@ -5098,10 +5045,9 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .build() - ); + .build()); - public static final View VIEW_2 = View.builder() + public final View VIEW_2 = View.builder() .id(VIEW_2_ID) .isInitialView(VIEW_2_INITIAL_VIEW) .name(VIEW_2_NAME) @@ -5116,7 +5062,7 @@ public abstract class BaseTest { .database(null) /* DATABASE_1 */ .build(); - public static final List<ViewColumn> VIEW_2_COLUMNS = List.of( + public final List<ViewColumn> VIEW_2_COLUMNS = List.of( ViewColumn.builder() .id(VIEW_COLUMN_2_1_ID) .ordinalPosition(0) @@ -5157,10 +5103,9 @@ public abstract class BaseTest { .d(0L) .isNullAllowed(true) .view(VIEW_2) - .build() - ); + .build()); - public static final ViewDto VIEW_2_DTO = ViewDto.builder() + public final ViewDto VIEW_2_DTO = ViewDto.builder() .id(VIEW_2_ID) .databaseId(DATABASE_1_ID) .isInitialView(VIEW_2_INITIAL_VIEW) @@ -5174,7 +5119,7 @@ public abstract class BaseTest { .owner(USER_1_BRIEF_DTO) .build(); - public static final ViewBriefDto VIEW_2_BRIEF_DTO = ViewBriefDto.builder() + public final ViewBriefDto VIEW_2_BRIEF_DTO = ViewBriefDto.builder() .id(VIEW_2_ID) .isInitialView(VIEW_2_INITIAL_VIEW) .name(VIEW_2_NAME) @@ -5187,26 +5132,21 @@ public abstract class BaseTest { .ownedBy(USER_1_ID) .build(); - public static final UUID VIEW_3_ID = UUID.fromString("88940939-d456-4aae-88a6-f2b6b343c614"); - public static final Boolean VIEW_3_INITIAL_VIEW = false; - public static final String VIEW_3_NAME = "JUnit3"; - public static final String VIEW_3_INTERNAL_NAME = "junit3"; - public static final Boolean VIEW_3_PUBLIC = true; - public static final Boolean VIEW_3_SCHEMA_PUBLIC = false; - public static final 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 static final String VIEW_3_QUERY_HASH = "bbbaa56a5206b3dc3e6cf9301b0db9344eb6f19b100c7b88550ffb597a0bd255"; - - public static final Long VIEW_3_DATA_COUNT = 3L; - - public static final UUID VIEW_COLUMN_3_1_ID = UUID.fromString("129839cb-dbd7-492d-8fd0-ee44a8f51c4d"); - - public static final UUID VIEW_COLUMN_3_2_ID = UUID.fromString("e229d80a-c25c-4fbe-8f31-bbb2e1dff3d5"); - - public static final UUID VIEW_COLUMN_3_3_ID = UUID.fromString("12083a5d-fdd3-41db-9f92-d1298558e477"); - - public static final UUID VIEW_COLUMN_3_4_ID = UUID.fromString("668f8a87-1fa6-4be7-9761-1844aa8315a4"); - - public static final List<ViewColumnDto> VIEW_3_COLUMNS_DTO = List.of( + public final static UUID VIEW_3_ID = UUID.fromString("88940939-d456-4aae-88a6-f2b6b343c614"); + public final static Boolean VIEW_3_INITIAL_VIEW = false; + public final static String VIEW_3_NAME = "JUnit3"; + public final static String VIEW_3_INTERNAL_NAME = "junit3"; + 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"; + public final static Long VIEW_3_DATA_COUNT = 3L; + public final static UUID VIEW_COLUMN_3_1_ID = UUID.fromString("129839cb-dbd7-492d-8fd0-ee44a8f51c4d"); + public final static UUID VIEW_COLUMN_3_2_ID = UUID.fromString("e229d80a-c25c-4fbe-8f31-bbb2e1dff3d5"); + public final static UUID VIEW_COLUMN_3_3_ID = UUID.fromString("12083a5d-fdd3-41db-9f92-d1298558e477"); + public final static UUID VIEW_COLUMN_3_4_ID = UUID.fromString("668f8a87-1fa6-4be7-9761-1844aa8315a4"); + + public final List<ViewColumnDto> VIEW_3_COLUMNS_DTO = List.of( ViewColumnDto.builder() .id(VIEW_COLUMN_3_1_ID) .databaseId(DATABASE_1_ID) @@ -5247,10 +5187,9 @@ public abstract class BaseTest { .internalName("date") .columnType(ColumnTypeDto.DATE) .isNullAllowed(true) - .build() - ); + .build()); - public static final View VIEW_3 = View.builder() + public final View VIEW_3 = View.builder() .id(VIEW_3_ID) .isInitialView(VIEW_3_INITIAL_VIEW) .name(VIEW_3_NAME) @@ -5265,7 +5204,7 @@ public abstract class BaseTest { .database(null) /* DATABASE_1 */ .build(); - public static final List<ViewColumn> VIEW_3_COLUMNS = List.of( + public final List<ViewColumn> VIEW_3_COLUMNS = List.of( ViewColumn.builder() .id(VIEW_COLUMN_3_1_ID) .ordinalPosition(0) @@ -5306,10 +5245,9 @@ public abstract class BaseTest { .columnType(TableColumnType.DATE) .isNullAllowed(true) .view(VIEW_3) - .build() - ); + .build()); - public static final ViewDto VIEW_3_DTO = ViewDto.builder() + public final ViewDto VIEW_3_DTO = ViewDto.builder() .id(VIEW_3_ID) .databaseId(DATABASE_1_ID) .isInitialView(VIEW_3_INITIAL_VIEW) @@ -5323,7 +5261,7 @@ public abstract class BaseTest { .owner(USER_1_BRIEF_DTO) .build(); - public static final ViewBriefDto VIEW_3_BRIEF_DTO = ViewBriefDto.builder() + public final ViewBriefDto VIEW_3_BRIEF_DTO = ViewBriefDto.builder() .id(VIEW_3_ID) .isInitialView(VIEW_3_INITIAL_VIEW) .name(VIEW_3_NAME) @@ -5336,17 +5274,16 @@ public abstract class BaseTest { .ownedBy(USER_1_ID) .build(); - public static final UUID VIEW_4_ID = UUID.fromString("13b36fa0-a65a-4ccf-80b1-5b3a2444a41a"); - public static final Boolean VIEW_4_INITIAL_VIEW = false; - public static final String VIEW_4_NAME = "Mock View"; - public static final String VIEW_4_INTERNAL_NAME = "mock_view"; - public static final Table VIEW_4_TABLE = TABLE_5; - public static final Boolean VIEW_4_PUBLIC = true; - public static final Boolean VIEW_4_SCHEMA_PUBLIC = false; - public static final 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 static final String VIEW_4_QUERY_HASH = "3561cd0bb0b0e94d6f15ae602134252a5760d09d660a71a4fb015b6991c8ba0b"; - - public static final List<ViewColumnDto> VIEW_4_COLUMNS_DTO = List.of( + public final static UUID VIEW_4_ID = UUID.fromString("13b36fa0-a65a-4ccf-80b1-5b3a2444a41a"); + public final static Boolean VIEW_4_INITIAL_VIEW = false; + public final static String VIEW_4_NAME = "Mock View"; + public final static String VIEW_4_INTERNAL_NAME = "mock_view"; + public final Table VIEW_4_TABLE = TABLE_5; + public final static Boolean VIEW_4_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"; + public final List<ViewColumnDto> VIEW_4_COLUMNS_DTO = List.of( ViewColumnDto.builder() .id(COLUMN_5_1_ID) .databaseId(DATABASE_2_ID) @@ -5501,7 +5438,7 @@ public abstract class BaseTest { .isNullAllowed(true) .build()); - public static final View VIEW_4 = View.builder() + public final View VIEW_4 = View.builder() .id(VIEW_4_ID) .isInitialView(VIEW_4_INITIAL_VIEW) .name(VIEW_4_NAME) @@ -5515,7 +5452,7 @@ public abstract class BaseTest { .columns(null) /* VIEW_4_COLUMNS */ .build(); - public static final ViewDto VIEW_4_DTO = ViewDto.builder() + public final ViewDto VIEW_4_DTO = ViewDto.builder() .id(VIEW_4_ID) .databaseId(DATABASE_2_ID) .isInitialView(VIEW_4_INITIAL_VIEW) @@ -5529,7 +5466,7 @@ public abstract class BaseTest { .columns(VIEW_4_COLUMNS_DTO) .build(); - public static final ViewBriefDto VIEW_4_BRIEF_DTO = ViewBriefDto.builder() + public final ViewBriefDto VIEW_4_BRIEF_DTO = ViewBriefDto.builder() .id(VIEW_4_ID) .isInitialView(VIEW_4_INITIAL_VIEW) .name(VIEW_4_NAME) @@ -5542,7 +5479,7 @@ public abstract class BaseTest { .ownedBy(USER_1_ID) .build(); - public static final List<ViewColumn> VIEW_4_COLUMNS = List.of( + public final List<ViewColumn> VIEW_4_COLUMNS = List.of( ViewColumn.builder() .id(COLUMN_5_1_ID) .ordinalPosition(0) @@ -5697,16 +5634,16 @@ public abstract class BaseTest { .view(VIEW_4) .build()); - public static final UUID VIEW_5_ID = UUID.fromString("bc6b8507-51f1-4d05-bb0c-1f619a991dec"); - public static final Boolean VIEW_5_INITIAL_VIEW = false; - public static final String VIEW_5_NAME = "Mock View"; - public static final String VIEW_5_INTERNAL_NAME = "mock_view"; - public static final Boolean VIEW_5_PUBLIC = true; - public static final Boolean VIEW_5_SCHEMA_PUBLIC = true; - public static final String VIEW_5_QUERY = "SELECT `location`, `lat`, `lng` FROM `weather_location` WHERE `location` = 'Albury'"; - public static final String VIEW_5_QUERY_HASH = "120f32478aaff874c25ab32eceb9f00b64cc9d422831046f2f5d43953aca01e7"; + public final static UUID VIEW_5_ID = UUID.fromString("bc6b8507-51f1-4d05-bb0c-1f619a991dec"); + public final static Boolean VIEW_5_INITIAL_VIEW = false; + public final static String VIEW_5_NAME = "Mock View"; + public final static String VIEW_5_INTERNAL_NAME = "mock_view"; + public final static Boolean VIEW_5_PUBLIC = true; + public final static Boolean VIEW_5_SCHEMA_PUBLIC = true; + public final static String VIEW_5_QUERY = "SELECT `location`, `lat`, `lng` FROM `weather_location` WHERE `location` = 'Albury'"; + public final static String VIEW_5_QUERY_HASH = "120f32478aaff874c25ab32eceb9f00b64cc9d422831046f2f5d43953aca01e7"; - public static final View VIEW_5 = View.builder() + public final View VIEW_5 = View.builder() .id(VIEW_5_ID) .isInitialView(VIEW_5_INITIAL_VIEW) .name(VIEW_5_NAME) @@ -5720,7 +5657,7 @@ public abstract class BaseTest { .columns(null) .build(); - public static final ViewDto VIEW_5_DTO = ViewDto.builder() + public final ViewDto VIEW_5_DTO = ViewDto.builder() .id(VIEW_5_ID) .databaseId(DATABASE_3_ID) .isInitialView(VIEW_5_INITIAL_VIEW) @@ -5734,7 +5671,7 @@ public abstract class BaseTest { .columns(new LinkedList<>()) .build(); - public static final ViewBriefDto VIEW_5_BRIEF_DTO = ViewBriefDto.builder() + public final ViewBriefDto VIEW_5_BRIEF_DTO = ViewBriefDto.builder() .id(VIEW_5_ID) .isInitialView(VIEW_5_INITIAL_VIEW) .name(VIEW_5_NAME) @@ -5746,7 +5683,7 @@ public abstract class BaseTest { .queryHash(VIEW_5_QUERY_HASH) .build(); - public static final List<ViewColumn> VIEW_5_COLUMNS = List.of( + public final List<ViewColumn> VIEW_5_COLUMNS = List.of( ViewColumn.builder() .id(COLUMN_2_1_ID) .ordinalPosition(0) @@ -5780,7 +5717,7 @@ public abstract class BaseTest { .view(VIEW_5) .build()); - public static final List<ViewColumnDto> VIEW_5_COLUMNS_DTO = List.of( + public final List<ViewColumnDto> VIEW_5_COLUMNS_DTO = List.of( ViewColumnDto.builder() .id(COLUMN_2_1_ID) .databaseId(DATABASE_3_ID) @@ -5814,8 +5751,8 @@ public abstract class BaseTest { .isNullAllowed(true) .build()); - public static final Long QUERY_1_RESULT_ID = 1L; - public static final List<Map<String, Object>> QUERY_1_RESULT_DTO = new LinkedList<>(List.of( + public final static Long QUERY_1_RESULT_ID = 1L; + public final List<Map<String, Object>> QUERY_1_RESULT_DTO = new LinkedList<>(List.of( new HashMap<>() {{ put("location", "Albury"); put("lat", -36.0653583); @@ -5826,33 +5763,30 @@ public abstract class BaseTest { put("lng", 150.6517942); }})); - public static final String LICENSE_1_IDENTIFIER = "MIT"; - public static final String LICENSE_1_URI = "https://opensource.org/license/mit/"; - - public static final License LICENSE_1 = License.builder() + public final static String LICENSE_1_IDENTIFIER = "MIT"; + public final static String LICENSE_1_URI = "https://opensource.org/license/mit/"; + public final License LICENSE_1 = License.builder() .identifier(LICENSE_1_IDENTIFIER) .uri(LICENSE_1_URI) .build(); - public static final LicenseDto LICENSE_1_DTO = LicenseDto.builder() + public final LicenseDto LICENSE_1_DTO = LicenseDto.builder() .identifier(LICENSE_1_IDENTIFIER) .uri(LICENSE_1_URI) .build(); - public static final UUID CREATOR_1_ID = UUID.fromString("a0417f34-80ff-419f-821d-ce179021484a"); - public static final String CREATOR_1_ORCID = "00000-00000-00000"; - public static final String CREATOR_1_AFFIL = "TU Graz"; - public static final String CREATOR_1_AFFIL_ROR = "https://ror.org/04wn28048"; - public static final String CREATOR_1_AFFIL_URI = "https://ror.org/"; - public static final AffiliationIdentifierSchemeType CREATOR_1_AFFIL_TYPE = AffiliationIdentifierSchemeType.ROR; - public static final AffiliationIdentifierSchemeTypeDto CREATOR_1_AFFIL_TYPE_DTO = AffiliationIdentifierSchemeTypeDto.ROR; - public static final String CREATOR_1_FIRSTNAME = "Max"; - public static final String CREATOR_1_LASTNAME = "Mustermann"; - public static final String CREATOR_1_NAME = CREATOR_1_LASTNAME + ", " + CREATOR_1_FIRSTNAME; - public static final Instant CREATOR_1_CREATED = Instant.ofEpochSecond(1641588352L); - public static final Instant CREATOR_1_MODIFIED = Instant.ofEpochSecond(1541588352L); - - public static final OrcidDto ORCID_1_DTO = OrcidDto.builder() + public final static UUID CREATOR_1_ID = UUID.fromString("a0417f34-80ff-419f-821d-ce179021484a"); + public final static String CREATOR_1_ORCID = "00000-00000-00000"; + public final static String CREATOR_1_AFFIL = "TU Graz"; + public final static String CREATOR_1_AFFIL_ROR = "https://ror.org/04wn28048"; + public final static String CREATOR_1_AFFIL_URI = "https://ror.org/"; + public final static AffiliationIdentifierSchemeType CREATOR_1_AFFIL_TYPE = AffiliationIdentifierSchemeType.ROR; + public final static AffiliationIdentifierSchemeTypeDto CREATOR_1_AFFIL_TYPE_DTO = AffiliationIdentifierSchemeTypeDto.ROR; + public final static String CREATOR_1_FIRSTNAME = "Max"; + public final static String CREATOR_1_LASTNAME = "Mustermann"; + public final static String CREATOR_1_NAME = CREATOR_1_LASTNAME + ", " + CREATOR_1_FIRSTNAME; + + public final OrcidDto ORCID_1_DTO = OrcidDto.builder() .person(OrcidPersonDto.builder() .name(OrcidNameDto.builder() .givenNames(OrcidValueDto.builder() @@ -5882,190 +5816,184 @@ public abstract class BaseTest { .build()) .build(); - public static final UUID CREATOR_2_ID = UUID.fromString("56b70dae-17a7-4f76-9c1e-a493762ba760"); - public static final Long CREATOR_2_QUERY_ID = 1L; - public static final String CREATOR_2_ORCID = "00000-00000-00000"; - public static final String CREATOR_2_AFFIL = "TU Wien"; - public static final String CREATOR_2_FIRSTNAME = "Martina"; - public static final String CREATOR_2_LASTNAME = "Mustermann"; - public static final String CREATOR_2_NAME = CREATOR_2_LASTNAME + ", " + CREATOR_2_FIRSTNAME; - public static final Instant CREATOR_2_CREATED = Instant.ofEpochSecond(1641588352L); - public static final Instant CREATOR_2_MODIFIED = Instant.ofEpochSecond(1541588352L); - - public static final UUID CREATOR_3_ID = UUID.fromString("a2dfea46-7d88-4069-9b93-2417e1fb578b"); - public static final Long CREATOR_3_QUERY_ID = 1L; - public static final String CREATOR_3_ORCID = "00000-00000-00000"; - public static final String CREATOR_3_AFFIL = "TU Graz"; - public static final String CREATOR_3_AFFIL_ROR = "https://ror.org/04wn28048"; - public static final AffiliationIdentifierSchemeType CREATOR_3_AFFIL_SCHEME_TYPE = AffiliationIdentifierSchemeType.ROR; - public static final AffiliationIdentifierSchemeTypeDto CREATOR_3_AFFIL_SCHEME_TYPE_DTO = AffiliationIdentifierSchemeTypeDto.ROR; - public static final String CREATOR_3_AFFIL_URI = "https://ror.org/"; - public static final String CREATOR_3_FIRSTNAME = "Max"; - public static final String CREATOR_3_LASTNAME = "Mustermann"; - public static final String CREATOR_3_NAME = CREATOR_3_LASTNAME + ", " + CREATOR_3_FIRSTNAME; - public static final Instant CREATOR_3_CREATED = Instant.ofEpochSecond(1641588352L); - public static final Instant CREATOR_3_MODIFIED = Instant.ofEpochSecond(1541588352L); - - public static final UUID CREATOR_4_ID = UUID.fromString("473489fa-ad02-4e48-856f-5a3f83ff541d"); - public static final Long CREATOR_4_QUERY_ID = 1L; - public static final String CREATOR_4_ORCID = "00000-00000-00000"; - public static final String CREATOR_4_AFFIL = "TU Wien"; - public static final String CREATOR_4_AFFIL_ROR = "https://ror.org/04d836q62"; - public static final String CREATOR_4_AFFIL_URI = "https://ror.org/"; - public static final AffiliationIdentifierSchemeType CREATOR_4_AFFIL_TYPE = AffiliationIdentifierSchemeType.ROR; - public static final AffiliationIdentifierSchemeTypeDto CREATOR_4_AFFIL_TYPE_DTO = AffiliationIdentifierSchemeTypeDto.ROR; - public static final String CREATOR_4_FIRSTNAME = "Martina"; - public static final String CREATOR_4_LASTNAME = "Mustermann"; - public static final String CREATOR_4_NAME = CREATOR_4_LASTNAME + ", " + CREATOR_4_FIRSTNAME; - public static final Instant CREATOR_4_CREATED = Instant.ofEpochSecond(1641588352L); - public static final Instant CREATOR_4_MODIFIED = Instant.ofEpochSecond(1541588352L); - - public static final UUID IDENTIFIER_1_ID = UUID.fromString("679a83f2-ef23-4b4b-98f7-ad77b9d68733"); - public static final String IDENTIFIER_1_DOI = "10.12345/183"; - public static final Instant IDENTIFIER_1_CREATED = Instant.ofEpochSecond(1641588352L) /* 2022-01-07 20:45:52 */; - public static final Instant IDENTIFIER_1_MODIFIED = Instant.ofEpochSecond(1541588352L) /* 2022-01-07 20:45:52 */; - public static final Instant IDENTIFIER_1_EXECUTION = Instant.ofEpochSecond(1541588352L) /* 2022-01-07 20:45:52 */; - public static final Integer IDENTIFIER_1_PUBLICATION_MONTH = 5; - public static final Integer IDENTIFIER_1_PUBLICATION_YEAR = 2022; - public static final Integer IDENTIFIER_1_PUBLICATION_DAY = null; - public static final String IDENTIFIER_1_PUBLISHER = "Austrian Government"; - public static final IdentifierType IDENTIFIER_1_TYPE = IdentifierType.DATABASE; - public static final IdentifierTypeDto IDENTIFIER_1_TYPE_DTO = IdentifierTypeDto.DATABASE; - public static final IdentifierStatusType IDENTIFIER_1_STATUS_TYPE = IdentifierStatusType.PUBLISHED; - public static final IdentifierStatusTypeDto IDENTIFIER_1_STATUS_TYPE_DTO = IdentifierStatusTypeDto.PUBLISHED; - - public static final UUID IDENTIFIER_1_TITLE_1_ID = UUID.fromString("3df6b286-9bd2-4ae3-b8f4-29c217544bef"); - public static final String IDENTIFIER_1_TITLE_1_TITLE = "Austrian weather data"; - public static final String IDENTIFIER_1_TITLE_1_TITLE_MODIFY = "Austrian weather some data"; - public static final TitleType IDENTIFIER_1_TITLE_1_TYPE = null; - public static final TitleTypeDto IDENTIFIER_1_TITLE_1_TYPE_DTO = null; - public static final LanguageType IDENTIFIER_1_TITLE_1_LANG = LanguageType.EN; - public static final LanguageTypeDto IDENTIFIER_1_TITLE_1_LANG_DTO = LanguageTypeDto.EN; - - public static final IdentifierTitle IDENTIFIER_1_TITLE_1 = IdentifierTitle.builder() + public final static UUID CREATOR_2_ID = UUID.fromString("56b70dae-17a7-4f76-9c1e-a493762ba760"); + public final static Long CREATOR_2_QUERY_ID = 1L; + public final static String CREATOR_2_ORCID = "00000-00000-00000"; + public final static String CREATOR_2_AFFIL = "TU Wien"; + public final static String CREATOR_2_FIRSTNAME = "Martina"; + public final static String CREATOR_2_LASTNAME = "Mustermann"; + public final static String CREATOR_2_NAME = CREATOR_2_LASTNAME + ", " + CREATOR_2_FIRSTNAME; + + public final static UUID CREATOR_3_ID = UUID.fromString("a2dfea46-7d88-4069-9b93-2417e1fb578b"); + public final static Long CREATOR_3_QUERY_ID = 1L; + public final static String CREATOR_3_ORCID = "00000-00000-00000"; + public final static String CREATOR_3_AFFIL = "TU Graz"; + public final static String CREATOR_3_AFFIL_ROR = "https://ror.org/04wn28048"; + public final static AffiliationIdentifierSchemeType CREATOR_3_AFFIL_SCHEME_TYPE = AffiliationIdentifierSchemeType.ROR; + public final static AffiliationIdentifierSchemeTypeDto CREATOR_3_AFFIL_SCHEME_TYPE_DTO = AffiliationIdentifierSchemeTypeDto.ROR; + public final static String CREATOR_3_AFFIL_URI = "https://ror.org/"; + public final static String CREATOR_3_FIRSTNAME = "Max"; + public final static String CREATOR_3_LASTNAME = "Mustermann"; + public final static String CREATOR_3_NAME = CREATOR_3_LASTNAME + ", " + CREATOR_3_FIRSTNAME; + + public final static UUID CREATOR_4_ID = UUID.fromString("473489fa-ad02-4e48-856f-5a3f83ff541d"); + public final static Long CREATOR_4_QUERY_ID = 1L; + public final static String CREATOR_4_ORCID = "00000-00000-00000"; + public final static String CREATOR_4_AFFIL = "TU Wien"; + public final static String CREATOR_4_AFFIL_ROR = "https://ror.org/04d836q62"; + public final static String CREATOR_4_AFFIL_URI = "https://ror.org/"; + public final static AffiliationIdentifierSchemeType CREATOR_4_AFFIL_TYPE = AffiliationIdentifierSchemeType.ROR; + public final static AffiliationIdentifierSchemeTypeDto CREATOR_4_AFFIL_TYPE_DTO = AffiliationIdentifierSchemeTypeDto.ROR; + public final static String CREATOR_4_FIRSTNAME = "Martina"; + public final static String CREATOR_4_LASTNAME = "Mustermann"; + public final static String CREATOR_4_NAME = CREATOR_4_LASTNAME + ", " + CREATOR_4_FIRSTNAME; + + public final static UUID IDENTIFIER_1_ID = UUID.fromString("679a83f2-ef23-4b4b-98f7-ad77b9d68733"); + public final static String IDENTIFIER_1_DOI = "10.12345/183"; + public final static Instant IDENTIFIER_1_CREATED = Instant.ofEpochSecond(1641588352L) /* 2022-01-07 20:45:52 */; + public final static Instant IDENTIFIER_1_MODIFIED = Instant.ofEpochSecond(1541588352L) /* 2022-01-07 20:45:52 */; + public final static Instant IDENTIFIER_1_EXECUTION = Instant.ofEpochSecond(1541588352L) /* 2022-01-07 20:45:52 */; + public final static Integer IDENTIFIER_1_PUBLICATION_MONTH = 5; + public final static Integer IDENTIFIER_1_PUBLICATION_YEAR = 2022; + public final static Integer IDENTIFIER_1_PUBLICATION_DAY = null; + public final static String IDENTIFIER_1_PUBLISHER = "Austrian Government"; + public final static IdentifierType IDENTIFIER_1_TYPE = IdentifierType.DATABASE; + public final static IdentifierTypeDto IDENTIFIER_1_TYPE_DTO = IdentifierTypeDto.DATABASE; + public final static IdentifierStatusType IDENTIFIER_1_STATUS_TYPE = IdentifierStatusType.PUBLISHED; + public final static IdentifierStatusTypeDto IDENTIFIER_1_STATUS_TYPE_DTO = IdentifierStatusTypeDto.PUBLISHED; + + public final static UUID IDENTIFIER_1_TITLE_1_ID = UUID.fromString("3df6b286-9bd2-4ae3-b8f4-29c217544bef"); + public final static String IDENTIFIER_1_TITLE_1_TITLE = "Austrian weather data"; + public final static String IDENTIFIER_1_TITLE_1_TITLE_MODIFY = "Austrian weather some data"; + public final static TitleType IDENTIFIER_1_TITLE_1_TYPE = null; + public final static TitleTypeDto IDENTIFIER_1_TITLE_1_TYPE_DTO = null; + public final static LanguageType IDENTIFIER_1_TITLE_1_LANG = LanguageType.EN; + public final static LanguageTypeDto IDENTIFIER_1_TITLE_1_LANG_DTO = LanguageTypeDto.EN; + + public final IdentifierTitle IDENTIFIER_1_TITLE_1 = IdentifierTitle.builder() .id(IDENTIFIER_1_TITLE_1_ID) .title(IDENTIFIER_1_TITLE_1_TITLE) .titleType(IDENTIFIER_1_TITLE_1_TYPE) .language(IDENTIFIER_1_TITLE_1_LANG) .build(); - public static final IdentifierTitleDto IDENTIFIER_1_TITLE_1_DTO = IdentifierTitleDto.builder() + public final IdentifierTitleDto IDENTIFIER_1_TITLE_1_DTO = IdentifierTitleDto.builder() .id(IDENTIFIER_1_TITLE_1_ID) .title(IDENTIFIER_1_TITLE_1_TITLE) .titleType(IDENTIFIER_1_TITLE_1_TYPE_DTO) .language(IDENTIFIER_1_TITLE_1_LANG_DTO) .build(); - public static final IdentifierTitleDto IDENTIFIER_1_TITLE_1_DTO_MODIFY = IdentifierTitleDto.builder() + public final IdentifierTitleDto IDENTIFIER_1_TITLE_1_DTO_MODIFY = IdentifierTitleDto.builder() .id(IDENTIFIER_1_TITLE_1_ID) .title(IDENTIFIER_1_TITLE_1_TITLE_MODIFY) .titleType(IDENTIFIER_1_TITLE_1_TYPE_DTO) .language(IDENTIFIER_1_TITLE_1_LANG_DTO) .build(); - public static final SaveIdentifierTitleDto IDENTIFIER_1_TITLE_1_CREATE_DTO = SaveIdentifierTitleDto.builder() + public final 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 static final SaveIdentifierTitleDto IDENTIFIER_1_TITLE_1_UPDATE_DTO = SaveIdentifierTitleDto.builder() + public final 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) .build(); - public static final UUID IDENTIFIER_1_TITLE_2_ID = UUID.fromString("903a7e5b-8014-4b8a-b8fd-44f477880905"); - public static final String IDENTIFIER_1_TITLE_2_TITLE = "Österreichische Wetterdaten"; - public static final String IDENTIFIER_1_TITLE_2_TITLE_MODIFY = "Österreichische Wetterdaten übersetzt"; - public static final TitleType IDENTIFIER_1_TITLE_2_TYPE = TitleType.TRANSLATED_TITLE; - public static final TitleTypeDto IDENTIFIER_1_TITLE_2_TYPE_DTO = TitleTypeDto.TRANSLATED_TITLE; - public static final LanguageType IDENTIFIER_1_TITLE_2_LANG = LanguageType.EN; - public static final LanguageTypeDto IDENTIFIER_1_TITLE_2_LANG_DTO = LanguageTypeDto.EN; + public final static UUID IDENTIFIER_1_TITLE_2_ID = UUID.fromString("903a7e5b-8014-4b8a-b8fd-44f477880905"); + public final static String IDENTIFIER_1_TITLE_2_TITLE = "Österreichische Wetterdaten"; + public final static String IDENTIFIER_1_TITLE_2_TITLE_MODIFY = "Österreichische Wetterdaten übersetzt"; + public final static TitleType IDENTIFIER_1_TITLE_2_TYPE = TitleType.TRANSLATED_TITLE; + public final static TitleTypeDto IDENTIFIER_1_TITLE_2_TYPE_DTO = TitleTypeDto.TRANSLATED_TITLE; + public final static LanguageType IDENTIFIER_1_TITLE_2_LANG = LanguageType.EN; + public final static LanguageTypeDto IDENTIFIER_1_TITLE_2_LANG_DTO = LanguageTypeDto.EN; - public static final IdentifierTitle IDENTIFIER_1_TITLE_2 = IdentifierTitle.builder() + public final IdentifierTitle IDENTIFIER_1_TITLE_2 = IdentifierTitle.builder() .id(IDENTIFIER_1_TITLE_2_ID) .title(IDENTIFIER_1_TITLE_2_TITLE) .titleType(IDENTIFIER_1_TITLE_2_TYPE) .language(IDENTIFIER_1_TITLE_2_LANG) .build(); - public static final IdentifierTitleDto IDENTIFIER_1_TITLE_2_DTO = IdentifierTitleDto.builder() + public final IdentifierTitleDto IDENTIFIER_1_TITLE_2_DTO = IdentifierTitleDto.builder() .id(IDENTIFIER_1_TITLE_2_ID) .title(IDENTIFIER_1_TITLE_2_TITLE) .titleType(IDENTIFIER_1_TITLE_2_TYPE_DTO) .language(IDENTIFIER_1_TITLE_2_LANG_DTO) .build(); - public static final IdentifierTitleDto IDENTIFIER_1_TITLE_2_DTO_MODIFY = IdentifierTitleDto.builder() + public final IdentifierTitleDto IDENTIFIER_1_TITLE_2_DTO_MODIFY = IdentifierTitleDto.builder() .id(IDENTIFIER_1_TITLE_2_ID) .title(IDENTIFIER_1_TITLE_2_TITLE_MODIFY) .titleType(IDENTIFIER_1_TITLE_2_TYPE_DTO) .language(IDENTIFIER_1_TITLE_2_LANG_DTO) .build(); - public static final SaveIdentifierTitleDto IDENTIFIER_1_TITLE_2_CREATE_DTO = SaveIdentifierTitleDto.builder() + public final 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 static final SaveIdentifierTitleDto IDENTIFIER_1_TITLE_2_UPDATE_DTO = SaveIdentifierTitleDto.builder() + public final 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) .build(); - public static final UUID IDENTIFIER_1_DESCRIPTION_1_ID = UUID.fromString("1c438756-93f0-4797-983c-175a17e18c2c"); - public static final String IDENTIFIER_1_DESCRIPTION_1_DESCRIPTION = "Selecting all from the weather Austrian table"; - public static final String IDENTIFIER_1_DESCRIPTION_1_DESCRIPTION_MODIFY = "Selecting some from the weather Austrian table"; - public static final DescriptionType IDENTIFIER_1_DESCRIPTION_1_TYPE = null; - public static final DescriptionTypeDto IDENTIFIER_1_DESCRIPTION_1_TYPE_DTO = null; - public static final LanguageType IDENTIFIER_1_DESCRIPTION_1_LANG = LanguageType.EN; - public static final LanguageTypeDto IDENTIFIER_1_DESCRIPTION_1_LANG_DTO = LanguageTypeDto.EN; + public final static UUID IDENTIFIER_1_DESCRIPTION_1_ID = UUID.fromString("1c438756-93f0-4797-983c-175a17e18c2c"); + public final static String IDENTIFIER_1_DESCRIPTION_1_DESCRIPTION = "Selecting all from the weather Austrian table"; + public final static String IDENTIFIER_1_DESCRIPTION_1_DESCRIPTION_MODIFY = "Selecting some from the weather Austrian table"; + public final static DescriptionType IDENTIFIER_1_DESCRIPTION_1_TYPE = null; + public final static DescriptionTypeDto IDENTIFIER_1_DESCRIPTION_1_TYPE_DTO = null; + public final static LanguageType IDENTIFIER_1_DESCRIPTION_1_LANG = LanguageType.EN; + public final static LanguageTypeDto IDENTIFIER_1_DESCRIPTION_1_LANG_DTO = LanguageTypeDto.EN; - public static final IdentifierDescription IDENTIFIER_1_DESCRIPTION_1 = IdentifierDescription.builder() + public final IdentifierDescription IDENTIFIER_1_DESCRIPTION_1 = IdentifierDescription.builder() .id(IDENTIFIER_1_DESCRIPTION_1_ID) .description(IDENTIFIER_1_DESCRIPTION_1_DESCRIPTION) .descriptionType(IDENTIFIER_1_DESCRIPTION_1_TYPE) .language(IDENTIFIER_1_DESCRIPTION_1_LANG) .build(); - public static final IdentifierDescriptionDto IDENTIFIER_1_DESCRIPTION_1_DTO = IdentifierDescriptionDto.builder() + public final IdentifierDescriptionDto IDENTIFIER_1_DESCRIPTION_1_DTO = IdentifierDescriptionDto.builder() .id(IDENTIFIER_1_DESCRIPTION_1_ID) .description(IDENTIFIER_1_DESCRIPTION_1_DESCRIPTION) .descriptionType(IDENTIFIER_1_DESCRIPTION_1_TYPE_DTO) .language(IDENTIFIER_1_DESCRIPTION_1_LANG_DTO) .build(); - public static final IdentifierDescriptionDto IDENTIFIER_1_DESCRIPTION_1_DTO_MODIFY = IdentifierDescriptionDto.builder() + public final IdentifierDescriptionDto IDENTIFIER_1_DESCRIPTION_1_DTO_MODIFY = IdentifierDescriptionDto.builder() .id(IDENTIFIER_1_DESCRIPTION_1_ID) .description(IDENTIFIER_1_DESCRIPTION_1_DESCRIPTION_MODIFY) .descriptionType(IDENTIFIER_1_DESCRIPTION_1_TYPE_DTO) .language(IDENTIFIER_1_DESCRIPTION_1_LANG_DTO) .build(); - public static final SaveIdentifierDescriptionDto IDENTIFIER_1_DESCRIPTION_1_CREATE_DTO = SaveIdentifierDescriptionDto.builder() + public final SaveIdentifierDescriptionDto IDENTIFIER_1_DESCRIPTION_1_CREATE_DTO = SaveIdentifierDescriptionDto.builder() .id(null) .description(IDENTIFIER_1_DESCRIPTION_1_DESCRIPTION) .descriptionType(IDENTIFIER_1_DESCRIPTION_1_TYPE_DTO) .language(IDENTIFIER_1_DESCRIPTION_1_LANG_DTO) .build(); - public static final UUID IDENTIFIER_1_CREATOR_1_ID = UUID.fromString("667cd1d6-4f94-4808-b5cb-12e5ec0788d8"); - public static final String IDENTIFIER_1_CREATOR_1_FIRSTNAME = CREATOR_1_FIRSTNAME; - public static final String IDENTIFIER_1_CREATOR_1_LASTNAME = CREATOR_1_LASTNAME; - public static final String IDENTIFIER_1_CREATOR_1_NAME = CREATOR_1_NAME; - public static final String IDENTIFIER_1_CREATOR_1_ORCID = CREATOR_1_ORCID; - public static final NameIdentifierSchemeType IDENTIFIER_1_CREATOR_1_IDENTIFIER_SCHEME_TYPE = NameIdentifierSchemeType.ORCID; - public static final NameIdentifierSchemeTypeDto IDENTIFIER_1_CREATOR_1_IDENTIFIER_SCHEME_TYPE_DTO = NameIdentifierSchemeTypeDto.ORCID; - public static final String IDENTIFIER_1_CREATOR_1_AFFILIATION = CREATOR_1_AFFIL; - public static final String IDENTIFIER_1_CREATOR_1_AFFILIATION_IDENTIFIER = CREATOR_1_AFFIL_ROR; - public static final AffiliationIdentifierSchemeType IDENTIFIER_1_CREATOR_1_AFFILIATION_IDENTIFIER_SCHEME = CREATOR_1_AFFIL_TYPE; - public static final AffiliationIdentifierSchemeTypeDto IDENTIFIER_1_CREATOR_1_AFFILIATION_IDENTIFIER_SCHEME_DTO = CREATOR_1_AFFIL_TYPE_DTO; - public static final String IDENTIFIER_1_CREATOR_1_AFFILIATION_IDENTIFIER_SCHEME_URI = CREATOR_1_AFFIL_URI; - - public static final Creator IDENTIFIER_1_CREATOR_1 = Creator.builder() + public final static UUID IDENTIFIER_1_CREATOR_1_ID = UUID.fromString("667cd1d6-4f94-4808-b5cb-12e5ec0788d8"); + public final static String IDENTIFIER_1_CREATOR_1_FIRSTNAME = CREATOR_1_FIRSTNAME; + public final static String IDENTIFIER_1_CREATOR_1_LASTNAME = CREATOR_1_LASTNAME; + public final static String IDENTIFIER_1_CREATOR_1_NAME = CREATOR_1_NAME; + public final static String IDENTIFIER_1_CREATOR_1_ORCID = CREATOR_1_ORCID; + public final NameIdentifierSchemeType IDENTIFIER_1_CREATOR_1_IDENTIFIER_SCHEME_TYPE = NameIdentifierSchemeType.ORCID; + public final NameIdentifierSchemeTypeDto IDENTIFIER_1_CREATOR_1_IDENTIFIER_SCHEME_TYPE_DTO = NameIdentifierSchemeTypeDto.ORCID; + public final static String IDENTIFIER_1_CREATOR_1_AFFILIATION = CREATOR_1_AFFIL; + public final static String IDENTIFIER_1_CREATOR_1_AFFILIATION_IDENTIFIER = CREATOR_1_AFFIL_ROR; + public final static AffiliationIdentifierSchemeType IDENTIFIER_1_CREATOR_1_AFFILIATION_IDENTIFIER_SCHEME = CREATOR_1_AFFIL_TYPE; + public final static AffiliationIdentifierSchemeTypeDto IDENTIFIER_1_CREATOR_1_AFFILIATION_IDENTIFIER_SCHEME_DTO = CREATOR_1_AFFIL_TYPE_DTO; + public final static String IDENTIFIER_1_CREATOR_1_AFFILIATION_IDENTIFIER_SCHEME_URI = CREATOR_1_AFFIL_URI; + + public final Creator IDENTIFIER_1_CREATOR_1 = Creator.builder() .id(IDENTIFIER_1_CREATOR_1_ID) .firstname(IDENTIFIER_1_CREATOR_1_FIRSTNAME) .lastname(IDENTIFIER_1_CREATOR_1_LASTNAME) @@ -6079,7 +6007,7 @@ public abstract class BaseTest { .affiliationIdentifierSchemeUri(IDENTIFIER_1_CREATOR_1_AFFILIATION_IDENTIFIER_SCHEME_URI) .build(); - public static final CreatorDto IDENTIFIER_1_CREATOR_1_DTO = CreatorDto.builder() + public final CreatorDto IDENTIFIER_1_CREATOR_1_DTO = CreatorDto.builder() .id(IDENTIFIER_1_CREATOR_1_ID) .firstname(IDENTIFIER_1_CREATOR_1_FIRSTNAME) .lastname(IDENTIFIER_1_CREATOR_1_LASTNAME) @@ -6093,7 +6021,7 @@ public abstract class BaseTest { .affiliationIdentifierSchemeUri(IDENTIFIER_1_CREATOR_1_AFFILIATION_IDENTIFIER_SCHEME_URI) .build(); - public static final SaveIdentifierCreatorDto IDENTIFIER_1_CREATOR_1_CREATE_DTO = SaveIdentifierCreatorDto.builder() + public final SaveIdentifierCreatorDto IDENTIFIER_1_CREATOR_1_CREATE_DTO = SaveIdentifierCreatorDto.builder() .id(null) .firstname(IDENTIFIER_1_CREATOR_1_FIRSTNAME) .lastname(IDENTIFIER_1_CREATOR_1_LASTNAME) @@ -6106,15 +6034,15 @@ public abstract class BaseTest { .affiliationIdentifierScheme(IDENTIFIER_1_CREATOR_1_AFFILIATION_IDENTIFIER_SCHEME_DTO) .build(); - public static final UUID FUNDER_1_ID = UUID.fromString("8deb273d-6dd6-407d-970a-01534035ac01"); - public static final String FUNDER_1_NAME = "European Commission"; - public static final String FUNDER_1_IDENTIFIER = "https://doi.org/10.13039/501100000780"; - public static final String FUNDER_1_IDENTIFIER_ID_ONLY = "10.13039/501100000780"; - public static final IdentifierFunderType FUNDER_1_IDENTIFIER_TYPE = IdentifierFunderType.CROSSREF_FUNDER_ID; - public static final IdentifierFunderTypeDto FUNDER_1_IDENTIFIER_TYPE_DTO = IdentifierFunderTypeDto.CROSSREF_FUNDER_ID; - public static final String FUNDER_1_AWARD_TITLE = "Institutionalizing global genetic-resource commons. Global Strategies for accessing and using essential public knowledge assets in the life science"; + public final static UUID FUNDER_1_ID = UUID.fromString("8deb273d-6dd6-407d-970a-01534035ac01"); + public final static String FUNDER_1_NAME = "European Commission"; + public final static String FUNDER_1_IDENTIFIER = "https://doi.org/10.13039/501100000780"; + public final static String FUNDER_1_IDENTIFIER_ID_ONLY = "10.13039/501100000780"; + public final IdentifierFunderType FUNDER_1_IDENTIFIER_TYPE = IdentifierFunderType.CROSSREF_FUNDER_ID; + public final IdentifierFunderTypeDto FUNDER_1_IDENTIFIER_TYPE_DTO = IdentifierFunderTypeDto.CROSSREF_FUNDER_ID; + public final static String FUNDER_1_AWARD_TITLE = "Institutionalizing global genetic-resource commons. Global Strategies for accessing and using essential public knowledge assets in the life science"; - public static final IdentifierFunder IDENTIFIER_1_FUNDER_1 = IdentifierFunder.builder() + public final IdentifierFunder IDENTIFIER_1_FUNDER_1 = IdentifierFunder.builder() .id(FUNDER_1_ID) .funderName(FUNDER_1_NAME) .funderIdentifier(FUNDER_1_IDENTIFIER) @@ -6122,7 +6050,7 @@ public abstract class BaseTest { .awardTitle(FUNDER_1_AWARD_TITLE) .build(); - public static final IdentifierFunderDto IDENTIFIER_1_FUNDER_1_DTO = IdentifierFunderDto.builder() + public final IdentifierFunderDto IDENTIFIER_1_FUNDER_1_DTO = IdentifierFunderDto.builder() .id(FUNDER_1_ID) .funderName(FUNDER_1_NAME) .funderIdentifier(FUNDER_1_IDENTIFIER) @@ -6130,14 +6058,14 @@ public abstract class BaseTest { .awardTitle(FUNDER_1_AWARD_TITLE) .build(); - public static final SaveIdentifierFunderDto IDENTIFIER_1_FUNDER_1_CREATE_DTO = SaveIdentifierFunderDto.builder() + public final SaveIdentifierFunderDto IDENTIFIER_1_FUNDER_1_CREATE_DTO = SaveIdentifierFunderDto.builder() .funderName(FUNDER_1_NAME) .funderIdentifier(FUNDER_1_IDENTIFIER) .funderIdentifierType(FUNDER_1_IDENTIFIER_TYPE_DTO) .awardTitle(FUNDER_1_AWARD_TITLE) .build(); - public static final DataCiteBody<DataCiteDoi> IDENTIFIER_1_DATA_CITE = DataCiteBody.<DataCiteDoi>builder() + public final DataCiteBody<DataCiteDoi> IDENTIFIER_1_DATA_CITE = DataCiteBody.<DataCiteDoi>builder() .data(DataCiteData.<DataCiteDoi>builder() .type("dois") .attributes(DataCiteDoi.builder() @@ -6146,7 +6074,7 @@ public abstract class BaseTest { .build()) .build(); - public static final Identifier IDENTIFIER_1 = Identifier.builder() + public final Identifier IDENTIFIER_1 = Identifier.builder() .id(IDENTIFIER_1_ID) .queryId(QUERY_1_ID) .titles(new LinkedList<>(List.of(IDENTIFIER_1_TITLE_1, IDENTIFIER_1_TITLE_2))) @@ -6173,32 +6101,7 @@ public abstract class BaseTest { .status(IDENTIFIER_1_STATUS_TYPE) .build(); - public static final Identifier IDENTIFIER_1_WITH_DOI = Identifier.builder() - .id(IDENTIFIER_1_ID) - .descriptions(new LinkedList<>(List.of(IDENTIFIER_1_DESCRIPTION_1))) - .titles(new LinkedList<>(List.of(IDENTIFIER_1_TITLE_1, IDENTIFIER_1_TITLE_2))) - .doi(IDENTIFIER_1_DOI) - .database(null /* for jpa */) - .created(IDENTIFIER_1_CREATED) - .lastModified(IDENTIFIER_1_MODIFIED) - .execution(IDENTIFIER_1_EXECUTION) - .publicationYear(IDENTIFIER_1_PUBLICATION_YEAR) - .publicationMonth(IDENTIFIER_1_PUBLICATION_MONTH) - .queryHash(QUERY_1_QUERY_HASH) - .resultHash(QUERY_1_RESULT_HASH) - .query(QUERY_1_STATEMENT) - .queryNormalized(QUERY_1_STATEMENT) - .resultNumber(QUERY_1_RESULT_NUMBER) - .publisher(IDENTIFIER_1_PUBLISHER) - .type(IDENTIFIER_1_TYPE) - .owner(USER_1) - .licenses(new LinkedList<>(List.of(LICENSE_1))) - .creators(new LinkedList<>(List.of(IDENTIFIER_1_CREATOR_1))) - .funders(new LinkedList<>(List.of(IDENTIFIER_1_FUNDER_1))) - .status(IDENTIFIER_1_STATUS_TYPE) - .build(); - - public static final IdentifierDto IDENTIFIER_1_DTO = IdentifierDto.builder() + public final IdentifierDto IDENTIFIER_1_DTO = IdentifierDto.builder() .id(IDENTIFIER_1_ID) .databaseId(DATABASE_1_ID) .links(LinksDto.builder() @@ -6226,7 +6129,7 @@ public abstract class BaseTest { .status(IDENTIFIER_1_STATUS_TYPE_DTO) .build(); - public static final IdentifierBriefDto IDENTIFIER_1_BRIEF_DTO = IdentifierBriefDto.builder() + public final IdentifierBriefDto IDENTIFIER_1_BRIEF_DTO = IdentifierBriefDto.builder() .id(IDENTIFIER_1_ID) .databaseId(DATABASE_1_ID) .titles(new LinkedList<>(List.of(IDENTIFIER_1_TITLE_1_DTO, IDENTIFIER_1_TITLE_2_DTO))) @@ -6237,7 +6140,7 @@ public abstract class BaseTest { .status(IDENTIFIER_1_STATUS_TYPE_DTO) .build(); - public static final CreateIdentifierDto IDENTIFIER_1_CREATE_DTO = CreateIdentifierDto.builder() + public final CreateIdentifierDto IDENTIFIER_1_CREATE_DTO = CreateIdentifierDto.builder() .databaseId(DATABASE_1_ID) .type(IDENTIFIER_1_TYPE_DTO) .publicationYear(IDENTIFIER_1_PUBLICATION_YEAR) @@ -6254,7 +6157,7 @@ public abstract class BaseTest { .funders(new LinkedList<>(List.of(IDENTIFIER_1_FUNDER_1_CREATE_DTO))) .build(); - public static final CreateIdentifierDto IDENTIFIER_1_CREATE_WITH_DOI_DTO = CreateIdentifierDto.builder() + public final CreateIdentifierDto IDENTIFIER_1_CREATE_WITH_DOI_DTO = CreateIdentifierDto.builder() .databaseId(DATABASE_1_ID) .type(IDENTIFIER_1_TYPE_DTO) .doi(IDENTIFIER_1_DOI) @@ -6271,7 +6174,7 @@ public abstract class BaseTest { .funders(new LinkedList<>(List.of(IDENTIFIER_1_FUNDER_1_CREATE_DTO))) .build(); - public static final IdentifierSaveDto IDENTIFIER_1_SAVE_DTO = IdentifierSaveDto.builder() + public final IdentifierSaveDto IDENTIFIER_1_SAVE_DTO = IdentifierSaveDto.builder() .id(IDENTIFIER_1_ID) .databaseId(DATABASE_1_ID) .descriptions(new LinkedList<>(List.of(IDENTIFIER_1_DESCRIPTION_1_CREATE_DTO))) @@ -6286,7 +6189,7 @@ public abstract class BaseTest { .licenses(new LinkedList<>(List.of(LICENSE_1_DTO))) .build(); - public static final IdentifierSaveDto IDENTIFIER_1_SAVE_MODIFY_DTO = IdentifierSaveDto.builder() + public final IdentifierSaveDto IDENTIFIER_1_SAVE_MODIFY_DTO = IdentifierSaveDto.builder() .id(IDENTIFIER_1_ID) .databaseId(DATABASE_1_ID) .descriptions(new LinkedList<>(List.of())) // <<< @@ -6301,84 +6204,83 @@ public abstract class BaseTest { .licenses(new LinkedList<>(List.of())) // <<< .build(); - public static final UUID IDENTIFIER_5_ID = UUID.fromString("e05bb4c9-ed26-48c9-bd91-5c48a93a04bd"); - public static final String IDENTIFIER_5_DOI = "10.12345/13/50BBFCFE08A12"; - public static final Instant IDENTIFIER_5_CREATED = Instant.ofEpochSecond(1641588352L); - public static final Instant IDENTIFIER_5_MODIFIED = Instant.ofEpochSecond(1541588352L); - public static final Instant IDENTIFIER_5_EXECUTION = Instant.ofEpochSecond(1541588352L); - public static final Integer IDENTIFIER_5_PUBLICATION_DAY = 14; - public static final Integer IDENTIFIER_5_PUBLICATION_MONTH = 7; - public static final Integer IDENTIFIER_5_PUBLICATION_YEAR = 2022; - public static final String IDENTIFIER_5_QUERY_HASH = QUERY_2_QUERY_HASH; - public static final String IDENTIFIER_5_RESULT_HASH = QUERY_2_RESULT_HASH; - public static final String IDENTIFIER_5_QUERY = QUERY_2_STATEMENT; - public static final String IDENTIFIER_5_NORMALIZED = QUERY_2_STATEMENT; - public static final Long IDENTIFIER_5_RESULT_NUMBER = QUERY_2_RESULT_NUMBER; - public static final String IDENTIFIER_5_PUBLISHER = "Australian Government"; - public static final IdentifierType IDENTIFIER_5_TYPE = IdentifierType.SUBSET; - public static final IdentifierTypeDto IDENTIFIER_5_TYPE_DTO = IdentifierTypeDto.SUBSET; - public static final IdentifierStatusType IDENTIFIER_5_STATUS_TYPE = IdentifierStatusType.DRAFT; - public static final IdentifierStatusTypeDto IDENTIFIER_5_STATUS_TYPE_DTO = IdentifierStatusTypeDto.DRAFT; - public static final UUID IDENTIFIER_5_CREATED_BY = USER_2_ID; - - public static final UUID IDENTIFIER_5_TITLE_1_ID = UUID.fromString("1a0ae9c2-61c6-44f8-b886-26a4f4dabc52"); - public static final String IDENTIFIER_5_TITLE_1_TITLE = "Australische Wetterdaten"; - public static final LanguageType IDENTIFIER_5_TITLE_1_LANG = LanguageType.DE; - public static final LanguageTypeDto IDENTIFIER_5_TITLE_1_LANG_DTO = LanguageTypeDto.DE; - public static final TitleType IDENTIFIER_5_TITLE_1_TYPE = TitleType.SUBTITLE; - public static final TitleTypeDto IDENTIFIER_5_TITLE_1_TYPE_DTO = TitleTypeDto.SUBTITLE; - - public static final IdentifierTitle IDENTIFIER_5_TITLE_1 = IdentifierTitle.builder() + public final static UUID IDENTIFIER_5_ID = UUID.fromString("e05bb4c9-ed26-48c9-bd91-5c48a93a04bd"); + public final static String IDENTIFIER_5_DOI = "10.12345/13/50BBFCFE08A12"; + public final static Instant IDENTIFIER_5_CREATED = Instant.ofEpochSecond(1641588352L); + public final static Instant IDENTIFIER_5_MODIFIED = Instant.ofEpochSecond(1541588352L); + public final static Instant IDENTIFIER_5_EXECUTION = Instant.ofEpochSecond(1541588352L); + public final static Integer IDENTIFIER_5_PUBLICATION_DAY = 14; + public final static Integer IDENTIFIER_5_PUBLICATION_MONTH = 7; + public final static Integer IDENTIFIER_5_PUBLICATION_YEAR = 2022; + public final static String IDENTIFIER_5_QUERY_HASH = QUERY_2_QUERY_HASH; + public final static String IDENTIFIER_5_RESULT_HASH = QUERY_2_RESULT_HASH; + public final static String IDENTIFIER_5_QUERY = QUERY_2_STATEMENT; + public final static String IDENTIFIER_5_NORMALIZED = QUERY_2_STATEMENT; + public final static Long IDENTIFIER_5_RESULT_NUMBER = QUERY_2_RESULT_NUMBER; + public final static String IDENTIFIER_5_PUBLISHER = "Australian Government"; + public final static IdentifierType IDENTIFIER_5_TYPE = IdentifierType.SUBSET; + public final static IdentifierTypeDto IDENTIFIER_5_TYPE_DTO = IdentifierTypeDto.SUBSET; + public final static IdentifierStatusType IDENTIFIER_5_STATUS_TYPE = IdentifierStatusType.DRAFT; + public final static IdentifierStatusTypeDto IDENTIFIER_5_STATUS_TYPE_DTO = IdentifierStatusTypeDto.DRAFT; + + public final static UUID IDENTIFIER_5_TITLE_1_ID = UUID.fromString("1a0ae9c2-61c6-44f8-b886-26a4f4dabc52"); + public final static String IDENTIFIER_5_TITLE_1_TITLE = "Australische Wetterdaten"; + public final static LanguageType IDENTIFIER_5_TITLE_1_LANG = LanguageType.DE; + public final static LanguageTypeDto IDENTIFIER_5_TITLE_1_LANG_DTO = LanguageTypeDto.DE; + public final static TitleType IDENTIFIER_5_TITLE_1_TYPE = TitleType.SUBTITLE; + public final static TitleTypeDto IDENTIFIER_5_TITLE_1_TYPE_DTO = TitleTypeDto.SUBTITLE; + + public final IdentifierTitle IDENTIFIER_5_TITLE_1 = IdentifierTitle.builder() .id(IDENTIFIER_5_TITLE_1_ID) .title(IDENTIFIER_5_TITLE_1_TITLE) .language(IDENTIFIER_5_TITLE_1_LANG) .titleType(IDENTIFIER_5_TITLE_1_TYPE) .build(); - public static final IdentifierTitleDto IDENTIFIER_5_TITLE_1_DTO = IdentifierTitleDto.builder() + public final IdentifierTitleDto IDENTIFIER_5_TITLE_1_DTO = IdentifierTitleDto.builder() .id(IDENTIFIER_5_TITLE_1_ID) .title(IDENTIFIER_5_TITLE_1_TITLE) .language(IDENTIFIER_5_TITLE_1_LANG_DTO) .titleType(IDENTIFIER_5_TITLE_1_TYPE_DTO) .build(); - public static final SaveIdentifierTitleDto IDENTIFIER_5_TITLE_1_CREATE_DTO = SaveIdentifierTitleDto.builder() + public final 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) .build(); - public static final UUID IDENTIFIER_5_DESCRIPTION_1_ID = UUID.fromString("ab49bdca-f373-4823-9947-2a0cbfa88350"); - public static final String IDENTIFIER_5_DESCRIPTION_1_DESCRIPTION = "Alle Wetterdaten in Australien"; - public static final LanguageType IDENTIFIER_5_DESCRIPTION_1_LANG = LanguageType.DE; - public static final LanguageTypeDto IDENTIFIER_5_DESCRIPTION_1_LANG_DTO = LanguageTypeDto.DE; - public static final DescriptionType IDENTIFIER_5_DESCRIPTION_1_TYPE = DescriptionType.ABSTRACT; - public static final DescriptionTypeDto IDENTIFIER_5_DESCRIPTION_1_TYPE_DTO = DescriptionTypeDto.ABSTRACT; + public final static UUID IDENTIFIER_5_DESCRIPTION_1_ID = UUID.fromString("ab49bdca-f373-4823-9947-2a0cbfa88350"); + public final static String IDENTIFIER_5_DESCRIPTION_1_DESCRIPTION = "Alle Wetterdaten in Australien"; + public final static LanguageType IDENTIFIER_5_DESCRIPTION_1_LANG = LanguageType.DE; + public final static LanguageTypeDto IDENTIFIER_5_DESCRIPTION_1_LANG_DTO = LanguageTypeDto.DE; + public final static DescriptionType IDENTIFIER_5_DESCRIPTION_1_TYPE = DescriptionType.ABSTRACT; + public final static DescriptionTypeDto IDENTIFIER_5_DESCRIPTION_1_TYPE_DTO = DescriptionTypeDto.ABSTRACT; - public static final IdentifierDescription IDENTIFIER_5_DESCRIPTION_1 = IdentifierDescription.builder() + public final IdentifierDescription IDENTIFIER_5_DESCRIPTION_1 = IdentifierDescription.builder() .id(IDENTIFIER_5_DESCRIPTION_1_ID) .description(IDENTIFIER_5_DESCRIPTION_1_DESCRIPTION) .language(IDENTIFIER_5_DESCRIPTION_1_LANG) .descriptionType(IDENTIFIER_5_DESCRIPTION_1_TYPE) .build(); - public static final IdentifierDescriptionDto IDENTIFIER_5_DESCRIPTION_1_DTO = IdentifierDescriptionDto.builder() + public final IdentifierDescriptionDto IDENTIFIER_5_DESCRIPTION_1_DTO = IdentifierDescriptionDto.builder() .id(IDENTIFIER_5_DESCRIPTION_1_ID) .description(IDENTIFIER_5_DESCRIPTION_1_DESCRIPTION) .language(IDENTIFIER_5_DESCRIPTION_1_LANG_DTO) .descriptionType(IDENTIFIER_5_DESCRIPTION_1_TYPE_DTO) .build(); - public static final SaveIdentifierDescriptionDto IDENTIFIER_5_DESCRIPTION_1_CREATE_DTO = SaveIdentifierDescriptionDto.builder() + public final SaveIdentifierDescriptionDto IDENTIFIER_5_DESCRIPTION_1_CREATE_DTO = SaveIdentifierDescriptionDto.builder() .id(null) .description(IDENTIFIER_5_DESCRIPTION_1_DESCRIPTION) .language(IDENTIFIER_5_DESCRIPTION_1_LANG_DTO) .descriptionType(IDENTIFIER_5_DESCRIPTION_1_TYPE_DTO) .build(); - public static final UUID IDENTIFIER_5_CREATOR_1_ID = UUID.fromString("6844b684-93e4-47d2-a615-5939127fdafe"); + public final static UUID IDENTIFIER_5_CREATOR_1_ID = UUID.fromString("6844b684-93e4-47d2-a615-5939127fdafe"); - public static final Creator IDENTIFIER_5_CREATOR_1 = Creator.builder() + public final Creator IDENTIFIER_5_CREATOR_1 = Creator.builder() .id(IDENTIFIER_5_CREATOR_1_ID) .firstname(CREATOR_1_FIRSTNAME) .lastname(CREATOR_1_LASTNAME) @@ -6391,7 +6293,7 @@ public abstract class BaseTest { .affiliationIdentifierSchemeUri(CREATOR_1_AFFIL_URI) .build(); - public static final CreatorDto IDENTIFIER_5_CREATOR_1_DTO = CreatorDto.builder() + public final CreatorDto IDENTIFIER_5_CREATOR_1_DTO = CreatorDto.builder() .id(IDENTIFIER_5_CREATOR_1_ID) .firstname(CREATOR_1_FIRSTNAME) .lastname(CREATOR_1_LASTNAME) @@ -6404,7 +6306,7 @@ public abstract class BaseTest { .affiliationIdentifierSchemeUri(CREATOR_1_AFFIL_URI) .build(); - public static final SaveIdentifierCreatorDto IDENTIFIER_5_CREATOR_1_CREATE_DTO = SaveIdentifierCreatorDto.builder() + public final SaveIdentifierCreatorDto IDENTIFIER_5_CREATOR_1_CREATE_DTO = SaveIdentifierCreatorDto.builder() .firstname(CREATOR_1_FIRSTNAME) .lastname(CREATOR_1_LASTNAME) .creatorName(CREATOR_1_NAME) @@ -6413,7 +6315,7 @@ public abstract class BaseTest { .affiliation(CREATOR_1_AFFIL) .build(); - public static final SaveIdentifierCreatorDto IDENTIFIER_5_CREATOR_1_MODIFY_DTO = SaveIdentifierCreatorDto.builder() + public final SaveIdentifierCreatorDto IDENTIFIER_5_CREATOR_1_MODIFY_DTO = SaveIdentifierCreatorDto.builder() .firstname(CREATOR_1_FIRSTNAME) .lastname(CREATOR_1_LASTNAME) .creatorName(CREATOR_1_NAME) @@ -6422,9 +6324,9 @@ public abstract class BaseTest { .affiliation(CREATOR_1_AFFIL) .build(); - public static final UUID IDENTIFIER_5_CREATOR_2_ID = UUID.fromString("14943ad6-a935-49f5-b07e-f9eb789b8604"); + public final static UUID IDENTIFIER_5_CREATOR_2_ID = UUID.fromString("14943ad6-a935-49f5-b07e-f9eb789b8604"); - public static final Creator IDENTIFIER_5_CREATOR_2 = Creator.builder() + public final Creator IDENTIFIER_5_CREATOR_2 = Creator.builder() .id(IDENTIFIER_5_CREATOR_2_ID) .firstname(CREATOR_2_FIRSTNAME) .lastname(CREATOR_2_LASTNAME) @@ -6434,7 +6336,7 @@ public abstract class BaseTest { .affiliation(CREATOR_2_AFFIL) .build(); - public static final CreatorDto IDENTIFIER_5_CREATOR_2_DTO = CreatorDto.builder() + public final CreatorDto IDENTIFIER_5_CREATOR_2_DTO = CreatorDto.builder() .id(IDENTIFIER_5_CREATOR_2_ID) .firstname(CREATOR_2_FIRSTNAME) .lastname(CREATOR_2_LASTNAME) @@ -6444,7 +6346,7 @@ public abstract class BaseTest { .affiliation(CREATOR_2_AFFIL) .build(); - public static final SaveIdentifierCreatorDto IDENTIFIER_5_CREATOR_2_CREATE_DTO = SaveIdentifierCreatorDto.builder() + public final SaveIdentifierCreatorDto IDENTIFIER_5_CREATOR_2_CREATE_DTO = SaveIdentifierCreatorDto.builder() .firstname(CREATOR_2_FIRSTNAME) .lastname(CREATOR_2_LASTNAME) .creatorName(CREATOR_2_NAME) @@ -6453,7 +6355,7 @@ public abstract class BaseTest { .affiliation(CREATOR_2_AFFIL) .build(); - public static final SaveIdentifierCreatorDto IDENTIFIER_5_CREATOR_2_MODIFY_DTO = SaveIdentifierCreatorDto.builder() + public final SaveIdentifierCreatorDto IDENTIFIER_5_CREATOR_2_MODIFY_DTO = SaveIdentifierCreatorDto.builder() .firstname(CREATOR_2_FIRSTNAME) .lastname(CREATOR_2_LASTNAME) .creatorName(CREATOR_2_NAME) @@ -6462,7 +6364,7 @@ public abstract class BaseTest { .affiliation(CREATOR_2_AFFIL) .build(); - public static final Identifier IDENTIFIER_5 = Identifier.builder() + public final Identifier IDENTIFIER_5 = Identifier.builder() .id(IDENTIFIER_5_ID) .queryId(QUERY_2_ID) .database(null) /* DATABASE_2 */ @@ -6488,7 +6390,7 @@ public abstract class BaseTest { .status(IDENTIFIER_5_STATUS_TYPE) .build(); - public static final IdentifierDto IDENTIFIER_5_DTO = IdentifierDto.builder() + public final IdentifierDto IDENTIFIER_5_DTO = IdentifierDto.builder() .id(IDENTIFIER_5_ID) .databaseId(DATABASE_2_ID) .queryId(QUERY_2_ID) @@ -6496,6 +6398,7 @@ public abstract class BaseTest { .self("/api/identifier/" + IDENTIFIER_5_ID) .selfHtml("/pid/" + IDENTIFIER_5_ID) .data("/api/database/" + DATABASE_2_ID + "/subset/" + QUERY_2_ID + "/data") + .dashboardHtml("/d/" + DATABASE_2_DASHBOARD_UID) .build()) .descriptions(new LinkedList<>(List.of(IDENTIFIER_5_DESCRIPTION_1_DTO))) .titles(new LinkedList<>(List.of(IDENTIFIER_5_TITLE_1_DTO))) @@ -6516,7 +6419,7 @@ public abstract class BaseTest { .creators(new LinkedList<>(List.of(IDENTIFIER_5_CREATOR_1_DTO, IDENTIFIER_5_CREATOR_2_DTO))) .build(); - public static final IdentifierBriefDto IDENTIFIER_5_BRIEF_DTO = IdentifierBriefDto.builder() + public final IdentifierBriefDto IDENTIFIER_5_BRIEF_DTO = IdentifierBriefDto.builder() .id(IDENTIFIER_5_ID) .databaseId(DATABASE_2_ID) .queryId(QUERY_2_ID) @@ -6527,14 +6430,14 @@ public abstract class BaseTest { .type(IDENTIFIER_5_TYPE_DTO) .build(); - public static final UUID RELATED_IDENTIFIER_5_ID = UUID.fromString("26545877-574d-44fa-819d-d9d9a9750b38"); - public static final String RELATED_IDENTIFIER_5_VALUE = "10.5281/zenodo.6637333"; - public static final RelatedType RELATED_IDENTIFIER_5_TYPE = RelatedType.DOI; - public static final RelatedTypeDto RELATED_IDENTIFIER_5_TYPE_DTO = RelatedTypeDto.DOI; - public static final RelationType RELATED_IDENTIFIER_5_RELATION_TYPE = RelationType.CITES; - public static final RelationTypeDto RELATED_IDENTIFIER_5_RELATION_TYPE_DTO = RelationTypeDto.CITES; + public final static UUID RELATED_IDENTIFIER_5_ID = UUID.fromString("26545877-574d-44fa-819d-d9d9a9750b38"); + public final static String RELATED_IDENTIFIER_5_VALUE = "10.5281/zenodo.6637333"; + public final RelatedType RELATED_IDENTIFIER_5_TYPE = RelatedType.DOI; + public final RelatedTypeDto RELATED_IDENTIFIER_5_TYPE_DTO = RelatedTypeDto.DOI; + public final RelationType RELATED_IDENTIFIER_5_RELATION_TYPE = RelationType.CITES; + public final RelationTypeDto RELATED_IDENTIFIER_5_RELATION_TYPE_DTO = RelationTypeDto.CITES; - public static final RelatedIdentifier IDENTIFIER_1_RELATED_IDENTIFIER_1 = RelatedIdentifier.builder() + public final RelatedIdentifier IDENTIFIER_1_RELATED_IDENTIFIER_1 = RelatedIdentifier.builder() .id(RELATED_IDENTIFIER_5_ID) .identifier(IDENTIFIER_5) .type(RELATED_IDENTIFIER_5_TYPE) @@ -6542,19 +6445,19 @@ public abstract class BaseTest { .value(RELATED_IDENTIFIER_5_VALUE) .build(); - public static final SaveRelatedIdentifierDto IDENTIFIER_1_RELATED_IDENTIFIER_5_CREATE_DTO = SaveRelatedIdentifierDto.builder() + public final 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 static final CreateIdentifierDto IDENTIFIER_5_CREATE_DTO = CreateIdentifierDto.builder() + public final CreateIdentifierDto IDENTIFIER_5_CREATE_DTO = CreateIdentifierDto.builder() .databaseId(DATABASE_2_ID) .publicationYear(IDENTIFIER_5_PUBLICATION_YEAR) .publisher(IDENTIFIER_5_PUBLISHER) .build(); - public static final IdentifierSaveDto IDENTIFIER_5_SAVE_DTO = IdentifierSaveDto.builder() + public final IdentifierSaveDto IDENTIFIER_5_SAVE_DTO = IdentifierSaveDto.builder() .id(IDENTIFIER_5_ID) .queryId(QUERY_2_ID) .databaseId(DATABASE_2_ID) @@ -6570,87 +6473,87 @@ public abstract class BaseTest { .type(IDENTIFIER_5_TYPE_DTO) .build(); - public static final UUID IDENTIFIER_6_ID = UUID.fromString("a244204d-9671-42a0-be07-9b14402238fd"); - public static final String IDENTIFIER_6_DOI = null; - public static final Instant IDENTIFIER_6_CREATED = Instant.ofEpochSecond(1641588352L); - public static final Instant IDENTIFIER_6_MODIFIED = Instant.ofEpochSecond(1541588352L); - public static final Instant IDENTIFIER_6_EXECUTION = Instant.ofEpochSecond(1541588352L); - public static final Integer IDENTIFIER_6_PUBLICATION_DAY = 14; - public static final Integer IDENTIFIER_6_PUBLICATION_MONTH = 7; - public static final Integer IDENTIFIER_6_PUBLICATION_YEAR = 2022; - public static final String IDENTIFIER_6_QUERY_HASH = QUERY_3_QUERY_HASH; - public static final String IDENTIFIER_6_RESULT_HASH = QUERY_3_RESULT_HASH; - public static final String IDENTIFIER_6_QUERY = QUERY_3_STATEMENT; - public static final String IDENTIFIER_6_NORMALIZED = QUERY_3_STATEMENT; - public static final Long IDENTIFIER_6_RESULT_NUMBER = QUERY_3_RESULT_NUMBER; - public static final String IDENTIFIER_6_PUBLISHER = "Norwegian Government"; - public static final IdentifierType IDENTIFIER_6_TYPE = IdentifierType.SUBSET; - public static final IdentifierTypeDto IDENTIFIER_6_TYPE_DTO = IdentifierTypeDto.SUBSET; - public static final IdentifierStatusType IDENTIFIER_6_STATUS_TYPE = IdentifierStatusType.PUBLISHED; - public static final IdentifierStatusTypeDto IDENTIFIER_6_STATUS_TYPE_DTO = IdentifierStatusTypeDto.PUBLISHED; - - public static final UUID IDENTIFIER_6_TITLE_1_ID = UUID.fromString("0449011c-1490-4c8e-b46c-c1f862126aea"); - public static final String IDENTIFIER_6_TITLE_1_TITLE = "Norwegian weather data"; - public static final String IDENTIFIER_6_TITLE_1_TITLE_MODIFY = "Norwegian weather some data"; - public static final LanguageType IDENTIFIER_6_TITLE_1_LANG = LanguageType.EN; - public static final LanguageTypeDto IDENTIFIER_6_TITLE_1_LANG_DTO = LanguageTypeDto.EN; - - public static final IdentifierTitle IDENTIFIER_6_TITLE_1 = IdentifierTitle.builder() + public final static UUID IDENTIFIER_6_ID = UUID.fromString("a244204d-9671-42a0-be07-9b14402238fd"); + public final static String IDENTIFIER_6_DOI = null; + public final static Instant IDENTIFIER_6_CREATED = Instant.ofEpochSecond(1641588352L); + public final static Instant IDENTIFIER_6_MODIFIED = Instant.ofEpochSecond(1541588352L); + public final static Instant IDENTIFIER_6_EXECUTION = Instant.ofEpochSecond(1541588352L); + public final static Integer IDENTIFIER_6_PUBLICATION_DAY = 14; + public final static Integer IDENTIFIER_6_PUBLICATION_MONTH = 7; + public final static Integer IDENTIFIER_6_PUBLICATION_YEAR = 2022; + public final static String IDENTIFIER_6_QUERY_HASH = QUERY_3_QUERY_HASH; + public final static String IDENTIFIER_6_RESULT_HASH = QUERY_3_RESULT_HASH; + public final static String IDENTIFIER_6_QUERY = QUERY_3_STATEMENT; + public final static String IDENTIFIER_6_NORMALIZED = QUERY_3_STATEMENT; + public final static Long IDENTIFIER_6_RESULT_NUMBER = QUERY_3_RESULT_NUMBER; + public final static String IDENTIFIER_6_PUBLISHER = "Norwegian Government"; + public final static IdentifierType IDENTIFIER_6_TYPE = IdentifierType.SUBSET; + public final static IdentifierTypeDto IDENTIFIER_6_TYPE_DTO = IdentifierTypeDto.SUBSET; + public final static IdentifierStatusType IDENTIFIER_6_STATUS_TYPE = IdentifierStatusType.PUBLISHED; + public final static IdentifierStatusTypeDto IDENTIFIER_6_STATUS_TYPE_DTO = IdentifierStatusTypeDto.PUBLISHED; + + public final static UUID IDENTIFIER_6_TITLE_1_ID = UUID.fromString("0449011c-1490-4c8e-b46c-c1f862126aea"); + public final static String IDENTIFIER_6_TITLE_1_TITLE = "Norwegian weather data"; + public final static String IDENTIFIER_6_TITLE_1_TITLE_MODIFY = "Norwegian weather some data"; + public final static LanguageType IDENTIFIER_6_TITLE_1_LANG = LanguageType.EN; + public final static LanguageTypeDto IDENTIFIER_6_TITLE_1_LANG_DTO = LanguageTypeDto.EN; + + public final IdentifierTitle IDENTIFIER_6_TITLE_1 = IdentifierTitle.builder() .id(IDENTIFIER_6_TITLE_1_ID) .title(IDENTIFIER_6_TITLE_1_TITLE) .language(IDENTIFIER_6_TITLE_1_LANG) .build(); - public static final IdentifierTitleDto IDENTIFIER_6_TITLE_1_DTO = IdentifierTitleDto.builder() + public final IdentifierTitleDto IDENTIFIER_6_TITLE_1_DTO = IdentifierTitleDto.builder() .id(IDENTIFIER_6_TITLE_1_ID) .title(IDENTIFIER_6_TITLE_1_TITLE) .language(IDENTIFIER_6_TITLE_1_LANG_DTO) .build(); - public static final IdentifierTitleDto IDENTIFIER_6_TITLE_1_DTO_MODIFY = IdentifierTitleDto.builder() + public final IdentifierTitleDto IDENTIFIER_6_TITLE_1_DTO_MODIFY = IdentifierTitleDto.builder() .id(IDENTIFIER_6_TITLE_1_ID) .title(IDENTIFIER_6_TITLE_1_TITLE_MODIFY) .language(IDENTIFIER_6_TITLE_1_LANG_DTO) .build(); - public static final SaveIdentifierTitleDto IDENTIFIER_6_TITLE_1_CREATE_DTO = SaveIdentifierTitleDto.builder() + public final SaveIdentifierTitleDto IDENTIFIER_6_TITLE_1_CREATE_DTO = SaveIdentifierTitleDto.builder() .title(IDENTIFIER_6_TITLE_1_TITLE_MODIFY) .language(IDENTIFIER_6_TITLE_1_LANG_DTO) .build(); - public static final UUID IDENTIFIER_6_DESCRIPTION_1_ID = UUID.fromString("aac03bbd-27e6-419d-8118-f996d594f00f"); - public static final String IDENTIFIER_6_DESCRIPTION_1_DESCRIPTION = "Selecting all from the weather Norwegian table"; - public static final String IDENTIFIER_6_DESCRIPTION_1_DESCRIPTION_MODIFY = "Selecting some from the weather Norwegian table"; - public static final LanguageType IDENTIFIER_6_DESCRIPTION_1_LANG = LanguageType.EN; - public static final LanguageTypeDto IDENTIFIER_6_DESCRIPTION_1_LANG_DTO = LanguageTypeDto.EN; + public final static UUID IDENTIFIER_6_DESCRIPTION_1_ID = UUID.fromString("aac03bbd-27e6-419d-8118-f996d594f00f"); + public final static String IDENTIFIER_6_DESCRIPTION_1_DESCRIPTION = "Selecting all from the weather Norwegian table"; + public final static String IDENTIFIER_6_DESCRIPTION_1_DESCRIPTION_MODIFY = "Selecting some from the weather Norwegian table"; + public final static LanguageType IDENTIFIER_6_DESCRIPTION_1_LANG = LanguageType.EN; + public final static LanguageTypeDto IDENTIFIER_6_DESCRIPTION_1_LANG_DTO = LanguageTypeDto.EN; - public static final IdentifierDescription IDENTIFIER_6_DESCRIPTION_1 = IdentifierDescription.builder() + public final IdentifierDescription IDENTIFIER_6_DESCRIPTION_1 = IdentifierDescription.builder() .id(IDENTIFIER_6_DESCRIPTION_1_ID) .description(IDENTIFIER_6_DESCRIPTION_1_DESCRIPTION) .language(IDENTIFIER_6_DESCRIPTION_1_LANG) .build(); - public static final IdentifierDescriptionDto IDENTIFIER_6_DESCRIPTION_1_DTO = IdentifierDescriptionDto.builder() + public final IdentifierDescriptionDto IDENTIFIER_6_DESCRIPTION_1_DTO = IdentifierDescriptionDto.builder() .id(IDENTIFIER_6_DESCRIPTION_1_ID) .description(IDENTIFIER_6_DESCRIPTION_1_DESCRIPTION) .language(IDENTIFIER_6_DESCRIPTION_1_LANG_DTO) .build(); - public static final IdentifierDescriptionDto IDENTIFIER_6_DESCRIPTION_1_DTO_MODIFY = IdentifierDescriptionDto.builder() + public final IdentifierDescriptionDto IDENTIFIER_6_DESCRIPTION_1_DTO_MODIFY = IdentifierDescriptionDto.builder() .id(IDENTIFIER_6_DESCRIPTION_1_ID) .description(IDENTIFIER_6_DESCRIPTION_1_DESCRIPTION_MODIFY) .language(IDENTIFIER_6_DESCRIPTION_1_LANG_DTO) .build(); - public static final SaveIdentifierDescriptionDto IDENTIFIER_6_DESCRIPTION_1_CREATE_DTO = SaveIdentifierDescriptionDto.builder() + public final 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) .build(); - private final static UUID IDENTIFIER_6_CREATOR_1_ID = UUID.fromString("f8a52dca-8aec-46c1-b0e1-603dbe6a1a65"); + public final static UUID IDENTIFIER_6_CREATOR_1_ID = UUID.fromString("f8a52dca-8aec-46c1-b0e1-603dbe6a1a65"); - public static final Creator IDENTIFIER_6_CREATOR_1 = Creator.builder() + public final Creator IDENTIFIER_6_CREATOR_1 = Creator.builder() .id(IDENTIFIER_6_CREATOR_1_ID) .firstname(CREATOR_1_FIRSTNAME) .lastname(CREATOR_1_LASTNAME) @@ -6663,7 +6566,7 @@ public abstract class BaseTest { .affiliationIdentifierSchemeUri(CREATOR_1_AFFIL_URI) .build(); - public static final CreatorDto IDENTIFIER_6_CREATOR_1_DTO = CreatorDto.builder() + public final CreatorDto IDENTIFIER_6_CREATOR_1_DTO = CreatorDto.builder() .id(IDENTIFIER_6_CREATOR_1_ID) .firstname(CREATOR_1_FIRSTNAME) .lastname(CREATOR_1_LASTNAME) @@ -6676,7 +6579,7 @@ public abstract class BaseTest { .affiliationIdentifierSchemeUri(CREATOR_1_AFFIL_URI) .build(); - public static final SaveIdentifierCreatorDto IDENTIFIER_6_CREATOR_1_CREATE_DTO = SaveIdentifierCreatorDto.builder() + public final SaveIdentifierCreatorDto IDENTIFIER_6_CREATOR_1_CREATE_DTO = SaveIdentifierCreatorDto.builder() .firstname(CREATOR_1_FIRSTNAME) .lastname(CREATOR_1_LASTNAME) .creatorName(CREATOR_1_NAME) @@ -6687,7 +6590,7 @@ public abstract class BaseTest { .affiliationIdentifierScheme(CREATOR_1_AFFIL_TYPE_DTO) .build(); - public static final SaveIdentifierCreatorDto IDENTIFIER_6_CREATOR_1_MODIFY_DTO = SaveIdentifierCreatorDto.builder() + public final SaveIdentifierCreatorDto IDENTIFIER_6_CREATOR_1_MODIFY_DTO = SaveIdentifierCreatorDto.builder() .firstname(CREATOR_1_FIRSTNAME) .lastname(CREATOR_1_LASTNAME) .creatorName(CREATOR_1_NAME) @@ -6698,9 +6601,9 @@ public abstract class BaseTest { .affiliationIdentifierScheme(CREATOR_1_AFFIL_TYPE_DTO) .build(); - private final static UUID IDENTIFIER_6_CREATOR_2_ID = UUID.fromString("eeae78cb-75a1-42e2-b608-7082e5fbecc6"); + public final static UUID IDENTIFIER_6_CREATOR_2_ID = UUID.fromString("eeae78cb-75a1-42e2-b608-7082e5fbecc6"); - public static final Creator IDENTIFIER_6_CREATOR_2 = Creator.builder() + public final Creator IDENTIFIER_6_CREATOR_2 = Creator.builder() .id(IDENTIFIER_6_CREATOR_2_ID) .firstname(CREATOR_2_FIRSTNAME) .lastname(CREATOR_2_LASTNAME) @@ -6710,7 +6613,7 @@ public abstract class BaseTest { .affiliation(CREATOR_2_AFFIL) .build(); - public static final CreatorDto IDENTIFIER_6_CREATOR_2_DTO = CreatorDto.builder() + public final CreatorDto IDENTIFIER_6_CREATOR_2_DTO = CreatorDto.builder() .id(IDENTIFIER_6_CREATOR_2_ID) .firstname(CREATOR_2_FIRSTNAME) .lastname(CREATOR_2_LASTNAME) @@ -6720,9 +6623,9 @@ public abstract class BaseTest { .affiliation(CREATOR_2_AFFIL) .build(); - private final static UUID IDENTIFIER_6_CREATOR_3_ID = UUID.fromString("700058f1-6314-4cd1-9c0c-62e75c8f422b"); + public final static UUID IDENTIFIER_6_CREATOR_3_ID = UUID.fromString("700058f1-6314-4cd1-9c0c-62e75c8f422b"); - public static final Creator IDENTIFIER_6_CREATOR_3 = Creator.builder() + public final Creator IDENTIFIER_6_CREATOR_3 = Creator.builder() .id(IDENTIFIER_6_CREATOR_3_ID) .firstname(CREATOR_3_FIRSTNAME) .lastname(CREATOR_3_LASTNAME) @@ -6735,7 +6638,7 @@ public abstract class BaseTest { .affiliationIdentifierSchemeUri(CREATOR_3_AFFIL_URI) .build(); - public static final CreatorDto IDENTIFIER_6_CREATOR_3_DTO = CreatorDto.builder() + public final CreatorDto IDENTIFIER_6_CREATOR_3_DTO = CreatorDto.builder() .id(IDENTIFIER_6_CREATOR_3_ID) .firstname(CREATOR_3_FIRSTNAME) .lastname(CREATOR_3_LASTNAME) @@ -6748,7 +6651,7 @@ public abstract class BaseTest { .affiliationIdentifierSchemeUri(CREATOR_3_AFFIL_URI) .build(); - public static final Identifier IDENTIFIER_6 = Identifier.builder() + public final Identifier IDENTIFIER_6 = Identifier.builder() .id(IDENTIFIER_6_ID) .queryId(QUERY_3_ID) .descriptions(new LinkedList<>(List.of(IDENTIFIER_6_DESCRIPTION_1))) @@ -6774,7 +6677,7 @@ public abstract class BaseTest { .status(IDENTIFIER_6_STATUS_TYPE) .build(); - public static final IdentifierDto IDENTIFIER_6_DTO = IdentifierDto.builder() + public final IdentifierDto IDENTIFIER_6_DTO = IdentifierDto.builder() .id(IDENTIFIER_6_ID) .databaseId(DATABASE_3_ID) .queryId(QUERY_3_ID) @@ -6782,6 +6685,7 @@ public abstract class BaseTest { .self("/api/identifier/" + IDENTIFIER_6_ID) .selfHtml("/pid/" + IDENTIFIER_6_ID) .data("/api/database/" + DATABASE_3_ID + "/subset/" + QUERY_3_ID + "/data") + .dashboardHtml("/d/" + DATABASE_3_DASHBOARD_UID) .build()) .descriptions(new LinkedList<>(List.of(IDENTIFIER_6_DESCRIPTION_1_DTO))) .titles(new LinkedList<>(List.of(IDENTIFIER_6_TITLE_1_DTO))) @@ -6804,7 +6708,7 @@ public abstract class BaseTest { .build(); - public static final IdentifierBriefDto IDENTIFIER_6_BRIEF_DTO = IdentifierBriefDto.builder() + public final IdentifierBriefDto IDENTIFIER_6_BRIEF_DTO = IdentifierBriefDto.builder() .id(IDENTIFIER_6_ID) .databaseId(DATABASE_3_ID) .queryId(QUERY_3_ID) @@ -6816,13 +6720,13 @@ public abstract class BaseTest { .status(IDENTIFIER_6_STATUS_TYPE_DTO) .build(); - public static final CreateIdentifierDto IDENTIFIER_6_CREATE_DTO = CreateIdentifierDto.builder() + public final CreateIdentifierDto IDENTIFIER_6_CREATE_DTO = CreateIdentifierDto.builder() .databaseId(DATABASE_3_ID) .publicationYear(IDENTIFIER_6_PUBLICATION_YEAR) .publisher(IDENTIFIER_6_PUBLISHER) .build(); - public static final IdentifierSaveDto IDENTIFIER_6_SAVE_DTO = IdentifierSaveDto.builder() + public final IdentifierSaveDto IDENTIFIER_6_SAVE_DTO = IdentifierSaveDto.builder() .id(IDENTIFIER_6_ID) .databaseId(DATABASE_3_ID) .queryId(QUERY_3_ID) @@ -6837,22 +6741,22 @@ public abstract class BaseTest { .licenses(new LinkedList<>(List.of(LICENSE_1_DTO))) .build(); - public static final UUID IDENTIFIER_7_ID = UUID.fromString("b216ae00-a31d-4ecb-95fb-37eb4da3946f"); - public static final String IDENTIFIER_7_DOI = null; - public static final Instant IDENTIFIER_7_CREATED = Instant.ofEpochSecond(1641588352L); - public static final Instant IDENTIFIER_7_MODIFIED = Instant.ofEpochSecond(1541588352L); - public static final Instant IDENTIFIER_7_EXECUTION = Instant.ofEpochSecond(1541588352L); - public static final Integer IDENTIFIER_7_PUBLICATION_DAY = 14; - public static final Integer IDENTIFIER_7_PUBLICATION_MONTH = 7; - public static final Integer IDENTIFIER_7_PUBLICATION_YEAR = 2022; - public static final Long IDENTIFIER_7_RESULT_NUMBER = 2L; - public static final String IDENTIFIER_7_PUBLISHER = "Swedish Government"; - public static final IdentifierType IDENTIFIER_7_TYPE = IdentifierType.DATABASE; - public static final IdentifierTypeDto IDENTIFIER_7_TYPE_DTO = IdentifierTypeDto.DATABASE; - public static final IdentifierStatusType IDENTIFIER_7_STATUS_TYPE = IdentifierStatusType.DRAFT; - public static final IdentifierStatusTypeDto IDENTIFIER_7_STATUS_TYPE_DTO = IdentifierStatusTypeDto.DRAFT; - - public static final DataCiteBody<DataCiteDoi> IDENTIFIER_7_DATA_CITE = DataCiteBody.<DataCiteDoi>builder() + public final static UUID IDENTIFIER_7_ID = UUID.fromString("b216ae00-a31d-4ecb-95fb-37eb4da3946f"); + public final static String IDENTIFIER_7_DOI = null; + public final static Instant IDENTIFIER_7_CREATED = Instant.ofEpochSecond(1641588352L); + public final static Instant IDENTIFIER_7_MODIFIED = Instant.ofEpochSecond(1541588352L); + public final static Instant IDENTIFIER_7_EXECUTION = Instant.ofEpochSecond(1541588352L); + public final static Integer IDENTIFIER_7_PUBLICATION_DAY = 14; + public final static Integer IDENTIFIER_7_PUBLICATION_MONTH = 7; + public final static Integer IDENTIFIER_7_PUBLICATION_YEAR = 2022; + public final static Long IDENTIFIER_7_RESULT_NUMBER = 2L; + public final static String IDENTIFIER_7_PUBLISHER = "Swedish Government"; + public final static IdentifierType IDENTIFIER_7_TYPE = IdentifierType.DATABASE; + public final static IdentifierTypeDto IDENTIFIER_7_TYPE_DTO = IdentifierTypeDto.DATABASE; + public final static IdentifierStatusType IDENTIFIER_7_STATUS_TYPE = IdentifierStatusType.DRAFT; + public final static IdentifierStatusTypeDto IDENTIFIER_7_STATUS_TYPE_DTO = IdentifierStatusTypeDto.DRAFT; + + public final DataCiteBody<DataCiteDoi> IDENTIFIER_7_DATA_CITE = DataCiteBody.<DataCiteDoi>builder() .data(DataCiteData.<DataCiteDoi>builder() .type("dois") .attributes(DataCiteDoi.builder() @@ -6861,9 +6765,9 @@ public abstract class BaseTest { .build()) .build(); - private final static UUID IDENTIFIER_7_CREATOR_1_ID = UUID.fromString("b899c367-06c7-4f47-8aea-5f15061ee3ee"); + public final static UUID IDENTIFIER_7_CREATOR_1_ID = UUID.fromString("b899c367-06c7-4f47-8aea-5f15061ee3ee"); - public static final Creator IDENTIFIER_7_CREATOR_1 = Creator.builder() + public final Creator IDENTIFIER_7_CREATOR_1 = Creator.builder() .id(IDENTIFIER_7_CREATOR_1_ID) .firstname(CREATOR_1_FIRSTNAME) .lastname(CREATOR_1_LASTNAME) @@ -6876,7 +6780,7 @@ public abstract class BaseTest { .affiliationIdentifierSchemeUri(CREATOR_1_AFFIL_URI) .build(); - public static final CreatorDto IDENTIFIER_7_CREATOR_1_DTO = CreatorDto.builder() + public final CreatorDto IDENTIFIER_7_CREATOR_1_DTO = CreatorDto.builder() .id(IDENTIFIER_7_CREATOR_1_ID) .firstname(CREATOR_1_FIRSTNAME) .lastname(CREATOR_1_LASTNAME) @@ -6889,12 +6793,13 @@ public abstract class BaseTest { .affiliationIdentifierSchemeUri(CREATOR_1_AFFIL_URI) .build(); - public static final IdentifierDto IDENTIFIER_7_DTO = IdentifierDto.builder() + public final IdentifierDto IDENTIFIER_7_DTO = IdentifierDto.builder() .id(IDENTIFIER_7_ID) .databaseId(DATABASE_4_ID) .links(LinksDto.builder() .self("/api/identifier/" + IDENTIFIER_7_ID) .selfHtml("/pid/" + IDENTIFIER_7_ID) + .dashboardHtml("/d/" + DATABASE_4_DASHBOARD_UID) .build()) .descriptions(new LinkedList<>()) .titles(new LinkedList<>()) @@ -6914,7 +6819,7 @@ public abstract class BaseTest { .status(IDENTIFIER_7_STATUS_TYPE_DTO) .build(); - public static final SaveIdentifierCreatorDto IDENTIFIER_7_CREATOR_1_CREATE_DTO = SaveIdentifierCreatorDto.builder() + public final SaveIdentifierCreatorDto IDENTIFIER_7_CREATOR_1_CREATE_DTO = SaveIdentifierCreatorDto.builder() .firstname(CREATOR_1_FIRSTNAME) .lastname(CREATOR_1_LASTNAME) .creatorName(CREATOR_1_NAME) @@ -6924,13 +6829,13 @@ public abstract class BaseTest { .affiliationIdentifier(CREATOR_1_AFFIL_ROR) .build(); - public static final CreateIdentifierDto IDENTIFIER_7_CREATE_DTO = CreateIdentifierDto.builder() + public final CreateIdentifierDto IDENTIFIER_7_CREATE_DTO = CreateIdentifierDto.builder() .databaseId(DATABASE_4_ID) .publicationYear(IDENTIFIER_7_PUBLICATION_YEAR) .publisher(IDENTIFIER_7_PUBLISHER) .build(); - public static final IdentifierSaveDto IDENTIFIER_7_SAVE_DTO = IdentifierSaveDto.builder() + public final IdentifierSaveDto IDENTIFIER_7_SAVE_DTO = IdentifierSaveDto.builder() .id(IDENTIFIER_7_ID) .databaseId(DATABASE_4_ID) .descriptions(new LinkedList<>()) @@ -6945,27 +6850,26 @@ public abstract class BaseTest { .type(IDENTIFIER_7_TYPE_DTO) .build(); - public static final UUID IDENTIFIER_2_ID = UUID.fromString("fdb95f60-48e7-4e74-8122-d3c8d079c889"); - public static final String IDENTIFIER_2_DOI = null; - public static final Instant IDENTIFIER_2_CREATED = Instant.ofEpochSecond(1651588352L); - public static final Instant IDENTIFIER_2_MODIFIED = Instant.ofEpochSecond(1551588352L); - public static final Instant IDENTIFIER_2_EXECUTION = Instant.ofEpochSecond(1551588352L); - public static final Integer IDENTIFIER_2_PUBLICATION_DAY = 10; - public static final Integer IDENTIFIER_2_PUBLICATION_MONTH = 7; - public static final Integer IDENTIFIER_2_PUBLICATION_YEAR = 2023; - public static final String IDENTIFIER_2_QUERY_HASH = QUERY_1_QUERY_HASH; - public static final String IDENTIFIER_2_RESULT_HASH = QUERY_1_RESULT_HASH; - public static final String IDENTIFIER_2_QUERY = QUERY_1_STATEMENT; - public static final String IDENTIFIER_2_NORMALIZED = QUERY_1_STATEMENT; - public static final Long IDENTIFIER_2_RESULT_NUMBER = QUERY_1_RESULT_NUMBER; - public static final String IDENTIFIER_2_PUBLISHER = "Swedish Government"; - public static final IdentifierType IDENTIFIER_2_TYPE = IdentifierType.SUBSET; - public static final IdentifierTypeDto IDENTIFIER_2_TYPE_DTO = IdentifierTypeDto.SUBSET; - public static final IdentifierStatusType IDENTIFIER_2_STATUS_TYPE = IdentifierStatusType.PUBLISHED; - public static final IdentifierStatusTypeDto IDENTIFIER_2_STATUS_TYPE_DTO = IdentifierStatusTypeDto.PUBLISHED; - public static final UUID IDENTIFIER_2_CREATED_BY = USER_1_ID; - - public static final CreateIdentifierDto IDENTIFIER_2_CREATE_DTO = CreateIdentifierDto.builder() + public final static UUID IDENTIFIER_2_ID = UUID.fromString("fdb95f60-48e7-4e74-8122-d3c8d079c889"); + public final static String IDENTIFIER_2_DOI = null; + public final static Instant IDENTIFIER_2_CREATED = Instant.ofEpochSecond(1651588352L); + public final static Instant IDENTIFIER_2_MODIFIED = Instant.ofEpochSecond(1551588352L); + public final static Instant IDENTIFIER_2_EXECUTION = Instant.ofEpochSecond(1551588352L); + public final static Integer IDENTIFIER_2_PUBLICATION_DAY = 10; + public final static Integer IDENTIFIER_2_PUBLICATION_MONTH = 7; + public final static Integer IDENTIFIER_2_PUBLICATION_YEAR = 2023; + public final static String IDENTIFIER_2_QUERY_HASH = QUERY_1_QUERY_HASH; + public final static String IDENTIFIER_2_RESULT_HASH = QUERY_1_RESULT_HASH; + public final static String IDENTIFIER_2_QUERY = QUERY_1_STATEMENT; + public final static String IDENTIFIER_2_NORMALIZED = QUERY_1_STATEMENT; + public final static Long IDENTIFIER_2_RESULT_NUMBER = QUERY_1_RESULT_NUMBER; + public final static String IDENTIFIER_2_PUBLISHER = "Swedish Government"; + public final static IdentifierType IDENTIFIER_2_TYPE = IdentifierType.SUBSET; + public final static IdentifierTypeDto IDENTIFIER_2_TYPE_DTO = IdentifierTypeDto.SUBSET; + public final static IdentifierStatusType IDENTIFIER_2_STATUS_TYPE = IdentifierStatusType.PUBLISHED; + public final static IdentifierStatusTypeDto IDENTIFIER_2_STATUS_TYPE_DTO = IdentifierStatusTypeDto.PUBLISHED; + + public final CreateIdentifierDto IDENTIFIER_2_CREATE_DTO = CreateIdentifierDto.builder() .databaseId(DATABASE_1_ID) .queryId(QUERY_1_ID) .type(IDENTIFIER_2_TYPE_DTO) @@ -6973,7 +6877,7 @@ public abstract class BaseTest { .publisher(IDENTIFIER_2_PUBLISHER) .build(); - public static final Identifier IDENTIFIER_2 = Identifier.builder() + public final Identifier IDENTIFIER_2 = Identifier.builder() .id(IDENTIFIER_2_ID) .queryId(QUERY_1_ID) .descriptions(new LinkedList<>()) @@ -7000,7 +6904,7 @@ public abstract class BaseTest { .status(IDENTIFIER_2_STATUS_TYPE) .build(); - public static final IdentifierDto IDENTIFIER_2_DTO = IdentifierDto.builder() + public final IdentifierDto IDENTIFIER_2_DTO = IdentifierDto.builder() .id(IDENTIFIER_2_ID) .queryId(QUERY_1_ID) .databaseId(DATABASE_1_ID) @@ -7029,7 +6933,7 @@ public abstract class BaseTest { .status(IDENTIFIER_2_STATUS_TYPE_DTO) .build(); - public static final IdentifierBriefDto IDENTIFIER_2_BRIEF_DTO = IdentifierBriefDto.builder() + public final IdentifierBriefDto IDENTIFIER_2_BRIEF_DTO = IdentifierBriefDto.builder() .id(IDENTIFIER_2_ID) .queryId(QUERY_1_ID) .databaseId(DATABASE_1_ID) @@ -7041,7 +6945,7 @@ public abstract class BaseTest { .status(IDENTIFIER_2_STATUS_TYPE_DTO) .build(); - public static final IdentifierSaveDto IDENTIFIER_2_SAVE_DTO = IdentifierSaveDto.builder() + public final IdentifierSaveDto IDENTIFIER_2_SAVE_DTO = IdentifierSaveDto.builder() .id(IDENTIFIER_2_ID) .databaseId(DATABASE_1_ID) .queryId(QUERY_1_ID) @@ -7057,27 +6961,26 @@ public abstract class BaseTest { .queryId(QUERY_1_ID) .build(); - public static final UUID IDENTIFIER_3_ID = UUID.fromString("e2d831c2-3694-4fdc-8c48-7a7e94b73c43"); - public static final String IDENTIFIER_3_DOI = null; - public static final Instant IDENTIFIER_3_CREATED = Instant.ofEpochSecond(1651588352L); - public static final Instant IDENTIFIER_3_MODIFIED = Instant.ofEpochSecond(1551588352L); - public static final Instant IDENTIFIER_3_EXECUTION = Instant.ofEpochSecond(1551588352L); - public static final Integer IDENTIFIER_3_PUBLICATION_DAY = 10; - public static final Integer IDENTIFIER_3_PUBLICATION_MONTH = 7; - public static final Integer IDENTIFIER_3_PUBLICATION_YEAR = 2023; - public static final String IDENTIFIER_3_QUERY_HASH = VIEW_1_QUERY_HASH; - public static final String IDENTIFIER_3_RESULT_HASH = null; - public static final String IDENTIFIER_3_QUERY = VIEW_1_QUERY; - public static final String IDENTIFIER_3_NORMALIZED = VIEW_1_QUERY; - public static final Long IDENTIFIER_3_RESULT_NUMBER = null; - public static final String IDENTIFIER_3_PUBLISHER = "Polish Government"; - public static final IdentifierType IDENTIFIER_3_TYPE = IdentifierType.VIEW; - public static final IdentifierTypeDto IDENTIFIER_3_TYPE_DTO = IdentifierTypeDto.VIEW; - public static final IdentifierStatusType IDENTIFIER_3_STATUS_TYPE = IdentifierStatusType.PUBLISHED; - public static final IdentifierStatusTypeDto IDENTIFIER_3_STATUS_TYPE_DTO = IdentifierStatusTypeDto.PUBLISHED; - public static final UUID IDENTIFIER_3_CREATED_BY = USER_1_ID; - - public static final Identifier IDENTIFIER_3 = Identifier.builder() + public final static UUID IDENTIFIER_3_ID = UUID.fromString("e2d831c2-3694-4fdc-8c48-7a7e94b73c43"); + public final static String IDENTIFIER_3_DOI = null; + public final static Instant IDENTIFIER_3_CREATED = Instant.ofEpochSecond(1651588352L); + public final static Instant IDENTIFIER_3_MODIFIED = Instant.ofEpochSecond(1551588352L); + public final static Instant IDENTIFIER_3_EXECUTION = Instant.ofEpochSecond(1551588352L); + public final static Integer IDENTIFIER_3_PUBLICATION_DAY = 10; + public final static Integer IDENTIFIER_3_PUBLICATION_MONTH = 7; + public final static Integer IDENTIFIER_3_PUBLICATION_YEAR = 2023; + public final static String IDENTIFIER_3_QUERY_HASH = VIEW_1_QUERY_HASH; + public final static String IDENTIFIER_3_RESULT_HASH = null; + public final static String IDENTIFIER_3_QUERY = VIEW_1_QUERY; + public final static String IDENTIFIER_3_NORMALIZED = VIEW_1_QUERY; + public final static Long IDENTIFIER_3_RESULT_NUMBER = null; + public final static String IDENTIFIER_3_PUBLISHER = "Polish Government"; + public final static IdentifierType IDENTIFIER_3_TYPE = IdentifierType.VIEW; + public final static IdentifierTypeDto IDENTIFIER_3_TYPE_DTO = IdentifierTypeDto.VIEW; + public final static IdentifierStatusType IDENTIFIER_3_STATUS_TYPE = IdentifierStatusType.PUBLISHED; + public final static IdentifierStatusTypeDto IDENTIFIER_3_STATUS_TYPE_DTO = IdentifierStatusTypeDto.PUBLISHED; + + public final Identifier IDENTIFIER_3 = Identifier.builder() .id(IDENTIFIER_3_ID) .viewId(VIEW_1_ID) .descriptions(new LinkedList<>()) @@ -7104,7 +7007,7 @@ public abstract class BaseTest { .status(IDENTIFIER_3_STATUS_TYPE) .build(); - public static final IdentifierDto IDENTIFIER_3_DTO = IdentifierDto.builder() + public final IdentifierDto IDENTIFIER_3_DTO = IdentifierDto.builder() .id(IDENTIFIER_3_ID) .databaseId(DATABASE_1_ID) .viewId(VIEW_1_ID) @@ -7133,7 +7036,7 @@ public abstract class BaseTest { .status(IDENTIFIER_3_STATUS_TYPE_DTO) .build(); - public static final IdentifierBriefDto IDENTIFIER_3_BRIEF_DTO = IdentifierBriefDto.builder() + public final IdentifierBriefDto IDENTIFIER_3_BRIEF_DTO = IdentifierBriefDto.builder() .id(IDENTIFIER_3_ID) .databaseId(DATABASE_1_ID) .viewId(VIEW_1_ID) @@ -7145,7 +7048,7 @@ public abstract class BaseTest { .status(IDENTIFIER_3_STATUS_TYPE_DTO) .build(); - public static final CreateIdentifierDto IDENTIFIER_3_CREATE_DTO = CreateIdentifierDto.builder() + public final CreateIdentifierDto IDENTIFIER_3_CREATE_DTO = CreateIdentifierDto.builder() .databaseId(DATABASE_1_ID) .viewId(VIEW_1_ID) .type(IDENTIFIER_3_TYPE_DTO) @@ -7153,7 +7056,7 @@ public abstract class BaseTest { .publisher(IDENTIFIER_3_PUBLISHER) .build(); - public static final IdentifierSaveDto IDENTIFIER_3_SAVE_DTO = IdentifierSaveDto.builder() + public final IdentifierSaveDto IDENTIFIER_3_SAVE_DTO = IdentifierSaveDto.builder() .id(IDENTIFIER_3_ID) .databaseId(DATABASE_1_ID) .viewId(VIEW_1_ID) @@ -7168,24 +7071,23 @@ public abstract class BaseTest { .licenses(new LinkedList<>(List.of(LICENSE_1_DTO))) .build(); - public static final UUID IDENTIFIER_4_ID = UUID.fromString("3bd69bb8-f7e3-48e4-9717-823787e7ba23"); - public static final String IDENTIFIER_4_DOI = null; - public static final Instant IDENTIFIER_4_CREATED = Instant.ofEpochSecond(1751588352L); - public static final Instant IDENTIFIER_4_MODIFIED = Instant.ofEpochSecond(1551588352L); - public static final Instant IDENTIFIER_4_EXECUTION = Instant.ofEpochSecond(1551588352L); - public static final Integer IDENTIFIER_4_PUBLICATION_DAY = 10; - public static final Integer IDENTIFIER_4_PUBLICATION_MONTH = 7; - public static final Integer IDENTIFIER_4_PUBLICATION_YEAR = 2023; - public static final String IDENTIFIER_4_RESULT_HASH = null; - public static final Long IDENTIFIER_4_RESULT_NUMBER = null; - public static final String IDENTIFIER_4_PUBLISHER = "Example Publisher"; - public static final IdentifierType IDENTIFIER_4_TYPE = IdentifierType.TABLE; - public static final IdentifierTypeDto IDENTIFIER_4_TYPE_DTO = IdentifierTypeDto.TABLE; - public static final IdentifierStatusType IDENTIFIER_4_STATUS_TYPE = IdentifierStatusType.PUBLISHED; - public static final IdentifierStatusTypeDto IDENTIFIER_4_STATUS_TYPE_DTO = IdentifierStatusTypeDto.PUBLISHED; - public static final UUID IDENTIFIER_4_CREATED_BY = USER_1_ID; - - public static final Identifier IDENTIFIER_4 = Identifier.builder() + public final static UUID IDENTIFIER_4_ID = UUID.fromString("3bd69bb8-f7e3-48e4-9717-823787e7ba23"); + public final static String IDENTIFIER_4_DOI = null; + public final static Instant IDENTIFIER_4_CREATED = Instant.ofEpochSecond(1751588352L); + public final static Instant IDENTIFIER_4_MODIFIED = Instant.ofEpochSecond(1551588352L); + public final static Instant IDENTIFIER_4_EXECUTION = Instant.ofEpochSecond(1551588352L); + public final static Integer IDENTIFIER_4_PUBLICATION_DAY = 10; + public final static Integer IDENTIFIER_4_PUBLICATION_MONTH = 7; + public final static Integer IDENTIFIER_4_PUBLICATION_YEAR = 2023; + public final static String IDENTIFIER_4_RESULT_HASH = null; + public final static Long IDENTIFIER_4_RESULT_NUMBER = null; + public final static String IDENTIFIER_4_PUBLISHER = "Example Publisher"; + public final static IdentifierType IDENTIFIER_4_TYPE = IdentifierType.TABLE; + public final static IdentifierTypeDto IDENTIFIER_4_TYPE_DTO = IdentifierTypeDto.TABLE; + public final static IdentifierStatusType IDENTIFIER_4_STATUS_TYPE = IdentifierStatusType.PUBLISHED; + public final static IdentifierStatusTypeDto IDENTIFIER_4_STATUS_TYPE_DTO = IdentifierStatusTypeDto.PUBLISHED; + + public final Identifier IDENTIFIER_4 = Identifier.builder() .id(IDENTIFIER_4_ID) .tableId(TABLE_1_ID) .descriptions(new LinkedList<>()) @@ -7209,7 +7111,7 @@ public abstract class BaseTest { .status(IDENTIFIER_4_STATUS_TYPE) .build(); - public static final IdentifierDto IDENTIFIER_4_DTO = IdentifierDto.builder() + public final IdentifierDto IDENTIFIER_4_DTO = IdentifierDto.builder() .id(IDENTIFIER_4_ID) .databaseId(DATABASE_1_ID) .tableId(TABLE_1_ID) @@ -7235,7 +7137,7 @@ public abstract class BaseTest { .status(IDENTIFIER_4_STATUS_TYPE_DTO) .build(); - public static final IdentifierBriefDto IDENTIFIER_4_BRIEF_DTO = IdentifierBriefDto.builder() + public final IdentifierBriefDto IDENTIFIER_4_BRIEF_DTO = IdentifierBriefDto.builder() .id(IDENTIFIER_4_ID) .databaseId(DATABASE_1_ID) .tableId(TABLE_1_ID) @@ -7247,13 +7149,13 @@ public abstract class BaseTest { .status(IDENTIFIER_4_STATUS_TYPE_DTO) .build(); - public static final CreateIdentifierDto IDENTIFIER_4_CREATE_DTO = CreateIdentifierDto.builder() + public final CreateIdentifierDto IDENTIFIER_4_CREATE_DTO = CreateIdentifierDto.builder() .databaseId(DATABASE_1_ID) .publicationYear(IDENTIFIER_4_PUBLICATION_YEAR) .publisher(IDENTIFIER_4_PUBLISHER) .build(); - public static final IdentifierSaveDto IDENTIFIER_4_SAVE_DTO = IdentifierSaveDto.builder() + public final IdentifierSaveDto IDENTIFIER_4_SAVE_DTO = IdentifierSaveDto.builder() .id(IDENTIFIER_4_ID) .databaseId(DATABASE_1_ID) .tableId(TABLE_1_ID) @@ -7268,36 +7170,36 @@ public abstract class BaseTest { .licenses(new LinkedList<>(List.of(LICENSE_1_DTO))) .build(); - public static final String VIRTUAL_HOST_NAME = "fda"; - public static final String VIRTUAL_HOST_DESCRIPTION = "FAIR Data Austria"; - public static final String VIRTUAL_HOST_TAGS = ""; + public final static String VIRTUAL_HOST_NAME = "fda"; + public final static String VIRTUAL_HOST_DESCRIPTION = "FAIR Data Austria"; + public final static String VIRTUAL_HOST_TAGS = ""; - public static final CreateVirtualHostDto VIRTUAL_HOST_CREATE_DTO = CreateVirtualHostDto.builder() + public final CreateVirtualHostDto VIRTUAL_HOST_CREATE_DTO = CreateVirtualHostDto.builder() .name(VIRTUAL_HOST_NAME) .description(VIRTUAL_HOST_DESCRIPTION) .tags(VIRTUAL_HOST_TAGS) .build(); - public static final ExchangeUpdatePermissionsDto VIRTUAL_HOST_EXCHANGE_UPDATE_DTO = ExchangeUpdatePermissionsDto.builder() + public final ExchangeUpdatePermissionsDto VIRTUAL_HOST_EXCHANGE_UPDATE_DTO = ExchangeUpdatePermissionsDto.builder() .exchange(DATABASE_1_EXCHANGE) .read(".*") .write(".*") .build(); - public static final GrantVirtualHostPermissionsDto VIRTUAL_HOST_GRANT_DTO = GrantVirtualHostPermissionsDto.builder() + public final GrantVirtualHostPermissionsDto VIRTUAL_HOST_GRANT_DTO = GrantVirtualHostPermissionsDto.builder() .read(".*") .write(".*") .configure(".*") .build(); - public static final UUID BANNER_MESSAGE_1_ID = UUID.fromString("81cf09b7-0d86-44ad-be8e-a407e7d114e1"); - public static final String BANNER_MESSAGE_1_MESSAGE = "Next maintenance in 7 days!"; - public static final BannerMessageType BANNER_MESSAGE_1_TYPE = BannerMessageType.INFO; - public static final BannerMessageTypeDto BANNER_MESSAGE_1_TYPE_DTO = BannerMessageTypeDto.INFO; - public static final Instant BANNER_MESSAGE_1_START = Instant.ofEpochSecond(1684577786L) /* 2022-12-23 22:00:00 (UTC) */; - public static final Instant BANNER_MESSAGE_1_END = null; + public final static UUID BANNER_MESSAGE_1_ID = UUID.fromString("81cf09b7-0d86-44ad-be8e-a407e7d114e1"); + public final static String BANNER_MESSAGE_1_MESSAGE = "Next maintenance in 7 days!"; + public final static BannerMessageType BANNER_MESSAGE_1_TYPE = BannerMessageType.INFO; + public final static BannerMessageTypeDto BANNER_MESSAGE_1_TYPE_DTO = BannerMessageTypeDto.INFO; + public final static Instant BANNER_MESSAGE_1_START = Instant.ofEpochSecond(1684577786L) /* 2022-12-23 22:00:00 (UTC) */; + public final static Instant BANNER_MESSAGE_1_END = null; - public static final BannerMessage BANNER_MESSAGE_1 = BannerMessage.builder() + public final BannerMessage BANNER_MESSAGE_1 = BannerMessage.builder() .id(BANNER_MESSAGE_1_ID) .message(BANNER_MESSAGE_1_MESSAGE) .type(BANNER_MESSAGE_1_TYPE) @@ -7305,7 +7207,7 @@ public abstract class BaseTest { .displayEnd(BANNER_MESSAGE_1_END) .build(); - public static final BannerMessageDto BANNER_MESSAGE_1_DTO = BannerMessageDto.builder() + public final BannerMessageDto BANNER_MESSAGE_1_DTO = BannerMessageDto.builder() .id(BANNER_MESSAGE_1_ID) .message(BANNER_MESSAGE_1_MESSAGE) .type(BANNER_MESSAGE_1_TYPE_DTO) @@ -7313,28 +7215,28 @@ public abstract class BaseTest { .displayEnd(BANNER_MESSAGE_1_END) .build(); - public static final BannerMessageCreateDto BANNER_MESSAGE_1_CREATE_DTO = BannerMessageCreateDto.builder() + public final BannerMessageCreateDto BANNER_MESSAGE_1_CREATE_DTO = BannerMessageCreateDto.builder() .message(BANNER_MESSAGE_1_MESSAGE) .type(BANNER_MESSAGE_1_TYPE_DTO) .displayStart(BANNER_MESSAGE_1_START) .displayEnd(BANNER_MESSAGE_1_END) .build(); - public static final BannerMessageUpdateDto BANNER_MESSAGE_1_UPDATE_DTO = BannerMessageUpdateDto.builder() + public final BannerMessageUpdateDto BANNER_MESSAGE_1_UPDATE_DTO = BannerMessageUpdateDto.builder() .message(BANNER_MESSAGE_1_MESSAGE) .type(BannerMessageTypeDto.WARNING) .displayStart(BANNER_MESSAGE_1_START) .displayEnd(BANNER_MESSAGE_1_END) .build(); - public static final UUID BANNER_MESSAGE_2_ID = UUID.fromString("1e7e2c03-e2c6-46b8-9fdc-6668ef055d99"); - public static final String BANNER_MESSAGE_2_MESSAGE = "No operation on Christmas 2022!"; - public static final BannerMessageType BANNER_MESSAGE_2_TYPE = BannerMessageType.ERROR; - public static final BannerMessageTypeDto BANNER_MESSAGE_2_TYPE_DTO = BannerMessageTypeDto.ERROR; - public static final Instant BANNER_MESSAGE_2_START = Instant.ofEpochSecond(1671836400L) /* 2022-12-23 22:00:00 (UTC) */; - public static final Instant BANNER_MESSAGE_2_END = Instant.ofEpochSecond(1672009200L) /* 2022-12-25 22:00:00 (UTC) */; + public final static UUID BANNER_MESSAGE_2_ID = UUID.fromString("1e7e2c03-e2c6-46b8-9fdc-6668ef055d99"); + public final static String BANNER_MESSAGE_2_MESSAGE = "No operation on Christmas 2022!"; + public final static BannerMessageType BANNER_MESSAGE_2_TYPE = BannerMessageType.ERROR; + public final static BannerMessageTypeDto BANNER_MESSAGE_2_TYPE_DTO = BannerMessageTypeDto.ERROR; + public final static Instant BANNER_MESSAGE_2_START = Instant.ofEpochSecond(1671836400L) /* 2022-12-23 22:00:00 (UTC) */; + public final static Instant BANNER_MESSAGE_2_END = Instant.ofEpochSecond(1672009200L) /* 2022-12-25 22:00:00 (UTC) */; - public static final BannerMessage BANNER_MESSAGE_2 = BannerMessage.builder() + public final BannerMessage BANNER_MESSAGE_2 = BannerMessage.builder() .id(BANNER_MESSAGE_2_ID) .message(BANNER_MESSAGE_2_MESSAGE) .type(BANNER_MESSAGE_2_TYPE) @@ -7342,29 +7244,31 @@ public abstract class BaseTest { .displayEnd(BANNER_MESSAGE_2_END) .build(); - public static final BannerMessageCreateDto BANNER_MESSAGE_2_CREATE_DTO = BannerMessageCreateDto.builder() + public final BannerMessageCreateDto BANNER_MESSAGE_2_CREATE_DTO = BannerMessageCreateDto.builder() .message(BANNER_MESSAGE_2_MESSAGE) .type(BANNER_MESSAGE_2_TYPE_DTO) .displayStart(BANNER_MESSAGE_2_START) .displayEnd(BANNER_MESSAGE_2_END) .build(); - public static final Database DATABASE_1 = Database.builder() + public final Database DATABASE_1 = Database.builder() .id(DATABASE_1_ID) .created(Instant.now().minus(1, HOURS)) .lastModified(Instant.now()) .isPublic(DATABASE_1_PUBLIC) .isSchemaPublic(DATABASE_1_SCHEMA_PUBLIC) + .isDashboardEnabled(DATABASE_1_DASHBOARD_ENABLED) + .dashboardUid(DATABASE_1_DASHBOARD_UID) .name(DATABASE_1_NAME) .description(DATABASE_1_DESCRIPTION) .identifiers(new LinkedList<>(List.of(IDENTIFIER_1, IDENTIFIER_2, IDENTIFIER_3, IDENTIFIER_4))) .cid(CONTAINER_1_ID) .container(CONTAINER_1) - .internalName(DATABASE_1_INTERNALNAME) + .internalName(DATABASE_1_INTERNAL_NAME) .exchangeName(DATABASE_1_EXCHANGE) .created(DATABASE_1_CREATED) .lastModified(DATABASE_1_LAST_MODIFIED) - .ownedBy(DATABASE_1_CREATED_BY) + .ownedBy(USER_1_ID) .owner(USER_1) .ownedBy(USER_1_ID) .owner(USER_1) @@ -7378,13 +7282,15 @@ public abstract class BaseTest { .identifiers(new LinkedList<>()) .build(); - public static final DatabaseDto DATABASE_1_DTO = DatabaseDto.builder() + public final DatabaseDto DATABASE_1_DTO = DatabaseDto.builder() .id(DATABASE_1_ID) .isPublic(DATABASE_1_PUBLIC) .isSchemaPublic(DATABASE_1_SCHEMA_PUBLIC) + .isDashboardEnabled(DATABASE_1_DASHBOARD_ENABLED) + .dashboardUid(DATABASE_1_DASHBOARD_UID) .name(DATABASE_1_NAME) .container(CONTAINER_1_DTO) - .internalName(DATABASE_1_INTERNALNAME) + .internalName(DATABASE_1_INTERNAL_NAME) .exchangeName(DATABASE_1_EXCHANGE) .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))) @@ -7392,13 +7298,13 @@ public abstract class BaseTest { .owner(USER_1_BRIEF_DTO) .build(); - public static final DatabaseDto DATABASE_1_PRIVILEGED_DTO = DatabaseDto.builder() + public final DatabaseDto DATABASE_1_PRIVILEGED_DTO = DatabaseDto.builder() .id(DATABASE_1_ID) .isPublic(DATABASE_1_PUBLIC) .isSchemaPublic(DATABASE_1_SCHEMA_PUBLIC) .name(DATABASE_1_NAME) .container(CONTAINER_1_PRIVILEGED_DTO) - .internalName(DATABASE_1_INTERNALNAME) + .internalName(DATABASE_1_INTERNAL_NAME) .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))) @@ -7408,16 +7314,16 @@ public abstract class BaseTest { .lastRetrieved(Instant.now()) .build(); - public static final DatabaseBriefDto DATABASE_1_BRIEF_DTO = DatabaseBriefDto.builder() + public final 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) + .internalName(DATABASE_1_INTERNAL_NAME) .identifiers(new LinkedList<>(List.of(IDENTIFIER_1_BRIEF_DTO, IDENTIFIER_2_BRIEF_DTO, IDENTIFIER_3_BRIEF_DTO, IDENTIFIER_4_BRIEF_DTO))) .build(); - public static final DatabaseAccess DATABASE_1_USER_1_READ_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_1_USER_1_READ_ACCESS = DatabaseAccess.builder() .type(AccessType.READ) .hdbid(DATABASE_1_ID) .database(DATABASE_1) @@ -7425,14 +7331,14 @@ public abstract class BaseTest { .user(USER_1) .build(); - public static final DatabaseAccessDto DATABASE_1_USER_1_READ_ACCESS_DTO = DatabaseAccessDto.builder() + public final DatabaseAccessDto DATABASE_1_USER_1_READ_ACCESS_DTO = DatabaseAccessDto.builder() .type(AccessTypeDto.READ) .hdbid(DATABASE_1_ID) .huserid(USER_1_ID) .user(USER_1_BRIEF_DTO) .build(); - public static final DatabaseAccess DATABASE_1_USER_1_WRITE_OWN_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_1_USER_1_WRITE_OWN_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_OWN) .hdbid(DATABASE_1_ID) .database(DATABASE_1) @@ -7440,7 +7346,7 @@ public abstract class BaseTest { .user(USER_1) .build(); - public static final DatabaseAccess DATABASE_1_USER_1_WRITE_ALL_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_1_USER_1_WRITE_ALL_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_ALL) .hdbid(DATABASE_1_ID) .database(DATABASE_1) @@ -7448,7 +7354,7 @@ public abstract class BaseTest { .user(USER_1) .build(); - public static final DatabaseAccess DATABASE_1_USER_2_READ_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_1_USER_2_READ_ACCESS = DatabaseAccess.builder() .type(AccessType.READ) .hdbid(DATABASE_1_ID) .database(DATABASE_1) @@ -7456,14 +7362,14 @@ public abstract class BaseTest { .user(USER_2) .build(); - public static final DatabaseAccessDto DATABASE_1_USER_2_READ_ACCESS_DTO = DatabaseAccessDto.builder() + public final DatabaseAccessDto DATABASE_1_USER_2_READ_ACCESS_DTO = DatabaseAccessDto.builder() .type(AccessTypeDto.READ) .hdbid(DATABASE_1_ID) .huserid(USER_2_ID) .user(USER_2_BRIEF_DTO) .build(); - public static final DatabaseAccess DATABASE_1_USER_2_WRITE_OWN_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_1_USER_2_WRITE_OWN_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_OWN) .hdbid(DATABASE_1_ID) .database(DATABASE_1) @@ -7471,14 +7377,14 @@ public abstract class BaseTest { .user(USER_2) .build(); - public static final DatabaseAccessDto DATABASE_1_USER_2_WRITE_OWN_ACCESS_DTO = DatabaseAccessDto.builder() + public final DatabaseAccessDto DATABASE_1_USER_2_WRITE_OWN_ACCESS_DTO = DatabaseAccessDto.builder() .type(AccessTypeDto.WRITE_OWN) .hdbid(DATABASE_1_ID) .huserid(USER_2_ID) .user(USER_2_BRIEF_DTO) .build(); - public static final DatabaseAccess DATABASE_1_USER_2_WRITE_ALL_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_1_USER_2_WRITE_ALL_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_ALL) .hdbid(DATABASE_1_ID) .database(DATABASE_1) @@ -7486,14 +7392,14 @@ public abstract class BaseTest { .user(USER_2) .build(); - public static final DatabaseAccessDto DATABASE_1_USER_2_WRITE_ALL_ACCESS_DTO = DatabaseAccessDto.builder() + public final DatabaseAccessDto DATABASE_1_USER_2_WRITE_ALL_ACCESS_DTO = DatabaseAccessDto.builder() .type(AccessTypeDto.WRITE_ALL) .hdbid(DATABASE_1_ID) .huserid(USER_2_ID) .user(USER_2_BRIEF_DTO) .build(); - public static final DatabaseAccess DATABASE_1_USER_3_READ_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_1_USER_3_READ_ACCESS = DatabaseAccess.builder() .type(AccessType.READ) .hdbid(DATABASE_1_ID) .database(DATABASE_1) @@ -7501,7 +7407,7 @@ public abstract class BaseTest { .user(USER_3) .build(); - public static final DatabaseAccess DATABASE_1_USER_3_WRITE_OWN_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_1_USER_3_WRITE_OWN_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_OWN) .hdbid(DATABASE_1_ID) .database(DATABASE_1) @@ -7509,7 +7415,7 @@ public abstract class BaseTest { .user(USER_3) .build(); - public static final DatabaseAccess DATABASE_1_USER_3_WRITE_ALL_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_1_USER_3_WRITE_ALL_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_ALL) .hdbid(DATABASE_1_ID) .database(DATABASE_1) @@ -7517,14 +7423,14 @@ public abstract class BaseTest { .user(USER_3) .build(); - public static final DatabaseAccessDto DATABASE_1_USER_3_WRITE_ALL_ACCESS_DTO = DatabaseAccessDto.builder() + public final DatabaseAccessDto DATABASE_1_USER_3_WRITE_ALL_ACCESS_DTO = DatabaseAccessDto.builder() .type(AccessTypeDto.WRITE_ALL) .hdbid(DATABASE_1_ID) .huserid(USER_3_ID) .user(USER_3_BRIEF_DTO) .build(); - public static final DatabaseAccess DATABASE_1_USER_4_READ_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_1_USER_4_READ_ACCESS = DatabaseAccess.builder() .type(AccessType.READ) .hdbid(DATABASE_1_ID) .database(DATABASE_1) @@ -7532,28 +7438,43 @@ public abstract class BaseTest { .user(USER_4) .build(); - public static final DatabaseAccessDto DATABASE_1_USER_4_READ_ACCESS_DTO = DatabaseAccessDto.builder() + public final DatabaseAccessDto DATABASE_1_USER_4_READ_ACCESS_DTO = DatabaseAccessDto.builder() .type(AccessTypeDto.READ) .hdbid(DATABASE_1_ID) .huserid(USER_4_ID) .user(USER_4_BRIEF_DTO) .build(); - public static final Database DATABASE_2 = Database.builder() + public final CreateDashboardResponseDto DATABASE_1_CREATE_DASHBOARD_RESPONSE_DTO = + CreateDashboardResponseDto.builder() + .id(1L) + .uid(DATABASE_1_DASHBOARD_UID) + .build(); + + public final CreateDashboardDto DATABASE_1_CREATE_DASHBOARD_DTO = CreateDashboardDto.builder() + .databaseName(DATABASE_1_INTERNAL_NAME) + .isPublic(DATABASE_1_PUBLIC) + .isSchemaPublic(DATABASE_1_SCHEMA_PUBLIC) + .ownerUsername(USER_1_USERNAME) + .build(); + + public final Database DATABASE_2 = Database.builder() .id(DATABASE_2_ID) .created(DATABASE_2_CREATED) .lastModified(Instant.now()) .isPublic(DATABASE_2_PUBLIC) .isSchemaPublic(DATABASE_2_SCHEMA_PUBLIC) + .isDashboardEnabled(DATABASE_2_DASHBOARD_ENABLED) + .dashboardUid(DATABASE_2_DASHBOARD_UID) .name(DATABASE_2_NAME) .description(DATABASE_2_DESCRIPTION) .cid(CONTAINER_1_ID) .container(CONTAINER_1) - .internalName(DATABASE_2_INTERNALNAME) + .internalName(DATABASE_2_INTERNAL_NAME) .exchangeName(DATABASE_2_EXCHANGE) .created(DATABASE_2_CREATED) .lastModified(DATABASE_2_LAST_MODIFIED) - .ownedBy(DATABASE_2_OWNER) + .ownedBy(USER_2_ID) .owner(USER_2) .contactPerson(USER_2_ID) .contact(USER_2) @@ -7563,13 +7484,13 @@ public abstract class BaseTest { .identifiers(new LinkedList<>()) .build(); - public static final DatabaseDto DATABASE_2_DTO = DatabaseDto.builder() + public final 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_DTO) - .internalName(DATABASE_2_INTERNALNAME) + .internalName(DATABASE_2_INTERNAL_NAME) .exchangeName(DATABASE_2_EXCHANGE) .identifiers(new LinkedList<>(List.of(IDENTIFIER_5_DTO))) .tables(new LinkedList<>(List.of(TABLE_5_DTO, TABLE_6_DTO, TABLE_7_DTO))) @@ -7578,13 +7499,13 @@ public abstract class BaseTest { .lastRetrieved(Instant.now()) .build(); - public static final DatabaseDto DATABASE_2_PRIVILEGED_DTO = DatabaseDto.builder() + public final 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_PRIVILEGED_DTO) - .internalName(DATABASE_2_INTERNALNAME) + .internalName(DATABASE_2_INTERNAL_NAME) .exchangeName(DATABASE_2_EXCHANGE) .identifiers(new LinkedList<>(List.of(IDENTIFIER_5_DTO))) .tables(new LinkedList<>(List.of(TABLE_5_DTO, TABLE_6_DTO, TABLE_7_DTO))) @@ -7593,27 +7514,27 @@ public abstract class BaseTest { .lastRetrieved(Instant.now()) .build(); - public static final DatabaseBriefDto DATABASE_2_PRIVILEGED_BRIEF_DTO = DatabaseBriefDto.builder() + public final DatabaseBriefDto DATABASE_2_PRIVILEGED_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) + .internalName(DATABASE_2_INTERNAL_NAME) .identifiers(new LinkedList<>(List.of(IDENTIFIER_5_BRIEF_DTO))) .ownerId(USER_2_ID) .build(); - public static final DatabaseBriefDto DATABASE_2_BRIEF_DTO = DatabaseBriefDto.builder() + public final 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) + .internalName(DATABASE_2_INTERNAL_NAME) .identifiers(new LinkedList<>(List.of(IDENTIFIER_5_BRIEF_DTO))) .ownerId(USER_2_ID) .build(); - public static final DatabaseAccess DATABASE_2_USER_1_READ_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_2_USER_1_READ_ACCESS = DatabaseAccess.builder() .type(AccessType.READ) .hdbid(DATABASE_2_ID) .database(DATABASE_2) @@ -7621,7 +7542,7 @@ public abstract class BaseTest { .user(USER_1) .build(); - public static final DatabaseAccess DATABASE_2_USER_1_WRITE_OWN_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_2_USER_1_WRITE_OWN_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_OWN) .hdbid(DATABASE_2_ID) .database(DATABASE_2) @@ -7629,7 +7550,7 @@ public abstract class BaseTest { .user(USER_1) .build(); - public static final DatabaseAccess DATABASE_2_USER_1_WRITE_ALL_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_2_USER_1_WRITE_ALL_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_ALL) .hdbid(DATABASE_2_ID) .database(DATABASE_2) @@ -7637,7 +7558,7 @@ public abstract class BaseTest { .user(USER_1) .build(); - public static final DatabaseAccess DATABASE_2_USER_2_READ_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_2_USER_2_READ_ACCESS = DatabaseAccess.builder() .type(AccessType.READ) .hdbid(DATABASE_2_ID) .database(DATABASE_2) @@ -7645,13 +7566,13 @@ public abstract class BaseTest { .user(USER_2) .build(); - public static final DatabaseAccessDto DATABASE_2_USER_2_READ_ACCESS_DTO = DatabaseAccessDto.builder() + public final DatabaseAccessDto DATABASE_2_USER_2_READ_ACCESS_DTO = DatabaseAccessDto.builder() .type(AccessTypeDto.READ) .hdbid(DATABASE_2_ID) .huserid(USER_2_ID) .build(); - public static final DatabaseAccess DATABASE_2_USER_2_WRITE_OWN_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_2_USER_2_WRITE_OWN_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_OWN) .hdbid(DATABASE_2_ID) .database(DATABASE_2) @@ -7659,7 +7580,7 @@ public abstract class BaseTest { .user(USER_2) .build(); - public static final DatabaseAccess DATABASE_2_USER_2_WRITE_ALL_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_2_USER_2_WRITE_ALL_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_ALL) .hdbid(DATABASE_2_ID) .database(DATABASE_2) @@ -7667,14 +7588,14 @@ public abstract class BaseTest { .user(USER_2) .build(); - public static final DatabaseAccessDto DATABASE_2_USER_2_WRITE_ALL_ACCESS_DTO = DatabaseAccessDto.builder() + public final DatabaseAccessDto DATABASE_2_USER_2_WRITE_ALL_ACCESS_DTO = DatabaseAccessDto.builder() .type(AccessTypeDto.WRITE_ALL) .hdbid(DATABASE_2_ID) .huserid(USER_2_ID) .user(USER_2_BRIEF_DTO) .build(); - public static final DatabaseAccess DATABASE_2_USER_3_READ_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_2_USER_3_READ_ACCESS = DatabaseAccess.builder() .type(AccessType.READ) .hdbid(DATABASE_2_ID) .database(DATABASE_2) @@ -7682,14 +7603,14 @@ public abstract class BaseTest { .user(USER_3) .build(); - public static final DatabaseAccessDto DATABASE_2_USER_3_READ_ACCESS_DTO = DatabaseAccessDto.builder() + public final DatabaseAccessDto DATABASE_2_USER_3_READ_ACCESS_DTO = DatabaseAccessDto.builder() .type(AccessTypeDto.READ) .hdbid(DATABASE_2_ID) .huserid(USER_3_ID) .user(USER_3_BRIEF_DTO) .build(); - public static final DatabaseAccess DATABASE_2_USER_3_WRITE_OWN_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_2_USER_3_WRITE_OWN_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_OWN) .hdbid(DATABASE_2_ID) .database(DATABASE_2) @@ -7697,7 +7618,7 @@ public abstract class BaseTest { .user(USER_3) .build(); - public static final DatabaseAccess DATABASE_2_USER_3_WRITE_ALL_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_2_USER_3_WRITE_ALL_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_ALL) .hdbid(DATABASE_2_ID) .database(DATABASE_2) @@ -7705,21 +7626,36 @@ public abstract class BaseTest { .user(USER_3) .build(); - public static final Database DATABASE_3 = Database.builder() + public final CreateDashboardResponseDto DATABASE_2_CREATE_DASHBOARD_RESPONSE_DTO = + CreateDashboardResponseDto.builder() + .id(2L) + .uid(DATABASE_2_DASHBOARD_UID) + .build(); + + public final CreateDashboardDto DATABASE_2_CREATE_DASHBOARD_DTO = CreateDashboardDto.builder() + .databaseName(DATABASE_2_INTERNAL_NAME) + .isPublic(DATABASE_2_PUBLIC) + .isSchemaPublic(DATABASE_2_SCHEMA_PUBLIC) + .ownerUsername(USER_2_USERNAME) + .build(); + + public final Database DATABASE_3 = Database.builder() .id(DATABASE_3_ID) .created(Instant.now().minus(1, HOURS)) .lastModified(Instant.now()) .isPublic(DATABASE_3_PUBLIC) .isSchemaPublic(DATABASE_3_SCHEMA_PUBLIC) + .isDashboardEnabled(DATABASE_3_DASHBOARD_ENABLED) + .dashboardUid(DATABASE_3_DASHBOARD_UID) .name(DATABASE_3_NAME) .description(DATABASE_3_DESCRIPTION) .cid(CONTAINER_1_ID) .container(CONTAINER_1) - .internalName(DATABASE_3_INTERNALNAME) + .internalName(DATABASE_3_INTERNAL_NAME) .exchangeName(DATABASE_3_EXCHANGE) .created(DATABASE_3_CREATED) .lastModified(DATABASE_3_LAST_MODIFIED) - .ownedBy(DATABASE_3_OWNER) + .ownedBy(USER_3_ID) .owner(USER_3) .contactPerson(USER_3_ID) .contact(USER_3) @@ -7729,7 +7665,7 @@ public abstract class BaseTest { .identifiers(new LinkedList<>()) /* IDENTIFIER_6 */ .build(); - public static final DatabaseAccess DATABASE_3_USER_1_READ_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_3_USER_1_READ_ACCESS = DatabaseAccess.builder() .type(AccessType.READ) .hdbid(DATABASE_3_ID) .database(DATABASE_3) @@ -7737,14 +7673,14 @@ public abstract class BaseTest { .user(USER_1) .build(); - public static final DatabaseAccessDto DATABASE_3_USER_1_READ_ACCESS_DTO = DatabaseAccessDto.builder() + public final DatabaseAccessDto DATABASE_3_USER_1_READ_ACCESS_DTO = DatabaseAccessDto.builder() .type(AccessTypeDto.READ) .hdbid(DATABASE_3_ID) .huserid(USER_1_ID) .user(USER_1_BRIEF_DTO) .build(); - public static final DatabaseAccess DATABASE_3_USER_1_WRITE_OWN_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_3_USER_1_WRITE_OWN_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_OWN) .hdbid(DATABASE_3_ID) .database(DATABASE_3) @@ -7752,14 +7688,14 @@ public abstract class BaseTest { .user(USER_1) .build(); - public static final DatabaseAccessDto DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO = DatabaseAccessDto.builder() + public final DatabaseAccessDto DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO = DatabaseAccessDto.builder() .type(AccessTypeDto.WRITE_OWN) .hdbid(DATABASE_3_ID) .huserid(USER_1_ID) .user(USER_1_BRIEF_DTO) .build(); - public static final DatabaseAccess DATABASE_3_USER_1_WRITE_ALL_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_3_USER_1_WRITE_ALL_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_ALL) .hdbid(DATABASE_3_ID) .database(DATABASE_3) @@ -7767,14 +7703,14 @@ public abstract class BaseTest { .user(USER_1) .build(); - public static final DatabaseAccessDto DATABASE_3_USER_1_WRITE_ALL_ACCESS_DTO = DatabaseAccessDto.builder() + public final 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 static final DatabaseAccess DATABASE_3_USER_2_READ_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_3_USER_2_READ_ACCESS = DatabaseAccess.builder() .type(AccessType.READ) .hdbid(DATABASE_3_ID) .database(DATABASE_3) @@ -7782,7 +7718,7 @@ public abstract class BaseTest { .user(USER_2) .build(); - public static final DatabaseAccess DATABASE_3_USER_2_WRITE_OWN_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_3_USER_2_WRITE_OWN_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_OWN) .hdbid(DATABASE_3_ID) .database(DATABASE_3) @@ -7790,7 +7726,7 @@ public abstract class BaseTest { .user(USER_2) .build(); - public static final DatabaseAccess DATABASE_3_USER_2_WRITE_ALL_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_3_USER_2_WRITE_ALL_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_ALL) .hdbid(DATABASE_3_ID) .database(DATABASE_3) @@ -7798,7 +7734,7 @@ public abstract class BaseTest { .user(USER_2) .build(); - public static final DatabaseAccess DATABASE_3_USER_3_READ_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_3_USER_3_READ_ACCESS = DatabaseAccess.builder() .type(AccessType.READ) .hdbid(DATABASE_3_ID) .database(DATABASE_3) @@ -7806,14 +7742,14 @@ public abstract class BaseTest { .user(USER_3) .build(); - public static final DatabaseAccessDto DATABASE_3_USER_3_READ_ACCESS_DTO = DatabaseAccessDto.builder() + public final DatabaseAccessDto DATABASE_3_USER_3_READ_ACCESS_DTO = DatabaseAccessDto.builder() .type(AccessTypeDto.READ) .hdbid(DATABASE_3_ID) .huserid(USER_3_ID) .user(USER_3_BRIEF_DTO) .build(); - public static final DatabaseAccess DATABASE_3_USER_3_WRITE_OWN_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_3_USER_3_WRITE_OWN_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_OWN) .hdbid(DATABASE_3_ID) .database(DATABASE_3) @@ -7821,14 +7757,14 @@ public abstract class BaseTest { .user(USER_3) .build(); - public static final DatabaseAccessDto DATABASE_3_USER_3_WRITE_OWN_ACCESS_DTO = DatabaseAccessDto.builder() + public final DatabaseAccessDto DATABASE_3_USER_3_WRITE_OWN_ACCESS_DTO = DatabaseAccessDto.builder() .type(AccessTypeDto.WRITE_OWN) .hdbid(DATABASE_3_ID) .huserid(USER_3_ID) .user(USER_3_BRIEF_DTO) .build(); - public static final DatabaseAccess DATABASE_3_USER_3_WRITE_ALL_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_3_USER_3_WRITE_ALL_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_ALL) .hdbid(DATABASE_3_ID) .database(DATABASE_3) @@ -7836,14 +7772,27 @@ public abstract class BaseTest { .user(USER_3) .build(); - public static final DatabaseAccessDto DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO = DatabaseAccessDto.builder() + public final DatabaseAccessDto DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO = DatabaseAccessDto.builder() .type(AccessTypeDto.WRITE_ALL) .hdbid(DATABASE_3_ID) .huserid(USER_3_ID) .user(USER_3_BRIEF_DTO) .build(); - public static final Identifier IDENTIFIER_7 = Identifier.builder() + public final CreateDashboardResponseDto DATABASE_3_CREATE_DASHBOARD_RESPONSE_DTO = + CreateDashboardResponseDto.builder() + .id(3L) + .uid(DATABASE_3_DASHBOARD_UID) + .build(); + + public final CreateDashboardDto DATABASE_3_CREATE_DASHBOARD_DTO = CreateDashboardDto.builder() + .databaseName(DATABASE_3_INTERNAL_NAME) + .isPublic(DATABASE_3_PUBLIC) + .isSchemaPublic(DATABASE_3_SCHEMA_PUBLIC) + .ownerUsername(USER_3_USERNAME) + .build(); + + public final Identifier IDENTIFIER_7 = Identifier.builder() .id(IDENTIFIER_7_ID) .descriptions(new LinkedList<>()) .titles(new LinkedList<>()) @@ -7866,21 +7815,23 @@ public abstract class BaseTest { .status(IDENTIFIER_7_STATUS_TYPE) .build(); - public static final Database DATABASE_4 = Database.builder() + public final Database DATABASE_4 = Database.builder() .id(DATABASE_4_ID) .created(Instant.now().minus(4, HOURS)) .lastModified(Instant.now()) .isPublic(DATABASE_4_PUBLIC) .isSchemaPublic(DATABASE_4_SCHEMA_PUBLIC) + .isDashboardEnabled(DATABASE_4_DASHBOARD_ENABLED) + .dashboardUid(DATABASE_4_DASHBOARD_UID) .name(DATABASE_4_NAME) .description(DATABASE_4_DESCRIPTION) .cid(CONTAINER_4_ID) .container(CONTAINER_4) - .internalName(DATABASE_4_INTERNALNAME) + .internalName(DATABASE_4_INTERNAL_NAME) .exchangeName(DATABASE_4_EXCHANGE) .created(DATABASE_4_CREATED) .lastModified(DATABASE_4_LAST_MODIFIED) - .ownedBy(DATABASE_4_OWNER) + .ownedBy(USER_4_ID) .owner(USER_4) .contactPerson(USER_4_ID) .contact(USER_4) @@ -7889,72 +7840,85 @@ public abstract class BaseTest { .identifiers(new LinkedList<>()) .build(); - public static final DatabaseAccess DATABASE_4_USER_1_READ_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_4_USER_1_READ_ACCESS = DatabaseAccess.builder() .type(AccessType.READ) .hdbid(DATABASE_4_ID) .database(DATABASE_4) .huserid(USER_1_ID) .build(); - public static final DatabaseAccess DATABASE_4_USER_1_WRITE_OWN_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_4_USER_1_WRITE_OWN_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_OWN) .hdbid(DATABASE_4_ID) .database(DATABASE_4) .huserid(USER_1_ID) .build(); - public static final DatabaseAccess DATABASE_4_USER_1_WRITE_ALL_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_4_USER_1_WRITE_ALL_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_ALL) .hdbid(DATABASE_4_ID) .database(DATABASE_4) .huserid(USER_1_ID) .build(); - public static final DatabaseAccess DATABASE_4_USER_2_READ_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_4_USER_2_READ_ACCESS = DatabaseAccess.builder() .type(AccessType.READ) .hdbid(DATABASE_4_ID) .database(DATABASE_4) .huserid(USER_2_ID) .build(); - public static final DatabaseAccess DATABASE_4_USER_2_WRITE_OWN_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_4_USER_2_WRITE_OWN_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_OWN) .hdbid(DATABASE_4_ID) .database(DATABASE_4) .huserid(USER_2_ID) .build(); - public static final DatabaseAccess DATABASE_4_USER_2_WRITE_ALL_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_4_USER_2_WRITE_ALL_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_ALL) .hdbid(DATABASE_4_ID) .database(DATABASE_4) .huserid(USER_2_ID) .build(); - public static final DatabaseAccess DATABASE_4_USER_3_READ_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_4_USER_3_READ_ACCESS = DatabaseAccess.builder() .type(AccessType.READ) .hdbid(DATABASE_4_ID) .database(DATABASE_4) .huserid(USER_3_ID) .build(); - public static final DatabaseAccess DATABASE_4_USER_3_WRITE_OWN_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_4_USER_3_WRITE_OWN_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_OWN) .hdbid(DATABASE_4_ID) .database(DATABASE_4) .huserid(USER_3_ID) .build(); - public static final DatabaseAccess DATABASE_4_USER_3_WRITE_ALL_ACCESS = DatabaseAccess.builder() + public final DatabaseAccess DATABASE_4_USER_3_WRITE_ALL_ACCESS = DatabaseAccess.builder() .type(AccessType.WRITE_ALL) .hdbid(DATABASE_4_ID) .database(DATABASE_4) .huserid(USER_3_ID) .build(); - public static final List<IdentifierDto> VIEW_1_DTO_IDENTIFIERS = List.of(IDENTIFIER_3_DTO); + public final CreateDashboardResponseDto DATABASE_4_CREATE_DASHBOARD_RESPONSE_DTO = + CreateDashboardResponseDto.builder() + .id(4L) + .uid(DATABASE_4_DASHBOARD_UID) + .build(); + + public final CreateDashboardDto DATABASE_4_CREATE_DASHBOARD_DTO = CreateDashboardDto.builder() + .databaseName(DATABASE_4_INTERNAL_NAME) + .isPublic(DATABASE_4_PUBLIC) + .isSchemaPublic(DATABASE_4_SCHEMA_PUBLIC) + .ownerUsername(USER_4_USERNAME) + .build(); + + public final List<IdentifierDto> VIEW_1_DTO_IDENTIFIERS = List.of(IDENTIFIER_3_DTO); - public static final Constraints TABLE_1_CONSTRAINTS = Constraints.builder() + public final Constraints TABLE_1_CONSTRAINTS = Constraints.builder() .checks(new LinkedHashSet<>()) .foreignKeys(new LinkedList<>()) .uniques(new LinkedList<>()) @@ -7965,7 +7929,7 @@ public abstract class BaseTest { .build()))) .build(); - public static final ConstraintsDto TABLE_1_CONSTRAINTS_DTO = ConstraintsDto.builder() + public final ConstraintsDto TABLE_1_CONSTRAINTS_DTO = ConstraintsDto.builder() .checks(new LinkedHashSet<>()) .foreignKeys(new LinkedList<>()) .uniques(new LinkedList<>()) @@ -7976,7 +7940,7 @@ public abstract class BaseTest { .build()))) .build(); - public static final Constraints TABLE_2_CONSTRAINTS = Constraints.builder() + public final Constraints TABLE_2_CONSTRAINTS = Constraints.builder() .checks(new LinkedHashSet<>(List.of("`mintemp` > 0"))) .foreignKeys(new LinkedList<>(List.of(ForeignKey.builder() .id(UUID.fromString("d79f0fb1-05d6-4f3e-a5e2-8559982b8516")) @@ -8005,36 +7969,36 @@ public abstract class BaseTest { .build()))) .build(); - public static final ConstraintsDto TABLE_2_CONSTRAINTS_DTO = ConstraintsDto.builder() + public final ConstraintsDto TABLE_2_CONSTRAINTS_DTO = ConstraintsDto.builder() .checks(new LinkedHashSet<>(List.of("`mintemp` > 0"))) .foreignKeys(new LinkedList<>(List.of(ForeignKeyDto.builder() - .id(UUID.fromString("ca833111-1e9a-48a3-bb16-ad6f90196f96")) + .id(UUID.fromString("d79f0fb1-05d6-4f3e-a5e2-8559982b8516")) .name("fk_location") .onDelete(ReferenceTypeDto.NO_ACTION) .references(new LinkedList<>(List.of(ForeignKeyReferenceDto.builder() - .id(UUID.fromString("8552f282-0403-424d-b2ba-4ed0f760197c")) - .column(TABLE_2_COLUMNS_BRIEF_2_DTO) + .id(UUID.fromString("a4da8f2f-2999-4621-8066-801a2fb73c8d")) + .column(TABLE_2_COLUMNS_BRIEF_DTO.get(2)) .referencedColumn(TABLE_1_COLUMNS_BRIEF_0_DTO) .foreignKey(null) // set later .build()))) - .table(TABLE_1_BRIEF_DTO) - .referencedTable(TABLE_2_BRIEF_DTO) + .table(TABLE_2_BRIEF_DTO) + .referencedTable(TABLE_1_BRIEF_DTO) .onUpdate(ReferenceTypeDto.NO_ACTION) .build()))) .uniques(new LinkedList<>(List.of(UniqueDto.builder() - .id(UUID.fromString("b9aba807-dd9c-43a3-9614-2493cb4b26bd")) + .id(UUID.fromString("408e398f-d157-49a1-8b45-87a070f3b4de")) .table(TABLE_2_BRIEF_DTO) .name("uk_1") .columns(new LinkedList<>(List.of(TABLE_2_COLUMNS_BRIEF_DTO.get(1)))) .build()))) - .primaryKey(new LinkedHashSet<>(Set.of(PrimaryKeyDto.builder() + .primaryKey(new LinkedHashSet<>(List.of(PrimaryKeyDto.builder() .table(TABLE_2_BRIEF_DTO) - .column(TABLE_2_COLUMNS_BRIEF_0_DTO) + .column(TABLE_2_COLUMNS_BRIEF_DTO.get(0)) .id(COLUMN_2_1_ID) .build()))) .build(); - public static final Constraints TABLE_3_CONSTRAINTS = Constraints.builder() + public final Constraints TABLE_3_CONSTRAINTS = Constraints.builder() .checks(new LinkedHashSet<>()) .foreignKeys(new LinkedList<>()) .uniques(new LinkedList<>()) @@ -8045,7 +8009,7 @@ public abstract class BaseTest { .build()))) .build(); - public static final ConstraintsDto TABLE_3_CONSTRAINTS_DTO = ConstraintsDto.builder() + public final ConstraintsDto TABLE_3_CONSTRAINTS_DTO = ConstraintsDto.builder() .checks(new LinkedHashSet<>()) .foreignKeys(new LinkedList<>()) .uniques(new LinkedList<>()) @@ -8056,7 +8020,7 @@ public abstract class BaseTest { .build()))) .build(); - public static final Constraints TABLE_4_CONSTRAINTS = Constraints.builder() + public final Constraints TABLE_4_CONSTRAINTS = Constraints.builder() .checks(new LinkedHashSet<>()) .foreignKeys(new LinkedList<>()) .uniques(new LinkedList<>()) @@ -8067,7 +8031,7 @@ public abstract class BaseTest { .build()))) .build(); - public static final ConstraintsDto TABLE_4_CONSTRAINTS_DTO = ConstraintsDto.builder() + public final ConstraintsDto TABLE_4_CONSTRAINTS_DTO = ConstraintsDto.builder() .checks(new LinkedHashSet<>()) .foreignKeys(new LinkedList<>()) .uniques(new LinkedList<>()) @@ -8078,7 +8042,7 @@ public abstract class BaseTest { .build()))) .build(); - public static final Constraints TABLE_5_CONSTRAINTS = Constraints.builder() + public final Constraints TABLE_5_CONSTRAINTS = Constraints.builder() .checks(new LinkedHashSet<>()) .foreignKeys(new LinkedList<>()) .uniques(new LinkedList<>()) @@ -8089,7 +8053,7 @@ public abstract class BaseTest { .build()))) .build(); - public static final ConstraintsDto TABLE_5_CONSTRAINTS_DTO = ConstraintsDto.builder() + public final ConstraintsDto TABLE_5_CONSTRAINTS_DTO = ConstraintsDto.builder() .checks(new LinkedHashSet<>()) .foreignKeys(new LinkedList<>()) .uniques(new LinkedList<>()) @@ -8100,7 +8064,7 @@ public abstract class BaseTest { .build()))) .build(); - public static final Constraints TABLE_6_CONSTRAINTS = Constraints.builder() + public final Constraints TABLE_6_CONSTRAINTS = Constraints.builder() .checks(new LinkedHashSet<>()) .foreignKeys(new LinkedList<>(List.of())) .uniques(new LinkedList<>()) @@ -8111,7 +8075,7 @@ public abstract class BaseTest { .build()))) .build(); - public static final ConstraintsDto TABLE_6_CONSTRAINTS_DTO = ConstraintsDto.builder() + public final ConstraintsDto TABLE_6_CONSTRAINTS_DTO = ConstraintsDto.builder() .checks(new LinkedHashSet<>()) .foreignKeys(new LinkedList<>()) .uniques(new LinkedList<>()) @@ -8122,7 +8086,7 @@ public abstract class BaseTest { .build()))) .build(); - public static final Constraints TABLE_7_CONSTRAINTS = Constraints.builder() + public final Constraints TABLE_7_CONSTRAINTS = Constraints.builder() .checks(new LinkedHashSet<>()) .foreignKeys(new LinkedList<>(List.of(ForeignKey.builder() .id(UUID.fromString("421c3dd8-ae09-4c72-a6ca-09de009e755f")) @@ -8160,7 +8124,7 @@ public abstract class BaseTest { .build()))) .build(); - public static final ForeignKeyDto TABLE_7_CONSTRAINTS_FOREIGN_KEY_0_DTO = ForeignKeyDto.builder() + public final ForeignKeyDto TABLE_7_CONSTRAINTS_FOREIGN_KEY_0_DTO = ForeignKeyDto.builder() .id(UUID.fromString("561b4933-54e5-4dad-a536-39836da87fe3")) .name("fk_name_id") .onDelete(ReferenceTypeDto.NO_ACTION) @@ -8175,11 +8139,11 @@ public abstract class BaseTest { .onUpdate(ReferenceTypeDto.NO_ACTION) .build(); - public static final ForeignKeyBriefDto TABLE_7_CONSTRAINTS_FOREIGN_KEY_BRIEF_0_DTO = ForeignKeyBriefDto.builder() + public final ForeignKeyBriefDto TABLE_7_CONSTRAINTS_FOREIGN_KEY_BRIEF_0_DTO = ForeignKeyBriefDto.builder() .id(UUID.fromString("a92f09c5-9bce-4f77-8f7b-a9afc1d30ec2")) .build(); - public static final ForeignKeyDto TABLE_7_CONSTRAINTS_FOREIGN_KEY_1_DTO = ForeignKeyDto.builder() + public final ForeignKeyDto TABLE_7_CONSTRAINTS_FOREIGN_KEY_1_DTO = ForeignKeyDto.builder() .id(UUID.fromString("f2e82566-ddc3-4b76-8d27-adc3c51780a9")) .name("fk_zoo_id") .onDelete(ReferenceTypeDto.NO_ACTION) @@ -8194,11 +8158,11 @@ public abstract class BaseTest { .onUpdate(ReferenceTypeDto.NO_ACTION) .build(); - public static final ForeignKeyBriefDto TABLE_7_CONSTRAINTS_FOREIGN_KEY_BRIEF_1_DTO = ForeignKeyBriefDto.builder() + public final ForeignKeyBriefDto TABLE_7_CONSTRAINTS_FOREIGN_KEY_BRIEF_1_DTO = ForeignKeyBriefDto.builder() .id(UUID.fromString("6ce1f707-0bdf-4930-be77-157801d2735a")) .build(); - public static final ConstraintsDto TABLE_7_CONSTRAINTS_DTO = ConstraintsDto.builder() + public final ConstraintsDto TABLE_7_CONSTRAINTS_DTO = ConstraintsDto.builder() .checks(new LinkedHashSet<>()) .foreignKeys(new LinkedList<>(List.of(TABLE_7_CONSTRAINTS_FOREIGN_KEY_0_DTO, TABLE_7_CONSTRAINTS_FOREIGN_KEY_1_DTO))) @@ -8210,7 +8174,7 @@ public abstract class BaseTest { .build()))) .build(); - public static final Constraints TABLE_8_CONSTRAINTS = Constraints.builder() + public final Constraints TABLE_8_CONSTRAINTS = Constraints.builder() .checks(new LinkedHashSet<>()) .foreignKeys(new LinkedList<>()) .uniques(new LinkedList<>()) @@ -8221,7 +8185,7 @@ public abstract class BaseTest { .build()))) .build(); - public static final ConstraintsDto TABLE_8_CONSTRAINTS_DTO = ConstraintsDto.builder() + public final ConstraintsDto TABLE_8_CONSTRAINTS_DTO = ConstraintsDto.builder() .checks(new LinkedHashSet<>()) .foreignKeys(new LinkedList<>()) .uniques(new LinkedList<>()) @@ -8232,12 +8196,12 @@ public abstract class BaseTest { .build()))) .build(); - public static final ExportResourceDto EXPORT_RESOURCE_DTO = ExportResourceDto.builder() + public final ExportResourceDto EXPORT_RESOURCE_DTO = ExportResourceDto.builder() .filename("68b329da9893e34099c7d8ad5cb9c940") .resource(new InputStreamResource(InputStream.nullInputStream())) .build(); - public static final QueryDto QUERY_1_DTO = QueryDto.builder() + public final QueryDto QUERY_1_DTO = QueryDto.builder() .id(QUERY_1_ID) .databaseId(DATABASE_1_ID) .query(QUERY_1_STATEMENT) @@ -8249,7 +8213,7 @@ public abstract class BaseTest { .resultNumber(3L) .build(); - public static final QueryDto QUERY_2_DTO = QueryDto.builder() + public final QueryDto QUERY_2_DTO = QueryDto.builder() .id(QUERY_2_ID) .databaseId(DATABASE_1_ID) .query(QUERY_2_STATEMENT) @@ -8263,7 +8227,7 @@ public abstract class BaseTest { .resultNumber(3L) .build(); - public static final QueryDto QUERY_3_DTO = QueryDto.builder() + public final QueryDto QUERY_3_DTO = QueryDto.builder() .id(QUERY_3_ID) .databaseId(DATABASE_1_ID) .query(QUERY_3_STATEMENT) @@ -8277,7 +8241,7 @@ public abstract class BaseTest { .resultNumber(2L) .build(); - public static final QueryDto QUERY_7_DTO = QueryDto.builder() + public final QueryDto QUERY_7_DTO = QueryDto.builder() .id(QUERY_7_ID) .databaseId(DATABASE_4_ID) .query(QUERY_7_STATEMENT) @@ -8291,7 +8255,7 @@ public abstract class BaseTest { .resultNumber(2L) .build(); - public static final QueryDto QUERY_6_DTO = QueryDto.builder() + public final QueryDto QUERY_6_DTO = QueryDto.builder() .id(QUERY_6_ID) .databaseId(DATABASE_1_ID) .query(QUERY_6_STATEMENT) @@ -8304,7 +8268,7 @@ public abstract class BaseTest { .isPersisted(QUERY_6_PERSISTED) .build(); - public static final QueryDto QUERY_8_DTO = QueryDto.builder() + public final QueryDto QUERY_8_DTO = QueryDto.builder() .id(QUERY_8_ID) .databaseId(DATABASE_2_ID) .query(QUERY_8_STATEMENT) @@ -8318,4 +8282,131 @@ public abstract class BaseTest { .resultNumber(3L) .build(); -} + public BaseTest() { + IMAGE_1_DTO.setOperators(IMAGE_1_OPERATORS_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))); + /* DATABASE 1 */ + DATABASE_1.setOwner(USER_1); + DATABASE_1.setSubsets(new LinkedList<>()); + DATABASE_1.setAccesses(new LinkedList<>(List.of(DATABASE_1_USER_1_READ_ACCESS, DATABASE_1_USER_2_WRITE_OWN_ACCESS, DATABASE_1_USER_3_WRITE_ALL_ACCESS))); + DATABASE_1_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); + TABLE_1.setColumns(new LinkedList<>(TABLE_1_COLUMNS)); + TABLE_1.setConstraints(TABLE_1_CONSTRAINTS); + 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); + IDENTIFIER_2.setDatabase(DATABASE_1); + IDENTIFIER_3.setDatabase(DATABASE_1); + 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_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_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_DTO.setColumns(new LinkedList<>(TABLE_2_COLUMNS_DTO)); + TABLE_2_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); + TABLE_3_DTO.setColumns(new LinkedList<>(TABLE_3_COLUMNS_DTO)); + TABLE_3_DTO.setConstraints(TABLE_3_CONSTRAINTS_DTO); + TABLE_4.setDatabase(DATABASE_1); + TABLE_4.setColumns(new LinkedList<>(TABLE_4_COLUMNS)); + TABLE_4.setConstraints(TABLE_4_CONSTRAINTS); + TABLE_4_DTO.setColumns(TABLE_4_COLUMNS_DTO); + TABLE_4_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))); + VIEW_2.setDatabase(DATABASE_1); + VIEW_2.setColumns(new LinkedList<>(VIEW_2_COLUMNS)); + VIEW_3.setDatabase(DATABASE_1); + VIEW_3.setColumns(new LinkedList<>(VIEW_3_COLUMNS)); + IDENTIFIER_1.setDatabase(DATABASE_1); + IDENTIFIER_2.setDatabase(DATABASE_1); + IDENTIFIER_3.setDatabase(DATABASE_1); + IDENTIFIER_4.setDatabase(DATABASE_1); + /* DATABASE 2 */ + DATABASE_2.setAccesses(new LinkedList<>(List.of(DATABASE_2_USER_2_WRITE_ALL_ACCESS, DATABASE_2_USER_3_READ_ACCESS))); + DATABASE_2.setTables(new LinkedList<>(List.of(TABLE_5, TABLE_6, TABLE_7))); + 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_DTO.setAccesses(new LinkedList<>(List.of(DATABASE_2_USER_2_WRITE_ALL_ACCESS_DTO, DATABASE_2_USER_3_READ_ACCESS_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))); + 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_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))); + TABLE_5.setDatabase(DATABASE_2); + TABLE_5.setColumns(new LinkedList<>(TABLE_5_COLUMNS)); + TABLE_5.setConstraints(TABLE_5_CONSTRAINTS); + TABLE_5_DTO.setColumns(new LinkedList<>(TABLE_5_COLUMNS_DTO)); + TABLE_5_DTO.setConstraints(TABLE_5_CONSTRAINTS_DTO); + TABLE_6.setDatabase(DATABASE_2); + TABLE_6.setColumns(new LinkedList<>(TABLE_6_COLUMNS)); + TABLE_6.setConstraints(TABLE_6_CONSTRAINTS); + TABLE_7.setDatabase(DATABASE_2); + TABLE_7.setColumns(new LinkedList<>(TABLE_7_COLUMNS)); + TABLE_7.setConstraints(TABLE_7_CONSTRAINTS); + TABLE_7_CONSTRAINTS.getForeignKeys().get(0).getReferences().get(0).setForeignKey(TABLE_7_CONSTRAINTS.getForeignKeys().get(0)); + TABLE_7_CONSTRAINTS.getForeignKeys().get(1).getReferences().get(0).setForeignKey(TABLE_7_CONSTRAINTS.getForeignKeys().get(1)); + TABLE_7_DTO.setColumns(TABLE_7_COLUMNS_DTO); + TABLE_7_DTO.setConstraints(TABLE_7_CONSTRAINTS_DTO); + TABLE_7_CONSTRAINTS_DTO.getForeignKeys().get(0).getReferences().get(0).setForeignKey(TABLE_7_CONSTRAINTS_FOREIGN_KEY_BRIEF_0_DTO); + TABLE_7_CONSTRAINTS_DTO.getForeignKeys().get(1).getReferences().get(0).setForeignKey(TABLE_7_CONSTRAINTS_FOREIGN_KEY_BRIEF_1_DTO); + VIEW_4.setDatabase(DATABASE_2); + IDENTIFIER_5.setDatabase(DATABASE_2); + /* DATABASE 3 */ + DATABASE_3.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))); + DATABASE_3_PRIVILEGED_DTO.setTables(new LinkedList<>(List.of(TABLE_8_DTO))); + DATABASE_3_PRIVILEGED_DTO.setViews(new LinkedList<>(List.of(VIEW_5_DTO))); + DATABASE_3_PRIVILEGED_DTO.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_6_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); + 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.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))); + DATABASE_4_PRIVILEGED_DTO.setTables(new LinkedList<>(List.of(TABLE_9_DTO))); + DATABASE_4_PRIVILEGED_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); + IDENTIFIER_7.setStatus(IdentifierStatusType.DRAFT); + IDENTIFIER_7.setDatabase(DATABASE_4); + } + +} \ No newline at end of file diff --git a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/dto/LocaleDto.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/test/dto/LocaleDto.java similarity index 86% rename from dbrepo-metadata-service/test/src/main/java/at/tuwien/test/dto/LocaleDto.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/test/dto/LocaleDto.java index d14ad880d9b1ee634f720eaaed48999fdda4f048..bec6d7ea05441e42fb76302717c1516d2065e28d 100644 --- a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/dto/LocaleDto.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/test/dto/LocaleDto.java @@ -1,4 +1,4 @@ -package at.tuwien.test.dto; +package at.ac.tuwien.ifs.dbrepo.core.test.dto; import lombok.*; diff --git a/dbrepo-metadata-service/test/pom.xml b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/test/pom.xml similarity index 94% rename from dbrepo-metadata-service/test/pom.xml rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/test/pom.xml index b6bf12dfa44cff39bf6c89127d48e3e2b0594276..a7995dec69978781b8286d235d583a93e55bb4d3 100644 --- a/dbrepo-metadata-service/test/pom.xml +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/test/pom.xml @@ -6,12 +6,12 @@ <parent> <groupId>at.tuwien</groupId> <artifactId>dbrepo-metadata-service</artifactId> - <version>1.7.3</version> + <version>1.8.0</version> </parent> <artifactId>dbrepo-metadata-service-test</artifactId> <name>dbrepo-metadata-service-test</name> - <version>1.7.3</version> + <version>1.8.0</version> <dependencies> <dependency> diff --git a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/utils/ArrayUtils.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/test/utils/ArrayUtils.java similarity index 87% rename from dbrepo-metadata-service/test/src/main/java/at/tuwien/test/utils/ArrayUtils.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/test/utils/ArrayUtils.java index 50dff12d856f79bcd78c8474fea34f757f33a13c..c30116295fa2532945ec3df6ab0d3660cb41813c 100644 --- a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/utils/ArrayUtils.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/test/utils/ArrayUtils.java @@ -1,4 +1,4 @@ -package at.tuwien.test.utils; +package at.ac.tuwien.ifs.dbrepo.core.test.utils; import java.util.Arrays; import java.util.LinkedList; diff --git a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/utils/EndpointUtils.java b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/test/utils/EndpointUtils.java similarity index 94% rename from dbrepo-metadata-service/test/src/main/java/at/tuwien/test/utils/EndpointUtils.java rename to lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/test/utils/EndpointUtils.java index a2101bf3abf5ed68b910a55c064cda00aaf4b847..56adf110c9f7fb3d002a13bf3a22de0b056c5a4c 100644 --- a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/utils/EndpointUtils.java +++ b/lib/java/dbrepo-core/src/main/java/at/ac/tuwien/ifs/dbrepo/core/test/utils/EndpointUtils.java @@ -1,6 +1,6 @@ -package at.tuwien.test.utils; +package at.ac.tuwien.ifs.dbrepo.core.test.utils; -import at.tuwien.test.dto.LocaleDto; +import at.ac.tuwien.ifs.dbrepo.core.test.dto.LocaleDto; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.config.BeanDefinition; diff --git a/lib/python/Makefile b/lib/python/Makefile deleted file mode 100644 index afebb199acc957c9972a89535b90052f510edbb5..0000000000000000000000000000000000000000 --- a/lib/python/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -all: build - -clean: - rm -rf ./python/dist/* ./docs/build/* ./dist/* - -docs: clean - sphinx-apidoc -o ./docs/source ./dbrepo - sphinx-build -M html ./docs/ ./docs/build/ - -check: - python3 ./python/setup.py develop - -build: clean - python3 -m build --sdist . - python3 -m build --wheel . - -deploy: build - python3 -m twine upload --config-file ~/.pypirc --verbose --repository pypi ./dist/dbrepo-* - -deploy-test: build - python3 -m twine upload --config-file ~/.pypirc --verbose --repository testpypi ./dist/dbrepo-* - -FORCE: ; \ No newline at end of file diff --git a/lib/python/Pipfile b/lib/python/Pipfile index b7ebe44f3ab7d19fdec0ee847e82f95f7ab5d7a6..e9fb9d21777709225f6ff6c3b0bd723a98d9a126 100644 --- a/lib/python/Pipfile +++ b/lib/python/Pipfile @@ -10,6 +10,9 @@ paho-mqtt = "*" pydantic = "*" tuspy = "*" pandas = "*" +jwt = "~=1.3" +grafana-client = "*" +opensearch-py = "~=2.2" [dev-packages] build = "*" @@ -22,6 +25,8 @@ requests-mock = "*" furo = "*" pytest-ordering = "*" httpx = "*" +testcontainers-minio = "*" +testcontainers-opensearch = "*" [requires] python_version = "3.11" diff --git a/lib/python/Pipfile.lock b/lib/python/Pipfile.lock index d4c90209c06fd3690890b9a76944cb25817ff139..a0cbd664aef73a91dca3603bc7826d110236da87 100644 --- a/lib/python/Pipfile.lock +++ b/lib/python/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "049bd8a6ac52e886dce11e7d7de630464e073e360471f35125a2eccf7c30a7a7" + "sha256": "b4e4c9e239afef86e7bfbe56d0f92336cacdc3fa9e4f85c0f51c8551771396ae" }, "pipfile-spec": 6, "requires": { @@ -18,98 +18,98 @@ "default": { "aiohappyeyeballs": { "hashes": [ - "sha256:147ec992cf873d74f5062644332c539fcd42956dc69453fe5204195e560517e1", - "sha256:9b05052f9042985d32ecbe4b59a77ae19c006a78f1344d7fdad69d28ded3d0b0" + "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", + "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8" ], "markers": "python_version >= '3.9'", - "version": "==2.4.6" + "version": "==2.6.1" }, "aiohttp": { "hashes": [ - "sha256:0450ada317a65383b7cce9576096150fdb97396dcfe559109b403c7242faffef", - "sha256:0b5263dcede17b6b0c41ef0c3ccce847d82a7da98709e75cf7efde3e9e3b5cae", - "sha256:0d5176f310a7fe6f65608213cc74f4228e4f4ce9fd10bcb2bb6da8fc66991462", - "sha256:0ed49efcd0dc1611378beadbd97beb5d9ca8fe48579fc04a6ed0844072261b6a", - "sha256:145a73850926018ec1681e734cedcf2716d6a8697d90da11284043b745c286d5", - "sha256:1987770fb4887560363b0e1a9b75aa303e447433c41284d3af2840a2f226d6e0", - "sha256:246067ba0cf5560cf42e775069c5d80a8989d14a7ded21af529a4e10e3e0f0e6", - "sha256:2c311e2f63e42c1bf86361d11e2c4a59f25d9e7aabdbdf53dc38b885c5435cdb", - "sha256:2cee3b117a8d13ab98b38d5b6bdcd040cfb4181068d05ce0c474ec9db5f3c5bb", - "sha256:2de1378f72def7dfb5dbd73d86c19eda0ea7b0a6873910cc37d57e80f10d64e1", - "sha256:30f546358dfa0953db92ba620101fefc81574f87b2346556b90b5f3ef16e55ce", - "sha256:34245498eeb9ae54c687a07ad7f160053911b5745e186afe2d0c0f2898a1ab8a", - "sha256:392432a2dde22b86f70dd4a0e9671a349446c93965f261dbaecfaf28813e5c42", - "sha256:3c0600bcc1adfaaac321422d615939ef300df81e165f6522ad096b73439c0f58", - "sha256:4016e383f91f2814e48ed61e6bda7d24c4d7f2402c75dd28f7e1027ae44ea204", - "sha256:40cd36749a1035c34ba8d8aaf221b91ca3d111532e5ccb5fa8c3703ab1b967ed", - "sha256:413ad794dccb19453e2b97c2375f2ca3cdf34dc50d18cc2693bd5aed7d16f4b9", - "sha256:4a93d28ed4b4b39e6f46fd240896c29b686b75e39cc6992692e3922ff6982b4c", - "sha256:4ee84c2a22a809c4f868153b178fe59e71423e1f3d6a8cd416134bb231fbf6d3", - "sha256:50c5c7b8aa5443304c55c262c5693b108c35a3b61ef961f1e782dd52a2f559c7", - "sha256:525410e0790aab036492eeea913858989c4cb070ff373ec3bc322d700bdf47c1", - "sha256:526c900397f3bbc2db9cb360ce9c35134c908961cdd0ac25b1ae6ffcaa2507ff", - "sha256:54775858c7f2f214476773ce785a19ee81d1294a6bedc5cc17225355aab74802", - "sha256:584096938a001378484aa4ee54e05dc79c7b9dd933e271c744a97b3b6f644957", - "sha256:6130459189e61baac5a88c10019b21e1f0c6d00ebc770e9ce269475650ff7f73", - "sha256:67453e603cea8e85ed566b2700efa1f6916aefbc0c9fcb2e86aaffc08ec38e78", - "sha256:68d54234c8d76d8ef74744f9f9fc6324f1508129e23da8883771cdbb5818cbef", - "sha256:6dfe7f984f28a8ae94ff3a7953cd9678550dbd2a1f9bda5dd9c5ae627744c78e", - "sha256:74bd573dde27e58c760d9ca8615c41a57e719bff315c9adb6f2a4281a28e8798", - "sha256:7603ca26d75b1b86160ce1bbe2787a0b706e592af5b2504e12caa88a217767b0", - "sha256:76719dd521c20a58a6c256d058547b3a9595d1d885b830013366e27011ffe804", - "sha256:7c3623053b85b4296cd3925eeb725e386644fd5bc67250b3bb08b0f144803e7b", - "sha256:7e44eba534381dd2687be50cbd5f2daded21575242ecfdaf86bbeecbc38dae8e", - "sha256:7fe3d65279bfbee8de0fb4f8c17fc4e893eed2dba21b2f680e930cc2b09075c5", - "sha256:8340def6737118f5429a5df4e88f440746b791f8f1c4ce4ad8a595f42c980bd5", - "sha256:84ede78acde96ca57f6cf8ccb8a13fbaf569f6011b9a52f870c662d4dc8cd854", - "sha256:850ff6155371fd802a280f8d369d4e15d69434651b844bde566ce97ee2277420", - "sha256:87a2e00bf17da098d90d4145375f1d985a81605267e7f9377ff94e55c5d769eb", - "sha256:88d385b8e7f3a870146bf5ea31786ef7463e99eb59e31db56e2315535d811f55", - "sha256:8a2fb742ef378284a50766e985804bd6adb5adb5aa781100b09befdbfa757b65", - "sha256:8dc0fba9a74b471c45ca1a3cb6e6913ebfae416678d90529d188886278e7f3f6", - "sha256:8fa1510b96c08aaad49303ab11f8803787c99222288f310a62f493faf883ede1", - "sha256:8fd12d0f989c6099e7b0f30dc6e0d1e05499f3337461f0b2b0dadea6c64b89df", - "sha256:9060addfa4ff753b09392efe41e6af06ea5dd257829199747b9f15bfad819460", - "sha256:930ffa1925393381e1e0a9b82137fa7b34c92a019b521cf9f41263976666a0d6", - "sha256:936d8a4f0f7081327014742cd51d320296b56aa6d324461a13724ab05f4b2933", - "sha256:97fe431f2ed646a3b56142fc81d238abcbaff08548d6912acb0b19a0cadc146b", - "sha256:9bd8695be2c80b665ae3f05cb584093a1e59c35ecb7d794d1edd96e8cc9201d7", - "sha256:9dec0000d2d8621d8015c293e24589d46fa218637d820894cb7356c77eca3259", - "sha256:a478aa11b328983c4444dacb947d4513cb371cd323f3845e53caeda6be5589d5", - "sha256:a481a574af914b6e84624412666cbfbe531a05667ca197804ecc19c97b8ab1b0", - "sha256:a4ac6a0f0f6402854adca4e3259a623f5c82ec3f0c049374133bcb243132baf9", - "sha256:a5e69046f83c0d3cb8f0d5bd9b8838271b1bc898e01562a04398e160953e8eb9", - "sha256:a7442662afebbf7b4c6d28cb7aab9e9ce3a5df055fc4116cc7228192ad6cb484", - "sha256:aa8a8caca81c0a3e765f19c6953416c58e2f4cc1b84829af01dd1c771bb2f91f", - "sha256:ab3247d58b393bda5b1c8f31c9edece7162fc13265334217785518dd770792b8", - "sha256:b10a47e5390c4b30a0d58ee12581003be52eedd506862ab7f97da7a66805befb", - "sha256:b34508f1cd928ce915ed09682d11307ba4b37d0708d1f28e5774c07a7674cac9", - "sha256:b8d3bb96c147b39c02d3db086899679f31958c5d81c494ef0fc9ef5bb1359b3d", - "sha256:b9d45dbb3aaec05cf01525ee1a7ac72de46a8c425cb75c003acd29f76b1ffe94", - "sha256:bf4480a5438f80e0f1539e15a7eb8b5f97a26fe087e9828e2c0ec2be119a9f72", - "sha256:c160a04283c8c6f55b5bf6d4cad59bb9c5b9c9cd08903841b25f1f7109ef1259", - "sha256:c96a43822f1f9f69cc5c3706af33239489a6294be486a0447fb71380070d4d5f", - "sha256:c9fd9dcf9c91affe71654ef77426f5cf8489305e1c66ed4816f5a21874b094b9", - "sha256:cddb31f8474695cd61fc9455c644fc1606c164b93bff2490390d90464b4655df", - "sha256:ce1bb21fc7d753b5f8a5d5a4bae99566386b15e716ebdb410154c16c91494d7f", - "sha256:d1c031a7572f62f66f1257db37ddab4cb98bfaf9b9434a3b4840bf3560f5e788", - "sha256:d589264dbba3b16e8951b6f145d1e6b883094075283dafcab4cdd564a9e353a0", - "sha256:dc065a4285307607df3f3686363e7f8bdd0d8ab35f12226362a847731516e42c", - "sha256:e10c440d142fa8b32cfdb194caf60ceeceb3e49807072e0dc3a8887ea80e8c16", - "sha256:e3552fe98e90fdf5918c04769f338a87fa4f00f3b28830ea9b78b1bdc6140e0d", - "sha256:e392804a38353900c3fd8b7cacbea5132888f7129f8e241915e90b85f00e3250", - "sha256:e4cecdb52aaa9994fbed6b81d4568427b6002f0a91c322697a4bfcc2b2363f5a", - "sha256:e5148ca8955affdfeb864aca158ecae11030e952b25b3ae15d4e2b5ba299bad2", - "sha256:e6b2732ef3bafc759f653a98881b5b9cdef0716d98f013d376ee8dfd7285abf1", - "sha256:ea756b5a7bac046d202a9a3889b9a92219f885481d78cd318db85b15cc0b7bcf", - "sha256:edb69b9589324bdc40961cdf0657815df674f1743a8d5ad9ab56a99e4833cfdd", - "sha256:f0203433121484b32646a5f5ea93ae86f3d9559d7243f07e8c0eab5ff8e3f70e", - "sha256:f6a19bcab7fbd8f8649d6595624856635159a6527861b9cdc3447af288a00c00", - "sha256:f752e80606b132140883bb262a457c475d219d7163d996dc9072434ffb0784c4", - "sha256:f7914ab70d2ee8ab91c13e5402122edbc77821c66d2758abb53aabe87f013287" + "sha256:04eb541ce1e03edc1e3be1917a0f45ac703e913c21a940111df73a2c2db11d73", + "sha256:05582cb2d156ac7506e68b5eac83179faedad74522ed88f88e5861b78740dc0e", + "sha256:0a29be28e60e5610d2437b5b2fed61d6f3dcde898b57fb048aa5079271e7f6f3", + "sha256:0b2501f1b981e70932b4a552fc9b3c942991c7ae429ea117e8fba57718cdeed0", + "sha256:0df3788187559c262922846087e36228b75987f3ae31dd0a1e5ee1034090d42f", + "sha256:12c5869e7ddf6b4b1f2109702b3cd7515667b437da90a5a4a50ba1354fe41881", + "sha256:14fc03508359334edc76d35b2821832f092c8f092e4b356e74e38419dfe7b6de", + "sha256:1a7169ded15505f55a87f8f0812c94c9412623c744227b9e51083a72a48b68a5", + "sha256:1c68e41c4d576cd6aa6c6d2eddfb32b2acfb07ebfbb4f9da991da26633a3db1a", + "sha256:20412c7cc3720e47a47e63c0005f78c0c2370020f9f4770d7fc0075f397a9fb0", + "sha256:22a8107896877212130c58f74e64b77f7007cb03cea8698be317272643602d45", + "sha256:28a3d083819741592685762d51d789e6155411277050d08066537c5edc4066e6", + "sha256:2b86efe23684b58a88e530c4ab5b20145f102916bbb2d82942cafec7bd36a647", + "sha256:2d0b46abee5b5737cb479cc9139b29f010a37b1875ee56d142aefc10686a390b", + "sha256:321238a42ed463848f06e291c4bbfb3d15ba5a79221a82c502da3e23d7525d06", + "sha256:3a8a0d127c10b8d89e69bbd3430da0f73946d839e65fec00ae48ca7916a31948", + "sha256:3a8b0321e40a833e381d127be993b7349d1564b756910b28b5f6588a159afef3", + "sha256:3b420d076a46f41ea48e5fcccb996f517af0d406267e31e6716f480a3d50d65c", + "sha256:3b512f1de1c688f88dbe1b8bb1283f7fbeb7a2b2b26e743bb2193cbadfa6f307", + "sha256:413fe39fd929329f697f41ad67936f379cba06fcd4c462b62e5b0f8061ee4a77", + "sha256:41cf0cefd9e7b5c646c2ef529c8335e7eafd326f444cc1cdb0c47b6bc836f9be", + "sha256:4848ae31ad44330b30f16c71e4f586cd5402a846b11264c412de99fa768f00f3", + "sha256:4b0a200e85da5c966277a402736a96457b882360aa15416bf104ca81e6f5807b", + "sha256:4e2e8ef37d4bc110917d038807ee3af82700a93ab2ba5687afae5271b8bc50ff", + "sha256:4edcbe34e6dba0136e4cabf7568f5a434d89cc9de5d5155371acda275353d228", + "sha256:51ba80d473eb780a329d73ac8afa44aa71dfb521693ccea1dea8b9b5c4df45ce", + "sha256:5409a59d5057f2386bb8b8f8bbcfb6e15505cedd8b2445db510563b5d7ea1186", + "sha256:572def4aad0a4775af66d5a2b5923c7de0820ecaeeb7987dcbccda2a735a993f", + "sha256:599b66582f7276ebefbaa38adf37585e636b6a7a73382eb412f7bc0fc55fb73d", + "sha256:59a05cdc636431f7ce843c7c2f04772437dd816a5289f16440b19441be6511f1", + "sha256:602d4db80daf4497de93cb1ce00b8fc79969c0a7cf5b67bec96fa939268d806a", + "sha256:65c75b14ee74e8eeff2886321e76188cbe938d18c85cff349d948430179ad02c", + "sha256:69bb252bfdca385ccabfd55f4cd740d421dd8c8ad438ded9637d81c228d0da49", + "sha256:6d3986112e34eaa36e280dc8286b9dd4cc1a5bcf328a7f147453e188f6fe148f", + "sha256:6dd9766da617855f7e85f27d2bf9a565ace04ba7c387323cd3e651ac4329db91", + "sha256:70ab0f61c1a73d3e0342cedd9a7321425c27a7067bebeeacd509f96695b875fc", + "sha256:749f1eb10e51dbbcdba9df2ef457ec060554842eea4d23874a3e26495f9e87b1", + "sha256:781c8bd423dcc4641298c8c5a2a125c8b1c31e11f828e8d35c1d3a722af4c15a", + "sha256:7e7abe865504f41b10777ac162c727af14e9f4db9262e3ed8254179053f63e6d", + "sha256:7f2dadece8b85596ac3ab1ec04b00694bdd62abc31e5618f524648d18d9dd7fa", + "sha256:86135c32d06927339c8c5e64f96e4eee8825d928374b9b71a3c42379d7437058", + "sha256:8778620396e554b758b59773ab29c03b55047841d8894c5e335f12bfc45ebd28", + "sha256:87f0e003fb4dd5810c7fbf47a1239eaa34cd929ef160e0a54c570883125c4831", + "sha256:8aa5c68e1e68fff7cd3142288101deb4316b51f03d50c92de6ea5ce646e6c71f", + "sha256:8d14e274828561db91e4178f0057a915f3af1757b94c2ca283cb34cbb6e00b50", + "sha256:8d1dd75aa4d855c7debaf1ef830ff2dfcc33f893c7db0af2423ee761ebffd22b", + "sha256:92007c89a8cb7be35befa2732b0b32bf3a394c1b22ef2dff0ef12537d98a7bda", + "sha256:92868f6512714efd4a6d6cb2bfc4903b997b36b97baea85f744229f18d12755e", + "sha256:948abc8952aff63de7b2c83bfe3f211c727da3a33c3a5866a0e2cf1ee1aa950f", + "sha256:95d7787f2bcbf7cb46823036a8d64ccfbc2ffc7d52016b4044d901abceeba3db", + "sha256:997b57e38aa7dc6caab843c5e042ab557bc83a2f91b7bd302e3c3aebbb9042a1", + "sha256:99b8bbfc8111826aa8363442c0fc1f5751456b008737ff053570f06a151650b3", + "sha256:9e73fa341d8b308bb799cf0ab6f55fc0461d27a9fa3e4582755a3d81a6af8c09", + "sha256:a0d2c04a623ab83963576548ce098baf711a18e2c32c542b62322a0b4584b990", + "sha256:a40087b82f83bd671cbeb5f582c233d196e9653220404a798798bfc0ee189fff", + "sha256:ad1f2fb9fe9b585ea4b436d6e998e71b50d2b087b694ab277b30e060c434e5db", + "sha256:b05774864c87210c531b48dfeb2f7659407c2dda8643104fb4ae5e2c311d12d9", + "sha256:b41693b7388324b80f9acfabd479bd1c84f0bc7e8f17bab4ecd9675e9ff9c734", + "sha256:b42dbd097abb44b3f1156b4bf978ec5853840802d6eee2784857be11ee82c6a0", + "sha256:b4e7c7ec4146a94a307ca4f112802a8e26d969018fabed526efc340d21d3e7d0", + "sha256:b59d096b5537ec7c85954cb97d821aae35cfccce3357a2cafe85660cc6295628", + "sha256:b9c60d1de973ca94af02053d9b5111c4fbf97158e139b14f1be68337be267be6", + "sha256:bccd2cb7aa5a3bfada72681bdb91637094d81639e116eac368f8b3874620a654", + "sha256:c32593ead1a8c6aabd58f9d7ee706e48beac796bb0cb71d6b60f2c1056f0a65f", + "sha256:c7571f99525c76a6280f5fe8e194eeb8cb4da55586c3c61c59c33a33f10cfce7", + "sha256:c8b2df9feac55043759aa89f722a967d977d80f8b5865a4153fc41c93b957efc", + "sha256:ca9f835cdfedcb3f5947304e85b8ca3ace31eef6346d8027a97f4de5fb687534", + "sha256:cc9253069158d57e27d47a8453d8a2c5a370dc461374111b5184cf2f147a3cc3", + "sha256:ced66c5c6ad5bcaf9be54560398654779ec1c3695f1a9cf0ae5e3606694a000a", + "sha256:d173c0ac508a2175f7c9a115a50db5fd3e35190d96fdd1a17f9cb10a6ab09aa1", + "sha256:d6edc538c7480fa0a3b2bdd705f8010062d74700198da55d16498e1b49549b9c", + "sha256:daf20d9c3b12ae0fdf15ed92235e190f8284945563c4b8ad95b2d7a31f331cd3", + "sha256:dc311634f6f28661a76cbc1c28ecf3b3a70a8edd67b69288ab7ca91058eb5a33", + "sha256:e2bc827c01f75803de77b134afdbf74fa74b62970eafdf190f3244931d7a5c0d", + "sha256:e365034c5cf6cf74f57420b57682ea79e19eb29033399dd3f40de4d0171998fa", + "sha256:e906da0f2bcbf9b26cc2b144929e88cb3bf943dd1942b4e5af066056875c7618", + "sha256:e9faafa74dbb906b2b6f3eb9942352e9e9db8d583ffed4be618a89bd71a4e914", + "sha256:ec6cd1954ca2bbf0970f531a628da1b1338f594bf5da7e361e19ba163ecc4f3b", + "sha256:f296d637a50bb15fb6a229fbb0eb053080e703b53dbfe55b1e4bb1c5ed25d325", + "sha256:f30fc72daf85486cdcdfc3f5e0aea9255493ef499e31582b34abadbfaafb0965", + "sha256:fe846f0a98aa9913c2852b630cd39b4098f296e0907dd05f6c7b30d911afa4c3" ], "markers": "python_version >= '3.9'", - "version": "==3.11.12" + "version": "==3.11.14" }, "aiosignal": { "hashes": [ @@ -129,11 +129,11 @@ }, "attrs": { "hashes": [ - "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e", - "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a" + "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", + "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b" ], "markers": "python_version >= '3.8'", - "version": "==25.1.0" + "version": "==25.3.0" }, "certifi": { "hashes": [ @@ -143,6 +143,79 @@ "markers": "python_version >= '3.6'", "version": "==2025.1.31" }, + "cffi": { + "hashes": [ + "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", + "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", + "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1", + "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", + "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", + "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", + "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", + "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", + "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", + "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", + "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc", + "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", + "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", + "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", + "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", + "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", + "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", + "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", + "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", + "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b", + "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", + "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", + "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c", + "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", + "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", + "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", + "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8", + "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1", + "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", + "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", + "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", + "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", + "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", + "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", + "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", + "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", + "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", + "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", + "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", + "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", + "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", + "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", + "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", + "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964", + "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", + "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", + "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", + "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", + "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", + "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", + "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", + "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", + "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", + "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", + "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", + "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", + "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", + "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9", + "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", + "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", + "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", + "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", + "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", + "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", + "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", + "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", + "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b" + ], + "markers": "platform_python_implementation != 'PyPy'", + "version": "==1.17.1" + }, "charset-normalizer": { "hashes": [ "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537", @@ -241,6 +314,53 @@ "markers": "python_version >= '3.7'", "version": "==3.4.1" }, + "cryptography": { + "hashes": [ + "sha256:04abd71114848aa25edb28e225ab5f268096f44cf0127f3d36975bdf1bdf3390", + "sha256:0529b1d5a0105dd3731fa65680b45ce49da4d8115ea76e9da77a875396727b41", + "sha256:1bc312dfb7a6e5d66082c87c34c8a62176e684b6fe3d90fcfe1568de675e6688", + "sha256:268e4e9b177c76d569e8a145a6939eca9a5fec658c932348598818acf31ae9a5", + "sha256:29ecec49f3ba3f3849362854b7253a9f59799e3763b0c9d0826259a88efa02f1", + "sha256:2bf7bf75f7df9715f810d1b038870309342bff3069c5bd8c6b96128cb158668d", + "sha256:3b721b8b4d948b218c88cb8c45a01793483821e709afe5f622861fc6182b20a7", + "sha256:3c00b6b757b32ce0f62c574b78b939afab9eecaf597c4d624caca4f9e71e7843", + "sha256:3dc62975e31617badc19a906481deacdeb80b4bb454394b4098e3f2525a488c5", + "sha256:4973da6ca3db4405c54cd0b26d328be54c7747e89e284fcff166132eb7bccc9c", + "sha256:4e389622b6927d8133f314949a9812972711a111d577a5d1f4bee5e58736b80a", + "sha256:51e4de3af4ec3899d6d178a8c005226491c27c4ba84101bfb59c901e10ca9f79", + "sha256:5f6f90b72d8ccadb9c6e311c775c8305381db88374c65fa1a68250aa8a9cb3a6", + "sha256:6210c05941994290f3f7f175a4a57dbbb2afd9273657614c506d5976db061181", + "sha256:6f101b1f780f7fc613d040ca4bdf835c6ef3b00e9bd7125a4255ec574c7916e4", + "sha256:7bdcd82189759aba3816d1f729ce42ffded1ac304c151d0a8e89b9996ab863d5", + "sha256:7ca25849404be2f8e4b3c59483d9d3c51298a22c1c61a0e84415104dacaf5562", + "sha256:81276f0ea79a208d961c433a947029e1a15948966658cf6710bbabb60fcc2639", + "sha256:8cadc6e3b5a1f144a039ea08a0bdb03a2a92e19c46be3285123d32029f40a922", + "sha256:8e0ddd63e6bf1161800592c71ac794d3fb8001f2caebe0966e77c5234fa9efc3", + "sha256:909c97ab43a9c0c0b0ada7a1281430e4e5ec0458e6d9244c0e821bbf152f061d", + "sha256:96e7a5e9d6e71f9f4fca8eebfd603f8e86c5225bb18eb621b2c1e50b290a9471", + "sha256:9a1e657c0f4ea2a23304ee3f964db058c9e9e635cc7019c4aa21c330755ef6fd", + "sha256:9eb9d22b0a5d8fd9925a7764a054dca914000607dff201a24c791ff5c799e1fa", + "sha256:af4ff3e388f2fa7bff9f7f2b31b87d5651c45731d3e8cfa0944be43dff5cfbdb", + "sha256:b042d2a275c8cee83a4b7ae30c45a15e6a4baa65a179a0ec2d78ebb90e4f6699", + "sha256:bc821e161ae88bfe8088d11bb39caf2916562e0a2dc7b6d56714a48b784ef0bb", + "sha256:c505d61b6176aaf982c5717ce04e87da5abc9a36a5b39ac03905c4aafe8de7aa", + "sha256:c63454aa261a0cf0c5b4718349629793e9e634993538db841165b3df74f37ec0", + "sha256:c7362add18b416b69d58c910caa217f980c5ef39b23a38a0880dfd87bdf8cd23", + "sha256:d03806036b4f89e3b13b6218fefea8d5312e450935b1a2d55f0524e2ed7c59d9", + "sha256:d1b3031093a366ac767b3feb8bcddb596671b3aaff82d4050f984da0c248b615", + "sha256:d1c3572526997b36f245a96a2b1713bf79ce99b271bbcf084beb6b9b075f29ea", + "sha256:efcfe97d1b3c79e486554efddeb8f6f53a4cdd4cf6086642784fa31fc384e1d7", + "sha256:f514ef4cd14bb6fb484b4a60203e912cfcb64f2ab139e88c2274511514bf7308" + ], + "markers": "python_version >= '3.7' and python_full_version not in '3.9.0, 3.9.1'", + "version": "==44.0.2" + }, + "events": { + "hashes": [ + "sha256:a7286af378ba3e46640ac9825156c93bdba7502174dd696090fdfcd4d80a1abd" + ], + "version": "==0.5" + }, "frozenlist": { "hashes": [ "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e", @@ -339,6 +459,22 @@ "markers": "python_version >= '3.8'", "version": "==1.5.0" }, + "grafana-client": { + "hashes": [ + "sha256:2477a47b923fd0637947e620b0b777c641af18a3025464fa4505783dbf05dfcc", + "sha256:8cb61bb2a87ec07bca10974df276b9a1a95bfdb63f3a696f065692ffc9b8c389" + ], + "index": "pypi", + "version": "==4.3.2" + }, + "h11": { + "hashes": [ + "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", + "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761" + ], + "markers": "python_version >= '3.7'", + "version": "==0.14.0" + }, "idna": { "hashes": [ "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", @@ -347,164 +483,289 @@ "markers": "python_version >= '3.6'", "version": "==3.10" }, + "jh2": { + "hashes": [ + "sha256:038091480cd1544e9389b0adbb1b1645a797689dcb68ceae7e45eec96ed24497", + "sha256:0c8e336df8ed1687590695f4469f480eeb4159bf13bb6193791c6530fe114b49", + "sha256:0c9bf2d5e4ef45c1686c6f76935e7ca263f5eae4de92bf5d1873a0e737e4eb7d", + "sha256:0faf6e96f74d27b8ca816b40217904891f91b664ed1c0388737949ceb50ac15d", + "sha256:10ea7f497e6226372e1d4fdbf42c8381f4887819a643ab930bff4072ad298d84", + "sha256:11650f7ed77ee1df30f25d6b3b74b2fa1c94124e074fd455abafea3cbc913d53", + "sha256:12ead3ee3e9c7caa00356b528a5cc7fe210fbe2060628af6e19ed76b8416572e", + "sha256:136b3c5b08883681fcb58f12393a5bbfa422d6e2d5ba887e263e776874276bc6", + "sha256:17d6e1691154ea9f726e43dcb717df48e56c66b5a01c90ad675c6494c36e5be1", + "sha256:19cb987915cc0d321746a12f2a693d087ffb721c37ac9a153cc088c57d4d90eb", + "sha256:1cdf15de698c4026e64fd914fead3180e52bf2a7bcbe44a3392404582dbf2d22", + "sha256:1e81e1c64e33506b8508ba5e3c7c139b2577e78b079c2c16a8e7a02a161f1080", + "sha256:2226c76e4ff2149c5d9f94bed22bf9c4f3411d38cc53d4a7ddfbe0899c8b558c", + "sha256:2837412fb7b684c6ce7392c8bc57440c6dbadaf1bde7a53144381f7df7083c1c", + "sha256:293f0f3da3c391e997e0d55fdb85540e98a8b0406622bb4ba57fb7617697f31e", + "sha256:2b9cc6c0239215a349d28c192fa4c4e7a7348eee7980531525c01bffe39eea80", + "sha256:2f3ad679f84ff236a0d7b71ddc4b3c09fe467abee2f1a86671f0cd417be5352b", + "sha256:358cad2f328c52c15756cf32b0ad17afb0d617e7cdfe93d59aa2616966d825b7", + "sha256:3663712305b509f79c002c8c0ca9994f716cadba576f5a59632dda1aec1ca8c6", + "sha256:41794820ccca039ca2ead6245f30b34601dd1456eee5b5dde620672bb989e79d", + "sha256:44b7e64aff542471c474c24f771eae5efd9152da02a12556f7cb7607020e1420", + "sha256:45770eb0990166026538d3c2fd7d92f17cfde13ca6567570c4baec3ce9162936", + "sha256:498060078a4d1b458e9381fefb027d85329397b50d65287712b3d48233e20836", + "sha256:4c2f18f337c2393f84e45e5011c8b02697b81638b1cec49da60a01b9ed067695", + "sha256:5162d6e475d2762035fb8ea25982bcbec6c58715e33bd0951499f743cd90b110", + "sha256:51e8c890bb59008c95b3a552cefd8bd9ce50a7466a6c920a78cf586e885d7449", + "sha256:56ad3839ac6ac5fd3d023cf59d4b04264b74bb4cb44c0780faf51d6b5ff38fbc", + "sha256:5821638ef0d7c973071810a6786f59b305172197f7e7e469a2ce169e7f4978e3", + "sha256:5ac1b2d379f4d40c13dcce537e69704452943cddbe991fd54a84fdb2da9026d5", + "sha256:5b465d4311b0429fe6fa85df8e2cfcb038c9fface95396dd14e838ecabaaadf2", + "sha256:5d8656b98057329bd03d968aac8d5198389cf51517511295cfc4cb827a507e39", + "sha256:5dcfb3e823ef4b91b70b92848570d1d8cfd584304bd2bd54272dc100c9494def", + "sha256:5e40d23ea43f683f3a7c032dde391104f609b05c21b6d284101120b51dbd50c1", + "sha256:63a01522bde161c713f7fa5ee5d850fee6386fc386073490ebcd438f14579cf2", + "sha256:6b2a3d7756035dde13571f4ad232629b78b7f35c2cd5fda7b464079fc697db3a", + "sha256:6b3be1a6bf6c965aea3b4e3a40df9d2c134c516d89c76cf2b6c81f67e6c5c6ed", + "sha256:6c7bea3357f2dc653756e6da55f66cd21c73d3875c8f3dc4e8d196a876252de0", + "sha256:6e6c8e229507cf29333a2f491cbaa7dff5b8a4a3e613af8090ccce9ce3e4f7a0", + "sha256:6fad27f2a63884ee45d491aebec4b1f38752cd6aaccc625038c21e7f43c02c49", + "sha256:71bfef52547c2b8b145897fa8d1b5142bc52313cfa38c0742e0ef755f0d09c60", + "sha256:72370d312323282b1bf74426e53fae861a310d7ae519b419da46673c38e7d147", + "sha256:76c7d36043a9c478b0c846fcec7da5cb095983722473e503e0122ccd170182b5", + "sha256:78d8a81ef51edb9a2f278a6fb278789b49e304b12bb21bccf2fe7e344f71a9fb", + "sha256:798a6b159ce32181a5e7ab7611c17d1080e74a5541fec47f961b728dab25a76f", + "sha256:7e370567f66a57e2c0e3ae2afcc6f126e1d6babd36831cfd0caad279b05c1c88", + "sha256:8004b845f606b95a8b17efa112aa10b327e46e95dcda604a257b4633d4ed45c8", + "sha256:80b20bf9ea4e709b3b9ae364ac298dfa872b084c186e5c1d60b0b79c79a7ee7e", + "sha256:87303f4bb1b493997f911a4f126123ccd2827d3a2e7dd2390cc6143fbc75805b", + "sha256:8d423f4631395b92dceda39f481a463498131ac02a58581124a44495491f715b", + "sha256:94ee262192db50fb9c069a0be7bb1a426fb1b43af26ce12bf4c6c30e13f46b56", + "sha256:960e4be2e7de340300ab4bcc2b45bed46be1d62330575b8265e6602dbcb9a14c", + "sha256:99397d5e1da6b345cec3e6125e2902b0e6864eb8eaa4be43a2013f059c502c93", + "sha256:9abbb8c1bad08817bad62ae1ea76c01bdbd0ee8c827d05f3ba038c9f6d6f14bb", + "sha256:9c0b8fadf80bc70d341032f92702bda1b0ed78c01e9c495f0df701938c99bcf5", + "sha256:9f977da9abae170eebdcf02bda33727c342fad5dcdbc08498bfdfb6cc6c65489", + "sha256:a6be712ca39d5e9c89b705bc9800be36739436fefb8d0b52b2d332f7d6d22a01", + "sha256:aa434418d6ee44b0ba3a5a407bc9e1543cf496328f43f149e9b58f74a63d5c21", + "sha256:ac4f778e32f7de0ba63346893a4af87c2280ffc1783f594a117be51d908a10da", + "sha256:ac85d65ee369c09b2904b55078ad589961e2e2e03c810963d35a26e6a3931425", + "sha256:ad5d78c664d39960435d4162db31117c8945ba74fb0c414e79ba85a8bdeafdec", + "sha256:ad91f57c3485d87a8edee558dafab0f08c716857d748731c0998dcefe9d3fd5f", + "sha256:afd255d42b340036883ca95bded553b29065b064e2fe5db64ad5988517db9694", + "sha256:b1c2c74f100a0c2110a8e30445554ae331860d32f145c60a2a1e1c27702022a2", + "sha256:b49a8c71378d40d43c6a56eaa536d7823baa43c27c93e082aeb60a9717be0c10", + "sha256:b5f52611323e8e35705e6750a760f32165b41c052d22da154ae343871e7cd50d", + "sha256:b6bf99ae529ac359263269710356d3ddb173c15d8f8dc8849ae794ab811e5cd0", + "sha256:ba361bf87c4701f11241be92c99ef5cf916865dd225955cccb2376bf76717b3c", + "sha256:bc351aa2158575e68943d8e1d5531719ad86bf6607776627ed5a1a60657664af", + "sha256:bd6eb7b1e12e4dd0b75cab1b023272f1333494add5ad61deedac738af1ffeede", + "sha256:bf8852595f5e2d2b072e24c29394b5aca7fba96ecc8656d56660535f9e9872c9", + "sha256:c1dd66541569a2bdbe92589cc96a89f470b20d168f2238fd463e1b59ee3e2d49", + "sha256:c36a7a004cba4e370d0675826eeefe4e42a256638b6b1432263ddb4af317bc02", + "sha256:c886cda61da4d39010be84802bed11bc75f03e8a6094cc18016957a2c80254d4", + "sha256:cc7aa83946f80c66a5d2dea7e165f15aa3eb21e7b74b24d8f850afc0d44bb00e", + "sha256:cea9c4bef70d1358bafec6019164abce362f4de15d79d1ecd64ae31c1749d77a", + "sha256:cfe1951e80869695857986be104a40a1e7fa8ec7de05f86bcbd7bd20854be764", + "sha256:d36cf6f139da3279644794fcfda18af425c8bb122ef9c2e7c762a937bbf7b0f4", + "sha256:d81308faaa9393b7e6ed20718d465c4c2b73c24d5e4826024961acf4b87b1524", + "sha256:db51ea1f9c5ac790848bc271fcdf4108ad1b77a77c6949a96320477962cf7ba5", + "sha256:dd05c18c920a15e00d7a52df37bffd3930fe2c004c690f9422b20e12077e6dbd", + "sha256:df05918a11e1db0198d00486e36673b4b4a89390e4458ff9479b4908dde357ac", + "sha256:e4c31dccf6be131709e545d0258eb5b75c5fac304857ad3976331c6740e8b9d6", + "sha256:e60954d673040430802b29fe5bba698e262182b5ba5f302ff4458e39f8101881", + "sha256:e60e2d2c88a0552e61c37172fe377f6a8abf479130a445314886de4a360ba940", + "sha256:e786f773ddc153846b2ebdb854011cfd1f7c874b8ee79cced3706801341c9f5d", + "sha256:e7cd91548fb95b69edd376f5204e27115ac7d093ec7d80066123a5bdb31c71d9", + "sha256:eaef2ea4f5602aefaaf3d6e8235f3b9ffde35aff15aac1c16cc802f6bbf0a3b5", + "sha256:ec8c5ea93a03775fbadd08462200cf34ce617ec75a032abfa44fd6d3a00e5424", + "sha256:eddeb8574bc9d9abb8491d4a46b60e553c2cea235b80373756acb06568101175", + "sha256:eeb300b0e4b428aab2f70d785cad4306529262af6de8c8c5fe6a4b41a674a434", + "sha256:f39d71ece8e97cf069e4154868eaac1256b133fe23e0459829432e4bb6406472", + "sha256:f4840ddad2b9d53710e92361391944da89e3576641a290066a1719520059247c", + "sha256:f70723a00bcbce0f9a216853139955be45da35741335eb3afead304e77662560", + "sha256:f829cf2ba5b553e6529d6238928c07096f1feb47f4ad536b7f06bca6cc77173f", + "sha256:f96386910467725895f7972939a6faabd6e96b1de0cc2c092e4bd2c40e956e25", + "sha256:fe259a9d6f555bc79aed9bb4b9a7fff73db443b4c483e4a81a428c8a2860428b" + ], + "markers": "python_version >= '3.7'", + "version": "==5.0.8" + }, + "jwt": { + "hashes": [ + "sha256:61c9170f92e736b530655e75374681d4fcca9cfa8763ab42be57353b2b203494" + ], + "index": "pypi", + "version": "==1.3.1" + }, "multidict": { "hashes": [ - "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f", - "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056", - "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761", - "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3", - "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b", - "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6", - "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748", - "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966", - "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f", - "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1", - "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6", - "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada", - "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305", - "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2", - "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d", - "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a", - "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef", - "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c", - "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb", - "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60", - "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6", - "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4", - "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478", - "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81", - "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7", - "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56", - "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3", - "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6", - "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30", - "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb", - "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", - "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0", - "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925", - "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c", - "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6", - "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e", - "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95", - "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2", - "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133", - "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2", - "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa", - "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3", - "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3", - "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436", - "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657", - "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581", - "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492", - "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43", - "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2", - "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2", - "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926", - "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057", - "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc", - "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80", - "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255", - "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1", - "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972", - "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53", - "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1", - "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423", - "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a", - "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160", - "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c", - "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd", - "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa", - "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5", - "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b", - "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa", - "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef", - "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44", - "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4", - "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156", - "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753", - "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28", - "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d", - "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a", - "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304", - "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008", - "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429", - "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72", - "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399", - "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3", - "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392", - "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167", - "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c", - "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774", - "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351", - "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76", - "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875", - "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd", - "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28", - "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db" + "sha256:0085b0afb2446e57050140240a8595846ed64d1cbd26cef936bfab3192c673b8", + "sha256:042028348dc5a1f2be6c666437042a98a5d24cee50380f4c0902215e5ec41844", + "sha256:05fefbc3cddc4e36da209a5e49f1094bbece9a581faa7f3589201fd95df40e5d", + "sha256:063be88bd684782a0715641de853e1e58a2f25b76388538bd62d974777ce9bc2", + "sha256:07bfa8bc649783e703263f783f73e27fef8cd37baaad4389816cf6a133141331", + "sha256:08549895e6a799bd551cf276f6e59820aa084f0f90665c0f03dd3a50db5d3c48", + "sha256:095a2eabe8c43041d3e6c2cb8287a257b5f1801c2d6ebd1dd877424f1e89cf29", + "sha256:0b183a959fb88ad1be201de2c4bdf52fa8e46e6c185d76201286a97b6f5ee65c", + "sha256:0c383d28857f66f5aebe3e91d6cf498da73af75fbd51cedbe1adfb85e90c0460", + "sha256:0d57a01a2a9fa00234aace434d8c131f0ac6e0ac6ef131eda5962d7e79edfb5b", + "sha256:0dc25a3293c50744796e87048de5e68996104d86d940bb24bc3ec31df281b191", + "sha256:0e5a644e50ef9fb87878d4d57907f03a12410d2aa3b93b3acdf90a741df52c49", + "sha256:0f249badb360b0b4d694307ad40f811f83df4da8cef7b68e429e4eea939e49dd", + "sha256:0f74f2fc51555f4b037ef278efc29a870d327053aba5cb7d86ae572426c7cccc", + "sha256:125dd82b40f8c06d08d87b3510beaccb88afac94e9ed4a6f6c71362dc7dbb04b", + "sha256:13551d0e2d7201f0959725a6a769b6f7b9019a168ed96006479c9ac33fe4096b", + "sha256:14ed9ed1bfedd72a877807c71113deac292bf485159a29025dfdc524c326f3e1", + "sha256:163f4604e76639f728d127293d24c3e208b445b463168af3d031b92b0998bb90", + "sha256:19e2819b0b468174de25c0ceed766606a07cedeab132383f1e83b9a4e96ccb4f", + "sha256:1e2a2193d3aa5cbf5758f6d5680a52aa848e0cf611da324f71e5e48a9695cc86", + "sha256:1f3c099d3899b14e1ce52262eb82a5f5cb92157bb5106bf627b618c090a0eadc", + "sha256:214207dcc7a6221d9942f23797fe89144128a71c03632bf713d918db99bd36de", + "sha256:2325105e16d434749e1be8022f942876a936f9bece4ec41ae244e3d7fae42aaf", + "sha256:2529ddbdaa424b2c6c2eb668ea684dd6b75b839d0ad4b21aad60c168269478d7", + "sha256:256d431fe4583c5f1e0f2e9c4d9c22f3a04ae96009b8cfa096da3a8723db0a16", + "sha256:25bb96338512e2f46f615a2bb7c6012fe92a4a5ebd353e5020836a7e33120349", + "sha256:2e87f1926e91855ae61769ba3e3f7315120788c099677e0842e697b0bfb659f2", + "sha256:2fc6af8e39f7496047c7876314f4317736eac82bf85b54c7c76cf1a6f8e35d98", + "sha256:3157126b028c074951839233647bd0e30df77ef1fedd801b48bdcad242a60f4e", + "sha256:32c9b4878f48be3e75808ea7e499d6223b1eea6d54c487a66bc10a1871e3dc6a", + "sha256:32ed748ff9ac682eae7859790d3044b50e3076c7d80e17a44239683769ff485e", + "sha256:3501621d5e86f1a88521ea65d5cad0a0834c77b26f193747615b7c911e5422d2", + "sha256:437c33561edb6eb504b5a30203daf81d4a9b727e167e78b0854d9a4e18e8950b", + "sha256:48d39b1824b8d6ea7de878ef6226efbe0773f9c64333e1125e0efcfdd18a24c7", + "sha256:4ac3fcf9a2d369bd075b2c2965544036a27ccd277fc3c04f708338cc57533081", + "sha256:4ccfd74957ef53fa7380aaa1c961f523d582cd5e85a620880ffabd407f8202c0", + "sha256:52b05e21ff05729fbea9bc20b3a791c3c11da61649ff64cce8257c82a020466d", + "sha256:5389445f0173c197f4a3613713b5fb3f3879df1ded2a1a2e4bc4b5b9c5441b7e", + "sha256:5c5e7d2e300d5cb3b2693b6d60d3e8c8e7dd4ebe27cd17c9cb57020cac0acb80", + "sha256:5d26547423e5e71dcc562c4acdc134b900640a39abd9066d7326a7cc2324c530", + "sha256:5dd7106d064d05896ce28c97da3f46caa442fe5a43bc26dfb258e90853b39b44", + "sha256:5f8cb1329f42fadfb40d6211e5ff568d71ab49be36e759345f91c69d1033d633", + "sha256:61d5541f27533f803a941d3a3f8a3d10ed48c12cf918f557efcbf3cd04ef265c", + "sha256:639556758c36093b35e2e368ca485dada6afc2bd6a1b1207d85ea6dfc3deab27", + "sha256:641cf2e3447c9ecff2f7aa6e9eee9eaa286ea65d57b014543a4911ff2799d08a", + "sha256:6aed763b6a1b28c46c055692836879328f0b334a6d61572ee4113a5d0c859872", + "sha256:6e2a2d6749e1ff2c9c76a72c6530d5baa601205b14e441e6d98011000f47a7ac", + "sha256:7243c5a6523c5cfeca76e063efa5f6a656d1d74c8b1fc64b2cd1e84e507f7e2a", + "sha256:76b34c12b013d813e6cb325e6bd4f9c984db27758b16085926bbe7ceeaace626", + "sha256:781b5dd1db18c9e9eacc419027b0acb5073bdec9de1675c0be25ceb10e2ad133", + "sha256:7c611345bbe7cb44aabb877cb94b63e86f2d0db03e382667dbd037866d44b4f8", + "sha256:83b78c680d4b15d33042d330c2fa31813ca3974197bddb3836a5c635a5fd013f", + "sha256:84e87a7d75fa36839a3a432286d719975362d230c70ebfa0948549cc38bd5b46", + "sha256:89b3857652183b8206a891168af47bac10b970d275bba1f6ee46565a758c078d", + "sha256:8cd1a0644ccaf27e9d2f6d9c9474faabee21f0578fe85225cc5af9a61e1653df", + "sha256:8de4d42dffd5ced9117af2ce66ba8722402541a3aa98ffdf78dde92badb68932", + "sha256:94a7bb972178a8bfc4055db80c51efd24baefaced5e51c59b0d598a004e8305d", + "sha256:98aa8325c7f47183b45588af9c434533196e241be0a4e4ae2190b06d17675c02", + "sha256:9e658d1373c424457ddf6d55ec1db93c280b8579276bebd1f72f113072df8a5d", + "sha256:9f49585f4abadd2283034fc605961f40c638635bc60f5162276fec075f2e37a4", + "sha256:9f6cad071960ba1914fa231677d21b1b4a3acdcce463cee41ea30bc82e6040cf", + "sha256:a0cc398350ef31167e03f3ca7c19313d4e40a662adcb98a88755e4e861170bdd", + "sha256:a1133414b771619aa3c3000701c11b2e4624a7f492f12f256aedde97c28331a2", + "sha256:a33273a541f1e1a8219b2a4ed2de355848ecc0254264915b9290c8d2de1c74e1", + "sha256:a3c0ff89fe40a152e77b191b83282c9664357dce3004032d42e68c514ceff27e", + "sha256:a49994481b99cd7dedde07f2e7e93b1d86c01c0fca1c32aded18f10695ae17eb", + "sha256:abf5b17bc0cf626a8a497d89ac691308dbd825d2ac372aa990b1ca114e470151", + "sha256:ac380cacdd3b183338ba63a144a34e9044520a6fb30c58aa14077157a033c13e", + "sha256:ad81012b24b88aad4c70b2cbc2dad84018783221b7f923e926f4690ff8569da3", + "sha256:b2c00ad31fbc2cbac85d7d0fcf90853b2ca2e69d825a2d3f3edb842ef1544a2c", + "sha256:b4c153863dd6569f6511845922c53e39c8d61f6e81f228ad5443e690fca403de", + "sha256:b4f3d66dd0354b79761481fc15bdafaba0b9d9076f1f42cc9ce10d7fcbda205a", + "sha256:b99aac6bb2c37db336fa03a39b40ed4ef2818bf2dfb9441458165ebe88b793af", + "sha256:b9f6392d98c0bd70676ae41474e2eecf4c7150cb419237a41f8f96043fcb81d1", + "sha256:c537da54ce4ff7c15e78ab1292e5799d0d43a2108e006578a57f531866f64025", + "sha256:ca23db5fb195b5ef4fd1f77ce26cadefdf13dba71dab14dadd29b34d457d7c44", + "sha256:cc826b9a8176e686b67aa60fd6c6a7047b0461cae5591ea1dc73d28f72332a8a", + "sha256:cca83a629f77402cfadd58352e394d79a61c8015f1694b83ab72237ec3941f88", + "sha256:cf8d370b2fea27fb300825ec3984334f7dd54a581bde6456799ba3776915a656", + "sha256:d1175b0e0d6037fab207f05774a176d71210ebd40b1c51f480a04b65ec5c786d", + "sha256:d1996ee1330e245cd3aeda0887b4409e3930524c27642b046e4fae88ffa66c5e", + "sha256:d5a36953389f35f0a4e88dc796048829a2f467c9197265504593f0e420571547", + "sha256:da51d8928ad8b4244926fe862ba1795f0b6e68ed8c42cd2f822d435db9c2a8f4", + "sha256:e16e7297f29a544f49340012d6fc08cf14de0ab361c9eb7529f6a57a30cbfda1", + "sha256:e25b11a0417475f093d0f0809a149aff3943c2c56da50fdf2c3c88d57fe3dfbd", + "sha256:e4371591e621579cb6da8401e4ea405b33ff25a755874a3567c4075ca63d56e2", + "sha256:e653d36b1bf48fa78c7fcebb5fa679342e025121ace8c87ab05c1cefd33b34fc", + "sha256:e7d91a230c7f8af86c904a5a992b8c064b66330544693fd6759c3d6162382ecf", + "sha256:e851e6363d0dbe515d8de81fd544a2c956fdec6f8a049739562286727d4a00c3", + "sha256:ef7d48207926edbf8b16b336f779c557dd8f5a33035a85db9c4b0febb0706817", + "sha256:f7716f7e7138252d88607228ce40be22660d6608d20fd365d596e7ca0738e019", + "sha256:facaf11f21f3a4c51b62931feb13310e6fe3475f85e20d9c9fdce0d2ea561b87" ], - "markers": "python_version >= '3.8'", - "version": "==6.1.0" + "markers": "python_version >= '3.9'", + "version": "==6.2.0" + }, + "niquests": { + "hashes": [ + "sha256:68e0a7e9f338466b3606945fffd11f75e3c90af7498aa9336ef03812323b7e36", + "sha256:86e484c2c60444aa96069c15f6295af6e25a8bad50781e1326df1b5c7ab48339" + ], + "markers": "python_version >= '3.7'", + "version": "==3.14.0" }, "numpy": { "hashes": [ - "sha256:0391ea3622f5c51a2e29708877d56e3d276827ac5447d7f45e9bc4ade8923c52", - "sha256:12c045f43b1d2915eca6b880a7f4a256f59d62df4f044788c8ba67709412128d", - "sha256:136553f123ee2951bfcfbc264acd34a2fc2f29d7cdf610ce7daf672b6fbaa693", - "sha256:1402da8e0f435991983d0a9708b779f95a8c98c6b18a171b9f1be09005e64d9d", - "sha256:16372619ee728ed67a2a606a614f56d3eabc5b86f8b615c79d01957062826ca8", - "sha256:1ad78ce7f18ce4e7df1b2ea4019b5817a2f6a8a16e34ff2775f646adce0a5027", - "sha256:1b416af7d0ed3271cad0f0a0d0bee0911ed7eba23e66f8424d9f3dfcdcae1304", - "sha256:1f45315b2dc58d8a3e7754fe4e38b6fce132dab284a92851e41b2b344f6441c5", - "sha256:2376e317111daa0a6739e50f7ee2a6353f768489102308b0d98fcf4a04f7f3b5", - "sha256:23c9f4edbf4c065fddb10a4f6e8b6a244342d95966a48820c614891e5059bb50", - "sha256:246535e2f7496b7ac85deffe932896a3577be7af8fb7eebe7146444680297e9a", - "sha256:2e8da03bd561504d9b20e7a12340870dfc206c64ea59b4cfee9fceb95070ee94", - "sha256:34c1b7e83f94f3b564b35f480f5652a47007dd91f7c839f404d03279cc8dd021", - "sha256:39261798d208c3095ae4f7bc8eaeb3481ea8c6e03dc48028057d3cbdbdb8937e", - "sha256:3b787adbf04b0db1967798dba8da1af07e387908ed1553a0d6e74c084d1ceafe", - "sha256:3c2ec8a0f51d60f1e9c0c5ab116b7fc104b165ada3f6c58abf881cb2eb16044d", - "sha256:435e7a933b9fda8126130b046975a968cc2d833b505475e588339e09f7672890", - "sha256:4d8335b5f1b6e2bce120d55fb17064b0262ff29b459e8493d1785c18ae2553b8", - "sha256:4d9828d25fb246bedd31e04c9e75714a4087211ac348cb39c8c5f99dbb6683fe", - "sha256:52659ad2534427dffcc36aac76bebdd02b67e3b7a619ac67543bc9bfe6b7cdb1", - "sha256:5266de33d4c3420973cf9ae3b98b54a2a6d53a559310e3236c4b2b06b9c07d4e", - "sha256:5521a06a3148686d9269c53b09f7d399a5725c47bbb5b35747e1cb76326b714b", - "sha256:596140185c7fa113563c67c2e894eabe0daea18cf8e33851738c19f70ce86aeb", - "sha256:5b732c8beef1d7bc2d9e476dbba20aaff6167bf205ad9aa8d30913859e82884b", - "sha256:5ebeb7ef54a7be11044c33a17b2624abe4307a75893c001a4800857956b41094", - "sha256:712a64103d97c404e87d4d7c47fb0c7ff9acccc625ca2002848e0d53288b90ea", - "sha256:7678556eeb0152cbd1522b684dcd215250885993dd00adb93679ec3c0e6e091c", - "sha256:77974aba6c1bc26e3c205c2214f0d5b4305bdc719268b93e768ddb17e3fdd636", - "sha256:783145835458e60fa97afac25d511d00a1eca94d4a8f3ace9fe2043003c678e4", - "sha256:7bfdb06b395385ea9b91bf55c1adf1b297c9fdb531552845ff1d3ea6e40d5aba", - "sha256:7c8dde0ca2f77828815fd1aedfdf52e59071a5bae30dac3b4da2a335c672149a", - "sha256:83807d445817326b4bcdaaaf8e8e9f1753da04341eceec705c001ff342002e5d", - "sha256:87eed225fd415bbae787f93a457af7f5990b92a334e346f72070bf569b9c9c95", - "sha256:8fb62fe3d206d72fe1cfe31c4a1106ad2b136fcc1606093aeab314f02930fdf2", - "sha256:95172a21038c9b423e68be78fd0be6e1b97674cde269b76fe269a5dfa6fadf0b", - "sha256:9f48ba6f6c13e5e49f3d3efb1b51c8193215c42ac82610a04624906a9270be6f", - "sha256:a0c03b6be48aaf92525cccf393265e02773be8fd9551a2f9adbe7db1fa2b60f1", - "sha256:a5ae282abe60a2db0fd407072aff4599c279bcd6e9a2475500fc35b00a57c532", - "sha256:aee2512827ceb6d7f517c8b85aa5d3923afe8fc7a57d028cffcd522f1c6fd082", - "sha256:c8b0451d2ec95010d1db8ca733afc41f659f425b7f608af569711097fd6014e2", - "sha256:c9aa4496fd0e17e3843399f533d62857cef5900facf93e735ef65aa4bbc90ef0", - "sha256:cbc6472e01952d3d1b2772b720428f8b90e2deea8344e854df22b0618e9cce71", - "sha256:cdfe0c22692a30cd830c0755746473ae66c4a8f2e7bd508b35fb3b6a0813d787", - "sha256:cf802eef1f0134afb81fef94020351be4fe1d6681aadf9c5e862af6602af64ef", - "sha256:d42f9c36d06440e34226e8bd65ff065ca0963aeecada587b937011efa02cdc9d", - "sha256:d5b47c440210c5d1d67e1cf434124e0b5c395eee1f5806fdd89b553ed1acd0a3", - "sha256:d9b4a8148c57ecac25a16b0e11798cbe88edf5237b0df99973687dd866f05e1b", - "sha256:daf43a3d1ea699402c5a850e5313680ac355b4adc9770cd5cfc2940e7861f1bf", - "sha256:dbdc15f0c81611925f382dfa97b3bd0bc2c1ce19d4fe50482cb0ddc12ba30020", - "sha256:deaa09cd492e24fd9b15296844c0ad1b3c976da7907e1c1ed3a0ad21dded6f76", - "sha256:e37242f5324ffd9f7ba5acf96d774f9276aa62a966c0bad8dae692deebec7716", - "sha256:ed2cf9ed4e8ebc3b754d398cba12f24359f018b416c380f577bbae112ca52fc9", - "sha256:f2712c5179f40af9ddc8f6727f2bd910ea0eb50206daea75f58ddd9fa3f715bb", - "sha256:f4ca91d61a4bf61b0f2228f24bbfa6a9facd5f8af03759fe2a655c50ae2c6610", - "sha256:f6b3dfc7661f8842babd8ea07e9897fe3d9b69a1d7e5fbb743e4160f9387833b" + "sha256:05c076d531e9998e7e694c36e8b349969c56eadd2cdcd07242958489d79a7286", + "sha256:0d54974f9cf14acf49c60f0f7f4084b6579d24d439453d5fc5805d46a165b542", + "sha256:11c43995255eb4127115956495f43e9343736edb7fcdb0d973defd9de14cd84f", + "sha256:188dcbca89834cc2e14eb2f106c96d6d46f200fe0200310fc29089657379c58d", + "sha256:1974afec0b479e50438fc3648974268f972e2d908ddb6d7fb634598cdb8260a0", + "sha256:1cf4e5c6a278d620dee9ddeb487dc6a860f9b199eadeecc567f777daace1e9e7", + "sha256:207a2b8441cc8b6a2a78c9ddc64d00d20c303d79fba08c577752f080c4007ee3", + "sha256:218f061d2faa73621fa23d6359442b0fc658d5b9a70801373625d958259eaca3", + "sha256:2aad3c17ed2ff455b8eaafe06bcdae0062a1db77cb99f4b9cbb5f4ecb13c5146", + "sha256:2fa8fa7697ad1646b5c93de1719965844e004fcad23c91228aca1cf0800044a1", + "sha256:31504f970f563d99f71a3512d0c01a645b692b12a63630d6aafa0939e52361e6", + "sha256:3387dd7232804b341165cedcb90694565a6015433ee076c6754775e85d86f1fc", + "sha256:4ba5054787e89c59c593a4169830ab362ac2bee8a969249dc56e5d7d20ff8df9", + "sha256:4f92084defa704deadd4e0a5ab1dc52d8ac9e8a8ef617f3fbb853e79b0ea3592", + "sha256:65ef3468b53269eb5fdb3a5c09508c032b793da03251d5f8722b1194f1790c00", + "sha256:6f527d8fdb0286fd2fd97a2a96c6be17ba4232da346931d967a0630050dfd298", + "sha256:7051ee569db5fbac144335e0f3b9c2337e0c8d5c9fee015f259a5bd70772b7e8", + "sha256:7716e4a9b7af82c06a2543c53ca476fa0b57e4d760481273e09da04b74ee6ee2", + "sha256:79bd5f0a02aa16808fcbc79a9a376a147cc1045f7dfe44c6e7d53fa8b8a79392", + "sha256:7a4e84a6283b36632e2a5b56e121961f6542ab886bc9e12f8f9818b3c266bfbb", + "sha256:8120575cb4882318c791f839a4fd66161a6fa46f3f0a5e613071aae35b5dd8f8", + "sha256:81413336ef121a6ba746892fad881a83351ee3e1e4011f52e97fba79233611fd", + "sha256:8146f3550d627252269ac42ae660281d673eb6f8b32f113538e0cc2a9aed42b9", + "sha256:879cf3a9a2b53a4672a168c21375166171bc3932b7e21f622201811c43cdd3b0", + "sha256:892c10d6a73e0f14935c31229e03325a7b3093fafd6ce0af704be7f894d95687", + "sha256:92bda934a791c01d6d9d8e038363c50918ef7c40601552a58ac84c9613a665bc", + "sha256:9ba03692a45d3eef66559efe1d1096c4b9b75c0986b5dff5530c378fb8331d4f", + "sha256:9eeea959168ea555e556b8188da5fa7831e21d91ce031e95ce23747b7609f8a4", + "sha256:a0258ad1f44f138b791327961caedffbf9612bfa504ab9597157806faa95194a", + "sha256:a761ba0fa886a7bb33c6c8f6f20213735cb19642c580a931c625ee377ee8bd39", + "sha256:a7b9084668aa0f64e64bd00d27ba5146ef1c3a8835f3bd912e7a9e01326804c4", + "sha256:a84eda42bd12edc36eb5b53bbcc9b406820d3353f1994b6cfe453a33ff101775", + "sha256:ab2939cd5bec30a7430cbdb2287b63151b77cf9624de0532d629c9a1c59b1d5c", + "sha256:ac0280f1ba4a4bfff363a99a6aceed4f8e123f8a9b234c89140f5e894e452ecd", + "sha256:adf8c1d66f432ce577d0197dceaac2ac00c0759f573f28516246351c58a85020", + "sha256:b4adfbbc64014976d2f91084915ca4e626fbf2057fb81af209c1a6d776d23e3d", + "sha256:bb649f8b207ab07caebba230d851b579a3c8711a851d29efe15008e31bb4de24", + "sha256:bce43e386c16898b91e162e5baaad90c4b06f9dcbe36282490032cec98dc8ae7", + "sha256:bd3ad3b0a40e713fc68f99ecfd07124195333f1e689387c180813f0e94309d6f", + "sha256:c3f7ac96b16955634e223b579a3e5798df59007ca43e8d451a0e6a50f6bfdfba", + "sha256:cf28633d64294969c019c6df4ff37f5698e8326db68cc2b66576a51fad634880", + "sha256:d0f35b19894a9e08639fd60a1ec1978cb7f5f7f1eace62f38dd36be8aecdef4d", + "sha256:db1f1c22173ac1c58db249ae48aa7ead29f534b9a948bc56828337aa84a32ed6", + "sha256:dbe512c511956b893d2dacd007d955a3f03d555ae05cfa3ff1c1ff6df8851854", + "sha256:df2f57871a96bbc1b69733cd4c51dc33bea66146b8c63cacbfed73eec0883017", + "sha256:e2f085ce2e813a50dfd0e01fbfc0c12bbe5d2063d99f8b29da30e544fb6483b8", + "sha256:e642d86b8f956098b564a45e6f6ce68a22c2c97a04f5acd3f221f57b8cb850ae", + "sha256:e9e0a277bb2eb5d8a7407e14688b85fd8ad628ee4e0c7930415687b6564207a4", + "sha256:ea2bb7e2ae9e37d96835b3576a4fa4b3a97592fbea8ef7c3587078b0068b8f09", + "sha256:ee4d528022f4c5ff67332469e10efe06a267e32f4067dc76bb7e2cddf3cd25ff", + "sha256:f05d4198c1bacc9124018109c5fba2f3201dbe7ab6e92ff100494f236209c960", + "sha256:f34dc300df798742b3d06515aa2a0aee20941c13579d7a2f2e10af01ae4901ee", + "sha256:f4162988a360a29af158aeb4a2f4f09ffed6a969c9776f8f3bdee9b06a8ab7e5", + "sha256:f486038e44caa08dbd97275a9a35a283a8f1d2f0ee60ac260a1790e76660833c", + "sha256:f7de08cbe5551911886d1ab60de58448c6df0f67d9feb7d1fb21e9875ef95e91" ], "markers": "python_version == '3.11'", - "version": "==2.2.3" + "version": "==2.2.4" + }, + "opensearch-py": { + "hashes": [ + "sha256:52c60fdb5d4dcf6cce3ee746c13b194529b0161e0f41268b98ab8f1624abe2fa", + "sha256:6598df0bc7a003294edd0ba88a331e0793acbb8c910c43edf398791e3b2eccda" + ], + "index": "pypi", + "version": "==2.8.0" }, "paho-mqtt": { "hashes": [ @@ -572,205 +833,228 @@ }, "propcache": { "hashes": [ - "sha256:03ff9d3f665769b2a85e6157ac8b439644f2d7fd17615a82fa55739bc97863f4", - "sha256:049324ee97bb67285b49632132db351b41e77833678432be52bdd0289c0e05e4", - "sha256:081a430aa8d5e8876c6909b67bd2d937bfd531b0382d3fdedb82612c618bc41a", - "sha256:0f022d381747f0dfe27e99d928e31bc51a18b65bb9e481ae0af1380a6725dd1f", - "sha256:12d1083f001ace206fe34b6bdc2cb94be66d57a850866f0b908972f90996b3e9", - "sha256:14d86fe14b7e04fa306e0c43cdbeebe6b2c2156a0c9ce56b815faacc193e320d", - "sha256:160291c60081f23ee43d44b08a7e5fb76681221a8e10b3139618c5a9a291b84e", - "sha256:1672137af7c46662a1c2be1e8dc78cb6d224319aaa40271c9257d886be4363a6", - "sha256:19a0f89a7bb9d8048d9c4370c9c543c396e894c76be5525f5e1ad287f1750ddf", - "sha256:1ac2f5fe02fa75f56e1ad473f1175e11f475606ec9bd0be2e78e4734ad575034", - "sha256:1cd9a1d071158de1cc1c71a26014dcdfa7dd3d5f4f88c298c7f90ad6f27bb46d", - "sha256:1ffc3cca89bb438fb9c95c13fc874012f7b9466b89328c3c8b1aa93cdcfadd16", - "sha256:297878dc9d0a334358f9b608b56d02e72899f3b8499fc6044133f0d319e2ec30", - "sha256:2d3af2e79991102678f53e0dbf4c35de99b6b8b58f29a27ca0325816364caaba", - "sha256:30b43e74f1359353341a7adb783c8f1b1c676367b011709f466f42fda2045e95", - "sha256:3156628250f46a0895f1f36e1d4fbe062a1af8718ec3ebeb746f1d23f0c5dc4d", - "sha256:31f5af773530fd3c658b32b6bdc2d0838543de70eb9a2156c03e410f7b0d3aae", - "sha256:3935bfa5fede35fb202c4b569bb9c042f337ca4ff7bd540a0aa5e37131659348", - "sha256:39d51fbe4285d5db5d92a929e3e21536ea3dd43732c5b177c7ef03f918dff9f2", - "sha256:3f77ce728b19cb537714499928fe800c3dda29e8d9428778fc7c186da4c09a64", - "sha256:4160d9283bd382fa6c0c2b5e017acc95bc183570cd70968b9202ad6d8fc48dce", - "sha256:4a571d97dbe66ef38e472703067021b1467025ec85707d57e78711c085984e54", - "sha256:4e6281aedfca15301c41f74d7005e6e3f4ca143584ba696ac69df4f02f40d629", - "sha256:52277518d6aae65536e9cea52d4e7fd2f7a66f4aa2d30ed3f2fcea620ace3c54", - "sha256:556fc6c10989f19a179e4321e5d678db8eb2924131e64652a51fe83e4c3db0e1", - "sha256:574faa3b79e8ebac7cb1d7930f51184ba1ccf69adfdec53a12f319a06030a68b", - "sha256:58791550b27d5488b1bb52bc96328456095d96206a250d28d874fafe11b3dfaf", - "sha256:5b750a8e5a1262434fb1517ddf64b5de58327f1adc3524a5e44c2ca43305eb0b", - "sha256:5d97151bc92d2b2578ff7ce779cdb9174337390a535953cbb9452fb65164c587", - "sha256:5eee736daafa7af6d0a2dc15cc75e05c64f37fc37bafef2e00d77c14171c2097", - "sha256:6445804cf4ec763dc70de65a3b0d9954e868609e83850a47ca4f0cb64bd79fea", - "sha256:647894f5ae99c4cf6bb82a1bb3a796f6e06af3caa3d32e26d2350d0e3e3faf24", - "sha256:66d4cfda1d8ed687daa4bc0274fcfd5267873db9a5bc0418c2da19273040eeb7", - "sha256:6a9a8c34fb7bb609419a211e59da8887eeca40d300b5ea8e56af98f6fbbb1541", - "sha256:6b3f39a85d671436ee3d12c017f8fdea38509e4f25b28eb25877293c98c243f6", - "sha256:6b6fb63ae352e13748289f04f37868099e69dba4c2b3e271c46061e82c745634", - "sha256:70693319e0b8fd35dd863e3e29513875eb15c51945bf32519ef52927ca883bc3", - "sha256:781e65134efaf88feb447e8c97a51772aa75e48b794352f94cb7ea717dedda0d", - "sha256:819ce3b883b7576ca28da3861c7e1a88afd08cc8c96908e08a3f4dd64a228034", - "sha256:857112b22acd417c40fa4595db2fe28ab900c8c5fe4670c7989b1c0230955465", - "sha256:887d9b0a65404929641a9fabb6452b07fe4572b269d901d622d8a34a4e9043b2", - "sha256:8b3489ff1ed1e8315674d0775dc7d2195fb13ca17b3808721b54dbe9fd020faf", - "sha256:92fc4500fcb33899b05ba73276dfb684a20d31caa567b7cb5252d48f896a91b1", - "sha256:9403db39be1393618dd80c746cb22ccda168efce239c73af13c3763ef56ffc04", - "sha256:98110aa363f1bb4c073e8dcfaefd3a5cea0f0834c2aab23dda657e4dab2f53b5", - "sha256:999779addc413181912e984b942fbcc951be1f5b3663cd80b2687758f434c583", - "sha256:9caac6b54914bdf41bcc91e7eb9147d331d29235a7c967c150ef5df6464fd1bb", - "sha256:a7a078f5d37bee6690959c813977da5291b24286e7b962e62a94cec31aa5188b", - "sha256:a7e65eb5c003a303b94aa2c3852ef130230ec79e349632d030e9571b87c4698c", - "sha256:a96dc1fa45bd8c407a0af03b2d5218392729e1822b0c32e62c5bf7eeb5fb3958", - "sha256:aca405706e0b0a44cc6bfd41fbe89919a6a56999157f6de7e182a990c36e37bc", - "sha256:accb6150ce61c9c4b7738d45550806aa2b71c7668c6942f17b0ac182b6142fd4", - "sha256:ad1af54a62ffe39cf34db1aa6ed1a1873bd548f6401db39d8e7cd060b9211f82", - "sha256:ae1aa1cd222c6d205853b3013c69cd04515f9d6ab6de4b0603e2e1c33221303e", - "sha256:b2d0a12018b04f4cb820781ec0dffb5f7c7c1d2a5cd22bff7fb055a2cb19ebce", - "sha256:b480c6a4e1138e1aa137c0079b9b6305ec6dcc1098a8ca5196283e8a49df95a9", - "sha256:b74c261802d3d2b85c9df2dfb2fa81b6f90deeef63c2db9f0e029a3cac50b518", - "sha256:ba278acf14471d36316159c94a802933d10b6a1e117b8554fe0d0d9b75c9d536", - "sha256:bb6178c241278d5fe853b3de743087be7f5f4c6f7d6d22a3b524d323eecec505", - "sha256:bf72af5e0fb40e9babf594308911436c8efde3cb5e75b6f206c34ad18be5c052", - "sha256:bfd3223c15bebe26518d58ccf9a39b93948d3dcb3e57a20480dfdd315356baff", - "sha256:c214999039d4f2a5b2073ac506bba279945233da8c786e490d411dfc30f855c1", - "sha256:c2f992c07c0fca81655066705beae35fc95a2fa7366467366db627d9f2ee097f", - "sha256:cba4cfa1052819d16699e1d55d18c92b6e094d4517c41dd231a8b9f87b6fa681", - "sha256:cea7daf9fc7ae6687cf1e2c049752f19f146fdc37c2cc376e7d0032cf4f25347", - "sha256:cf6c4150f8c0e32d241436526f3c3f9cbd34429492abddbada2ffcff506c51af", - "sha256:d09c333d36c1409d56a9d29b3a1b800a42c76a57a5a8907eacdbce3f18768246", - "sha256:d27b84d5880f6d8aa9ae3edb253c59d9f6642ffbb2c889b78b60361eed449787", - "sha256:d2ccec9ac47cf4e04897619c0e0c1a48c54a71bdf045117d3a26f80d38ab1fb0", - "sha256:d71264a80f3fcf512eb4f18f59423fe82d6e346ee97b90625f283df56aee103f", - "sha256:d93f3307ad32a27bda2e88ec81134b823c240aa3abb55821a8da553eed8d9439", - "sha256:d9631c5e8b5b3a0fda99cb0d29c18133bca1e18aea9effe55adb3da1adef80d3", - "sha256:ddfab44e4489bd79bda09d84c430677fc7f0a4939a73d2bba3073036f487a0a6", - "sha256:e7048abd75fe40712005bcfc06bb44b9dfcd8e101dda2ecf2f5aa46115ad07ca", - "sha256:e73091191e4280403bde6c9a52a6999d69cdfde498f1fdf629105247599b57ec", - "sha256:e800776a79a5aabdb17dcc2346a7d66d0777e942e4cd251defeb084762ecd17d", - "sha256:edc9fc7051e3350643ad929df55c451899bb9ae6d24998a949d2e4c87fb596d3", - "sha256:f089118d584e859c62b3da0892b88a83d611c2033ac410e929cb6754eec0ed16", - "sha256:f174bbd484294ed9fdf09437f889f95807e5f229d5d93588d34e92106fbf6717", - "sha256:f508b0491767bb1f2b87fdfacaba5f7eddc2f867740ec69ece6d1946d29029a6", - "sha256:f7a31fc1e1bd362874863fdeed71aed92d348f5336fd84f2197ba40c59f061bd", - "sha256:f9479aa06a793c5aeba49ce5c5692ffb51fcd9a7016e017d555d5e2b0045d212" + "sha256:050b571b2e96ec942898f8eb46ea4bfbb19bd5502424747e83badc2d4a99a44e", + "sha256:05543250deac8e61084234d5fc54f8ebd254e8f2b39a16b1dce48904f45b744b", + "sha256:069e7212890b0bcf9b2be0a03afb0c2d5161d91e1bf51569a64f629acc7defbf", + "sha256:09400e98545c998d57d10035ff623266927cb784d13dd2b31fd33b8a5316b85b", + "sha256:0c3c3a203c375b08fd06a20da3cf7aac293b834b6f4f4db71190e8422750cca5", + "sha256:0c86e7ceea56376216eba345aa1fc6a8a6b27ac236181f840d1d7e6a1ea9ba5c", + "sha256:0fbe94666e62ebe36cd652f5fc012abfbc2342de99b523f8267a678e4dfdee3c", + "sha256:17d1c688a443355234f3c031349da69444be052613483f3e4158eef751abcd8a", + "sha256:19a06db789a4bd896ee91ebc50d059e23b3639c25d58eb35be3ca1cbe967c3bf", + "sha256:1c5c7ab7f2bb3f573d1cb921993006ba2d39e8621019dffb1c5bc94cdbae81e8", + "sha256:1eb34d90aac9bfbced9a58b266f8946cb5935869ff01b164573a7634d39fbcb5", + "sha256:1f6cc0ad7b4560e5637eb2c994e97b4fa41ba8226069c9277eb5ea7101845b42", + "sha256:27c6ac6aa9fc7bc662f594ef380707494cb42c22786a558d95fcdedb9aa5d035", + "sha256:2d219b0dbabe75e15e581fc1ae796109b07c8ba7d25b9ae8d650da582bed01b0", + "sha256:2fce1df66915909ff6c824bbb5eb403d2d15f98f1518e583074671a30fe0c21e", + "sha256:319fa8765bfd6a265e5fa661547556da381e53274bc05094fc9ea50da51bfd46", + "sha256:359e81a949a7619802eb601d66d37072b79b79c2505e6d3fd8b945538411400d", + "sha256:3a02a28095b5e63128bcae98eb59025924f121f048a62393db682f049bf4ac24", + "sha256:3e19ea4ea0bf46179f8a3652ac1426e6dcbaf577ce4b4f65be581e237340420d", + "sha256:3e584b6d388aeb0001d6d5c2bd86b26304adde6d9bb9bfa9c4889805021b96de", + "sha256:40d980c33765359098837527e18eddefc9a24cea5b45e078a7f3bb5b032c6ecf", + "sha256:4114c4ada8f3181af20808bedb250da6bae56660e4b8dfd9cd95d4549c0962f7", + "sha256:43593c6772aa12abc3af7784bff4a41ffa921608dd38b77cf1dfd7f5c4e71371", + "sha256:47ef24aa6511e388e9894ec16f0fbf3313a53ee68402bc428744a367ec55b833", + "sha256:4cf9e93a81979f1424f1a3d155213dc928f1069d697e4353edb8a5eba67c6259", + "sha256:4d0dfdd9a2ebc77b869a0b04423591ea8823f791293b527dc1bb896c1d6f1136", + "sha256:563f9d8c03ad645597b8d010ef4e9eab359faeb11a0a2ac9f7b4bc8c28ebef25", + "sha256:58aa11f4ca8b60113d4b8e32d37e7e78bd8af4d1a5b5cb4979ed856a45e62005", + "sha256:5a0a9898fdb99bf11786265468571e628ba60af80dc3f6eb89a3545540c6b0ef", + "sha256:5aed8d8308215089c0734a2af4f2e95eeb360660184ad3912686c181e500b2e7", + "sha256:5b9145c35cc87313b5fd480144f8078716007656093d23059e8993d3a8fa730f", + "sha256:5cb5918253912e088edbf023788de539219718d3b10aef334476b62d2b53de53", + "sha256:5cdb0f3e1eb6dfc9965d19734d8f9c481b294b5274337a8cb5cb01b462dcb7e0", + "sha256:5ced33d827625d0a589e831126ccb4f5c29dfdf6766cac441d23995a65825dcb", + "sha256:603f1fe4144420374f1a69b907494c3acbc867a581c2d49d4175b0de7cc64566", + "sha256:61014615c1274df8da5991a1e5da85a3ccb00c2d4701ac6f3383afd3ca47ab0a", + "sha256:64a956dff37080b352c1c40b2966b09defb014347043e740d420ca1eb7c9b908", + "sha256:668ddddc9f3075af019f784456267eb504cb77c2c4bd46cc8402d723b4d200bf", + "sha256:6d8e309ff9a0503ef70dc9a0ebd3e69cf7b3894c9ae2ae81fc10943c37762458", + "sha256:6f173bbfe976105aaa890b712d1759de339d8a7cef2fc0a1714cc1a1e1c47f64", + "sha256:71ebe3fe42656a2328ab08933d420df5f3ab121772eef78f2dc63624157f0ed9", + "sha256:730178f476ef03d3d4d255f0c9fa186cb1d13fd33ffe89d39f2cda4da90ceb71", + "sha256:7d2d5a0028d920738372630870e7d9644ce437142197f8c827194fca404bf03b", + "sha256:7f30241577d2fef2602113b70ef7231bf4c69a97e04693bde08ddab913ba0ce5", + "sha256:813fbb8b6aea2fc9659815e585e548fe706d6f663fa73dff59a1677d4595a037", + "sha256:82de5da8c8893056603ac2d6a89eb8b4df49abf1a7c19d536984c8dd63f481d5", + "sha256:83be47aa4e35b87c106fc0c84c0fc069d3f9b9b06d3c494cd404ec6747544894", + "sha256:8638f99dca15b9dff328fb6273e09f03d1c50d9b6512f3b65a4154588a7595fe", + "sha256:87380fb1f3089d2a0b8b00f006ed12bd41bd858fabfa7330c954c70f50ed8757", + "sha256:88c423efef9d7a59dae0614eaed718449c09a5ac79a5f224a8b9664d603f04a3", + "sha256:89498dd49c2f9a026ee057965cdf8192e5ae070ce7d7a7bd4b66a8e257d0c976", + "sha256:8a17583515a04358b034e241f952f1715243482fc2c2945fd99a1b03a0bd77d6", + "sha256:916cd229b0150129d645ec51614d38129ee74c03293a9f3f17537be0029a9641", + "sha256:9532ea0b26a401264b1365146c440a6d78269ed41f83f23818d4b79497aeabe7", + "sha256:967a8eec513dbe08330f10137eacb427b2ca52118769e82ebcfcab0fba92a649", + "sha256:975af16f406ce48f1333ec5e912fe11064605d5c5b3f6746969077cc3adeb120", + "sha256:9979643ffc69b799d50d3a7b72b5164a2e97e117009d7af6dfdd2ab906cb72cd", + "sha256:9a8ecf38de50a7f518c21568c80f985e776397b902f1ce0b01f799aba1608b40", + "sha256:9cec3239c85ed15bfaded997773fdad9fb5662b0a7cbc854a43f291eb183179e", + "sha256:9e64e948ab41411958670f1093c0a57acfdc3bee5cf5b935671bbd5313bcf229", + "sha256:9f64d91b751df77931336b5ff7bafbe8845c5770b06630e27acd5dbb71e1931c", + "sha256:a0ab8cf8cdd2194f8ff979a43ab43049b1df0b37aa64ab7eca04ac14429baeb7", + "sha256:a110205022d077da24e60b3df8bcee73971be9575dec5573dd17ae5d81751111", + "sha256:a34aa3a1abc50740be6ac0ab9d594e274f59960d3ad253cd318af76b996dd654", + "sha256:a444192f20f5ce8a5e52761a031b90f5ea6288b1eef42ad4c7e64fef33540b8f", + "sha256:a461959ead5b38e2581998700b26346b78cd98540b5524796c175722f18b0294", + "sha256:a75801768bbe65499495660b777e018cbe90c7980f07f8aa57d6be79ea6f71da", + "sha256:aa8efd8c5adc5a2c9d3b952815ff8f7710cefdcaf5f2c36d26aff51aeca2f12f", + "sha256:aca63103895c7d960a5b9b044a83f544b233c95e0dcff114389d64d762017af7", + "sha256:b0313e8b923b3814d1c4a524c93dfecea5f39fa95601f6a9b1ac96cd66f89ea0", + "sha256:b23c11c2c9e6d4e7300c92e022046ad09b91fd00e36e83c44483df4afa990073", + "sha256:b303b194c2e6f171cfddf8b8ba30baefccf03d36a4d9cab7fd0bb68ba476a3d7", + "sha256:b655032b202028a582d27aeedc2e813299f82cb232f969f87a4fde491a233f11", + "sha256:bd39c92e4c8f6cbf5f08257d6360123af72af9f4da75a690bef50da77362d25f", + "sha256:bef100c88d8692864651b5f98e871fb090bd65c8a41a1cb0ff2322db39c96c27", + "sha256:c2fe5c910f6007e716a06d269608d307b4f36e7babee5f36533722660e8c4a70", + "sha256:c66d8ccbc902ad548312b96ed8d5d266d0d2c6d006fd0f66323e9d8f2dd49be7", + "sha256:cd6a55f65241c551eb53f8cf4d2f4af33512c39da5d9777694e9d9c60872f519", + "sha256:d249609e547c04d190e820d0d4c8ca03ed4582bcf8e4e160a6969ddfb57b62e5", + "sha256:d4e89cde74154c7b5957f87a355bb9c8ec929c167b59c83d90654ea36aeb6180", + "sha256:dc1915ec523b3b494933b5424980831b636fe483d7d543f7afb7b3bf00f0c10f", + "sha256:e1c4d24b804b3a87e9350f79e2371a705a188d292fd310e663483af6ee6718ee", + "sha256:e474fc718e73ba5ec5180358aa07f6aded0ff5f2abe700e3115c37d75c947e18", + "sha256:e4fe2a6d5ce975c117a6bb1e8ccda772d1e7029c1cca1acd209f91d30fa72815", + "sha256:e7fb9a84c9abbf2b2683fa3e7b0d7da4d8ecf139a1c635732a8bda29c5214b0e", + "sha256:e861ad82892408487be144906a368ddbe2dc6297074ade2d892341b35c59844a", + "sha256:ec314cde7314d2dd0510c6787326bbffcbdc317ecee6b7401ce218b3099075a7", + "sha256:ed5f6d2edbf349bd8d630e81f474d33d6ae5d07760c44d33cd808e2f5c8f4ae6", + "sha256:ef2e4e91fb3945769e14ce82ed53007195e616a63aa43b40fb7ebaaf907c8d4c", + "sha256:f011f104db880f4e2166bcdcf7f58250f7a465bc6b068dc84c824a3d4a5c94dc", + "sha256:f1528ec4374617a7a753f90f20e2f551121bb558fcb35926f99e3c42367164b8", + "sha256:f27785888d2fdd918bc36de8b8739f2d6c791399552333721b58193f68ea3e98", + "sha256:f35c7070eeec2cdaac6fd3fe245226ed2a6292d3ee8c938e5bb645b434c5f256", + "sha256:f3bbecd2f34d0e6d3c543fdb3b15d6b60dd69970c2b4c822379e5ec8f6f621d5", + "sha256:f6f1324db48f001c2ca26a25fa25af60711e09b9aaf4b28488602776f4f9a744", + "sha256:f78eb8422acc93d7b69964012ad7048764bb45a54ba7a39bb9e146c72ea29723", + "sha256:fb6e0faf8cb6b4beea5d6ed7b5a578254c6d7df54c36ccd3d8b3eb00d6770277", + "sha256:feccd282de1f6322f56f6845bf1207a537227812f0a9bf5571df52bb418d79d5" ], "markers": "python_version >= '3.9'", - "version": "==0.2.1" + "version": "==0.3.1" + }, + "pycparser": { + "hashes": [ + "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", + "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc" + ], + "markers": "python_version >= '3.8'", + "version": "==2.22" }, "pydantic": { "hashes": [ - "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584", - "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236" + "sha256:442557d2910e75c991c39f4b4ab18963d57b9b55122c8b2a9cd176d8c29ce968", + "sha256:5b6c415eee9f8123a14d859be0c84363fec6b1feb6b688d6435801230b56e0b8" ], "index": "pypi", - "version": "==2.10.6" + "version": "==2.11.1" }, "pydantic-core": { "hashes": [ - "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278", - "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50", - "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9", - "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f", - "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", - "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", - "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54", - "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630", - "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9", - "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236", - "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", - "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", - "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", - "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", - "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", - "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", - "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", - "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd", - "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", - "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", - "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7", - "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", - "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e", - "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa", - "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", - "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962", - "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", - "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f", - "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", - "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5", - "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", - "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf", - "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a", - "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c", - "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76", - "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362", - "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4", - "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", - "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320", - "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118", - "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96", - "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", - "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046", - "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3", - "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", - "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af", - "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", - "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67", - "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a", - "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", - "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35", - "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", - "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151", - "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b", - "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", - "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133", - "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", - "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145", - "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", - "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", - "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", - "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", - "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", - "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", - "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5", - "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", - "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", - "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8", - "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", - "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da", - "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", - "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc", - "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993", - "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656", - "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4", - "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", - "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb", - "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d", - "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", - "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e", - "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", - "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc", - "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a", - "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9", - "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506", - "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b", - "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1", - "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", - "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", - "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", - "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31", - "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c", - "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", - "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", - "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308", - "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2", - "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228", - "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b", - "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", - "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad" + "sha256:024d136ae44d233e6322027bbf356712b3940bee816e6c948ce4b90f18471b3d", + "sha256:0310524c833d91403c960b8a3cf9f46c282eadd6afd276c8c5edc617bd705dc9", + "sha256:07b4ced28fccae3f00626eaa0c4001aa9ec140a29501770a88dbbb0966019a86", + "sha256:085d8985b1c1e48ef271e98a658f562f29d89bda98bf120502283efbc87313eb", + "sha256:0a98257451164666afafc7cbf5fb00d613e33f7e7ebb322fbcd99345695a9a61", + "sha256:0bcf0bab28995d483f6c8d7db25e0d05c3efa5cebfd7f56474359e7137f39856", + "sha256:138d31e3f90087f42aa6286fb640f3c7a8eb7bdae829418265e7e7474bd2574b", + "sha256:14229c1504287533dbf6b1fc56f752ce2b4e9694022ae7509631ce346158de11", + "sha256:1583539533160186ac546b49f5cde9ffc928062c96920f58bd95de32ffd7bffd", + "sha256:175ab598fb457a9aee63206a1993874badf3ed9a456e0654273e56f00747bbd6", + "sha256:1a69b7596c6603afd049ce7f3835bcf57dd3892fc7279f0ddf987bebed8caa5a", + "sha256:1a73be93ecef45786d7d95b0c5e9b294faf35629d03d5b145b09b81258c7cd6d", + "sha256:1b1262b912435a501fa04cd213720609e2cefa723a07c92017d18693e69bf00b", + "sha256:1b2ea72dea0825949a045fa4071f6d5b3d7620d2a208335207793cf29c5a182d", + "sha256:20d4275f3c4659d92048c70797e5fdc396c6e4446caf517ba5cad2db60cd39d3", + "sha256:23c3e77bf8a7317612e5c26a3b084c7edeb9552d645742a54a5867635b4f2453", + "sha256:26a4ea04195638dcd8c53dadb545d70badba51735b1594810e9768c2c0b4a5da", + "sha256:26bc7367c0961dec292244ef2549afa396e72e28cc24706210bd44d947582c59", + "sha256:2a0147c0bef783fd9abc9f016d66edb6cac466dc54a17ec5f5ada08ff65caf5d", + "sha256:2c0afd34f928383e3fd25740f2050dbac9d077e7ba5adbaa2227f4d4f3c8da5c", + "sha256:30369e54d6d0113d2aa5aee7a90d17f225c13d87902ace8fcd7bbf99b19124db", + "sha256:31860fbda80d8f6828e84b4a4d129fd9c4535996b8249cfb8c720dc2a1a00bb8", + "sha256:34e7fb3abe375b5c4e64fab75733d605dda0f59827752debc99c17cb2d5f3276", + "sha256:40eb8af662ba409c3cbf4a8150ad32ae73514cd7cb1f1a2113af39763dd616b3", + "sha256:41d698dcbe12b60661f0632b543dbb119e6ba088103b364ff65e951610cb7ce0", + "sha256:4726f1f3f42d6a25678c67da3f0b10f148f5655813c5aca54b0d1742ba821b8f", + "sha256:4927564be53239a87770a5f86bdc272b8d1fbb87ab7783ad70255b4ab01aa25b", + "sha256:4b6d77c75a57f041c5ee915ff0b0bb58eabb78728b69ed967bc5b780e8f701b8", + "sha256:4d9149e7528af8bbd76cc055967e6e04617dcb2a2afdaa3dea899406c5521faa", + "sha256:4deac83a8cc1d09e40683be0bc6d1fa4cde8df0a9bf0cda5693f9b0569ac01b6", + "sha256:4f1ab031feb8676f6bd7c85abec86e2935850bf19b84432c64e3e239bffeb1ec", + "sha256:502ed542e0d958bd12e7c3e9a015bce57deaf50eaa8c2e1c439b512cb9db1e3a", + "sha256:5461934e895968655225dfa8b3be79e7e927e95d4bd6c2d40edd2fa7052e71b6", + "sha256:58c1151827eef98b83d49b6ca6065575876a02d2211f259fb1a6b7757bd24dd8", + "sha256:5bdd36b362f419c78d09630cbaebc64913f66f62bda6d42d5fbb08da8cc4f181", + "sha256:5bf637300ff35d4f59c006fff201c510b2b5e745b07125458a5389af3c0dff8c", + "sha256:5bf68bb859799e9cec3d9dd8323c40c00a254aabb56fe08f907e437005932f2b", + "sha256:5d8dc9f63a26f7259b57f46a7aab5af86b2ad6fbe48487500bb1f4b27e051e4c", + "sha256:5f36afd0d56a6c42cf4e8465b6441cf546ed69d3a4ec92724cc9c8c61bd6ecf4", + "sha256:5f72914cfd1d0176e58ddc05c7a47674ef4222c8253bf70322923e73e14a4ac3", + "sha256:6291797cad239285275558e0a27872da735b05c75d5237bbade8736f80e4c225", + "sha256:62c151ce3d59ed56ebd7ce9ce5986a409a85db697d25fc232f8e81f195aa39a1", + "sha256:635702b2fed997e0ac256b2cfbdb4dd0bf7c56b5d8fba8ef03489c03b3eb40e2", + "sha256:64672fa888595a959cfeff957a654e947e65bbe1d7d82f550417cbd6898a1d6b", + "sha256:68504959253303d3ae9406b634997a2123a0b0c1da86459abbd0ffc921695eac", + "sha256:69297418ad644d521ea3e1aa2e14a2a422726167e9ad22b89e8f1130d68e1e9a", + "sha256:6c32a40712e3662bebe524abe8abb757f2fa2000028d64cc5a1006016c06af43", + "sha256:715c62af74c236bf386825c0fdfa08d092ab0f191eb5b4580d11c3189af9d330", + "sha256:71dffba8fe9ddff628c68f3abd845e91b028361d43c5f8e7b3f8b91d7d85413e", + "sha256:7419241e17c7fbe5074ba79143d5523270e04f86f1b3a0dff8df490f84c8273a", + "sha256:759871f00e26ad3709efc773ac37b4d571de065f9dfb1778012908bcc36b3a73", + "sha256:7a25493320203005d2a4dac76d1b7d953cb49bce6d459d9ae38e30dd9f29bc9c", + "sha256:7b79af799630af263eca9ec87db519426d8c9b3be35016eddad1832bac812d87", + "sha256:7c9c84749f5787781c1c45bb99f433402e484e515b40675a5d121ea14711cf61", + "sha256:7da333f21cd9df51d5731513a6d39319892947604924ddf2e24a4612975fb936", + "sha256:82a4eba92b7ca8af1b7d5ef5f3d9647eee94d1f74d21ca7c21e3a2b92e008358", + "sha256:89670d7a0045acb52be0566df5bc8b114ac967c662c06cf5e0c606e4aadc964b", + "sha256:8a1d581e8cdbb857b0e0e81df98603376c1a5c34dc5e54039dcc00f043df81e7", + "sha256:8ec86b5baa36f0a0bfb37db86c7d52652f8e8aa076ab745ef7725784183c3fdd", + "sha256:91301a0980a1d4530d4ba7e6a739ca1a6b31341252cb709948e0aca0860ce0ae", + "sha256:918f2013d7eadea1d88d1a35fd4a1e16aaf90343eb446f91cb091ce7f9b431a2", + "sha256:9cb2390355ba084c1ad49485d18449b4242da344dea3e0fe10babd1f0db7dcfc", + "sha256:9ee65f0cc652261744fd07f2c6e6901c914aa6c5ff4dcfaf1136bc394d0dd26b", + "sha256:a608a75846804271cf9c83e40bbb4dab2ac614d33c6fd5b0c6187f53f5c593ef", + "sha256:a66d931ea2c1464b738ace44b7334ab32a2fd50be023d863935eb00f42be1778", + "sha256:a7a7f2a3f628d2f7ef11cb6188bcf0b9e1558151d511b974dfea10a49afe192b", + "sha256:abaeec1be6ed535a5d7ffc2e6c390083c425832b20efd621562fbb5bff6dc518", + "sha256:abfa44cf2f7f7d7a199be6c6ec141c9024063205545aa09304349781b9a125e6", + "sha256:ade5dbcf8d9ef8f4b28e682d0b29f3008df9842bb5ac48ac2c17bc55771cc976", + "sha256:ae62032ef513fe6281ef0009e30838a01057b832dc265da32c10469622613885", + "sha256:aec79acc183865bad120b0190afac467c20b15289050648b876b07777e67ea48", + "sha256:b716294e721d8060908dbebe32639b01bfe61b15f9f57bcc18ca9a0e00d9520b", + "sha256:b9ec80eb5a5f45a2211793f1c4aeddff0c3761d1c70d684965c1807e923a588b", + "sha256:ba95691cf25f63df53c1d342413b41bd7762d9acb425df8858d7efa616c0870e", + "sha256:bccc06fa0372151f37f6b69834181aa9eb57cf8665ed36405fb45fbf6cac3bae", + "sha256:c860773a0f205926172c6644c394e02c25421dc9a456deff16f64c0e299487d3", + "sha256:ca1103d70306489e3d006b0f79db8ca5dd3c977f6f13b2c59ff745249431a606", + "sha256:ce72d46eb201ca43994303025bd54d8a35a3fc2a3495fac653d6eb7205ce04f4", + "sha256:d20cbb9d3e95114325780f3cfe990f3ecae24de7a2d75f978783878cce2ad585", + "sha256:dcfebee69cd5e1c0b76a17e17e347c84b00acebb8dd8edb22d4a03e88e82a207", + "sha256:e1c69aa459f5609dec2fa0652d495353accf3eda5bdb18782bc5a2ae45c9273a", + "sha256:e2762c568596332fdab56b07060c8ab8362c56cf2a339ee54e491cd503612c50", + "sha256:e37f10f6d4bc67c58fbd727108ae1d8b92b397355e68519f1e4a7babb1473442", + "sha256:e790954b5093dff1e3a9a2523fddc4e79722d6f07993b4cd5547825c3cbf97b5", + "sha256:e81a295adccf73477220e15ff79235ca9dcbcee4be459eb9d4ce9a2763b8386c", + "sha256:e925819a98318d17251776bd3d6aa9f3ff77b965762155bdad15d1a9265c4cfd", + "sha256:ea30239c148b6ef41364c6f51d103c2988965b643d62e10b233b5efdca8c0099", + "sha256:eabf946a4739b5237f4f56d77fa6668263bc466d06a8036c055587c130a46f7b", + "sha256:ecb158fb9b9091b515213bed3061eb7deb1d3b4e02327c27a0ea714ff46b0760", + "sha256:ecc6d02d69b54a2eb83ebcc6f29df04957f734bcf309d346b4f83354d8376862", + "sha256:eddb18a00bbb855325db27b4c2a89a4ba491cd6a0bd6d852b225172a1f54b36c", + "sha256:f00e8b59e1fc8f09d05594aa7d2b726f1b277ca6155fc84c0396db1b373c4555", + "sha256:f1fb026c575e16f673c61c7b86144517705865173f3d0907040ac30c4f9f5915", + "sha256:f200b2f20856b5a6c3a35f0d4e344019f805e363416e609e9b47c552d35fd5ea", + "sha256:f225f3a3995dbbc26affc191d0443c6c4aa71b83358fd4c2b7d63e2f6f0336f9", + "sha256:f22dab23cdbce2005f26a8f0c71698457861f97fc6318c75814a50c75e87d025", + "sha256:f3eb479354c62067afa62f53bb387827bee2f75c9c79ef25eef6ab84d4b1ae3b", + "sha256:fc53e05c16697ff0c1c7c2b98e45e131d4bfb78068fffff92a82d169cbb4c7b7", + "sha256:ff48a55be9da6930254565ff5238d71d5e9cd8c5487a191cb85df3bdb8c77365" ], - "markers": "python_version >= '3.8'", - "version": "==2.27.2" + "markers": "python_version >= '3.9'", + "version": "==2.33.0" }, "python-dateutil": { "hashes": [ @@ -782,10 +1066,111 @@ }, "pytz": { "hashes": [ - "sha256:89dd22dca55b46eac6eda23b2d72721bf1bdfef212645d81513ef5d03038de57", - "sha256:c2db42be2a2518b28e65f9207c4d05e6ff547d1efa4086469ef855e4ab70178e" - ], - "version": "==2025.1" + "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", + "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00" + ], + "version": "==2025.2" + }, + "qh3": { + "hashes": [ + "sha256:0107f576a0524421e1b0f9e0437d2881a1835b1b6105eadd7ea0c1c9bf2da917", + "sha256:06159707895c606a321ccb5630347a2d2a44ee584f22945e5b22b0ad34f21ec8", + "sha256:06255835f99ea1af9e5d358056011686fcccbafaba893454027daa62ab6f701f", + "sha256:09b2305a954e61a9ed8b46a7a45f54e8d95ef870a47d5fd1836e14c7600d3b92", + "sha256:0a51dcffae03a89ddbab1884860569e0d1dbbf95deee47457c1fd29b4ac8d220", + "sha256:0a5d1cd881b7d43481ad60262cf3390a555e0e51751bc2af70ba4a612487e797", + "sha256:0e1c273660f9b8511c22d0b082137556e46d6a7eccf132bd82f95d29f90488b2", + "sha256:0e540cc7e7da65da30381bdb73a789a8635c6aaef98688d904eee3bc587654a5", + "sha256:10ed818f47dc522350a12641e8f2bea19ff824f8ce373c23a8e594b3481fd7a4", + "sha256:195b4ad58cf5a8da218e2368d34f47628c14581f3cc9863fc0406b32e137f3a6", + "sha256:1a80d07249c7ccbaa57bb9015b5ead0ead7ac1940cd5483548dfe56db99ce7a4", + "sha256:1cf0b18823801078d2294a0356abc2be34b4a224bea863a87029c1c97d6c34e0", + "sha256:1fac2ab4b8a2e50894b54a19416cd363defe0fb33f52754686ea58999f98dfc5", + "sha256:205cdaea9da8881b31b76eb6da5b88c9558ba96bc16a3ecf11333098ac7f3859", + "sha256:2294e78bcc40728a3a772df0f8ecf8b8756616d06dd001029016876aa4e5c9de", + "sha256:235236ab195d34e7cd18d186e46b7a4f8aceafe246bf36b42913f72627ded414", + "sha256:25eef1f2be50d79d23e01a567c719e46e4892518a5ccc96685fcb4746357320b", + "sha256:2ae147b756c3adf59699756feb9e07d4a69674f57b4e13d6c25f9d1dc3c8707c", + "sha256:2c9cdd7ea49c79b671e7de35dad61d2aa91920e2498d0c6dfa932d5e05070a5e", + "sha256:2dc9f269d7316b0a44e61ae7a11ffd8daa800b3f5ba773de2e9d8c4ee636a896", + "sha256:2f94d69edb0070ef4ec414deabfc2369aa2100b11bf4a4f2f393f2c28c4bc7ba", + "sha256:311da331e31c55afc3f4f4f2ba9d07a1d700ffb7db5aa4f58300b9f56f2523dc", + "sha256:3578844a9ff4c342a409d010f909782afc52a31680876f7fab65bf133aa3f4db", + "sha256:4032c2898b4c0ff7a25cf7d68c3b1f2abdcaf4f25cc8b6802a941a842f9a95b6", + "sha256:40abd150eddfa0884c139bd281e87ff920d4cd52d685fc4ef25ddcc77ff7a220", + "sha256:43e32602651d07f8a0860ba0a45d8c8fe9ccd537030e7632d1258f7b84881416", + "sha256:45a21d25fe17168f4db09fcaabee5dd171763ad1bd8753c257297837f5ba9197", + "sha256:45bfbb126e31ecf63ef74c249d38d07e149c0663b4a191cf9e2e3445a80758d5", + "sha256:4745667c9956bcfd74ff677edd4c73d6cb578b6b47c5fb3d246aaa223dd6a004", + "sha256:4936a5d8915866b4f08ab18018f41ed93a2593788ad0a80796aada2e23d402e5", + "sha256:4a45a9698b3bcae05f91356f50df8dab3c3fdef3187548b9c4a396a6eb6760b5", + "sha256:4b84c1ca283278e2e22a3b9e2ce8ea55c0a1797d6e86255640a1b6293fe18b2a", + "sha256:4dc88397ed7f3b46f542f87e19050a7f82267225009ce65651ac44cb55b204b1", + "sha256:4e10a872077373c71d7938fb1a7ae0561f2e79aad2b1b5323dbb6325a389041a", + "sha256:4f1b5dcb4d9da5b441e0b14216b816be7b5b5d080c2ccb957adf84266411ff6b", + "sha256:50d25182d598312197f500a65acebf5430391764e6ffcdb73d96e80c5dd06fc7", + "sha256:529c5b9e27fced27befce26e2699eca3110c576f6427dfbd26e30b7666b2d6d1", + "sha256:571da625b22e953731307539b44b2177f6ab13b6142d7698c0f28b9379ae1be6", + "sha256:5a9de89e2480b385a99613798d375e69a0a53d4575bd74b133307c8e83a84751", + "sha256:5bcc46cf89cb1036c2d029c01f360c82180329997a75728b20dc205f34114327", + "sha256:5dfa6238a6236f2bb3ecaac9befd23cee0bcbb9e497003fb3aef875e19325c61", + "sha256:6342b961b18037e3df8692e8914c576816a966bf29f913ee2728e7e838bde9bd", + "sha256:65e112c175a0b0328822dd0d19ead9ef1d7925359d154fb52e46b080945eef38", + "sha256:6f8a2b15c4dd58133e92f95d4312efd09b87ec15b881885629dff70e89f1e751", + "sha256:726f749444d1cc73c1bf221343dc6fdbde2541ffe30860d2d5ef6e310a1f5478", + "sha256:742f39cd807df31c21e035aec63f6f61e139a60545cffb16e8e87f61609d7cba", + "sha256:7840c18ec27aa08ecdd8ff23df348c124378c6f3edf9a0e02b16a5a4ce504c89", + "sha256:79d1de24d3c7345719af8333b64f19a8777dd50a059851bfcfa583c7109eddf2", + "sha256:7ba9303c5334d64b547483be92c4bbacd37964ff3abd0b1e8c82c63ec6f7b3ec", + "sha256:85587d9dfbd2f7f8622cf57f3c1a19cee441b5607a982cdf4c08ef38d45d5a36", + "sha256:8711b86e447e689d1b693419708b6ad64bf0c57091b94a3f65c6d4bd7cfb7d9a", + "sha256:877edc4db25309d86af07d992926394936f491cce84fce439961729552e942fe", + "sha256:8bb17669e362d3456bebd5c69abb0c26e8ab29c10894f123c715b0217aece479", + "sha256:8bb17a1e50e35a8d07cab784caea68b33f739391ccb5e3161afb9db0bde8faf4", + "sha256:8d4640a6bb3aa29797bdcf0c5bae4e86da5f2fbf84b67a7fad549fa34c19aa98", + "sha256:90697f3d9e4b3ddccfb31b40637bac6d44b39288cd57f78e51ff13e70916eccc", + "sha256:90f127f57c00b111ea3ffd95f4c12ad83efebd10310fd718d66771dd64e568f1", + "sha256:95f8f70bca1e880da7559ef38b7f1778a3b39b586fc829b8a7e989e912aa988f", + "sha256:9a60c102a01dfa8c5d737499c9a5d5e7c2b6642009c9b80b27f228ec50ce6fb0", + "sha256:9c7f1821ec749ea29bd9d079e4f13a552371731d0b664962a60cbb2f31d571b5", + "sha256:9f81ee66fadedbfd4d5c49e64151db3b6f353b041ddf5ab0b151340a4467e038", + "sha256:9f8e530e29e1afe9231b1100645aa5cc240b823c0e4162f70046270a3559400c", + "sha256:a0c647db3f156e8c94a63c1fa0fc4f2ce8b70f0eb12f2726e6c19493198b1e99", + "sha256:a0cda60607ab4ffc14fa8425ea7c9ae78ad60923c3c8be94d19c14f83198b1cf", + "sha256:a5bff397d49da302b5afbdf244dd7ca480a827f5de856d957df05dfd7e73b490", + "sha256:a94bd391b955b24948b2986845f9c6ad8abc709c2d57d0515daeacf16a2a3a4c", + "sha256:ad4572bd37c1a6a7a12ff47da4f3578a13e3c8ee85a1f02d2435dfdc6d9ed394", + "sha256:b13b7de1686f1b5da7526dc4f0de410a685f5cb654e984b09ddd8d14be6fffc0", + "sha256:b1724c43c5c0d08b68c3407467e07794b9adf153b6de8300d61883e8d95fa640", + "sha256:b27d29cb718df9ed006f8c75a89dd90534437761b2477dc7a4145bde0daa60fc", + "sha256:b3afa3a78b0f011ff5a09dea37d74fcea9269b318d2828f18b2fbf9dde625a71", + "sha256:bd6a61007e678284178bb00931af59f686a2a55797505e0886241050ec5c243c", + "sha256:befeca45fd7787c08a3286fb72caaccfa4c3962760981dfeb0992f5ba9be5cb2", + "sha256:c2d31b8233f406e00f180e221986f436765c3bb06839e72c898feca31fef1d4e", + "sha256:c3e2518ce442b70314892a594e21157deb13fbc436f77ad6555439cfd9912035", + "sha256:c8d5fbee607db24ef6c7b0bd08c21226d10782df4149b9d6f1f1516c7c85092b", + "sha256:cc2cc804998e852bdffcc87e8d008043ffa85efe6d3516d9784714d709f14774", + "sha256:cd8a681107c6118f60a0714671cec7b301533f25984a5c898e547a33a01af75c", + "sha256:d056831ebf3fa8116672ae970ad19a9f5f1427a2217cd0e01c1eaac5f8222668", + "sha256:d5ac3e8e3f66ff88819205dbc67e6f771cbb80529325ca9f3bc03fa00c5c83aa", + "sha256:dba15ca2da7859300ae79d2ea2eb8bb0eb827b93a2f104981783add16a97058a", + "sha256:de6cabb89248b60ea9bb9d7848de78dfb824abfdc15f52448a8efe821dd7d559", + "sha256:e02f6d1cc2005b847176dd8770fdfe90f04a34a3f094b79a8369bde0aa8f6a04", + "sha256:e514bd4b27c953c46485b2be0ecd2421aa196c5a0cd7d67f1ccec16a56b00507", + "sha256:e53464124379764f982a69f5ab34d0d5c527e8ac1e788db86a25f79045e5b18d", + "sha256:e9cf59660a543bef86de457c671c1d78ad2d88c53bb9eb3fce6ce0cb9729d490", + "sha256:edfc1bc732bc5e62fdaea268a541eb442d5e04927cb27dfd8e92ef07213658d2", + "sha256:ee8e7a66be70a18f5e0558f2f6a89e39c608f87b027234848f76a6699975dcf8", + "sha256:effb7072efef7dca10a98c24be0cc882a40edc78e293b41f5b6dc7f1952215ed", + "sha256:f04e4ee7e3c123ac7f21cee6f819cfa9b5a376e656257dfa7a4d133b3590bdd9", + "sha256:f0531c7abe963affebd3fb6cf9ea87eb8c63a0240535d81d0223945bd41be254", + "sha256:f5afd1c216315682a6bbf606618de0e3817ed8eeafc27ad7660ef2f581d4fd46", + "sha256:f93d3c74e00268ac6042c080653a34d0f0e8903697fd8dc480c1e3de81c90faf", + "sha256:fbc4e6452cc48c3e1398fe930349e2ec9ad76a2c00e729f3e797700c2f0646e6", + "sha256:fc73fc2889a01a43737c7a7c7fb9ee13aa56065b22abbed0e787cc58a3747808" + ], + "markers": "python_version < '3.12' and (platform_python_implementation != 'CPython' or python_full_version > '3.7.10') and (platform_system == 'Darwin' or platform_system == 'Windows' or platform_system == 'Linux') and (platform_machine == 'x86_64' or platform_machine == 's390x' or platform_machine == 'armv7l' or platform_machine == 'ppc64le' or platform_machine == 'ppc64' or platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'arm64' or platform_machine == 'ARM64' or platform_machine == 'x86' or platform_machine == 'i686') and (platform_python_implementation == 'CPython' or platform_python_implementation == 'PyPy')", + "version": "==1.4.2" }, "requests": { "hashes": [ @@ -821,28 +1206,148 @@ }, "typing-extensions": { "hashes": [ - "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", - "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" + "sha256:0a4ac55a5820789d87e297727d229866c9650f6521b64206413c4fbada24d95b", + "sha256:c8dd92cc0d6425a97c18fbb9d1954e5ff92c1ca881a309c45f06ebc0b79058e5" ], "markers": "python_version >= '3.8'", - "version": "==4.12.2" + "version": "==4.13.0" + }, + "typing-inspection": { + "hashes": [ + "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f", + "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122" + ], + "markers": "python_version >= '3.9'", + "version": "==0.4.0" }, "tzdata": { "hashes": [ - "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694", - "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639" + "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", + "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9" ], "markers": "python_version >= '2'", - "version": "==2025.1" + "version": "==2025.2" }, "urllib3": { "hashes": [ "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d" ], - "markers": "python_version >= '3.9'", + "markers": "python_version >= '3.10'", "version": "==2.3.0" }, + "urllib3-future": { + "hashes": [ + "sha256:255fa9ba873e9045a5fb2e9838e2b108be35519c29e7f3accff13ee4c417a1cf", + "sha256:7243b5bb8d8cdbcbff342bc31b885e35662c4dcfd94d097473cce1bd02944cbf" + ], + "markers": "python_version >= '3.7'", + "version": "==2.12.914" + }, + "verlib2": { + "hashes": [ + "sha256:2862f19528db400d130253a2b71c7c3616ee14e1d54bf6833bc0929d2cddd141", + "sha256:cf8e2be044b834a2670f2d4c20a93cfc674933c0070543a6f61d531439cca200" + ], + "markers": "python_version >= '3.6'", + "version": "==0.3.1" + }, + "wassima": { + "hashes": [ + "sha256:10508102696d5e2cf4df6942a8ae251c136a49dc32591e9c3f7dd007f5ea1c2f", + "sha256:1102836ba373912537eba891e7e5893532d4ee915ee2486e981b73f925f63c37", + "sha256:11887557464e0c3f9694fb16406bb56c1fb1566178cd04bfb5b4624fad183b31", + "sha256:12c855cc5b96a2ac32d405ab7de1563fc91be54108b4fb16b06d125d07ea892b", + "sha256:134e863b692c35afe8f5ccbe8082fa39963804e20439a4c7aa98510197034704", + "sha256:17f129f4d36591772d906bcc893b76b236363fda61b575067ddfa8250f84ad30", + "sha256:17f132ffbab294902f8740708f27fd995ea04182fe4b4fde20be563f8a010715", + "sha256:18bc78b2230c6f1f9ddbeb6ca38439fea4cc8f60836af4f3538ed259e60e5eb8", + "sha256:194c3fad38603618dec03307d10a4ece852516df56560e04fb2562506f79c175", + "sha256:1b18ec743ab98dcbfc221749026b23fc573891651342f20971e53bdbf56d28ae", + "sha256:1fa19a3652509edd18f693cd9c873d8f73c9d1624eae6c3bf93e561b18ae2766", + "sha256:24bdb1a2b90c215e11ed7ce82ed7eada339c7dca8e0366916e4e3215b3b9d8d3", + "sha256:27d518f0863788c826faf387326f3babb3ea95a0b908f5b3ad2bc1fcc3c5a37d", + "sha256:350b5854dfb3eeb95cd17723b0f3503de0c01454da5ae7d60f192be2009239eb", + "sha256:3b3a4c8ffa76147507f0c88c5cc8c76ef96ab93b81e49b288a3a0b94ebfb34af", + "sha256:3e00fa8ff1aef7d8aad2e1b957add6cba8549a42e415400bd72ff1b61dc9da9d", + "sha256:3f29045dd0a7c287f850f1dc3948632a2d2cf7dd7ec02271c5f248f058da5650", + "sha256:4a528244e4a0f9e01b8593b1c8a60ac1d80ce8b13fe079f44b38328e4be075e3", + "sha256:4c4f5ca102fd083aa2b05c65a1fd18175e3dc7a889525fd2964219ee3c51edef", + "sha256:52358d86195954816231d2aa8c2919b85075320b6d3ba5b96216985c3182bfa0", + "sha256:52f473233ec4d57322c6295e85b3912dc1fc400d6308a04bd427b863934aa74e", + "sha256:556cded582aef3089de889b5a6efcf6d87fabfec55d574fcc3a4ada21308d487", + "sha256:564eda7bf0420c8cbebe5e8efc15f1b27fdcb37ebc4c2f92b8461ca83381b223", + "sha256:57a0ab5aed596f129fd4ea7584336b11fbef25c07d1351e37a959901dea8728e", + "sha256:58f1fddd660da8c8f30f4b8460129e2f217c226cd1b54b1cabb6465881fd788a", + "sha256:597b0d8ba697f4319bc1f301ed31630ca783c9fe82d2a2434dd2f7f709c4e394", + "sha256:5b194f0de77a4ae7bcf217a3ccd10798e94ca430cec6307628098a61cd2ac230", + "sha256:5f5ee564f4b836ed1b70ddb187c817e8f6f1ffb521a636bb20676f07b523396b", + "sha256:601f96340e4c8071994a39a76d4278e8e1d087cf385781dba795c5334262d865", + "sha256:61bfa09f38c36f1b1e6e44e7af888bb8f9d739e86099082a3b45875651a425e2", + "sha256:67fd323b8ad0e057c06b153983d8c50f812aad979ac89b07ed6952c345f6da02", + "sha256:69cb51f629d118256da3d2373575190c7e30d3fa67c344dc655f6c8ab3e83f0d", + "sha256:6b1d7ceeede8d8eed48616d2d33ed23d2dff307d0b17c577eafdadafe86a0478", + "sha256:6b7d696155ddd7ab5739ac221e8854115d0d8171bbf805074d9484083de386aa", + "sha256:6d23e9483756b81850b82e8b7ed20fd23de22b50d6a678f765c660d4206b7ce9", + "sha256:7b0229fecc849234f2a2d11e948ac38a9bab02d201fa4d6ad43c143e18c1a66e", + "sha256:7c53050b670d702eed541503175bd5441fc4bdf3898714f8eac8c6ae9db548ac", + "sha256:7d65676f1fc138d1742f704bf490045571b9c2c48cab7d2c2076a52729c143e5", + "sha256:7db25328c40cd574e5a68ef6507c5af4d1fa2a44cb3c028ff9ca6b522f8faf32", + "sha256:83ce1b09e9eb2ae033c303b74ecc4f3186bbc0897db1d8cd9942153b0631b8e0", + "sha256:86c509900cbb90b7b75155c580b22af591b696fa059059bcdbd75bc74179df85", + "sha256:87f80d0075f0d396b73d41bb1626a2dd5607e0db4b74cb17e55d874fcd538971", + "sha256:8b719755d556649f2fbf226cf1ca8581ade114751df1facec96f94e75bffdb3c", + "sha256:8e739d4192758df6e5363791f527deb91c615d63020ee8965df4bcd1a217f9a5", + "sha256:923d3bf8770dfeb3d94bdfee1c5b5a081592de69766436a395e1e6203c19cf71", + "sha256:97772bb55cb47da3de49ca4b59309a9bd91ead730a7cfac1992932486fb41352", + "sha256:98bdfdf734144277132f34f770eeb6b0db2c4de87415f34b178adee766632f24", + "sha256:98f38b1b01e6f270b9279d76261d6f222b72ef06b025cbd4911b962bb6de4c98", + "sha256:99318b5ea78843e3c3e19cd56367216774674a99848f00a6f2dcf84e36039641", + "sha256:9c623ef06876d432dc8acc93ed3494d3453333d767b1b06bba1a016ea9d850c9", + "sha256:9d0f9720dfd0155432d23bcc3605fe5831cd0f586ede4f14ff6f3bebe8fb867a", + "sha256:9e79216760faac6395bee8ca4077a53a309312faba0f71982127ad8625861780", + "sha256:a470c908fd9baaecf41715ea3c30c57b530d598ae5e9de7e0bd532755e66bb1b", + "sha256:a634b9b79e059f45a56ff3ef6e7241662bc6f0e5a096ee6eed6770ea368e8278", + "sha256:acd8195a53d0e84ea95bdf15a2651c53b829a3ddead21b4a620b6a0c5e1ae2ff", + "sha256:addbd207df3718fc9d9de5b6c90a5e3fbe667830cf629186c9fdcafbb6578cb4", + "sha256:ae2aec9d55e108ae2d22fd0bda24450a6c13c116f9698b9e7ba2c6492c4fe715", + "sha256:af6b70ca9788964c5da5b59ca412b62db2ea7f2386a91c0117667bdd963e828c", + "sha256:afa7d60a9203db36a55b6f2868da90aaa829ab415a21fba7fa75678789aeb16f", + "sha256:b08c1931c44e3c034e645f3e3a7f4c47e8b0758fb8f09a52d1e880a307a1066f", + "sha256:b22e356914e606ff398c002b9925df4454c5deca9dbe55b3ba4a5c9b2365cf0f", + "sha256:b8c0f50397c51086df941b48057c82f85d9da000bf4fe6f4bc64c4f649b26a5b", + "sha256:bc068bcd79fe017866f536e0ad9424793220be34e3124476e17e6cb77a97e690", + "sha256:bc30f5a605a366acb7f301b3421508eaec3c1a515c960791bd776cb63d016302", + "sha256:c0d246b3f8a771578279eab9cfcb820dedefd3dd5dc0e34b37a337fe46271fc0", + "sha256:c0fee0a8593028bde17b57527b1ac21fea74f209b3522363e3ba0197ffaa6323", + "sha256:c139d5b103bb1f085d8918815d62ad946224a658ac1a7cc1b93dc44bd498ff9a", + "sha256:c25235cec12c0e38b4104268e312c9c2f3527ebc126d296cff69ea7aa13434dc", + "sha256:c7429d038dc383966c692e752010cbb4d5dab0e515f231aa01cd746aed9db359", + "sha256:c85cd2e64967c0dce2927ad7c62c090aae6d6b7f9e3a6b9fb91f58b890ea6adc", + "sha256:ca04984df012020dd846599b8555666c544982c2a91dc6135565e6708624eb71", + "sha256:cb7d43c07d58ba13736e70dc3e064496efeb1ed4475a28afb26b7a3b030b89df", + "sha256:d018e05cb61eed3050d45bd0c0ef9b75420899f6ae254e68e7f2ef26975098c9", + "sha256:d24d42881eb74729b34014e2e87f3a4d0419c43db309de2dff3f39118716865f", + "sha256:d6e17f218af856ca22c30d1a1ac58b19bccf768b8589eb8d6e45e1f1ff258404", + "sha256:d855d0be1759c5efc404c04977ee48a8b6260aef6441e72c10973924dbde5a73", + "sha256:dea0dcc0e50978ef73be8cb384694b71a6e64b46847ee7decad96dc85fbf650c", + "sha256:e1e9228049cf2442ac486a03a0d543c5dff3089a915a3e39ab809b22672e1d76", + "sha256:e26d052a248d5be2257d848d6078d932cc1fd4e8226639f550344d0a7a2b8813", + "sha256:ee6ccb8197936a308a4034c90a42b30b37c46b7cbda66101d439d6983f59b368", + "sha256:eea9c37b45e73cebb4670afd1779db138eeff0f84ffc0871d2fb90c04c8d3aa8", + "sha256:f195bf641276261e6bc5f79f52601850c9bdbff8af401483b4805dbff535ed30", + "sha256:f264827618400ebeab16708c8acf7870f693b03bfb4d7e95253eb9b35074db5c", + "sha256:f44ccd2eaa433ff1a10f70242dc33315fc192b81664696154127bdd66ad7d3b2", + "sha256:f7a6068d8857c403e105e62132a00e9d9d401bd0efbff7f8b5b5bc8ab768a2d8", + "sha256:f9886176fe4bf1ac008c02adb5bd103f1191799f1897777d203ee44f615325a5", + "sha256:fa1f38d5583d283b40f998e2f13471bfa952e0c423ff95ec2ec329f3e1898107", + "sha256:fa65494e7bd0e3ba33b3e5a5ab30c2b6e95d3d1762baaa56151a0861618dc261", + "sha256:fd7186e23963714bab3c9a2ab75d002078335110d2c9fc883c65cbce43717f26", + "sha256:fec32c22b521fcdeb9aa7dee4373b2d81ca2d3fc8edc532f3e189d6f4f6f1f81" + ], + "markers": "python_version >= '3.7'", + "version": "==1.2.2" + }, "yarl": { "hashes": [ "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba", @@ -943,11 +1448,46 @@ }, "anyio": { "hashes": [ - "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a", - "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a" + "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", + "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c" ], "markers": "python_version >= '3.9'", - "version": "==4.8.0" + "version": "==4.9.0" + }, + "argon2-cffi": { + "hashes": [ + "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08", + "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea" + ], + "markers": "python_version >= '3.7'", + "version": "==23.1.0" + }, + "argon2-cffi-bindings": { + "hashes": [ + "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670", + "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f", + "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583", + "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194", + "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c", + "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a", + "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082", + "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5", + "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f", + "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7", + "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d", + "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f", + "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae", + "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3", + "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86", + "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367", + "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d", + "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93", + "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb", + "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e", + "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351" + ], + "markers": "python_version >= '3.6'", + "version": "==21.2.0" }, "babel": { "hashes": [ @@ -1162,109 +1702,121 @@ }, "coverage": { "hashes": [ - "sha256:00b2086892cf06c7c2d74983c9595dc511acca00665480b3ddff749ec4fb2a95", - "sha256:0533adc29adf6a69c1baa88c3d7dbcaadcffa21afbed3ca7a225a440e4744bf9", - "sha256:06097c7abfa611c91edb9e6920264e5be1d6ceb374efb4986f38b09eed4cb2fe", - "sha256:07e92ae5a289a4bc4c0aae710c0948d3c7892e20fd3588224ebe242039573bf0", - "sha256:0a9d8be07fb0832636a0f72b80d2a652fe665e80e720301fb22b191c3434d924", - "sha256:0e549f54ac5f301e8e04c569dfdb907f7be71b06b88b5063ce9d6953d2d58574", - "sha256:0ef01d70198431719af0b1f5dcbefc557d44a190e749004042927b2a3fed0702", - "sha256:0f16f44025c06792e0fb09571ae454bcc7a3ec75eeb3c36b025eccf501b1a4c3", - "sha256:14d47376a4f445e9743f6c83291e60adb1b127607a3618e3185bbc8091f0467b", - "sha256:1a936309a65cc5ca80fa9f20a442ff9e2d06927ec9a4f54bcba9c14c066323f2", - "sha256:1ceeb90c3eda1f2d8c4c578c14167dbd8c674ecd7d38e45647543f19839dd6ea", - "sha256:1f7ffa05da41754e20512202c866d0ebfc440bba3b0ed15133070e20bf5aeb5f", - "sha256:200e10beb6ddd7c3ded322a4186313d5ca9e63e33d8fab4faa67ef46d3460af3", - "sha256:220fa6c0ad7d9caef57f2c8771918324563ef0d8272c94974717c3909664e674", - "sha256:2251fabcfee0a55a8578a9d29cecfee5f2de02f11530e7d5c5a05859aa85aee9", - "sha256:2458f275944db8129f95d91aee32c828a408481ecde3b30af31d552c2ce284a0", - "sha256:299cf973a7abff87a30609879c10df0b3bfc33d021e1adabc29138a48888841e", - "sha256:2b996819ced9f7dbb812c701485d58f261bef08f9b85304d41219b1496b591ef", - "sha256:3688b99604a24492bcfe1c106278c45586eb819bf66a654d8a9a1433022fb2eb", - "sha256:3a1e465f398c713f1b212400b4e79a09829cd42aebd360362cd89c5bdc44eb87", - "sha256:488c27b3db0ebee97a830e6b5a3ea930c4a6e2c07f27a5e67e1b3532e76b9ef1", - "sha256:48cfc4641d95d34766ad41d9573cc0f22a48aa88d22657a1fe01dca0dbae4de2", - "sha256:4b467a8c56974bf06e543e69ad803c6865249d7a5ccf6980457ed2bc50312703", - "sha256:53c56358d470fa507a2b6e67a68fd002364d23c83741dbc4c2e0680d80ca227e", - "sha256:5d1095bbee1851269f79fd8e0c9b5544e4c00c0c24965e66d8cba2eb5bb535fd", - "sha256:641dfe0ab73deb7069fb972d4d9725bf11c239c309ce694dd50b1473c0f641c3", - "sha256:64cbb1a3027c79ca6310bf101014614f6e6e18c226474606cf725238cf5bc2d4", - "sha256:66fe626fd7aa5982cdebad23e49e78ef7dbb3e3c2a5960a2b53632f1f703ea45", - "sha256:676f92141e3c5492d2a1596d52287d0d963df21bf5e55c8b03075a60e1ddf8aa", - "sha256:69e62c5034291c845fc4df7f8155e8544178b6c774f97a99e2734b05eb5bed31", - "sha256:704c8c8c6ce6569286ae9622e534b4f5b9759b6f2cd643f1c1a61f666d534fe8", - "sha256:78f5243bb6b1060aed6213d5107744c19f9571ec76d54c99cc15938eb69e0e86", - "sha256:79cac3390bfa9836bb795be377395f28410811c9066bc4eefd8015258a7578c6", - "sha256:7ae6eabf519bc7871ce117fb18bf14e0e343eeb96c377667e3e5dd12095e0288", - "sha256:7e39e845c4d764208e7b8f6a21c541ade741e2c41afabdfa1caa28687a3c98cf", - "sha256:8161d9fbc7e9fe2326de89cd0abb9f3599bccc1287db0aba285cb68d204ce929", - "sha256:8bec2ac5da793c2685ce5319ca9bcf4eee683b8a1679051f8e6ec04c4f2fd7dc", - "sha256:959244a17184515f8c52dcb65fb662808767c0bd233c1d8a166e7cf74c9ea985", - "sha256:9b148068e881faa26d878ff63e79650e208e95cf1c22bd3f77c3ca7b1d9821a3", - "sha256:aa6f302a3a0b5f240ee201297fff0bbfe2fa0d415a94aeb257d8b461032389bd", - "sha256:ace9048de91293e467b44bce0f0381345078389814ff6e18dbac8fdbf896360e", - "sha256:ad7525bf0241e5502168ae9c643a2f6c219fa0a283001cee4cf23a9b7da75879", - "sha256:b01a840ecc25dce235ae4c1b6a0daefb2a203dba0e6e980637ee9c2f6ee0df57", - "sha256:b076e625396e787448d27a411aefff867db2bffac8ed04e8f7056b07024eed5a", - "sha256:b172f8e030e8ef247b3104902cc671e20df80163b60a203653150d2fc204d1ad", - "sha256:b1f097878d74fe51e1ddd1be62d8e3682748875b461232cf4b52ddc6e6db0bba", - "sha256:b95574d06aa9d2bd6e5cc35a5bbe35696342c96760b69dc4287dbd5abd4ad51d", - "sha256:bda1c5f347550c359f841d6614fb8ca42ae5cb0b74d39f8a1e204815ebe25750", - "sha256:cec6b9ce3bd2b7853d4a4563801292bfee40b030c05a3d29555fd2a8ee9bd68c", - "sha256:d1a987778b9c71da2fc8948e6f2656da6ef68f59298b7e9786849634c35d2c3c", - "sha256:d74c08e9aaef995f8c4ef6d202dbd219c318450fe2a76da624f2ebb9c8ec5d9f", - "sha256:e18aafdfb3e9ec0d261c942d35bd7c28d031c5855dadb491d2723ba54f4c3015", - "sha256:e216c5c45f89ef8971373fd1c5d8d1164b81f7f5f06bbf23c37e7908d19e8558", - "sha256:e695df2c58ce526eeab11a2e915448d3eb76f75dffe338ea613c1201b33bab2f", - "sha256:e7575ab65ca8399c8c4f9a7d61bbd2d204c8b8e447aab9d355682205c9dd948d", - "sha256:e995b3b76ccedc27fe4f477b349b7d64597e53a43fc2961db9d3fbace085d69d", - "sha256:ea31689f05043d520113e0552f039603c4dd71fa4c287b64cb3606140c66f425", - "sha256:eb5507795caabd9b2ae3f1adc95f67b1104971c22c624bb354232d65c4fc90b3", - "sha256:eb8668cfbc279a536c633137deeb9435d2962caec279c3f8cf8b91fff6ff8953", - "sha256:ecea0c38c9079570163d663c0433a9af4094a60aafdca491c6a3d248c7432827", - "sha256:f25d8b92a4e31ff1bd873654ec367ae811b3a943583e05432ea29264782dc32c", - "sha256:f60a297c3987c6c02ffb29effc70eadcbb412fe76947d394a1091a3615948e2f", - "sha256:f973643ef532d4f9be71dd88cf7588936685fdb576d93a79fe9f65bc337d9d73" + "sha256:02fad4f8faa4153db76f9246bc95c1d99f054f4e0a884175bff9155cf4f856cb", + "sha256:092b134129a8bb940c08b2d9ceb4459af5fb3faea77888af63182e17d89e1cf1", + "sha256:0ce92c5a9d7007d838456f4b77ea159cb628187a137e1895331e530973dcf862", + "sha256:0dab4ef76d7b14f432057fdb7a0477e8bffca0ad39ace308be6e74864e632271", + "sha256:1165490be0069e34e4f99d08e9c5209c463de11b471709dfae31e2a98cbd49fd", + "sha256:11dd6f52c2a7ce8bf0a5f3b6e4a8eb60e157ffedc3c4b4314a41c1dfbd26ce58", + "sha256:15d54ecef1582b1d3ec6049b20d3c1a07d5e7f85335d8a3b617c9960b4f807e0", + "sha256:171e9977c6a5d2b2be9efc7df1126fd525ce7cad0eb9904fe692da007ba90d81", + "sha256:177d837339883c541f8524683e227adcaea581eca6bb33823a2a1fdae4c988e1", + "sha256:18f544356bceef17cc55fcf859e5664f06946c1b68efcea6acdc50f8f6a6e776", + "sha256:199a1272e642266b90c9f40dec7fd3d307b51bf639fa0d15980dc0b3246c1393", + "sha256:1e6f867379fd033a0eeabb1be0cffa2bd660582b8b0c9478895c509d875a9d9e", + "sha256:2444fbe1ba1889e0b29eb4d11931afa88f92dc507b7248f45be372775b3cef4f", + "sha256:25fe40967717bad0ce628a0223f08a10d54c9d739e88c9cbb0f77b5959367542", + "sha256:264ff2bcce27a7f455b64ac0dfe097680b65d9a1a293ef902675fa8158d20b24", + "sha256:2a79c4a09765d18311c35975ad2eb1ac613c0401afdd9cb1ca4110aeb5dd3c4c", + "sha256:2c492401bdb3a85824669d6a03f57b3dfadef0941b8541f035f83bbfc39d4282", + "sha256:315ff74b585110ac3b7ab631e89e769d294f303c6d21302a816b3554ed4c81af", + "sha256:34a3bf6b92e6621fc4dcdaab353e173ccb0ca9e4bfbcf7e49a0134c86c9cd303", + "sha256:37351dc8123c154fa05b7579fdb126b9f8b1cf42fd6f79ddf19121b7bdd4aa04", + "sha256:385618003e3d608001676bb35dc67ae3ad44c75c0395d8de5780af7bb35be6b2", + "sha256:392cc8fd2b1b010ca36840735e2a526fcbd76795a5d44006065e79868cc76ccf", + "sha256:3d03287eb03186256999539d98818c425c33546ab4901028c8fa933b62c35c3a", + "sha256:44683f2556a56c9a6e673b583763096b8efbd2df022b02995609cf8e64fc8ae0", + "sha256:44af11c00fd3b19b8809487630f8a0039130d32363239dfd15238e6d37e41a48", + "sha256:452735fafe8ff5918236d5fe1feac322b359e57692269c75151f9b4ee4b7e1bc", + "sha256:4c181ceba2e6808ede1e964f7bdc77bd8c7eb62f202c63a48cc541e5ffffccb6", + "sha256:4dd532dac197d68c478480edde74fd4476c6823355987fd31d01ad9aa1e5fb59", + "sha256:520af84febb6bb54453e7fbb730afa58c7178fd018c398a8fcd8e269a79bf96d", + "sha256:553ba93f8e3c70e1b0031e4dfea36aba4e2b51fe5770db35e99af8dc5c5a9dfe", + "sha256:5b7b02e50d54be6114cc4f6a3222fec83164f7c42772ba03b520138859b5fde1", + "sha256:63306486fcb5a827449464f6211d2991f01dfa2965976018c9bab9d5e45a35c8", + "sha256:75c82b27c56478d5e1391f2e7b2e7f588d093157fa40d53fd9453a471b1191f2", + "sha256:7ba5ff236c87a7b7aa1441a216caf44baee14cbfbd2256d306f926d16b026578", + "sha256:7e688010581dbac9cab72800e9076e16f7cccd0d89af5785b70daa11174e94de", + "sha256:80b5b207a8b08c6a934b214e364cab2fa82663d4af18981a6c0a9e95f8df7602", + "sha256:822fa99dd1ac686061e1219b67868e25d9757989cf2259f735a4802497d6da31", + "sha256:881cae0f9cbd928c9c001487bb3dcbfd0b0af3ef53ae92180878591053be0cb3", + "sha256:88d96127ae01ff571d465d4b0be25c123789cef88ba0879194d673fdea52f54e", + "sha256:8b1c65a739447c5ddce5b96c0a388fd82e4bbdff7251396a70182b1d83631019", + "sha256:8fed429c26b99641dc1f3a79179860122b22745dd9af36f29b141e178925070a", + "sha256:9bb47cc9f07a59a451361a850cb06d20633e77a9118d05fd0f77b1864439461b", + "sha256:a6b6b3bd121ee2ec4bd35039319f3423d0be282b9752a5ae9f18724bc93ebe7c", + "sha256:ae13ed5bf5542d7d4a0a42ff5160e07e84adc44eda65ddaa635c484ff8e55917", + "sha256:af94fb80e4f159f4d93fb411800448ad87b6039b0500849a403b73a0d36bb5ae", + "sha256:b4c144c129343416a49378e05c9451c34aae5ccf00221e4fa4f487db0816ee2f", + "sha256:b52edb940d087e2a96e73c1523284a2e94a4e66fa2ea1e2e64dddc67173bad94", + "sha256:b559adc22486937786731dac69e57296cb9aede7e2687dfc0d2696dbd3b1eb6b", + "sha256:b838a91e84e1773c3436f6cc6996e000ed3ca5721799e7789be18830fad009a2", + "sha256:ba8480ebe401c2f094d10a8c4209b800a9b77215b6c796d16b6ecdf665048950", + "sha256:bc96441c9d9ca12a790b5ae17d2fa6654da4b3962ea15e0eabb1b1caed094777", + "sha256:c90e9141e9221dd6fbc16a2727a5703c19443a8d9bf7d634c792fa0287cee1ab", + "sha256:d2e73e2ac468536197e6b3ab79bc4a5c9da0f078cd78cfcc7fe27cf5d1195ef0", + "sha256:d3154b369141c3169b8133973ac00f63fcf8d6dbcc297d788d36afbb7811e511", + "sha256:d66ff48ab3bb6f762a153e29c0fc1eb5a62a260217bc64470d7ba602f5886d20", + "sha256:d6874929d624d3a670f676efafbbc747f519a6121b581dd41d012109e70a5ebd", + "sha256:e33426a5e1dc7743dd54dfd11d3a6c02c5d127abfaa2edd80a6e352b58347d1a", + "sha256:e52eb31ae3afacdacfe50705a15b75ded67935770c460d88c215a9c0c40d0e9c", + "sha256:eae79f8e3501133aa0e220bbc29573910d096795882a70e6f6e6637b09522133", + "sha256:eebd927b86761a7068a06d3699fd6c20129becf15bb44282db085921ea0f1585", + "sha256:eff187177d8016ff6addf789dcc421c3db0d014e4946c1cc3fbf697f7852459d", + "sha256:f5f99a93cecf799738e211f9746dc83749b5693538fbfac279a61682ba309387", + "sha256:fbba59022e7c20124d2f520842b75904c7b9f16c854233fa46575c69949fb5b9" ], "index": "pypi", - "version": "==7.6.12" + "version": "==7.7.1" }, "cryptography": { "hashes": [ - "sha256:00918d859aa4e57db8299607086f793fa7813ae2ff5a4637e318a25ef82730f7", - "sha256:1e8d181e90a777b63f3f0caa836844a1182f1f265687fac2115fcf245f5fbec3", - "sha256:1f9a92144fa0c877117e9748c74501bea842f93d21ee00b0cf922846d9d0b183", - "sha256:21377472ca4ada2906bc313168c9dc7b1d7ca417b63c1c3011d0c74b7de9ae69", - "sha256:24979e9f2040c953a94bf3c6782e67795a4c260734e5264dceea65c8f4bae64a", - "sha256:2a46a89ad3e6176223b632056f321bc7de36b9f9b93b2cc1cccf935a3849dc62", - "sha256:322eb03ecc62784536bc173f1483e76747aafeb69c8728df48537eb431cd1911", - "sha256:436df4f203482f41aad60ed1813811ac4ab102765ecae7a2bbb1dbb66dcff5a7", - "sha256:4f422e8c6a28cf8b7f883eb790695d6d45b0c385a2583073f3cec434cc705e1a", - "sha256:53f23339864b617a3dfc2b0ac8d5c432625c80014c25caac9082314e9de56f41", - "sha256:5fed5cd6102bb4eb843e3315d2bf25fede494509bddadb81e03a859c1bc17b83", - "sha256:610a83540765a8d8ce0f351ce42e26e53e1f774a6efb71eb1b41eb01d01c3d12", - "sha256:6c8acf6f3d1f47acb2248ec3ea261171a671f3d9428e34ad0357148d492c7864", - "sha256:6f76fdd6fd048576a04c5210d53aa04ca34d2ed63336d4abd306d0cbe298fddf", - "sha256:72198e2b5925155497a5a3e8c216c7fb3e64c16ccee11f0e7da272fa93b35c4c", - "sha256:887143b9ff6bad2b7570da75a7fe8bbf5f65276365ac259a5d2d5147a73775f2", - "sha256:888fcc3fce0c888785a4876ca55f9f43787f4c5c1cc1e2e0da71ad481ff82c5b", - "sha256:8e6a85a93d0642bd774460a86513c5d9d80b5c002ca9693e63f6e540f1815ed0", - "sha256:94f99f2b943b354a5b6307d7e8d19f5c423a794462bde2bf310c770ba052b1c4", - "sha256:9b336599e2cb77b1008cb2ac264b290803ec5e8e89d618a5e978ff5eb6f715d9", - "sha256:a2d8a7045e1ab9b9f803f0d9531ead85f90c5f2859e653b61497228b18452008", - "sha256:b8272f257cf1cbd3f2e120f14c68bff2b6bdfcc157fafdee84a1b795efd72862", - "sha256:bf688f615c29bfe9dfc44312ca470989279f0e94bb9f631f85e3459af8efc009", - "sha256:d9c5b9f698a83c8bd71e0f4d3f9f839ef244798e5ffe96febfa9714717db7af7", - "sha256:dd7c7e2d71d908dc0f8d2027e1604102140d84b155e658c20e8ad1304317691f", - "sha256:df978682c1504fc93b3209de21aeabf2375cb1571d4e61907b3e7a2540e83026", - "sha256:e403f7f766ded778ecdb790da786b418a9f2394f36e8cc8b796cc056ab05f44f", - "sha256:eb3889330f2a4a148abead555399ec9a32b13b7c8ba969b72d8e500eb7ef84cd", - "sha256:f4daefc971c2d1f82f03097dc6f216744a6cd2ac0f04c68fb935ea2ba2a0d420", - "sha256:f51f5705ab27898afda1aaa430f34ad90dc117421057782022edf0600bec5f14", - "sha256:fd0ee90072861e276b0ff08bd627abec29e32a53b2be44e41dbcdf87cbee2b00" + "sha256:04abd71114848aa25edb28e225ab5f268096f44cf0127f3d36975bdf1bdf3390", + "sha256:0529b1d5a0105dd3731fa65680b45ce49da4d8115ea76e9da77a875396727b41", + "sha256:1bc312dfb7a6e5d66082c87c34c8a62176e684b6fe3d90fcfe1568de675e6688", + "sha256:268e4e9b177c76d569e8a145a6939eca9a5fec658c932348598818acf31ae9a5", + "sha256:29ecec49f3ba3f3849362854b7253a9f59799e3763b0c9d0826259a88efa02f1", + "sha256:2bf7bf75f7df9715f810d1b038870309342bff3069c5bd8c6b96128cb158668d", + "sha256:3b721b8b4d948b218c88cb8c45a01793483821e709afe5f622861fc6182b20a7", + "sha256:3c00b6b757b32ce0f62c574b78b939afab9eecaf597c4d624caca4f9e71e7843", + "sha256:3dc62975e31617badc19a906481deacdeb80b4bb454394b4098e3f2525a488c5", + "sha256:4973da6ca3db4405c54cd0b26d328be54c7747e89e284fcff166132eb7bccc9c", + "sha256:4e389622b6927d8133f314949a9812972711a111d577a5d1f4bee5e58736b80a", + "sha256:51e4de3af4ec3899d6d178a8c005226491c27c4ba84101bfb59c901e10ca9f79", + "sha256:5f6f90b72d8ccadb9c6e311c775c8305381db88374c65fa1a68250aa8a9cb3a6", + "sha256:6210c05941994290f3f7f175a4a57dbbb2afd9273657614c506d5976db061181", + "sha256:6f101b1f780f7fc613d040ca4bdf835c6ef3b00e9bd7125a4255ec574c7916e4", + "sha256:7bdcd82189759aba3816d1f729ce42ffded1ac304c151d0a8e89b9996ab863d5", + "sha256:7ca25849404be2f8e4b3c59483d9d3c51298a22c1c61a0e84415104dacaf5562", + "sha256:81276f0ea79a208d961c433a947029e1a15948966658cf6710bbabb60fcc2639", + "sha256:8cadc6e3b5a1f144a039ea08a0bdb03a2a92e19c46be3285123d32029f40a922", + "sha256:8e0ddd63e6bf1161800592c71ac794d3fb8001f2caebe0966e77c5234fa9efc3", + "sha256:909c97ab43a9c0c0b0ada7a1281430e4e5ec0458e6d9244c0e821bbf152f061d", + "sha256:96e7a5e9d6e71f9f4fca8eebfd603f8e86c5225bb18eb621b2c1e50b290a9471", + "sha256:9a1e657c0f4ea2a23304ee3f964db058c9e9e635cc7019c4aa21c330755ef6fd", + "sha256:9eb9d22b0a5d8fd9925a7764a054dca914000607dff201a24c791ff5c799e1fa", + "sha256:af4ff3e388f2fa7bff9f7f2b31b87d5651c45731d3e8cfa0944be43dff5cfbdb", + "sha256:b042d2a275c8cee83a4b7ae30c45a15e6a4baa65a179a0ec2d78ebb90e4f6699", + "sha256:bc821e161ae88bfe8088d11bb39caf2916562e0a2dc7b6d56714a48b784ef0bb", + "sha256:c505d61b6176aaf982c5717ce04e87da5abc9a36a5b39ac03905c4aafe8de7aa", + "sha256:c63454aa261a0cf0c5b4718349629793e9e634993538db841165b3df74f37ec0", + "sha256:c7362add18b416b69d58c910caa217f980c5ef39b23a38a0880dfd87bdf8cd23", + "sha256:d03806036b4f89e3b13b6218fefea8d5312e450935b1a2d55f0524e2ed7c59d9", + "sha256:d1b3031093a366ac767b3feb8bcddb596671b3aaff82d4050f984da0c248b615", + "sha256:d1c3572526997b36f245a96a2b1713bf79ce99b271bbcf084beb6b9b075f29ea", + "sha256:efcfe97d1b3c79e486554efddeb8f6f53a4cdd4cf6086642784fa31fc384e1d7", + "sha256:f514ef4cd14bb6fb484b4a60203e912cfcb64f2ab139e88c2274511514bf7308" ], "markers": "python_version >= '3.7' and python_full_version not in '3.9.0, 3.9.1'", - "version": "==44.0.1" + "version": "==44.0.2" + }, + "docker": { + "hashes": [ + "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c", + "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0" + ], + "markers": "python_version >= '3.8'", + "version": "==7.1.0" }, "docutils": { "hashes": [ @@ -1274,6 +1826,12 @@ "markers": "python_version >= '3.9'", "version": "==0.21.2" }, + "events": { + "hashes": [ + "sha256:a7286af378ba3e46640ac9825156c93bdba7502174dd696090fdfcd4d80a1abd" + ], + "version": "==0.5" + }, "furo": { "hashes": [ "sha256:6cd97c58b47813d3619e63e9081169880fbe331f0ca883c871ff1f3f11814f5c", @@ -1340,11 +1898,11 @@ }, "iniconfig": { "hashes": [ - "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", - "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" + "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", + "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760" ], - "markers": "python_version >= '3.7'", - "version": "==2.0.0" + "markers": "python_version >= '3.8'", + "version": "==2.1.0" }, "jaraco.classes": { "hashes": [ @@ -1372,19 +1930,19 @@ }, "jeepney": { "hashes": [ - "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806", - "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755" + "sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683", + "sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732" ], "markers": "sys_platform == 'linux'", - "version": "==0.8.0" + "version": "==0.9.0" }, "jinja2": { "hashes": [ - "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb", - "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb" + "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", + "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67" ], "markers": "python_version >= '3.7'", - "version": "==3.1.5" + "version": "==3.1.6" }, "keyring": { "hashes": [ @@ -1477,6 +2035,14 @@ "markers": "python_version >= '3.7'", "version": "==0.1.2" }, + "minio": { + "hashes": [ + "sha256:5247df5d4dca7bfa4c9b20093acd5ad43e82d8710ceb059d79c6eea970f49f79", + "sha256:c06ef7a43e5d67107067f77b6c07ebdd68733e5aa7eed03076472410ca19d876" + ], + "markers": "python_version >= '3.9'", + "version": "==7.2.15" + }, "more-itertools": { "hashes": [ "sha256:2cd7fad1009c31cc9fb6a035108509e6547547a7a738374f10bd49a09eb3ee3b", @@ -1487,33 +2053,41 @@ }, "nh3": { "hashes": [ - "sha256:09f037c02fc2c43b211ff1523de32801dcfb0918648d8e651c36ef890f1731ec", - "sha256:0ae9cbd713524cdb81e64663d0d6aae26f678db9f2cd9db0bf162606f1f9f20c", - "sha256:10317cd96fe4bbd4eb6b95f3920b71c902157ad44fed103fdcde43e3b8ee8be6", - "sha256:181063c581defe683bd4bb78188ac9936d208aebbc74c7f7c16b6a32ae2ebb38", - "sha256:1b9a8340a0aab991c68a5ca938d35ef4a8a3f4bf1b455da8855a40bee1fa0ace", - "sha256:231addb7643c952cd6d71f1c8702d703f8fe34afcb20becb3efb319a501a12d7", - "sha256:3eb04b9c3deb13c3a375ea39fd4a3c00d1f92e8fb2349f25f1e3e4506751774b", - "sha256:47b2946c0e13057855209daeffb45dc910bd0c55daf10190bb0b4b60e2999784", - "sha256:4fd2e9248725ebcedac3997a8d3da0d90a12a28c9179c6ba51f1658938ac30d0", - "sha256:6ed834c68452a600f517dd3e1534dbfaff1f67f98899fecf139a055a25d99150", - "sha256:76e2f603b30c02ff6456b233a83fc377dedab6a50947b04e960a6b905637b776", - "sha256:813f1c8012dd64c990514b795508abb90789334f76a561fa0fd4ca32d2275330", - "sha256:8698db4c04b140800d1a1cd3067fda399e36e1e2b8fc1fe04292a907350a3e9b", - "sha256:92f3f1c4f47a2c6f3ca7317b1d5ced05bd29556a75d3a4e2715652ae9d15c05d", - "sha256:9705c42d7ff88a0bea546c82d7fe5e59135e3d3f057e485394f491248a1f8ed5", - "sha256:ac4d27dc836a476efffc6eb661994426b8b805c951b29c9cf2ff36bc9ad58bc5", - "sha256:ce3731c8f217685d33d9268362e5b4f770914e922bba94d368ab244a59a6c397", - "sha256:d2a176fd4306b6f0f178a3f67fac91bd97a3a8d8fafb771c9b9ef675ba5c8886", - "sha256:da87573f03084edae8eb87cfe811ec338606288f81d333c07d2a9a0b9b976c0b", - "sha256:ddefa9fd6794a87e37d05827d299d4b53a3ec6f23258101907b96029bfef138a", - "sha256:e1061a4ab6681f6bdf72b110eea0c4e1379d57c9de937db3be4202f7ad6043db", - "sha256:e1f7370b4e14cc03f5ae141ef30a1caf81fa5787711f80be9081418dd9eb79d2", - "sha256:eb4254b1dac4a1ee49919a5b3f1caf9803ea8dada1816d9e8289e63d3cd0dd9a", - "sha256:f7d564871833ddbe54df3aa59053b1110729d3a800cb7628ae8f42adb3d75208" + "sha256:087ffadfdcd497658c3adc797258ce0f06be8a537786a7217649fc1c0c60c293", + "sha256:20979783526641c81d2f5bfa6ca5ccca3d1e4472474b162c6256745fbfe31cd1", + "sha256:2a5174551f95f2836f2ad6a8074560f261cf9740a48437d6151fd2d4d7d617ab", + "sha256:31eedcd7d08b0eae28ba47f43fd33a653b4cdb271d64f1aeda47001618348fde", + "sha256:4990e7ee6a55490dbf00d61a6f476c9a3258e31e711e13713b2ea7d6616f670e", + "sha256:55823c5ea1f6b267a4fad5de39bc0524d49a47783e1fe094bcf9c537a37df251", + "sha256:6141caabe00bbddc869665b35fc56a478eb774a8c1dfd6fba9fe1dfdf29e6efa", + "sha256:637d4a10c834e1b7d9548592c7aad760611415fcd5bd346f77fd8a064309ae6d", + "sha256:63ca02ac6f27fc80f9894409eb61de2cb20ef0a23740c7e29f9ec827139fa578", + "sha256:6ae319f17cd8960d0612f0f0ddff5a90700fa71926ca800e9028e7851ce44a6f", + "sha256:6c9c30b8b0d291a7c5ab0967ab200598ba33208f754f2f4920e9343bdd88f79a", + "sha256:713d16686596e556b65e7f8c58328c2df63f1a7abe1277d87625dcbbc012ef82", + "sha256:818f2b6df3763e058efa9e69677b5a92f9bc0acff3295af5ed013da544250d5b", + "sha256:9d67709bc0d7d1f5797b21db26e7a8b3d15d21c9c5f58ccfe48b5328483b685b", + "sha256:a5f77e62aed5c4acad635239ac1290404c7e940c81abe561fd2af011ff59f585", + "sha256:a772dec5b7b7325780922dd904709f0f5f3a79fbf756de5291c01370f6df0967", + "sha256:a7ea28cd49293749d67e4fcf326c554c83ec912cd09cd94aa7ec3ab1921c8283", + "sha256:ac7006c3abd097790e611fe4646ecb19a8d7f2184b882f6093293b8d9b887431", + "sha256:b3b5c58161e08549904ac4abd450dacd94ff648916f7c376ae4b2c0652b98ff9", + "sha256:b8d55ea1fc7ae3633d758a92aafa3505cd3cc5a6e40470c9164d54dff6f96d42", + "sha256:bb0014948f04d7976aabae43fcd4cb7f551f9f8ce785a4c9ef66e6c2590f8629", + "sha256:d002b648592bf3033adfd875a48f09b8ecc000abd7f6a8769ed86b6ccc70c759", + "sha256:d426d7be1a2f3d896950fe263332ed1662f6c78525b4520c8e9861f8d7f0d243", + "sha256:fcff321bd60c6c5c9cb4ddf2554e22772bb41ebd93ad88171bbbb6f271255286" ], "markers": "python_version >= '3.8'", - "version": "==0.2.20" + "version": "==0.2.21" + }, + "opensearch-py": { + "hashes": [ + "sha256:52c60fdb5d4dcf6cce3ee746c13b194529b0161e0f41268b98ab8f1624abe2fa", + "sha256:6598df0bc7a003294edd0ba88a331e0793acbb8c910c43edf398791e3b2eccda" + ], + "index": "pypi", + "version": "==2.8.0" }, "packaging": { "hashes": [ @@ -1539,6 +2113,41 @@ "markers": "python_version >= '3.8'", "version": "==2.22" }, + "pycryptodome": { + "hashes": [ + "sha256:009e1c80eea42401a5bd5983c4bab8d516aef22e014a4705622e24e6d9d703c6", + "sha256:18d5b0ddc7cf69231736d778bd3ae2b3efb681ae33b64b0c92fb4626bb48bb89", + "sha256:2988ffcd5137dc2d27eb51cd18c0f0f68e5b009d5fec56fbccb638f90934f333", + "sha256:37ddcd18284e6b36b0a71ea495a4c4dca35bb09ccc9bfd5b91bfaf2321f131c1", + "sha256:3b76fa80daeff9519d7e9f6d9e40708f2fce36b9295a847f00624a08293f4f00", + "sha256:56c6f9342fcb6c74e205fbd2fee568ec4cdbdaa6165c8fde55dbc4ba5f584464", + "sha256:87a88dc543b62b5c669895caf6c5a958ac7abc8863919e94b7a6cafd2f64064f", + "sha256:8f4f6f47a7f411f2c157e77bbbda289e0c9f9e1e9944caa73c1c2e33f3f92d6e", + "sha256:96e73527c9185a3d9b4c6d1cfb4494f6ced418573150be170f6580cb975a7f5a", + "sha256:98fd9da809d5675f3a65dcd9ed384b9dc67edab6a4cda150c5870a8122ec961d", + "sha256:9dbb749cef71c28271484cbef684f9b5b19962153487735411e1020ca3f59cb1", + "sha256:9e1bb165ea1dc83a11e5dbbe00ef2c378d148f3a2d3834fb5ba4e0f6fd0afe4b", + "sha256:a0092fd476701eeeb04df5cc509d8b739fa381583cda6a46ff0a60639b7cd70d", + "sha256:a26bcfee1293b7257c83b0bd13235a4ee58165352be4f8c45db851ba46996dc6", + "sha256:a31fa5914b255ab62aac9265654292ce0404f6b66540a065f538466474baedbc", + "sha256:a6cf9553b29624961cab0785a3177a333e09e37ba62ad22314ebdbb01ca79840", + "sha256:aec7b40a7ea5af7c40f8837adf20a137d5e11a6eb202cde7e588a48fb2d871a8", + "sha256:b4bdce34af16c1dcc7f8c66185684be15f5818afd2a82b75a4ce6b55f9783e13", + "sha256:d086aed307e96d40c23c42418cbbca22ecc0ab4a8a0e24f87932eeab26c08627", + "sha256:d21c1eda2f42211f18a25db4eaf8056c94a8563cd39da3683f89fe0d881fb772", + "sha256:d4d1174677855c266eed5c4b4e25daa4225ad0c9ffe7584bb1816767892545d0", + "sha256:e653519dedcd1532788547f00eeb6108cc7ce9efdf5cc9996abce0d53f95d5a9", + "sha256:e7514a1aebee8e85802d154fdb261381f1cb9b7c5a54594545145b8ec3056ae6", + "sha256:f02baa9f5e35934c6e8dcec91fcde96612bdefef6e442813b8ea34e82c84bbfb", + "sha256:f1ae7beb64d4fc4903a6a6cca80f1f448e7a8a95b77d106f8a29f2eb44d17547", + "sha256:f5810bc7494e4ac12a4afef5a32218129e7d3890ce3f2b5ec520cc69eb1102ad", + "sha256:f6cf6aa36fcf463e622d2165a5ad9963b2762bebae2f632d719dfb8544903cf5", + "sha256:f7a683bc9fa585c0dfec7fa4801c96a48d30b30b096e3297f9374f40c2fedafc", + "sha256:fd7ab568b3ad7b77c908d7c3f7e167ec5a8f035c64ff74f10d47a4edd043d723" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", + "version": "==3.22.0" + }, "pygments": { "hashes": [ "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", @@ -1557,11 +2166,11 @@ }, "pytest": { "hashes": [ - "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", - "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761" + "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", + "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845" ], "index": "pypi", - "version": "==8.3.4" + "version": "==8.3.5" }, "pytest-ordering": { "hashes": [ @@ -1572,6 +2181,14 @@ "index": "pypi", "version": "==0.6" }, + "python-dateutil": { + "hashes": [ + "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", + "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.9.0.post0" + }, "pyyaml": { "hashes": [ "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", @@ -1673,19 +2290,19 @@ }, "rich": { "hashes": [ - "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", - "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90" + "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", + "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725" ], "markers": "python_full_version >= '3.8.0'", - "version": "==13.9.4" + "version": "==14.0.0" }, "roman-numerals-py": { "hashes": [ - "sha256:91199c4373658c03d87d9fe004f4a5120a20f6cb192be745c2377cce274ef41c", - "sha256:a1421ce66b3eab7e8735065458de3fa5c4a46263d50f9f4ac8f0e5e7701dd125" + "sha256:9da2ad2fb670bcf24e81070ceb3be72f6c11c440d73bd579fbeca1e9f330954c", + "sha256:be4bf804f083a4ce001b5eb7e3c0862479d10f94c936f6c4e5f250aa5ff5bd2d" ], "markers": "python_version >= '3.9'", - "version": "==3.0.0" + "version": "==3.1.0" }, "secretstorage": { "hashes": [ @@ -1697,11 +2314,19 @@ }, "setuptools": { "hashes": [ - "sha256:c5afc8f407c626b8313a86e10311dd3f661c6cd9c09d4bf8c15c0e11f9f2b0e6", - "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3" + "sha256:18fd474d4a82a5f83dac888df697af65afa82dec7323d09c3e37d1f14288da54", + "sha256:3e386e96793c8702ae83d17b853fb93d3e09ef82ec62722e61da5cd22376dcd8" ], "index": "pypi", - "version": "==75.8.0" + "version": "==78.1.0" + }, + "six": { + "hashes": [ + "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", + "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.17.0" }, "sniffio": { "hashes": [ @@ -1728,11 +2353,11 @@ }, "sphinx": { "hashes": [ - "sha256:3c0a40ff71ace28b316bde7387d93b9249a3688c202181519689b66d5d0aed53", - "sha256:5b0067853d6e97f3fa87563e3404ebd008fce03525b55b25da90706764da6215" + "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348", + "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3" ], "markers": "python_version >= '3.11'", - "version": "==8.2.0" + "version": "==8.2.3" }, "sphinx-basic-ng": { "hashes": [ @@ -1790,6 +2415,27 @@ "markers": "python_version >= '3.9'", "version": "==2.0.0" }, + "testcontainers-core": { + "hashes": [ + "sha256:69a8bf2ddb52ac2d03c26401b12c70db0453cced40372ad783d6dce417e52095" + ], + "markers": "python_version >= '3.7'", + "version": "==0.0.1rc1" + }, + "testcontainers-minio": { + "hashes": [ + "sha256:54d330d085c0a11fc5da0b001af87aec4dd3e814104376bf7513e8646c77442a" + ], + "index": "pypi", + "version": "==0.0.1rc1" + }, + "testcontainers-opensearch": { + "hashes": [ + "sha256:0bdf270b5b7f53915832f7c31dd2bd3ffdc20b534ea6b32231cc7003049bd0e1" + ], + "index": "pypi", + "version": "==0.0.1rc1" + }, "twine": { "hashes": [ "sha256:a47f973caf122930bf0fbbf17f80b83bc1602c9ce393c7845f289a3001dc5384", @@ -1800,20 +2446,105 @@ }, "typing-extensions": { "hashes": [ - "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", - "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" + "sha256:0a4ac55a5820789d87e297727d229866c9650f6521b64206413c4fbada24d95b", + "sha256:c8dd92cc0d6425a97c18fbb9d1954e5ff92c1ca881a309c45f06ebc0b79058e5" ], "markers": "python_version >= '3.8'", - "version": "==4.12.2" + "version": "==4.13.0" }, "urllib3": { "hashes": [ "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d" ], - "markers": "python_version >= '3.9'", + "markers": "python_version >= '3.10'", "version": "==2.3.0" }, + "wrapt": { + "hashes": [ + "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.2" + }, "zipp": { "hashes": [ "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4", diff --git a/lib/python/coverage.xml b/lib/python/coverage.xml index b23a031c5fe13102ab04331b3ef60329ee9353c0..ba3da4f2e6334a47f8e1fc55af11e024bbf698fc 100644 --- a/lib/python/coverage.xml +++ b/lib/python/coverage.xml @@ -1,14 +1,14 @@ <?xml version="1.0" ?> -<coverage version="7.6.10" timestamp="1741253336897" lines-valid="1941" lines-covered="1818" line-rate="0.9366" branches-covered="0" branches-valid="0" branch-rate="0" complexity="0"> - <!-- Generated by coverage.py: https://coverage.readthedocs.io/en/7.6.10 --> +<coverage version="7.7.1" timestamp="1743366739557" lines-valid="1967" lines-covered="1831" line-rate="0.9309" branches-covered="0" branches-valid="0" branch-rate="0" complexity="0"> + <!-- Generated by coverage.py: https://coverage.readthedocs.io/en/7.7.1 --> <!-- Based on https://raw.githubusercontent.com/cobertura/web/master/htdocs/xml/coverage-04.dtd --> <sources> <source>/home/mweise/Projects/fda-services/lib/python</source> </sources> <packages> - <package name="dbrepo" line-rate="0.9102" branch-rate="0" complexity="0"> + <package name="dbrepo" line-rate="0.8972" branch-rate="0" complexity="0"> <classes> - <class name="RestClient.py" filename="dbrepo/RestClient.py" complexity="0" line-rate="0.9102" branch-rate="0"> + <class name="RestClient.py" filename="dbrepo/RestClient.py" complexity="0" line-rate="0.8972" branch-rate="0"> <methods/> <lines> <line number="1" hits="1"/> @@ -902,6 +902,20 @@ <line number="1923" hits="1"/> <line number="1924" hits="1"/> <line number="1925" hits="1"/> + <line number="1927" hits="1"/> + <line number="1941" hits="0"/> + <line number="1942" hits="0"/> + <line number="1944" hits="0"/> + <line number="1945" hits="0"/> + <line number="1946" hits="0"/> + <line number="1947" hits="0"/> + <line number="1948" hits="0"/> + <line number="1949" hits="0"/> + <line number="1950" hits="0"/> + <line number="1951" hits="0"/> + <line number="1953" hits="0"/> + <line number="1954" hits="0"/> + <line number="1955" hits="0"/> </lines> </class> <class name="__init__.py" filename="dbrepo/__init__.py" complexity="0" line-rate="1" branch-rate="0"> @@ -910,7 +924,7 @@ </class> </classes> </package> - <package name="dbrepo.api" line-rate="0.959" branch-rate="0" complexity="0"> + <package name="dbrepo.api" line-rate="0.9595" branch-rate="0" complexity="0"> <classes> <class name="__init__.py" filename="dbrepo/api/__init__.py" complexity="0" line-rate="1" branch-rate="0"> <methods/> @@ -1326,20 +1340,18 @@ <line number="502" hits="1"/> <line number="505" hits="1"/> <line number="506" hits="1"/> - <line number="507" hits="1"/> + <line number="509" hits="1"/> <line number="510" hits="1"/> <line number="511" hits="1"/> <line number="514" hits="1"/> <line number="515" hits="1"/> - <line number="516" hits="1"/> - <line number="517" hits="1"/> <line number="518" hits="1"/> <line number="519" hits="1"/> <line number="520" hits="1"/> + <line number="521" hits="1"/> + <line number="522" hits="1"/> <line number="523" hits="1"/> <line number="524" hits="1"/> - <line number="525" hits="1"/> - <line number="526" hits="1"/> <line number="527" hits="1"/> <line number="528" hits="1"/> <line number="529" hits="1"/> @@ -1348,24 +1360,24 @@ <line number="532" hits="1"/> <line number="533" hits="1"/> <line number="534" hits="1"/> + <line number="535" hits="1"/> + <line number="536" hits="1"/> <line number="537" hits="1"/> <line number="538" hits="1"/> - <line number="539" hits="1"/> - <line number="540" hits="1"/> <line number="541" hits="1"/> + <line number="542" hits="1"/> + <line number="543" hits="1"/> <line number="544" hits="1"/> + <line number="545" hits="1"/> <line number="548" hits="1"/> - <line number="549" hits="1"/> - <line number="550" hits="1"/> - <line number="551" hits="1"/> + <line number="552" hits="1"/> + <line number="553" hits="1"/> <line number="554" hits="1"/> + <line number="555" hits="1"/> <line number="558" hits="1"/> - <line number="559" hits="1"/> - <line number="560" hits="1"/> + <line number="562" hits="1"/> <line number="563" hits="1"/> <line number="564" hits="1"/> - <line number="565" hits="1"/> - <line number="566" hits="1"/> <line number="567" hits="1"/> <line number="568" hits="1"/> <line number="569" hits="1"/> @@ -1375,19 +1387,19 @@ <line number="573" hits="1"/> <line number="574" hits="1"/> <line number="575" hits="1"/> + <line number="576" hits="1"/> + <line number="577" hits="1"/> <line number="578" hits="1"/> <line number="579" hits="1"/> - <line number="580" hits="1"/> - <line number="581" hits="1"/> <line number="582" hits="1"/> <line number="583" hits="1"/> <line number="584" hits="1"/> <line number="585" hits="1"/> <line number="586" hits="1"/> + <line number="587" hits="1"/> + <line number="588" hits="1"/> <line number="589" hits="1"/> <line number="590" hits="1"/> - <line number="591" hits="1"/> - <line number="592" hits="1"/> <line number="593" hits="1"/> <line number="594" hits="1"/> <line number="595" hits="1"/> @@ -1396,23 +1408,23 @@ <line number="598" hits="1"/> <line number="599" hits="1"/> <line number="600" hits="1"/> + <line number="601" hits="1"/> + <line number="602" hits="1"/> <line number="603" hits="1"/> <line number="604" hits="1"/> <line number="607" hits="1"/> <line number="608" hits="1"/> - <line number="609" hits="1"/> - <line number="610" hits="1"/> <line number="611" hits="1"/> + <line number="612" hits="1"/> + <line number="613" hits="1"/> <line number="614" hits="1"/> <line number="615" hits="1"/> - <line number="616" hits="1"/> - <line number="617" hits="1"/> + <line number="618" hits="1"/> + <line number="619" hits="1"/> <line number="620" hits="1"/> <line number="621" hits="1"/> <line number="624" hits="1"/> <line number="625" hits="1"/> - <line number="626" hits="1"/> - <line number="627" hits="1"/> <line number="628" hits="1"/> <line number="629" hits="1"/> <line number="630" hits="1"/> @@ -1432,12 +1444,12 @@ <line number="644" hits="1"/> <line number="645" hits="1"/> <line number="646" hits="1"/> + <line number="647" hits="1"/> + <line number="648" hits="1"/> <line number="649" hits="1"/> <line number="650" hits="1"/> <line number="653" hits="1"/> <line number="654" hits="1"/> - <line number="655" hits="1"/> - <line number="656" hits="1"/> <line number="657" hits="1"/> <line number="658" hits="1"/> <line number="659" hits="1"/> @@ -1461,17 +1473,17 @@ <line number="677" hits="1"/> <line number="678" hits="1"/> <line number="679" hits="1"/> + <line number="680" hits="1"/> + <line number="681" hits="1"/> <line number="682" hits="1"/> <line number="683" hits="1"/> - <line number="684" hits="1"/> - <line number="685" hits="1"/> <line number="686" hits="1"/> <line number="687" hits="1"/> <line number="688" hits="1"/> + <line number="689" hits="1"/> + <line number="690" hits="1"/> <line number="691" hits="1"/> <line number="692" hits="1"/> - <line number="693" hits="1"/> - <line number="694" hits="1"/> <line number="695" hits="1"/> <line number="696" hits="1"/> <line number="697" hits="1"/> @@ -1481,10 +1493,10 @@ <line number="701" hits="1"/> <line number="702" hits="1"/> <line number="703" hits="1"/> + <line number="704" hits="1"/> + <line number="705" hits="1"/> <line number="706" hits="1"/> <line number="707" hits="1"/> - <line number="708" hits="1"/> - <line number="709" hits="1"/> <line number="710" hits="1"/> <line number="711" hits="1"/> <line number="712" hits="1"/> @@ -1494,19 +1506,19 @@ <line number="716" hits="1"/> <line number="717" hits="1"/> <line number="718" hits="1"/> + <line number="719" hits="1"/> + <line number="720" hits="1"/> <line number="721" hits="1"/> <line number="722" hits="1"/> - <line number="723" hits="1"/> - <line number="724" hits="1"/> <line number="725" hits="1"/> + <line number="726" hits="1"/> + <line number="727" hits="1"/> <line number="728" hits="1"/> <line number="729" hits="1"/> - <line number="730" hits="1"/> - <line number="731" hits="1"/> + <line number="732" hits="1"/> + <line number="733" hits="1"/> <line number="734" hits="1"/> <line number="735" hits="1"/> - <line number="736" hits="1"/> - <line number="737" hits="1"/> <line number="738" hits="1"/> <line number="739" hits="1"/> <line number="740" hits="1"/> @@ -1514,68 +1526,73 @@ <line number="742" hits="1"/> <line number="743" hits="1"/> <line number="744" hits="1"/> + <line number="745" hits="1"/> + <line number="746" hits="1"/> <line number="747" hits="1"/> <line number="748" hits="1"/> - <line number="749" hits="1"/> - <line number="750" hits="1"/> <line number="751" hits="1"/> + <line number="752" hits="1"/> + <line number="753" hits="1"/> <line number="754" hits="1"/> <line number="755" hits="1"/> - <line number="756" hits="1"/> - <line number="757" hits="1"/> + <line number="758" hits="1"/> + <line number="759" hits="1"/> <line number="760" hits="1"/> <line number="761" hits="1"/> <line number="764" hits="1"/> <line number="765" hits="1"/> - <line number="766" hits="1"/> - <line number="767" hits="1"/> <line number="768" hits="1"/> <line number="769" hits="1"/> + <line number="770" hits="1"/> + <line number="771" hits="1"/> <line number="772" hits="1"/> <line number="773" hits="1"/> <line number="774" hits="1"/> - <line number="775" hits="1"/> + <line number="777" hits="1"/> <line number="778" hits="1"/> <line number="779" hits="1"/> - <line number="782" hits="1"/> + <line number="780" hits="1"/> <line number="783" hits="1"/> <line number="784" hits="1"/> <line number="785" hits="1"/> <line number="786" hits="1"/> + <line number="787" hits="1"/> + <line number="788" hits="1"/> <line number="789" hits="1"/> + <line number="792" hits="1"/> <line number="793" hits="1"/> <line number="794" hits="1"/> <line number="795" hits="1"/> - <line number="798" hits="1"/> - <line number="802" hits="1"/> + <line number="796" hits="1"/> + <line number="799" hits="1"/> <line number="803" hits="1"/> - <line number="806" hits="1"/> - <line number="807" hits="1"/> + <line number="804" hits="1"/> + <line number="805" hits="1"/> <line number="808" hits="1"/> - <line number="809" hits="1"/> - <line number="810" hits="1"/> + <line number="812" hits="1"/> <line number="813" hits="1"/> - <line number="814" hits="1"/> - <line number="815" hits="1"/> <line number="816" hits="1"/> <line number="817" hits="1"/> + <line number="818" hits="1"/> + <line number="819" hits="1"/> <line number="820" hits="1"/> - <line number="821" hits="1"/> - <line number="822" hits="1"/> + <line number="823" hits="1"/> + <line number="824" hits="1"/> <line number="825" hits="1"/> <line number="826" hits="1"/> <line number="827" hits="1"/> <line number="830" hits="1"/> <line number="831" hits="1"/> <line number="832" hits="1"/> - <line number="833" hits="1"/> - <line number="834" hits="1"/> + <line number="835" hits="1"/> + <line number="836" hits="1"/> <line number="837" hits="1"/> - <line number="838" hits="1"/> - <line number="839" hits="1"/> <line number="840" hits="1"/> <line number="841" hits="1"/> + <line number="842" hits="1"/> + <line number="843" hits="1"/> <line number="844" hits="1"/> + <line number="847" hits="1"/> <line number="848" hits="1"/> <line number="849" hits="1"/> <line number="850" hits="1"/> @@ -1583,17 +1600,12 @@ <line number="854" hits="1"/> <line number="858" hits="1"/> <line number="859" hits="1"/> - <line number="862" hits="1"/> - <line number="866" hits="1"/> - <line number="867" hits="1"/> + <line number="860" hits="1"/> + <line number="861" hits="1"/> + <line number="864" hits="1"/> <line number="868" hits="1"/> <line number="869" hits="1"/> - <line number="870" hits="1"/> - <line number="871" hits="1"/> <line number="872" hits="1"/> - <line number="873" hits="1"/> - <line number="874" hits="1"/> - <line number="875" hits="1"/> <line number="876" hits="1"/> <line number="877" hits="1"/> <line number="878" hits="1"/> @@ -1602,17 +1614,17 @@ <line number="881" hits="1"/> <line number="882" hits="1"/> <line number="883" hits="1"/> + <line number="884" hits="1"/> + <line number="885" hits="1"/> <line number="886" hits="1"/> + <line number="887" hits="1"/> + <line number="888" hits="1"/> + <line number="889" hits="1"/> <line number="890" hits="1"/> <line number="891" hits="1"/> <line number="892" hits="1"/> <line number="893" hits="1"/> - <line number="894" hits="1"/> - <line number="895" hits="1"/> <line number="896" hits="1"/> - <line number="897" hits="1"/> - <line number="898" hits="1"/> - <line number="899" hits="1"/> <line number="900" hits="1"/> <line number="901" hits="1"/> <line number="902" hits="1"/> @@ -1637,69 +1649,69 @@ <line number="921" hits="1"/> <line number="922" hits="1"/> <line number="923" hits="1"/> + <line number="924" hits="1"/> + <line number="925" hits="1"/> <line number="926" hits="1"/> + <line number="927" hits="1"/> + <line number="928" hits="1"/> + <line number="929" hits="1"/> <line number="930" hits="1"/> <line number="931" hits="1"/> <line number="932" hits="1"/> <line number="933" hits="1"/> - <line number="934" hits="1"/> - <line number="935" hits="1"/> - <line number="938" hits="1"/> + <line number="936" hits="1"/> + <line number="940" hits="1"/> + <line number="941" hits="1"/> <line number="942" hits="1"/> <line number="943" hits="1"/> + <line number="944" hits="1"/> <line number="945" hits="1"/> - <line number="946" hits="1"/> - <line number="949" hits="1"/> + <line number="948" hits="1"/> + <line number="952" hits="1"/> <line number="953" hits="1"/> - <line number="954" hits="1"/> + <line number="955" hits="1"/> <line number="956" hits="1"/> - <line number="957" hits="1"/> <line number="959" hits="1"/> - <line number="960" hits="1"/> - <line number="962" hits="1"/> <line number="963" hits="1"/> + <line number="964" hits="1"/> <line number="966" hits="1"/> + <line number="967" hits="1"/> + <line number="969" hits="1"/> <line number="970" hits="1"/> - <line number="971" hits="1"/> + <line number="972" hits="1"/> <line number="973" hits="1"/> - <line number="974" hits="1"/> - <line number="977" hits="1"/> - <line number="978" hits="1"/> - <line number="979" hits="1"/> + <line number="976" hits="1"/> <line number="980" hits="1"/> <line number="981" hits="1"/> - <line number="982" hits="1"/> <line number="983" hits="1"/> <line number="984" hits="1"/> - <line number="985" hits="1"/> - <line number="986" hits="1"/> <line number="987" hits="1"/> <line number="988" hits="1"/> <line number="989" hits="1"/> + <line number="990" hits="1"/> + <line number="991" hits="1"/> <line number="992" hits="1"/> <line number="993" hits="1"/> <line number="994" hits="1"/> <line number="995" hits="1"/> + <line number="996" hits="1"/> + <line number="997" hits="1"/> <line number="998" hits="1"/> <line number="999" hits="1"/> <line number="1002" hits="1"/> <line number="1003" hits="1"/> <line number="1004" hits="1"/> - <line number="1007" hits="1"/> + <line number="1005" hits="1"/> <line number="1008" hits="1"/> <line number="1009" hits="1"/> <line number="1012" hits="1"/> <line number="1013" hits="1"/> - <line number="1016" hits="1"/> + <line number="1014" hits="1"/> <line number="1017" hits="1"/> <line number="1018" hits="1"/> <line number="1019" hits="1"/> - <line number="1020" hits="1"/> - <line number="1021" hits="1"/> <line number="1022" hits="1"/> <line number="1023" hits="1"/> - <line number="1024" hits="1"/> - <line number="1025" hits="1"/> <line number="1026" hits="1"/> <line number="1027" hits="1"/> <line number="1028" hits="1"/> @@ -1707,6 +1719,8 @@ <line number="1030" hits="1"/> <line number="1031" hits="1"/> <line number="1032" hits="1"/> + <line number="1033" hits="1"/> + <line number="1034" hits="1"/> <line number="1035" hits="1"/> <line number="1036" hits="1"/> <line number="1037" hits="1"/> @@ -1715,8 +1729,6 @@ <line number="1040" hits="1"/> <line number="1041" hits="1"/> <line number="1042" hits="1"/> - <line number="1043" hits="1"/> - <line number="1044" hits="1"/> <line number="1045" hits="1"/> <line number="1046" hits="1"/> <line number="1047" hits="1"/> @@ -1734,6 +1746,8 @@ <line number="1059" hits="1"/> <line number="1060" hits="1"/> <line number="1061" hits="1"/> + <line number="1062" hits="1"/> + <line number="1063" hits="1"/> <line number="1064" hits="1"/> <line number="1065" hits="1"/> <line number="1066" hits="1"/> @@ -1742,8 +1756,6 @@ <line number="1069" hits="1"/> <line number="1070" hits="1"/> <line number="1071" hits="1"/> - <line number="1072" hits="1"/> - <line number="1073" hits="1"/> <line number="1074" hits="1"/> <line number="1075" hits="1"/> <line number="1076" hits="1"/> @@ -1751,6 +1763,8 @@ <line number="1078" hits="1"/> <line number="1079" hits="1"/> <line number="1080" hits="1"/> + <line number="1081" hits="1"/> + <line number="1082" hits="1"/> <line number="1083" hits="1"/> <line number="1084" hits="1"/> <line number="1085" hits="1"/> @@ -1761,8 +1775,6 @@ <line number="1090" hits="1"/> <line number="1091" hits="1"/> <line number="1092" hits="1"/> - <line number="1093" hits="1"/> - <line number="1094" hits="1"/> <line number="1095" hits="1"/> <line number="1096" hits="1"/> <line number="1097" hits="1"/> @@ -1771,6 +1783,8 @@ <line number="1100" hits="1"/> <line number="1101" hits="1"/> <line number="1102" hits="1"/> + <line number="1103" hits="1"/> + <line number="1104" hits="1"/> <line number="1105" hits="1"/> <line number="1106" hits="1"/> <line number="1107" hits="1"/> @@ -1781,7 +1795,7 @@ <line number="1112" hits="1"/> <line number="1113" hits="1"/> <line number="1114" hits="1"/> - <line number="1115" hits="1"/> + <line number="1117" hits="1"/> <line number="1118" hits="1"/> <line number="1119" hits="1"/> <line number="1120" hits="1"/> @@ -1792,34 +1806,36 @@ <line number="1125" hits="1"/> <line number="1126" hits="1"/> <line number="1127" hits="1"/> - <line number="1128" hits="1"/> - <line number="1129" hits="1"/> <line number="1130" hits="1"/> <line number="1131" hits="1"/> <line number="1132" hits="1"/> <line number="1133" hits="1"/> <line number="1134" hits="1"/> <line number="1135" hits="1"/> + <line number="1136" hits="1"/> + <line number="1137" hits="1"/> <line number="1138" hits="1"/> <line number="1139" hits="1"/> <line number="1140" hits="1"/> <line number="1141" hits="1"/> + <line number="1142" hits="1"/> + <line number="1143" hits="1"/> <line number="1144" hits="1"/> <line number="1145" hits="1"/> <line number="1146" hits="1"/> <line number="1147" hits="1"/> <line number="1148" hits="1"/> - <line number="1151" hits="1"/> + <line number="1149" hits="1"/> + <line number="1152" hits="1"/> + <line number="1153" hits="1"/> + <line number="1154" hits="1"/> <line number="1155" hits="1"/> - <line number="1156" hits="1"/> - <line number="1157" hits="1"/> <line number="1158" hits="1"/> <line number="1159" hits="1"/> + <line number="1160" hits="1"/> + <line number="1161" hits="1"/> <line number="1162" hits="1"/> - <line number="1163" hits="1"/> - <line number="1166" hits="1"/> - <line number="1167" hits="1"/> - <line number="1168" hits="1"/> + <line number="1165" hits="1"/> <line number="1169" hits="1"/> <line number="1170" hits="1"/> <line number="1171" hits="1"/> @@ -1827,10 +1843,10 @@ <line number="1173" hits="1"/> <line number="1176" hits="1"/> <line number="1177" hits="1"/> - <line number="1178" hits="1"/> - <line number="1179" hits="1"/> <line number="1180" hits="1"/> <line number="1181" hits="1"/> + <line number="1182" hits="1"/> + <line number="1183" hits="1"/> <line number="1184" hits="1"/> <line number="1185" hits="1"/> <line number="1186" hits="1"/> @@ -1840,6 +1856,16 @@ <line number="1192" hits="1"/> <line number="1193" hits="1"/> <line number="1194" hits="1"/> + <line number="1195" hits="1"/> + <line number="1198" hits="1"/> + <line number="1199" hits="1"/> + <line number="1200" hits="1"/> + <line number="1201" hits="1"/> + <line number="1204" hits="1"/> + <line number="1205" hits="1"/> + <line number="1206" hits="1"/> + <line number="1207" hits="1"/> + <line number="1208" hits="1"/> </lines> </class> <class name="exceptions.py" filename="dbrepo/api/exceptions.py" complexity="0" line-rate="1" branch-rate="0"> diff --git a/lib/python/dbrepo/RestClient.py b/lib/python/dbrepo/RestClient.py index 3459543d838cc76ee125f2ad84165caf9bced574..dbf1c7911f9b1e46b88125540c0cd716e00f643f 100644 --- a/lib/python/dbrepo/RestClient.py +++ b/lib/python/dbrepo/RestClient.py @@ -1915,11 +1915,42 @@ class RestClient: if response.status_code == 400: raise MalformedError(f'Failed to update column: {response.text}') if response.status_code == 403: - raise ForbiddenError(f'Failed to update colum: not allowed') + raise ForbiddenError(f'Failed to update column: not allowed') if response.status_code == 404: - raise NotExistsError(f'Failed to update colum: not found') + raise NotExistsError(f'Failed to update column: not found') if response.status_code == 502: - raise ServiceConnectionError(f'Failed to update colum: failed to establish connection to search service') + raise ServiceConnectionError(f'Failed to update column: failed to establish connection to search service') if response.status_code == 503: - raise ServiceError(f'Failed to update colum: failed to save in search service') - raise ResponseCodeError(f'Failed to update colum: response code: {response.status_code} is not 202 (ACCEPTED)') + raise ServiceError(f'Failed to update column: failed to save in search service') + raise ResponseCodeError(f'Failed to update column: response code: {response.status_code} is not 202 (ACCEPTED)') + + def update_database_dashboard(self, database_id: str, uid: str) -> None: + """ + Update semantic information of a table column by given database id and table id and column id. + + :param database_id: The database id. + :param uid: The database uid. + + :raises MalformedError: If the payload is rejected by the service. + :raises ForbiddenError: If something went wrong with the authorization. + :raises NotExistsError: If the accept header is neither application/json nor application/ld+json. + :raises ServiceConnectionError: If something went wrong with connection to the search service. + :raises ServiceError: If something went wrong with obtaining the information in the search service. + :raises ResponseCodeError: If something went wrong with the retrieval of the identifiers. + """ + url = f'/api/database/{database_id}/dashboard' + response = self._wrapper(method="put", url=url, force_auth=True, + payload=DatabaseModifyDashboard(uid=uid)) + if response.status_code == 202: + return + if response.status_code == 400: + raise MalformedError(f'Failed to update database dashboard: {response.text}') + if response.status_code == 404: + raise NotExistsError(f'Failed to update database dashboard: not found') + if response.status_code == 502: + raise ServiceConnectionError( + f'Failed to update database dashboard: failed to establish connection to search service') + if response.status_code == 503: + raise ServiceError(f'Failed to update database dashboard: failed to save in search service') + raise ResponseCodeError( + f'Failed to update database dashboard: response code: {response.status_code} is not 202 (ACCEPTED)') diff --git a/lib/python/dbrepo/api/dto.py b/lib/python/dbrepo/api/dto.py index 356f9b220095970886e524e8cccefdd49ea823c7..00376c3737afa0deeab6257a4c5b976fca3ae865 100644 --- a/lib/python/dbrepo/api/dto.py +++ b/lib/python/dbrepo/api/dto.py @@ -502,6 +502,10 @@ class UpdateColumn(BaseModel): unit_uri: Optional[str] = None +class DatabaseModifyDashboard(BaseModel): + uid: str + + class ModifyVisibility(BaseModel): is_public: bool is_schema_public: bool @@ -762,11 +766,12 @@ class KeyAnalysis(BaseModel): class ColumnStatistic(BaseModel): - val_min: float - val_max: float + name: str mean: float median: float std_dev: float + val_min: float + val_max: float class ApiError(BaseModel): @@ -776,6 +781,11 @@ class ApiError(BaseModel): class TableStatistics(BaseModel): + total_rows: Optional[int] = None + total_columns: int + data_length: Optional[int] = None + max_data_length: Optional[int] = None + avg_row_length: Optional[int] = None columns: dict[str, ColumnStatistic] @@ -1076,6 +1086,8 @@ class ViewColumn(BaseModel): median: Optional[float] = None concept: Optional[ConceptBrief] = None unit: Optional[UnitBrief] = None + enums: Optional[List[ColumnEnum]] = field(default_factory=list) + sets: Optional[List[ColumnSet]] = field(default_factory=list) index_length: Optional[int] = None length: Optional[int] = None @@ -1124,14 +1136,16 @@ class Database(BaseModel): internal_name: str is_public: bool is_schema_public: bool + is_dashboard_enabled: bool 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) accesses: Optional[List[DatabaseAccess]] = field(default_factory=list) + preview_image: Optional[str] = None + description: Optional[str] = None + dashboard_uid: Optional[str] = None exchange_name: Optional[str] = None diff --git a/dbrepo-search-service/init/omlib/exceptions/__init__.py b/lib/python/dbrepo/core/__init__.py similarity index 100% rename from dbrepo-search-service/init/omlib/exceptions/__init__.py rename to lib/python/dbrepo/core/__init__.py diff --git a/dbrepo-search-service/init/omlib/rdf/__init__.py b/lib/python/dbrepo/core/api/__init__.py similarity index 100% rename from dbrepo-search-service/init/omlib/rdf/__init__.py rename to lib/python/dbrepo/core/api/__init__.py diff --git a/dbrepo-dashboard-service/api/dto.py b/lib/python/dbrepo/core/api/dto.py similarity index 91% rename from dbrepo-dashboard-service/api/dto.py rename to lib/python/dbrepo/core/api/dto.py index e2dab237d52e9aa7a29b93081f20d76c97fabd19..73c50cfd91110191c74ec71207cb1403b1f34a4c 100644 --- a/dbrepo-dashboard-service/api/dto.py +++ b/lib/python/dbrepo/core/api/dto.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Optional +from typing import Optional, List from pydantic import BaseModel @@ -48,3 +48,9 @@ class CreateDatasourceRequest(BaseModel): database_internal_name: str readonly: bool type: str + + +class User(BaseModel): + id: str + username: str + roles: List[str] diff --git a/lib/python/dbrepo/core/api/exceptions.py b/lib/python/dbrepo/core/api/exceptions.py new file mode 100644 index 0000000000000000000000000000000000000000..fda8031e3f7e81bf0605d0edf6e30f0afbdad157 --- /dev/null +++ b/lib/python/dbrepo/core/api/exceptions.py @@ -0,0 +1,5 @@ +class DashboardNotFound(Exception): + """ + The dashboard could not be found. + """ + pass diff --git a/lib/python/dbrepo/core/client/__init__.py b/lib/python/dbrepo/core/client/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/lib/python/dbrepo/core/client/auth.py b/lib/python/dbrepo/core/client/auth.py new file mode 100644 index 0000000000000000000000000000000000000000..ec2bf4bf205be28291c0d6b380c6e4c5d28a5b46 --- /dev/null +++ b/lib/python/dbrepo/core/client/auth.py @@ -0,0 +1,75 @@ +import logging +from typing import List, Any + +import requests +from jwt import jwk_from_pem, JWT +from jwt.exceptions import JWTDecodeError + +from dbrepo.api.dto import ApiError +from dbrepo.core.api.dto import User + + +class AuthServiceClient: + + def __init__(self, endpoint: str, client_id: str, client_secret: str, jwt_public_key: str): + self.endpoint = endpoint + self.client_id = client_id + self.client_secret = client_secret + self.jwt_public_key = jwt_public_key + + def get_user_token(self, username: str, password: str) -> str: + response = requests.post(f"{self.endpoint}/realms/dbrepo/protocol/openid-connect/token", + data={ + "username": username, + "password": password, + "grant_type": "password", + "client_id": self.client_id, + "client_secret": self.client_secret + }) + body = response.json() + if "access_token" not in body: + raise AssertionError("Failed to obtain user token(s)") + return response.json()["access_token"] + + def get_user_id(self, auth_header: str | None) -> (str | None, ApiError, int): + if auth_header is None: + return None, None, None + try: + user = self.verify_jwt(auth_header.split(" ")[1]) + logging.debug(f'mapped JWT to user.id {user.id}') + return user.id, None, None + except JWTDecodeError as e: + logging.error(f'Failed to decode JWT: {e}') + if str(e) == 'JWT Expired': + return None, ApiError(status='UNAUTHORIZED', message=f'Token expired', + code='search.user.unauthorized').model_dump(), 401 + return None, ApiError(status='FORBIDDEN', message=str(e), code='search.user.forbidden').model_dump(), 403 + + def verify_jwt(self, access_token: str) -> User: + public_key = jwk_from_pem(self.jwt_public_key.encode('utf-8')) + payload = JWT().decode(message=access_token, key=public_key, do_time_check=True) + return User(id=payload.get('uid'), username=payload.get('preferred_username'), + roles=payload.get('realm_access')["roles"]) + + def is_valid_token(self, token: str) -> bool | User: + if token is None or token == "": + return False + try: + return self.verify_jwt(access_token=token) + except JWTDecodeError: + return False + + def is_valid_password(self, username: str, password: str) -> Any: + if username is None or username == "" or password is None or password == "": + return False + try: + return self.verify_jwt(access_token=self.get_user_token(username=username, password=password)) + except AssertionError as error: + logging.error(error) + return False + except requests.exceptions.ConnectionError as error: + logging.error(f"Failed to connect to Authentication Service {error}") + return False + + def get_user_roles(self, user: User) -> List[str]: + return user.roles diff --git a/lib/python/dbrepo/core/client/dashboard.py b/lib/python/dbrepo/core/client/dashboard.py new file mode 100644 index 0000000000000000000000000000000000000000..0797c0a76f00cecf4da7bb7eab90fe609cfdc9e1 --- /dev/null +++ b/lib/python/dbrepo/core/client/dashboard.py @@ -0,0 +1,451 @@ +import logging + +import requests +from grafana_client import GrafanaApi +from grafana_client.client import GrafanaClientError, GrafanaException +from requests import Response + +from dbrepo.api.dto import Database, ColumnType, ViewColumn, View +from dbrepo.core.api.dto import Permission +from dbrepo.core.api.exceptions import DashboardNotFound + +statistics_row_title = 'Generated Statistics' + +disclaimer = 'Generic auto-generated chart' + +number_types = [ColumnType.SERIAL, ColumnType.BIT, ColumnType.SMALLINT, ColumnType.MEDIUMINT, ColumnType.INT, + ColumnType.BIGINT, ColumnType.FLOAT, ColumnType.DOUBLE, ColumnType.DECIMAL] + +time_types = [ColumnType.DATE, ColumnType.TIME, ColumnType.TIMESTAMP, ColumnType.YEAR] + +bool_types = [ColumnType.TINYINT, ColumnType.BOOL] + +section_height = 3 * 8 + + +def map_link(title: str, url: str, icon: str = 'info', open_new_window: bool = True) -> dict: + return dict(targetBlank=open_new_window, + asDropdown=False, + includeVars=False, + keepTime=False, + tags=[], + type='link', + icon=icon, + title=title, + url=url) + + +def _get_start_index(dashboard: dict) -> int | None: + return [panel['title'] for panel in dashboard['panels']].index(statistics_row_title) + + +def map_column_conversion(column: ViewColumn) -> dict: + destinationType = 'string' + dateFormat = None + if column.type in number_types: + destinationType = 'number' + elif column.type in time_types: + destinationType = 'time' + if column.type == ColumnType.YEAR: + dateFormat = 'YYYY' + elif column.type == ColumnType.TIME: + dateFormat = 'HH:mm:ss' + else: + dateFormat = 'YYYY-MM-dd' + elif column.type in bool_types: + destinationType = 'boolean' + return dict(targetField=column.internal_name, + destinationType=destinationType, + dateFormat=dateFormat) + + +def map_row(title: str, x: int = 0, y: int = 0) -> dict: + return dict(collapsed=False, + title=title, + type='row', + panels=[], + targets=[], + parser='backend', + gridPos=dict(h=1, + w=24, + x=x, + y=y)) + + +class DashboardServiceClient: + + def __init__(self, endpoint: str, username: str, password: str, base_url: str = 'http://localhost', + datasource_uid: str = 'dbrepojson0'): + self.client: GrafanaApi = GrafanaApi.from_url(url=f'{endpoint}', credential=(username, password)) + self.endpoint = endpoint + self.username = username + self.password = password + self.base_url = base_url + self.datasource_uid = datasource_uid + + def get_client(self): + return self.client + + def generic_get(self, api_url: str) -> Response: + request_url = self.endpoint + api_url + logging.debug(f'generic get url={request_url}, auth=({self.username}, <reacted>)') + return requests.get(request_url, auth=(self.username, self.password)) + + def generic_post(self, api_url: str, payload: dict) -> Response: + request_url = self.endpoint + api_url + logging.debug(f'generic post url={request_url}, payload={payload}, auth=({self.username}, <reacted>)') + return requests.post(request_url, json=payload, auth=(self.username, self.password)) + + def find(self, uid: str): + """ + Finds a dashboard with the given uid. + + @return The dashboard, if successful. Otherwise, `None`. + """ + if uid is None: + return None + try: + return self.client.dashboard.get_dashboard(uid) + except GrafanaClientError: + logging.warning(f"Failed to find dashboard with uid: {uid}") + return None + + def create(self, database_name: str, uid: str = '') -> dict: + dashboard = dict(uid=uid, + title=f'{database_name} Overview', + tags=['managed'], + timezone='browser', + refresh='30m', + preload=False, + panels=[]) + dashboard['panels'] = [] + payload = dict(folderUid='', + overwrite=False, + dashboard=dashboard) + dashboard = self.client.dashboard.update_dashboard(payload) + logging.info(f"Created dashboard with uid: {dashboard['uid']}") + return dashboard + + def delete(self, uid: str) -> None: + self.client.dashboard.delete_dashboard(uid) + + def update(self, database: Database) -> None: + dashboard = self.find(database.dashboard_uid) + if dashboard is None: + raise DashboardNotFound(f'Dashboard {database.dashboard_uid} not found') + dashboard = dashboard['dashboard'] + # update metadata + if not database.is_dashboard_enabled and 'managed' in dashboard['tags']: + dashboard['tags'].remove('managed') + if len(database.identifiers) > 0 and len(database.identifiers[0].titles) > 0: + dashboard['title'] = database.identifiers[0].titles[0].title + if len(database.identifiers) > 0 and len(database.identifiers[0].descriptions) > 0: + dashboard['description'] = database.identifiers[0].descriptions[0].description + dashboard['links'] = self.map_links(database) + # update panels + dashboard['panels'] = self.get_panels(dashboard, database) + payload = dict(folderUid='', + overwrite=True, + dashboard=dashboard) + response = self.client.dashboard.update_dashboard(payload) + logging.info(f"Updated dashboard with uid: {response['uid']}") + + def map_links(self, database: Database) -> [dict]: + links = [] + if len(database.identifiers) > 0: + links.append(map_link('Database', f"{self.base_url}/pid/{database.identifiers[0].id}")) + else: + links.append(map_link('Database', f"{self.base_url}/database/{database.id}")) + return links + + def update_anonymous_read_access(self, uid: str, is_public: bool, is_schema_public: bool) -> None: + permissions = self.client.dashboard.get_permissions_by_uid(uid) + viewer_role = [permission for permission in permissions if + 'permissionName' in permission and permission['permissionName'] != 'View'] + permission = '' + if is_public or is_schema_public: + permission = 'View' + if len(viewer_role) == 0: + logging.warning(f'Failed to find permissionName=View') + return None + try: + response = self.generic_post(f'/api/access-control/dashboards/{uid}/builtInRoles/Viewer', + Permission(permission=permission).model_dump()) + if response.status_code != 200: + raise OSError(f'Failed to update anonymous read access: {response.content}') + except GrafanaException as e: + raise OSError(f'Failed to update anonymous read access: {e.message}') + logging.info(f"Updated anonymous read access for dashboard with uid: {uid}") + + def _map_timeseries_panel(self, database_id: str, view: View, panel_type: str, h: int = 8, w: int = 12, x: int = 12, + y: int = 8) -> dict: + datasource = dict(uid=self.datasource_uid, + type='yesoreyeram-infinity-datasource') + fillOpacity = 0 + if panel_type == 'histogram': + fillOpacity = 60 + return dict(title=panel_type.capitalize(), + description=disclaimer, + type=panel_type, + datasource=datasource, + targets=[dict(datasource=datasource, + format='table', + global_query_id='', + hide=False, + refId='A', + root_selector='', + source='url', + type='json', + url=f'/api/database/{database_id}/view/{view.id}/data', + parser='backend', + url_options=dict(data='', + method='GET'))], + gridPos=dict(h=h, + w=w, + x=x, + y=y), + options=dict(legend=dict(displayMode='list', + placement='bottom', + showLegend=True), + tooltip=dict(mode='single', + sort='none')), + fieldConfig=dict( + defaults=dict(color=dict(mode='palette-classic'), + custom=dict( + axisBorderShow=False, + axisCenteredZero=False, + axisColorMode='text', + axisLabel='', + axisPlacement='auto', + barAlignment=0, + drawStyle='line', + fillOpacity=fillOpacity, + gradientMode='none', + hideFrom=dict(legend=False, + tooltip=False, + viz=False), + insertNulls=False, + lineInterpolation='linear', + lineWidth=1, + pointSize=5, + scaleDistribution=dict(type='linear'), + showPoints='auto', + spanNulls=False, + stacking=dict(group='A', + mode='none'), + thresholdsStyle=dict(mode='absolute')))), + transformations=[dict(id='convertFieldType', + options=dict(fields=dict(), + conversions=[map_column_conversion(column) for column in + view.columns]))]) + + def _map_number_panel(self, database_id: str, view_id: str, title: str, field: str, x: int = 18, + y: int = 0) -> dict: + datasource = dict(uid=self.datasource_uid, + type='yesoreyeram-infinity-datasource') + return dict(title=title, + type='stat', + datasource=datasource, + targets=[dict(datasource=datasource, + columns=[], + filters=[], + format='table', + global_query_id='', + hide=False, + refId='A', + root_selector='', + source='url', + type='json', + url=f'/api/database/{database_id}/view/{view_id}/statistic', + parser='backend', + url_options=dict(data='', + method='GET'))], + fieldConfig=dict(defaults=dict(mappings=[], + thresholds=dict(mode='absolute', + steps=[dict(color='blue', + value=None)]), + unit=''), + overrides=[]), + transformations=[dict(id='extractFields', + options=dict(delimiter=',', + source=field, + format='auto', + replace=False, + keepTime=False)), + dict(id='filterFieldsByName', + options=dict(include=dict(names=[field])))], + gridPos=dict(h=4, + w=6, + x=x, + y=y), + options=dict(colorMode='background', + graphMode='area', + justifyMode='auto', + orientation='auto', + reduceOptions=dict(calcs=[], + fields='/.*/', + values=True), + showPercentChange=False, + textMode='auto', + wideLayout=True)) + + def map_overview_panel(self, database_id: str, view_id: str, x: int = 0, y: int = 4) -> dict: + datasource = dict(uid=self.datasource_uid, + type='yesoreyeram-infinity-datasource') + return dict(title='Datasource Preview', + type='table', + gridPos=dict(h=8, + w=18, + x=x, + y=y), + fieldConfig=dict( + defaults=dict( + color=dict(mode='palette-classic'), + custom=dict(axisBorderShow=False, + axisCenteredZero=False, + axisColorMode='text', + axisLabel='', + axisPlacement='auto', + barAlignment=0, + drawStyle='line', + fillOpacity=0, + gradientMode='none', + hideFrom=dict( + legend=False, + tooltip=False, + viz=False), + insertNulls=False, + lineInterpolation='linear', + lineWidth=1, + pointSize=5, + scaleDistribution=dict( + type='linear'), + showPoints='auto', + spanNulls=False, + stacking=dict(group='A', + mode='none'), + thresholdsStyle=dict( + mode='off'))), + overrides=[]), + options=dict(legend=dict(displayMode='list', + placement='bottom', + showLegend=True, + calcs=[]), + tooltip=dict(mode='single', + sort='none')), + targets=[dict(format='json', + columns=[], + datasource=datasource, + filters=[], + global_query_id='', + refId='A', + root_selector='', + source='url', + type='json', + url=f'/api/database/{database_id}/view/{view_id}/data', + parser='backend', + url_options=dict(data='', + method='GET'))], + links=[dict(title='Cite', + url=f'{self.base_url}/database/{database_id}/view/{view_id}/data', + targetBlank=True)], + datasource=datasource) + + def map_statistics_panel(self, database_id: str, view_id: str, w: int = 12, h: int = 8, x: int = 0, + y: int = 8) -> dict: + datasource = dict(uid=self.datasource_uid, + type='yesoreyeram-infinity-datasource') + return dict(title='Statistics', + type='table', + gridPos=dict(h=h, + w=w, + x=x, + y=y), + datasource=datasource, + targets=[dict(datasource=datasource, + columns=[], + filters=[], + format='table', + global_query_id='', + hide=False, + refId='A', + root_selector='columns', + source='url', + type='json', + url=f'/api/database/{database_id}/view/{view_id}/statistic', + parser='backend', + url_options=dict(data='', + method='GET'))], + options=dict(cellHeight="sm", + showHeader=True, + footer=dict(countRows=False, + fields="", + reducer=["sum"], + show=False)), + transformations=[dict(id="organize", + options=dict(excludeByName=dict(), + includeByName=dict(), + indexByName=dict(name=0, + val_min=1, + val_max=2, + mean=3, + median=4, + std_dev=5), + renameByName=dict(name="Name", + mean="Mean", + median="Median", + std_dev="std.dev", + val_min="Minimum", + val_max="Maximum")))], + fieldConfig=dict(defaults=dict(custom=dict(align="auto", + filterable="true", + cellOptions=dict(type="auto"), + inspect=False), + mappings=[], + thresholds=dict(mode="absolute", + steps=[dict(color="green", + value=None), + dict(color="red", + value=80) + ])), + overrides=[])) + + def map_timeseries_panel(self, database_id: str, view: View, h: int = 8, w: int = 12, x: int = 12, + y: int = 8) -> dict: + return self._map_timeseries_panel(database_id, view, 'timeseries', h, w, x, y) + + def map_pie_panel(self, database_id: str, view: View, h: int = 8, w: int = 12, x: int = 12, y: int = 8) -> dict: + return self._map_timeseries_panel(database_id, view, 'piechart', h, w, x, y) + + def map_histogram_panel(self, database_id: str, view: View, h: int = 8, w: int = 12, x: int = 12, + y: int = 8) -> dict: + return self._map_timeseries_panel(database_id, view, 'histogram', h, w, x, y) + + def map_rows_panel(self, database_id: str, view_id: str, x: int = 18, y: int = 0) -> dict: + return self._map_number_panel(database_id, view_id, 'Rows', 'total_rows', x, y) + + def map_columns_panel(self, database_id: str, view_id: str, x: int = 18, y: int = 0) -> dict: + return self._map_number_panel(database_id, view_id, 'Variables', 'total_columns', x, y) + + def get_panels(self, dashboard: dict, database: Database) -> [dict]: + panels = dashboard['panels'] + try: + end_index = _get_start_index(dashboard) + logging.debug(f'splicing managed panels after index: {end_index}') + panels = panels[:end_index] + except ValueError: + logging.warning(f'No managed panels found') + original_panels_size = len(panels) + panels.append(map_row(statistics_row_title, 0, 0)) # statistics row + for i, view in enumerate(database.views): + # section + panels.append(map_row(view.name, 0, i * section_height + 0)) + panels.append(self.map_overview_panel(database.id, view.id, 0, i * section_height + 4)) + panels.append(self.map_rows_panel(database.id, view.id, 18, i * section_height + 0)) + panels.append(self.map_columns_panel(database.id, view.id, 18, i * section_height + 4)) + panels.append(self.map_statistics_panel(database.id, view.id, h=8, w=12, x=0, y=i * section_height + 8)) + panels.append(self.map_histogram_panel(database.id, view, h=8, w=12, x=12, y=i * section_height + 8)) + panels.append(self.map_timeseries_panel(database.id, view, h=8, w=8, x=0, y=i * section_height + 16)) + panels.append(self.map_pie_panel(database.id, view, h=8, w=8, x=8, y=i * section_height + 16)) + logging.info(f'Added {len(panels) - original_panels_size} managed panel(s)') + return panels diff --git a/dbrepo-search-service/init/clients/opensearch_client.py b/lib/python/dbrepo/core/client/search.py similarity index 88% rename from dbrepo-search-service/init/clients/opensearch_client.py rename to lib/python/dbrepo/core/client/search.py index deca261ce273563bb84aa19e7525440f4d64bdeb..e4836dd0211fecb0fc3b4d49dd1c86145197aa04 100644 --- a/dbrepo-search-service/init/clients/opensearch_client.py +++ b/lib/python/dbrepo/core/client/search.py @@ -6,38 +6,33 @@ import os from collections.abc import MutableMapping from json import dumps, load -from dbrepo.api.dto import Database -from dbrepo.api.exceptions import ForbiddenError, NotExistsError from opensearchpy import OpenSearch, NotFoundError from requests import head -from omlib.constants import OM_IDS -from omlib.measure import om -from omlib.omconstants import OM -from omlib.unit import Unit +from dbrepo.api.dto import Database +from dbrepo.api.exceptions import ForbiddenError, NotExistsError +from dbrepo.core.omlib.constants import OM_IDS +from dbrepo.core.omlib.measure import om +from dbrepo.core.omlib.omconstants import OM +from dbrepo.core.omlib.unit import Unit -class OpenSearchClient: +class SearchServiceClient: """ The client to communicate with the OpenSearch database. """ - host: str = None instance: OpenSearch = None - metadata_endpoint: str = None - password: str = None - port: int = None - system_username: str = None - system_password: str = None - username: str = None - - def __init__(self, host: str = None, port: int = None, username: str = None, password: str = None): + + def __init__(self, host: str = None, port: int = 9000, username: str = None, password: str = None): + if host is None: + host = 'search-db' self.host = os.getenv('OPENSEARCH_HOST', host) self.metadata_endpoint = os.getenv('METADATA_SERVICE_ENDPOINT', 'http://metadata-service:8080') + self.username = os.getenv('OPENSEARCH_USERNAME', username) self.password = os.getenv('OPENSEARCH_PASSWORD', password) self.port = int(os.getenv('OPENSEARCH_PORT', port)) self.system_username = os.getenv('SYSTEM_USERNAME', 'admin') self.system_password = os.getenv('SYSTEM_PASSWORD', 'admin') - self.username = os.getenv('OPENSEARCH_USERNAME', username) def _instance(self) -> OpenSearch: """ @@ -51,19 +46,40 @@ class OpenSearchClient: http_auth=(self.username, self.password)) return self.instance - def update_database(self, database_id: str, data: Database) -> Database: + def database_exists(self, database_id: str): + try: + SearchServiceClient()._instance().get(index="database", id=database_id) + return True + except NotFoundError: + return False + + def index_update(self, mapping: dict) -> None: + if SearchServiceClient()._instance().indices.exists(index="database"): + logging.debug(f"index 'database' exists, removing...") + SearchServiceClient()._instance().indices.delete(index="database") + SearchServiceClient()._instance().indices.create(index="database", body=mapping) + logging.info(f"Created index 'database'") + + def save_database(self, database_id: str, data: Database, fetch: bool = False) -> Database | None: """ - Updates the database data with given id. + Creates the database data with given id. If a document with the id already exists, the document is updated. @param database_id: The database id. @param data: The database data. + @param fetch: When enabled, fetches the saved database data. Default: `False`. + + :return The saved database data. @returns: The updated database, if successful. - @throws: opensearchpy.exceptions.NotFoundError If the database was not found in the Search Database. + @throws: opensearchpy.exceptions.NotFoundError If the database was not found in the Search Database. Ignored when `force` is `True`. """ - logging.debug(f"updating database with id: {database_id} in search database") - self._instance().index(index="database", id=database_id, body=dumps(data.model_dump())) - response: dict = self._instance().get(index="database", id=database_id) + self._instance().update(index="database", id=database_id, + body={'doc': data.model_dump(), 'doc_as_upsert': True}) + logging.info(f'Updated database with id: {database_id}') + if fetch is False: + return None + response = self._instance().get(index="database", id=database_id) + logging.debug(f'fetched database for return value with id: {database_id}') return Database.model_validate(response["_source"]) def delete_database(self, database_id: str) -> None: @@ -215,7 +231,6 @@ class OpenSearchClient: "query": {"bool": {"must": musts}} } logging.debug(f'search in index database for type: {field_type}') - logging.debug(f'search body: {dumps(body)}') response = self._instance().search( index="database", body=dumps(body) diff --git a/dbrepo-analyse-service/clients/s3_client.py b/lib/python/dbrepo/core/client/storage.py similarity index 86% rename from dbrepo-analyse-service/clients/s3_client.py rename to lib/python/dbrepo/core/client/storage.py index 18cdba1ec35acbcfbd029b43076de22ee1f97069..8455cba8a5f9de72a7b2041a1c9e8c8d1de6b76c 100644 --- a/dbrepo-analyse-service/clients/s3_client.py +++ b/lib/python/dbrepo/core/client/storage.py @@ -7,14 +7,16 @@ from boto3.exceptions import S3UploadFailedError from botocore.exceptions import ClientError -class S3Client: +class StorageServiceClient: - def __init__(self): - endpoint_url = current_app.config['S3_ENDPOINT'] - aws_access_key_id = current_app.config['S3_ACCESS_KEY_ID'] - aws_secret_access_key = current_app.config['S3_SECRET_ACCESS_KEY'] - logging.info(f"retrieve file from S3, endpoint_url={current_app.config['S3_PROTO']}://{endpoint_url}, aws_access_key_id={aws_access_key_id}, aws_secret_access_key=(hidden)") - self.client = boto3.client(service_name='s3', endpoint_url=f"{current_app.config['S3_PROTO']}://{endpoint_url}", aws_access_key_id=aws_access_key_id, + def __init__(self, endpoint: str, access_key_id: str, secret_access_key: str): + endpoint = endpoint + aws_access_key_id = access_key_id + aws_secret_access_key = secret_access_key + logging.info( + f"retrieve file from S3, endpoint={current_app.config['S3_PROTO']}://{endpoint}, aws_access_key_id={aws_access_key_id}, aws_secret_access_key=(hidden)") + self.client = boto3.client(service_name='s3', endpoint_url=f"{current_app.config['S3_PROTO']}://{endpoint}", + aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key) self.bucket_exists_or_exit(current_app.config['S3_BUCKET']) diff --git a/lib/python/dbrepo/core/omlib/__init__.py b/lib/python/dbrepo/core/omlib/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/dbrepo-search-service/init/omlib/constants.py b/lib/python/dbrepo/core/omlib/constants.py similarity index 96% rename from dbrepo-search-service/init/omlib/constants.py rename to lib/python/dbrepo/core/omlib/constants.py index 34dad53e340bef61c37a2fb342ef98403559b7ba..8460043979f7449ad005562de92c6ba6ba57a590 100644 --- a/dbrepo-search-service/init/omlib/constants.py +++ b/lib/python/dbrepo/core/omlib/constants.py @@ -1,9 +1,9 @@ import rdflib from rdflib import URIRef -from omlib.dimension import Dimension -from omlib.scale import Scale -from omlib.unit import Prefix, Unit +from dbrepo.core.omlib.dimension import Dimension +from dbrepo.core.omlib.scale import Scale +from dbrepo.core.omlib.unit import Prefix, Unit class OM_IDS: diff --git a/dbrepo-search-service/init/omlib/dimension.py b/lib/python/dbrepo/core/omlib/dimension.py similarity index 96% rename from dbrepo-search-service/init/omlib/dimension.py rename to lib/python/dbrepo/core/omlib/dimension.py index bc05571bcf1f7450bb362dbb69a4e9d8fac162d4..8a6e94306d4064d65fc7489657459a2addd23ce3 100644 --- a/dbrepo-search-service/init/omlib/dimension.py +++ b/lib/python/dbrepo/core/omlib/dimension.py @@ -1,4 +1,4 @@ -from omlib.exceptions.dimensionexception import DimensionalException +from dbrepo.core.omlib.exceptions.dimensionexception import DimensionalException class Dimension: diff --git a/lib/python/dbrepo/core/omlib/exceptions/__init__.py b/lib/python/dbrepo/core/omlib/exceptions/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/dbrepo-search-service/init/omlib/exceptions/dimensionexception.py b/lib/python/dbrepo/core/omlib/exceptions/dimensionexception.py similarity index 100% rename from dbrepo-search-service/init/omlib/exceptions/dimensionexception.py rename to lib/python/dbrepo/core/omlib/exceptions/dimensionexception.py diff --git a/dbrepo-search-service/init/omlib/exceptions/unitconversionexception.py b/lib/python/dbrepo/core/omlib/exceptions/unitconversionexception.py similarity index 100% rename from dbrepo-search-service/init/omlib/exceptions/unitconversionexception.py rename to lib/python/dbrepo/core/omlib/exceptions/unitconversionexception.py diff --git a/dbrepo-search-service/init/omlib/exceptions/unitidentityexception.py b/lib/python/dbrepo/core/omlib/exceptions/unitidentityexception.py similarity index 100% rename from dbrepo-search-service/init/omlib/exceptions/unitidentityexception.py rename to lib/python/dbrepo/core/omlib/exceptions/unitidentityexception.py diff --git a/dbrepo-search-service/init/omlib/measure.py b/lib/python/dbrepo/core/omlib/measure.py similarity index 98% rename from dbrepo-search-service/init/omlib/measure.py rename to lib/python/dbrepo/core/omlib/measure.py index eb19729b5df05a5167cd4be3c125ac992ae4a289..f8b2d7fdc31135e3e38cd618b8da3fd823bdb9f2 100644 --- a/dbrepo-search-service/init/omlib/measure.py +++ b/lib/python/dbrepo/core/omlib/measure.py @@ -1,10 +1,10 @@ import math -from omlib.constants import SI -from omlib.exceptions.dimensionexception import DimensionalException -from omlib.scale import Scale -from omlib.thing import Thing -from omlib.unit import Unit, PrefixedUnit, SingularUnit +from dbrepo.core.omlib.constants import SI +from dbrepo.core.omlib.exceptions.dimensionexception import DimensionalException +from dbrepo.core.omlib.scale import Scale +from dbrepo.core.omlib.thing import Thing +from dbrepo.core.omlib.unit import Unit, PrefixedUnit, SingularUnit def om(numerical_value, unit_or_scale, identifier=None): diff --git a/dbrepo-search-service/init/omlib/omconstants.py b/lib/python/dbrepo/core/omlib/omconstants.py similarity index 99% rename from dbrepo-search-service/init/omlib/omconstants.py rename to lib/python/dbrepo/core/omlib/omconstants.py index 8afb3f896a5fc30f7fde4636d0006c8cd0dd0f01..0163fa69ede34f91fc5cd54ec539b6eca480e397 100644 --- a/dbrepo-search-service/init/omlib/omconstants.py +++ b/lib/python/dbrepo/core/omlib/omconstants.py @@ -2,9 +2,9 @@ import rdflib from rdflib import URIRef, Literal -from omlib.dimension import Dimension -from omlib.scale import Scale -from omlib.unit import Prefix, Unit +from dbrepo.core.omlib.dimension import Dimension +from dbrepo.core.omlib.scale import Scale +from dbrepo.core.omlib.unit import Prefix, Unit class OM: diff --git a/lib/python/dbrepo/core/omlib/rdf/__init__.py b/lib/python/dbrepo/core/omlib/rdf/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/dbrepo-search-service/init/omlib/rdf/om-2.0.rdf b/lib/python/dbrepo/core/omlib/rdf/om-2.0.rdf similarity index 100% rename from dbrepo-search-service/init/omlib/rdf/om-2.0.rdf rename to lib/python/dbrepo/core/omlib/rdf/om-2.0.rdf diff --git a/dbrepo-search-service/init/omlib/scale.py b/lib/python/dbrepo/core/omlib/scale.py similarity index 95% rename from dbrepo-search-service/init/omlib/scale.py rename to lib/python/dbrepo/core/omlib/scale.py index b0fedec5c052f02f41b1df536b6595d8b620dcde..44c5783dbe48a087f1d7273e521a424d062e0f97 100644 --- a/dbrepo-search-service/init/omlib/scale.py +++ b/lib/python/dbrepo/core/omlib/scale.py @@ -1,11 +1,11 @@ from rdflib import URIRef -from omlib.dimension import Dimension -from omlib.exceptions.dimensionexception import DimensionalException -from omlib.exceptions.unitconversionexception import ScaleConversionException -from omlib.exceptions.unitidentityexception import ScaleIdentityException -from omlib.thing import Thing -from omlib.unit import Unit +from dbrepo.core.omlib.dimension import Dimension +from dbrepo.core.omlib.exceptions.dimensionexception import DimensionalException +from dbrepo.core.omlib.exceptions.unitconversionexception import ScaleConversionException +from dbrepo.core.omlib.exceptions.unitidentityexception import ScaleIdentityException +from dbrepo.core.omlib.thing import Thing +from dbrepo.core.omlib.unit import Unit class Scale(Thing): diff --git a/dbrepo-search-service/init/omlib/thing.py b/lib/python/dbrepo/core/omlib/thing.py similarity index 100% rename from dbrepo-search-service/init/omlib/thing.py rename to lib/python/dbrepo/core/omlib/thing.py diff --git a/dbrepo-search-service/init/omlib/unit.py b/lib/python/dbrepo/core/omlib/unit.py similarity index 99% rename from dbrepo-search-service/init/omlib/unit.py rename to lib/python/dbrepo/core/omlib/unit.py index c05fef1e9d97149ab4ab46dc93209c53d9a7dd58..c9c63afe028aa1b4990e8ad90d3854e70cae8c40 100644 --- a/dbrepo-search-service/init/omlib/unit.py +++ b/lib/python/dbrepo/core/omlib/unit.py @@ -2,11 +2,11 @@ import math from rdflib import URIRef -from omlib.exceptions.dimensionexception import DimensionalException -from omlib.exceptions.unitconversionexception import UnitConversionException -from omlib.exceptions.unitidentityexception import UnitIdentityException -from omlib.dimension import Dimension -from omlib.thing import SymbolThing +from dbrepo.core.omlib.exceptions.dimensionexception import DimensionalException +from dbrepo.core.omlib.exceptions.unitconversionexception import UnitConversionException +from dbrepo.core.omlib.exceptions.unitidentityexception import UnitIdentityException +from dbrepo.core.omlib.dimension import Dimension +from dbrepo.core.omlib.thing import SymbolThing class Unit(SymbolThing): diff --git a/lib/python/docs/index.rst b/lib/python/docs/index.rst index 80d1d6806badcfa31f8f533eb3885949a14e35be..b7b6bf88e0d7401360df5b7c8b15409e8c3c1fb1 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.7.3, earlier versions may be supported but are not tested for compatibility. + The SDK has been implemented and documented for DBRepo version 1.8.0, earlier versions may be supported but are not tested for compatibility. Quickstart ---------- diff --git a/lib/python/package.sh b/lib/python/package.sh deleted file mode 100755 index 2ad8d301e8d4ed3b0bac1433505bcd4bfedabdfa..0000000000000000000000000000000000000000 --- a/lib/python/package.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -python -m build --sdist ./lib/python -python -m build --wheel ./lib/python diff --git a/lib/python/pyproject.toml b/lib/python/pyproject.toml index 0a34c76816eefe3459b5dec8a4ddbed779021a59..4ca8d9dfa9085fbb02505970892941682b91eadc 100644 --- a/lib/python/pyproject.toml +++ b/lib/python/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "dbrepo" -version = "1.7.3" +version = "1.8.0" description = "DBRepo Python Library" keywords = [ "DBRepo", @@ -10,13 +10,13 @@ authors = [ { name = "Martin Weise, TU Wien", email = "martin.weise@tuwien.ac.at" } ] readme = "README.md" -license = { file = "LICENSE" } +license = "Apache-2.0" +license-files = ["LICENSE"] classifiers = [ "Development Status :: 4 - Beta", "Topic :: Software Development :: Libraries", "Programming Language :: Python :: 3.11", "Operating System :: OS Independent", - "License :: OSI Approved :: Apache Software License", ] requires-python = ">=3.11" dependencies = [ @@ -34,7 +34,7 @@ requires = [ build-backend = "setuptools.build_meta" [project.urls] -Homepage = "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.7/" +Homepage = "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.8/" Documentation = "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.6/python/" Issues = "https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues" Source = "https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/" \ No newline at end of file diff --git a/lib/python/release.sh b/lib/python/release.sh deleted file mode 100755 index 9c5e62d2d0893d1810fbfd1cd772a1abdfbba2f8..0000000000000000000000000000000000000000 --- a/lib/python/release.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -echo "${CI_PIPYRC}" | base64 -d > .pypirc -python -m twine upload --config-file .pypirc --verbose --repository pypi ./lib/python/dist/dbrepo-* diff --git a/lib/python/setup.py b/lib/python/setup.py index 635365883ee441508cf13b645ccfd022a7cbf8f0..5180231936caab75c18ac532e70f75557875d272 100644 --- a/lib/python/setup.py +++ b/lib/python/setup.py @@ -2,13 +2,19 @@ from distutils.core import setup setup(name="dbrepo", - version="1.7.3", + version="1.8.0", description="A library for communicating with DBRepo", - url="https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.7/", + url="https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.8/", author="Martin Weise", license="Apache-2.0", author_email="martin.weise@tuwien.ac.at", packages=[ "dbrepo", - "dbrepo.api" + "dbrepo.api", + "dbrepo.core", + "dbrepo.core.api", + "dbrepo.core.client", + "dbrepo.core.omlib", + "dbrepo.core.omlib.exceptions", + "dbrepo.core.omlib.rdf", ]) diff --git a/lib/python/test.sh b/lib/python/test.sh deleted file mode 100644 index cd0129654a468e4aa0d9bec0b1ba3b04f193fd24..0000000000000000000000000000000000000000 --- a/lib/python/test.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -source ./lib/python/venv/bin/activate -cd ./lib/python/ && coverage run -m pytest tests/*.py --junitxml=report.xml && coverage html && coverage report > ./coverage.txt \ No newline at end of file diff --git a/dbrepo-search-service/init/tests/conftest.py b/lib/python/tests/conftest.py similarity index 90% rename from dbrepo-search-service/init/tests/conftest.py rename to lib/python/tests/conftest.py index e2a00b1d86a7129935c7dbd42acb4a51254d3dbc..c906c18fa7c09a77baac9122c687d45f4037b586 100644 --- a/dbrepo-search-service/init/tests/conftest.py +++ b/lib/python/tests/conftest.py @@ -1,9 +1,8 @@ +import json import logging import os import pytest -import json - from testcontainers.opensearch import OpenSearchContainer @@ -15,7 +14,7 @@ def session(request): :return: The OpenSearch container """ logging.debug("[fixture] creating opensearch container") - container = OpenSearchContainer() + container = OpenSearchContainer("opensearchproject/opensearch:2.10.0") logging.debug("[fixture] starting opensearch container") container.start() @@ -41,7 +40,7 @@ def cleanup(request, session): :return: """ logging.info("[fixture] clean schema") - with open('./database.json', 'r') as f: + with open('./tests/opensearch/database.json', 'r') as f: if session.get_client().indices.exists(index="database"): session.get_client().indices.delete(index="database") session.get_client().indices.create(index="database", body=json.load(f)) diff --git a/lib/python/tests/keycloak/rs256.key b/lib/python/tests/keycloak/rs256.key new file mode 100644 index 0000000000000000000000000000000000000000..86b3eaf5c6c4c6b83071b6d1e9d69cb22bcd4085 --- /dev/null +++ b/lib/python/tests/keycloak/rs256.key @@ -0,0 +1,3 @@ +-----BEGIN RSA PRIVATE KEY----- +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== +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/lib/python/tests/keycloak/rsa256.pkey b/lib/python/tests/keycloak/rsa256.pkey new file mode 100644 index 0000000000000000000000000000000000000000..857dfb22beeac202c2955d7cc4f782b787492beb --- /dev/null +++ b/lib/python/tests/keycloak/rsa256.pkey @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB +-----END PUBLIC KEY----- diff --git a/lib/python/tests/opensearch/database.json b/lib/python/tests/opensearch/database.json new file mode 100644 index 0000000000000000000000000000000000000000..175a50dd9b829d0ce855a5c9eceae694937009cc --- /dev/null +++ b/lib/python/tests/opensearch/database.json @@ -0,0 +1,1418 @@ +{ + "aliases": {}, + "mappings": { + "properties": { + "accesses": { + "properties": { + "created": { + "type": "date" + }, + "type": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "user": { + "properties": { + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "qualified_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "orcid": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "username": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + } + } + }, + "contact": { + "properties": { + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "qualified_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "orcid": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "username": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "container": { + "properties": { + "created": { + "type": "date" + }, + "host": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "image": { + "properties": { + "dialect": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "driver_class": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "registry": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "version": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "internal_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "port": { + "type": "long" + }, + "ui_host": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "ui_port": { + "type": "long" + } + } + }, + "created": { + "type": "date" + }, + "owner": { + "properties": { + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "qualified_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "orcid": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "username": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "exchange_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "identifiers": { + "properties": { + "created": { + "type": "date" + }, + "owner": { + "properties": { + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "qualified_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "orcid": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "username": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "owners": { + "properties": { + "owner_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "name_identifier": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "name_identifier_scheme": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "name_identifier_scheme_uri": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "name_type": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "database_id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "descriptions": { + "properties": { + "description": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "licenses": { + "properties": { + "description": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "identifier": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "uri": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "publication_day": { + "type": "long" + }, + "publication_month": { + "type": "long" + }, + "publication_year": { + "type": "long" + }, + "publisher": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "query": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "query_normalized": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "status": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "titles": { + "properties": { + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "title": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "type": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "view_id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "image": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "internal_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "is_public": { + "type": "boolean" + }, + "is_schema_public": { + "type": "boolean" + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "tables": { + "properties": { + "columns": { + "properties": { + "auto_generated": { + "type": "boolean" + }, + "type": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "d": { + "type": "long" + }, + "database_id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "internal_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "is_null_allowed": { + "type": "boolean" + }, + "is_public": { + "type": "boolean" + }, + "is_schema_public": { + "type": "boolean" + }, + "mean": { + "type": "float" + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "size": { + "type": "long" + }, + "std_dev": { + "type": "float" + }, + "table_id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "constraints": { + "properties": { + "primary_key": { + "properties": { + "column": { + "properties": { + "database_id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "table_id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "table": { + "properties": { + "database_id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + } + } + }, + "uniques": { + "properties": { + "columns": { + "properties": { + "database_id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "table_id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "table": { + "properties": { + "database_id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + } + } + } + } + }, + "created": { + "type": "date" + }, + "owner": { + "properties": { + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "qualified_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "orcid": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "username": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "data_length": { + "type": "long" + }, + "database_id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "description": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "internal_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "is_public": { + "type": "boolean" + }, + "is_schema_public": { + "type": "boolean" + }, + "is_versioned": { + "type": "boolean" + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "num_rows": { + "type": "long" + }, + "queue_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "routing_key": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "views": { + "properties": { + "columns": { + "properties": { + "auto_generated": { + "type": "boolean" + }, + "type": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "database_id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "internal_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "is_null_allowed": { + "type": "boolean" + }, + "is_public": { + "type": "boolean" + }, + "is_schema_public": { + "type": "boolean" + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "created": { + "type": "date" + }, + "owner": { + "properties": { + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "qualified_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "orcid": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "username": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "database_id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "identifiers": { + "properties": { + "created": { + "type": "date" + }, + "owner": { + "properties": { + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "qualified_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "orcid": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "username": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "owners": { + "properties": { + "owner_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "name_identifier": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "name_identifier_scheme": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "name_identifier_scheme_uri": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "name_type": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "database_id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "descriptions": { + "properties": { + "description": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "licenses": { + "properties": { + "description": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "identifier": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "uri": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "publication_day": { + "type": "long" + }, + "publication_month": { + "type": "long" + }, + "publication_year": { + "type": "long" + }, + "publisher": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "query": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "query_normalized": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "status": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "titles": { + "properties": { + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "title": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "type": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "view_id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "initial_view": { + "type": "boolean" + }, + "internal_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "is_public": { + "type": "boolean" + }, + "is_schema_public": { + "type": "boolean" + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "query": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "query_hash": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + } + } + }, + "settings": { + "index": { + "number_of_shards": "1", + "number_of_replicas": "1" + } + } +} \ No newline at end of file diff --git a/dbrepo-analyse-service/tests/test_s3_client.py b/lib/python/tests/test_integration_core_storage_client.py similarity index 98% rename from dbrepo-analyse-service/tests/test_s3_client.py rename to lib/python/tests/test_integration_core_storage_client.py index cbc47a67409caa05a2b54738cc36ccc9534cdaa3..c69fce877f2b91267df85f400c4f6c32f16c8177 100644 --- a/dbrepo-analyse-service/tests/test_s3_client.py +++ b/lib/python/tests/test_integration_core_storage_client.py @@ -4,7 +4,7 @@ from clients.s3_client import S3Client from botocore.exceptions import ClientError -class S3ClientTest(unittest.TestCase): +class StorageServiceClientIntegrationTest(unittest.TestCase): # @Test def test_upload_file_succeeds(self): diff --git a/dbrepo-search-service/init/tests/test_keycloak_client.py b/lib/python/tests/test_unit_core_auth_client.py similarity index 97% rename from dbrepo-search-service/init/tests/test_keycloak_client.py rename to lib/python/tests/test_unit_core_auth_client.py index f52faf78c69ae7ec816721036d8f3c3fc58692e8..e8296b79930cd740990a2a606b305a4c2775cd6c 100644 --- a/dbrepo-search-service/init/tests/test_keycloak_client.py +++ b/lib/python/tests/test_unit_core_auth_client.py @@ -7,7 +7,7 @@ import requests_mock from clients.keycloak_client import KeycloakClient -class JwtTest(unittest.TestCase): +class AuthServiceClientUnitTest(unittest.TestCase): def response(self, username) -> dict: return dict({ diff --git a/dbrepo-search-service/init/tests/test_opensearch_client.py b/lib/python/tests/test_unit_core_search_client.py similarity index 99% rename from dbrepo-search-service/init/tests/test_opensearch_client.py rename to lib/python/tests/test_unit_core_search_client.py index 54ef2340ab0cf7763122cbf300deb5f8d44d6fa1..6aeb6f98a786efc9abd5968d65027e703b289906 100644 --- a/dbrepo-search-service/init/tests/test_opensearch_client.py +++ b/lib/python/tests/test_unit_core_search_client.py @@ -16,6 +16,7 @@ req = Database(id="209acf92-5c9b-4633-ad99-113c86f6e948", exchange_name="dbrepo", is_public=True, is_schema_public=True, + is_dashboard_enabled=True, container=ContainerBrief(id="7efe8b27-6cdc-4387-80e3-92ee28f4a7c5", name="MariaDB", internal_name="mariadb", @@ -53,7 +54,7 @@ req = Database(id="209acf92-5c9b-4633-ad99-113c86f6e948", )]) -class OpenSearchClientTest(unittest.TestCase): +class SearchServiceClientUnitTest(unittest.TestCase): def test_update_database_succeeds(self): req.tables = [Table(id="f94a6164-cad4-4873-a9fd-3fe5313b2e95", diff --git a/lib/python/tests/test_unit_database.py b/lib/python/tests/test_unit_database.py index 54a41cfbd79027fad93e5b2c570110ac17a4ea8f..ee4d0aeae40e6880f3ef3999c398023d76cbc4aa 100644 --- a/lib/python/tests/test_unit_database.py +++ b/lib/python/tests/test_unit_database.py @@ -76,6 +76,7 @@ class DatabaseUnitTest(unittest.TestCase): internal_name='test_abcd', is_public=True, is_schema_public=True, + is_dashboard_enabled=True, container=ContainerBrief( id="44d811a8-4019-46ba-bd57-ea10a2eb0c74", name='MariaDB Galera 11.1.3', @@ -134,6 +135,7 @@ class DatabaseUnitTest(unittest.TestCase): internal_name='test_abcd', is_public=True, is_schema_public=True, + is_dashboard_enabled=True, container=ContainerBrief( id="44d811a8-4019-46ba-bd57-ea10a2eb0c74", name='MariaDB Galera 11.1.3', @@ -261,6 +263,7 @@ class DatabaseUnitTest(unittest.TestCase): internal_name='test_abcd', is_public=True, is_schema_public=True, + is_dashboard_enabled=True, container=ContainerBrief( id="44d811a8-4019-46ba-bd57-ea10a2eb0c74", name='MariaDB Galera 11.1.3', @@ -379,6 +382,7 @@ class DatabaseUnitTest(unittest.TestCase): internal_name='test_abcd', is_public=True, is_schema_public=True, + is_dashboard_enabled=True, container=ContainerBrief( id="44d811a8-4019-46ba-bd57-ea10a2eb0c74", name='MariaDB Galera 11.1.3', diff --git a/lib/python/tests/test_unit_query.py b/lib/python/tests/test_unit_query.py index 528d6775a7e3b84a3afdceb68344518d234ba21d..719847fbfee49a5ec101d3a1ebca693d5b7585f2 100644 --- a/lib/python/tests/test_unit_query.py +++ b/lib/python/tests/test_unit_query.py @@ -23,6 +23,7 @@ class QueryUnitTest(unittest.TestCase): internal_name='test_abcd', is_public=True, is_schema_public=True, + is_dashboard_enabled=True, tables=[Table(id="029d773f-f98b-40c0-ab22-b8b1635d4fbc", name="Some Table", description="Test Table", diff --git a/lib/python/tests/test_unit_table.py b/lib/python/tests/test_unit_table.py index c67b54c6144016df23a85fc6bb8fe8c46b9a0565..8aa67d924e255836a76824614b21db7c19801ec7 100644 --- a/lib/python/tests/test_unit_table.py +++ b/lib/python/tests/test_unit_table.py @@ -1105,7 +1105,10 @@ class TableUnitTest(unittest.TestCase): def test_analyse_table_statistics_succeeds(self): with requests_mock.Mocker() as mock: exp = TableStatistics( - columns={"id": ColumnStatistic(val_min=1.0, val_max=9.0, mean=5.0, median=5.0, std_dev=2.73)}) + total_columns=1, + total_rows=1000, + columns={ + "id": ColumnStatistic(name="id", val_min=1.0, val_max=9.0, mean=5.0, median=5.0, std_dev=2.73)}) # mock mock.get( '/api/analyse/database/6bd39359-b154-456d-b9c2-caa516a45732/table/b3230b86-4743-498d-9015-3fad58049692/statistics', diff --git a/lib/python/tests/test_unit_view.py b/lib/python/tests/test_unit_view.py index cb26eeaba8584d201202f7b6693f240b36701011..a3319f1fad59c7e2bd2b8a2d5cfb6745fcfd6fcd 100644 --- a/lib/python/tests/test_unit_view.py +++ b/lib/python/tests/test_unit_view.py @@ -22,6 +22,7 @@ class ViewUnitTest(unittest.TestCase): internal_name='test_abcd', is_public=True, is_schema_public=True, + is_dashboard_enabled=True, tables=[Table(id="029d773f-f98b-40c0-ab22-b8b1635d4fbc", name="Some Table", description="Test Table", diff --git a/make/build.mk b/make/build.mk index 968bd94d552e16d689d40c0eb47641fa7450e14e..48e9212a6ac44f9d64c93fb981fa197bc407cd4e 100644 --- a/make/build.mk +++ b/make/build.mk @@ -2,8 +2,9 @@ .PHONY: build-images build-images: ## Build Docker images. - docker build --network=host -t dbrepo-metadata-service:build --target build dbrepo-metadata-service + docker build --network=host -t dbrepo-core:build --target build ./lib/java/dbrepo-core docker build --network=host -t dbrepo-data-service:build --target build dbrepo-data-service + docker build --network=host -t dbrepo-metadata-service:build --target build dbrepo-metadata-service docker compose build --parallel .PHONY: build-data-service @@ -28,14 +29,20 @@ build-lib: ## Build the Python Library. rm -rf ./dbrepo-analyse-service/venv/ ./dbrepo-analyse-service/Pipfile.lock ./dbrepo-analyse-service/lib/* rm -rf ./dbrepo-search-service/venv/ ./dbrepo-search-service/Pipfile.lock ./dbrepo-search-service/lib/* rm -rf ./dbrepo-search-service/init/venv/ ./dbrepo-search-service/init/Pipfile.lock ./dbrepo-search-service/init/lib/* + rm -rf ./dbrepo-dashboard-service/venv/ ./dbrepo-dashboard-service/Pipfile.lock ./dbrepo-dashboard-service/lib/* + rm -rf ./dbrepo-dashboard-service/init/venv/ ./dbrepo-dashboard-service/init/Pipfile.lock ./dbrepo-dashboard-service/init/lib/* python3 -m build --sdist ./lib/python python3 -m build --wheel ./lib/python cp -r ./lib/python/dist/dbrepo-${APP_VERSION}* ./dbrepo-analyse-service/lib - (cd ./dbrepo-analyse-service && PIPENV_IGNORE_VIRTUALENVS=1 pipenv install --dev) + (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 && PIPENV_IGNORE_VIRTUALENVS=1 pipenv install --dev) + (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 && PIPENV_IGNORE_VIRTUALENVS=1 pipenv install --dev) + (cd ./dbrepo-search-service/init && python3 -m venv venv && PIPENV_IGNORE_VIRTUALENVS=1 pipenv install --dev) + cp -r ./lib/python/dist/dbrepo-${APP_VERSION}* ./dbrepo-dashboard-service/lib + (cd ./dbrepo-dashboard-service && python3 -m venv venv && PIPENV_IGNORE_VIRTUALENVS=1 pipenv install --dev) + cp -r ./lib/python/dist/dbrepo-${APP_VERSION}* ./dbrepo-dashboard-service/init/lib + (cd ./dbrepo-dashboard-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/rel.mk b/make/rel.mk index c98668f08b9bc79f23be811f3fdfa0f753ca3d24..f5969e3cbfe96e73b041e70315d488d09f9c2f14 100644 --- a/make/rel.mk +++ b/make/rel.mk @@ -3,28 +3,30 @@ .PHONY: tag-images tag-images: build-images ## Tag the docker images. docker tag dbrepo-analyse-service:latest "${REPOSITORY_URL}/analyse-service:${APP_VERSION}${BUILD_VERSION}" + docker tag dbrepo-auth-service-init:latest "${REPOSITORY_URL}/auth-service-init:${APP_VERSION}${BUILD_VERSION}" docker tag dbrepo-dashboard-service:latest "${REPOSITORY_URL}/dashboard-service:${APP_VERSION}${BUILD_VERSION}" - docker tag dbrepo-ui:latest "${REPOSITORY_URL}/ui:${APP_VERSION}${BUILD_VERSION}" + docker tag dbrepo-dashboard-service-init:latest "${REPOSITORY_URL}/dashboard-service-init:${APP_VERSION}${BUILD_VERSION}" docker tag dbrepo-data-service:latest "${REPOSITORY_URL}/data-service:${APP_VERSION}${BUILD_VERSION}" - docker tag dbrepo-auth-service-init:latest "${REPOSITORY_URL}/auth-service-init:${APP_VERSION}${BUILD_VERSION}" docker tag dbrepo-metadata-service:latest "${REPOSITORY_URL}/metadata-service:${APP_VERSION}${BUILD_VERSION}" docker tag dbrepo-search-db:latest "${REPOSITORY_URL}/search-db:${APP_VERSION}${BUILD_VERSION}" docker tag dbrepo-search-service:latest "${REPOSITORY_URL}/search-service:${APP_VERSION}${BUILD_VERSION}" docker tag dbrepo-search-service-init:latest "${REPOSITORY_URL}/search-service-init:${APP_VERSION}${BUILD_VERSION}" docker tag dbrepo-storage-service-init:latest "${REPOSITORY_URL}/storage-service-init:${APP_VERSION}${BUILD_VERSION}" + docker tag dbrepo-ui:latest "${REPOSITORY_URL}/ui:${APP_VERSION}${BUILD_VERSION}" .PHONY: release-images release-images: tag-images ## Release the docker images. docker push "${REPOSITORY_URL}/analyse-service:${APP_VERSION}${BUILD_VERSION}" + docker push "${REPOSITORY_URL}/auth-service-init:${APP_VERSION}${BUILD_VERSION}" docker push "${REPOSITORY_URL}/dashboard-service:${APP_VERSION}${BUILD_VERSION}" - docker push "${REPOSITORY_URL}/ui:${APP_VERSION}${BUILD_VERSION}" + docker push "${REPOSITORY_URL}/dashboard-service-init:${APP_VERSION}${BUILD_VERSION}" docker push "${REPOSITORY_URL}/data-service:${APP_VERSION}${BUILD_VERSION}" - docker push "${REPOSITORY_URL}/auth-service-init:${APP_VERSION}${BUILD_VERSION}" docker push "${REPOSITORY_URL}/search-db:${APP_VERSION}${BUILD_VERSION}" docker push "${REPOSITORY_URL}/metadata-service:${APP_VERSION}${BUILD_VERSION}" docker push "${REPOSITORY_URL}/search-service:${APP_VERSION}${BUILD_VERSION}" docker push "${REPOSITORY_URL}/search-service-init:${APP_VERSION}${BUILD_VERSION}" docker push "${REPOSITORY_URL}/storage-service-init:${APP_VERSION}${BUILD_VERSION}" + docker push "${REPOSITORY_URL}/ui:${APP_VERSION}${BUILD_VERSION}" .PHONY: release-helm release-helm: gen-helm-doc ## Release the DBRepo and DBRepo MariaDB Galera Helm charts. diff --git a/mkdocs.yml b/mkdocs.yml index 536eed294ed4f5683d601f2e0a460a8ade5267d1..bf9e14a9ddaee6a9cd28222734bb93372233711b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,5 +1,5 @@ site_name: Database Repository -site_url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.7/ +site_url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.8/ repo_url: https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services repo_name: fda-services site_author: Research Unit Data Science, Technische Universität Wien @@ -18,12 +18,12 @@ nav: - Overview: concepts/index.md - Authentication: concepts/authentication.md - Data Versioning: concepts/data-versioning.md + - Dashboards: concepts/dashboards.md - Data Visibility: concepts/data-visibility.md - Messaging: concepts/messaging.md - Monitoring: concepts/monitoring.md - Persistent Identifier: concepts/pid.md - Search: concepts/search.md - - User Interface: concepts/ui.md - API: - Overview: api/index.md - Databases: @@ -37,16 +37,14 @@ nav: - Analyse Service: api/analyse-service.md - Auth Service: api/auth-service.md - Broker Service: api/broker-service.md - - Dashboard Service: api/dashboard-service.md - Data Service: api/data-service.md - Gateway Service: api/gateway-service.md - Identity Service: api/identity-service.md - Metadata Service: api/metadata-service.md - Search Service: api/search-service.md - Storage Service: api/storage-service.md - - Upload Service: api/upload-service.md - UI: - - Customization: api/ui.md + - Repository: api/ui.md - Examples: - Air Quality Data: examples/air.md - COVID-19 Data: examples/covid-19.md @@ -120,9 +118,9 @@ markdown_extensions: custom_icons: - .docs/overrides/.icons extra: - homepage: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.7/ + homepage: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.8/ version: - default: 1.7 + default: 1.8 provider: mike social: - icon: simple/artifacthub diff --git a/sonar-project.properties b/sonar-project.properties index 0ec728cec72a9c239f6bfa0dc04ce5c992369251..90e7004f974bb489e112db73e22f41ced6ddc8b9 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.7.3 +sonar.projectVersion=1.8.0 # general sonar.qualitygate.wait=true sonar.projectCreation.mainBranchName=master diff --git a/versions.json b/versions.json index 95ca2a62a6fec4b73534bc3d6981b1bcdfd8fff2..0fafe8664cc9c3d6369b92b643fb53ae98cb1cbf 100644 --- a/versions.json +++ b/versions.json @@ -1,4 +1,9 @@ [ + { + "version": "1.8", + "title": "1.8", + "aliases": [] + }, { "version": "1.7", "title": "1.7",