diff --git a/.docs/.openapi/api-data.yaml b/.docs/.openapi/api-data.yaml index 6d3e8693c52c8817f2d0243c22870005da54b556..6b1855a99e5e183c98270ce961899322beaa569e 100644 --- a/.docs/.openapi/api-data.yaml +++ b/.docs/.openapi/api-data.yaml @@ -11,7 +11,7 @@ info: version: 1.7.1 externalDocs: description: Sourcecode Documentation - url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.7/system-services-metadata/ + url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.7.1/system-services-metadata/ servers: - url: http://localhost description: Development instance @@ -57,48 +57,60 @@ paths: schema: type: string format: date-time + - name: Accept + in: header + required: true + schema: + type: string responses: - "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 + "403": + description: Not allowed to retrieve view data content: application/json: schema: - type: string - "409": - description: View schema could not be mapped + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find view in metadata database content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to establish connection with the metadata service + "400": + description: Request pagination is malformed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Failed to find view in metadata database + "406": + description: Failed to format data content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Request pagination is malformed + "409": + description: View schema could not be mapped content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Not allowed to retrieve view data + "200": + description: Retrieved view data + headers: + Access-Control-Expose-Headers: + description: Expose `X-Count` custom header + required: true + style: simple + X-Count: + description: Number of rows + required: true + style: simple + content: + application/json: + schema: + type: string + text/csv: {} + "503": + description: Failed to establish connection with the metadata service content: application/json: schema: @@ -144,48 +156,60 @@ paths: schema: type: string format: date-time + - name: Accept + in: header + required: true + schema: + type: string responses: - "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 + "403": + description: Not allowed to retrieve view data content: application/json: schema: - type: string - "409": - description: View schema could not be mapped + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find view in metadata database content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to establish connection with the metadata service + "400": + description: Request pagination is malformed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Failed to find view in metadata database + "406": + description: Failed to format data content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Request pagination is malformed + "409": + description: View schema could not be mapped content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Not allowed to retrieve view data + "200": + description: Retrieved view data + headers: + Access-Control-Expose-Headers: + description: Expose `X-Count` custom header + required: true + style: simple + X-Count: + description: Number of rows + required: true + style: simple + content: + application/json: + schema: + type: string + text/csv: {} + "503": + description: Failed to establish connection with the metadata service content: application/json: schema: @@ -234,7 +258,24 @@ paths: schema: type: integer format: int64 + - name: Accept + in: header + required: true + schema: + type: string responses: + "404": + description: Failed to find table in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Request pagination or table data select query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" "200": description: Get table data headers: @@ -250,26 +291,21 @@ paths: application/json: schema: type: string - "503": - description: Failed to establish connection with the metadata service - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Not allowed to get table data + text/csv: {} + "406": + description: Failed to format data content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Failed to find table in metadata database + "503": + description: Failed to establish connection with the metadata service content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Request pagination or table data select query is malformed + "403": + description: Not allowed to get table data content: application/json: schema: @@ -310,28 +346,28 @@ paths: $ref: "#/components/schemas/TupleUpdateDto" required: true responses: - "403": - description: Update 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 + "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 + "202": + description: Updated table data + "503": + description: Failed to establish connection with the metadata service content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "202": - description: Updated table data - "400": - description: Request pagination or table data select query is malformed + "403": + description: Update table data not allowed content: application/json: schema: @@ -372,30 +408,30 @@ paths: $ref: "#/components/schemas/TupleDto" required: true responses: - "404": - description: Failed to find table in metadata database or blob in storage - service + "400": + description: Request pagination or table data select query is malformed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "201": - description: Created table data - "503": - description: Failed to establish connection with the metadata service or - storage service + "403": + description: Create table data not allowed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Create table data not allowed + "503": + description: Failed to establish connection with the metadata service or + storage service content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Request pagination or table data select query is malformed + "201": + description: Created table data + "404": + description: Failed to find table in metadata database or blob in storage + service content: application/json: schema: @@ -436,14 +472,6 @@ paths: $ref: "#/components/schemas/TupleDeleteDto" required: true responses: - "503": - description: Failed to establish connection with the metadata service - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "202": - description: Deleted table data "404": description: Failed to find table in metadata database content: @@ -462,6 +490,14 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Deleted table data + "503": + description: Failed to establish connection with the metadata service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" security: - basicAuth: [] - bearerAuth: [] @@ -505,7 +541,24 @@ paths: schema: type: integer format: int64 + - name: Accept + in: header + required: true + schema: + type: string responses: + "404": + description: Failed to find table in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Request pagination or table data select query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" "200": description: Get table data headers: @@ -521,26 +574,21 @@ paths: application/json: schema: type: string - "503": - description: Failed to establish connection with the metadata service - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Not allowed to get table data + text/csv: {} + "406": + description: Failed to format data content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Failed to find table in metadata database + "503": + description: Failed to establish connection with the metadata service content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Request pagination or table data select query is malformed + "403": + description: Not allowed to get table data content: application/json: schema: @@ -571,6 +619,11 @@ paths: schema: type: string format: uuid + - name: Accept + in: header + required: true + schema: + type: string - name: timestamp in: query required: false @@ -590,14 +643,27 @@ paths: type: integer format: int64 responses: - "400": - description: Invalid pagination + "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 + "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" + "400": + description: Invalid pagination content: application/json: schema: @@ -623,15 +689,9 @@ paths: application/json: schema: type: string - "404": - description: Failed to find database in metadata database or query in query - store of the data database - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Not allowed to retrieve subset data + text/csv: {} + "503": + description: Failed to communicate with database content: application/json: schema: @@ -661,6 +721,11 @@ paths: schema: type: string format: uuid + - name: Accept + in: header + required: true + schema: + type: string - name: timestamp in: query required: false @@ -680,14 +745,27 @@ paths: type: integer format: int64 responses: - "400": - description: Invalid pagination + "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 + "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" + "400": + description: Invalid pagination content: application/json: schema: @@ -710,18 +788,12 @@ paths: description: The list of headers separated by comma style: simple content: - application/json: - schema: - type: string - "404": - description: Failed to find database in metadata database or query in query - store of the data database - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Not allowed to retrieve subset data + application/json: + schema: + type: string + text/csv: {} + "503": + description: Failed to communicate with database content: application/json: schema: @@ -756,39 +828,39 @@ paths: $ref: "#/components/schemas/QueryPersistDto" required: true responses: - "202": - description: Persisted subset + "403": + description: Not allowed to persist subset content: application/json: schema: - $ref: "#/components/schemas/QueryDto" - "503": - description: Failed to communicate with database + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find database in metadata database or query in query + store of the data database content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "417": - description: Failed to persist subset + "202": + description: Persisted subset content: application/json: schema: - $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Failed to find database in metadata database or query in query - store of the data database + $ref: "#/components/schemas/QueryDto" + "400": + description: Malformed select query content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Not allowed to persist subset + "503": + description: Failed to communicate with database content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Malformed select query + "417": + description: Failed to persist subset content: application/json: schema: @@ -867,28 +939,28 @@ paths: $ref: "#/components/schemas/ImportDto" required: true responses: - "202": - description: Imported dataset successfully - "403": - description: Import table dataset 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 + "202": + description: Imported dataset successfully + "400": + description: Dataset and/or query are malformed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Failed to find table in metadata database + "503": + description: Failed to establish connection with the metadata service content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Dataset and/or query are malformed + "403": + description: Import table dataset not allowed content: application/json: schema: @@ -920,12 +992,6 @@ paths: schema: type: boolean responses: - "503": - description: Failed to communicate with database - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "200": description: Found subsets content: @@ -934,15 +1000,21 @@ paths: type: array items: $ref: "#/components/schemas/QueryDto" + "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 subsets content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Failed to find database in metadata database or query in query - store of the data database + "503": + description: Failed to communicate with database content: application/json: schema: @@ -991,8 +1063,8 @@ paths: $ref: "#/components/schemas/SubsetDto" required: true responses: - "417": - description: Failed to insert query into query store of data database + "403": + description: Not allowed to find subset content: application/json: schema: @@ -1003,21 +1075,21 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to communicate with 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 + "417": + description: Failed to insert query into query store of data database content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Failed to find database in metadata database or query in query - store of the data database + "406": + description: Failed to format data content: application/json: schema: @@ -1034,65 +1106,8 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - security: - - basicAuth: [] - - bearerAuth: [] - /api/database/{databaseId}/view/{viewId}/export: - get: - tags: - - view-endpoint - summary: Get view data - description: "Gets data from view with id as downloadable file. For tables in\ - \ private databases, the user needs to have at least *READ* access to the\ - \ associated database." - operationId: exportDataset - parameters: - - name: databaseId - in: path - required: true - schema: - type: string - format: uuid - - name: viewId - in: path - required: true - schema: - type: string - format: uuid - - name: timestamp - in: query - required: false - schema: - type: string - format: date-time - responses: - "404": - description: Failed to find view in metadata database or export dataset - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "503": - description: Failed to establish connection with the metadata service - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Export view data not allowed - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "200": - description: Exported view data - content: - application/json: - schema: - type: string - format: binary - "400": - description: Request pagination or view data select query is malformed + description: Failed to communicate with database content: application/json: schema: @@ -1129,26 +1144,6 @@ paths: type: integer format: int64 responses: - "200": - description: Found table history - content: - application/json: - schema: - type: array - items: - $ref: "#/components/schemas/TableHistoryDto" - "404": - description: Failed to find table history in data database - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to establish connection with the metadata service - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "403": description: Find table history not allowed content: @@ -1161,69 +1156,26 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - security: - - basicAuth: [] - - bearerAuth: [] - /api/database/{databaseId}/table/{tableId}/export: - get: - tags: - - table-endpoint - summary: Get table data - description: "Gets data from table with id as downloadable file. For tables\ - \ in private databases, the user needs to have at least *READ* access to the\ - \ associated database." - operationId: exportDataset_1 - parameters: - - name: databaseId - in: path - required: true - schema: - type: string - format: uuid - - name: tableId - in: path - required: true - schema: - type: string - format: uuid - - name: timestamp - in: query - required: false - schema: - type: string - format: date-time - responses: - "503": - description: Failed to establish connection with the metadata service - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Failed to find table in metadata database + "200": + description: Found table history content: application/json: schema: - $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Export table data not allowed + type: array + items: + $ref: "#/components/schemas/TableHistoryDto" + "503": + description: Failed to establish connection with the metadata service 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 history in data database content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "200": - description: Exported table data - content: - application/json: - schema: - type: string - format: binary security: - basicAuth: [] - bearerAuth: [] @@ -1251,11 +1203,6 @@ paths: schema: type: string format: uuid - - name: Accept - in: header - required: true - schema: - type: string - name: timestamp in: query required: false @@ -1263,40 +1210,40 @@ paths: type: string format: date-time responses: - "503": - description: Failed to communicate with database + "200": + description: Found subset content: application/json: schema: - $ref: "#/components/schemas/ApiErrorDto" + $ref: "#/components/schemas/QueryDto" + text/csv: {} "403": description: Not allowed to find subset content: 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" - "404": - description: Failed to find database in metadata database or query in query - store of the data database + "400": + description: Malformed select query content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "200": - description: Found subset + "406": + description: Failed to find acceptable representation content: application/json: schema: - $ref: "#/components/schemas/QueryDto" - text/csv: {} - "400": - description: Malformed select query + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to communicate with database content: application/json: schema: @@ -2102,6 +2049,7 @@ components: - id - language - licenses + - links - owner - publication_year - publisher @@ -2117,6 +2065,8 @@ components: type: string format: uuid example: b97cd56b-66ca-4354-9e6c-f47210cfaaec + links: + $ref: "#/components/schemas/LinksDto" type: type: string example: database @@ -2448,6 +2398,21 @@ 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 + type: object + properties: + self: + type: string + example: http://example.com/api/ + data: + type: string + example: http://example.com + self_html: + type: string + example: http://example.com RelatedIdentifierDto: required: - id diff --git a/.docs/.openapi/api-metadata.yaml b/.docs/.openapi/api-metadata.yaml index b7f380213b76fcf6455cba3b309a6fcf85c59440..e3769be04d2a9726dc40999bad56daa1c537d613 100644 --- a/.docs/.openapi/api-metadata.yaml +++ b/.docs/.openapi/api-metadata.yaml @@ -11,7 +11,7 @@ info: version: 1.7.1 externalDocs: description: Sourcecode Documentation - url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.7/system-services-metadata/ + url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.7.1/system-services-metadata/ servers: - url: http://localhost description: Development instance @@ -36,18 +36,18 @@ paths: type: string format: uuid responses: - "200": - description: Found user - content: - application/json: - schema: - $ref: "#/components/schemas/UserDto" "404": description: User was not found content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Found user + content: + application/json: + schema: + $ref: "#/components/schemas/UserDto" "403": description: Find user is not permitted content: @@ -77,20 +77,20 @@ paths: $ref: "#/components/schemas/UserUpdateDto" required: true responses: - "403": - description: Not allowed to modify user metadata + "400": + description: Modify user query is malformed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to modify user at auth service + "404": + description: Failed to find database/user in metadata database content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Failed to find database/user in metadata database + "503": + description: Failed to modify user at auth service content: application/json: schema: @@ -101,8 +101,8 @@ paths: application/json: schema: $ref: "#/components/schemas/UserDto" - "400": - description: Modify user query is malformed + "403": + description: Not allowed to modify user metadata content: application/json: schema: @@ -127,18 +127,18 @@ paths: type: string format: uuid responses: - "200": - description: Found user - content: - application/json: - schema: - $ref: "#/components/schemas/UserDto" "404": description: User was not found content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Found user + content: + application/json: + schema: + $ref: "#/components/schemas/UserDto" "403": description: Find user is not permitted content: @@ -194,20 +194,8 @@ paths: $ref: "#/components/schemas/CreateDatabaseDto" required: true responses: - "502": - description: Connection to search service failed - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "409": - description: Query store could not be created - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to save in search service + "400": + description: Database create query is malformed or image is not supported content: application/json: schema: @@ -224,8 +212,8 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Database create query is malformed or image is not supported + "409": + description: Query store could not be created content: application/json: schema: @@ -243,6 +231,18 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" security: - bearerAuth: [] - basicAuth: [] @@ -303,6 +303,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 +321,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: [] @@ -351,14 +351,9 @@ paths: $ref: "#/components/schemas/CreateAccessDto" required: true responses: - "404": - description: Database or user not found - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Access could not be updated in the data service + "502": + description: Access could not be updated due to connection error in the + data service content: application/json: schema: @@ -372,9 +367,8 @@ paths: $ref: "#/components/schemas/ApiErrorDto" "202": description: Modified access - "502": - description: Access could not be updated due to connection error in the - data service + "503": + description: Access could not be updated in the data service content: application/json: schema: @@ -385,6 +379,12 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Database or user not found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" security: - bearerAuth: [] - basicAuth: [] @@ -415,14 +415,20 @@ paths: $ref: "#/components/schemas/CreateAccessDto" required: true responses: + "502": + description: Access could not be created due to connection error + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" "202": description: Granting access succeeded content: application/json: schema: $ref: "#/components/schemas/DatabaseAccessDto" - "404": - description: Database or user not found + "403": + description: Failed giving access content: application/json: schema: @@ -439,14 +445,8 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Failed giving access - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "502": - description: Access could not be created due to connection error + "404": + description: Database or user not found content: application/json: schema: @@ -475,6 +475,12 @@ paths: type: string format: uuid responses: + "502": + description: Access could not be created due to connection error + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" "403": description: Revoke of access not permitted as no access was found content: @@ -489,12 +495,6 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "502": - description: Access could not be created due to connection error - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "404": description: "User, database with access was not found" content: @@ -534,6 +534,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 +552,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: [] @@ -665,18 +665,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: [] @@ -694,16 +694,16 @@ paths: type: string format: uuid responses: - "202": - description: Deleted message - content: - application/json: {} "404": description: Could not find message content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Deleted message + content: + application/json: {} security: - bearerAuth: [] - basicAuth: [] @@ -817,9 +817,8 @@ paths: schema: type: string responses: - "400": - description: "Identifier could not be exported, the requested style is not\ - \ known" + "403": + description: Not allowed to view identifier content: application/json: schema: @@ -830,24 +829,6 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "409": - description: Exported resource was not found - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to find in data service - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "410": - description: Failed to retrieve from S3 endpoint - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "200": description: Found identifier successfully content: @@ -857,20 +838,26 @@ paths: application/ld+json: schema: $ref: "#/components/schemas/LdDatasetDto" - text/csv: {} text/xml: {} text/bibliography: {} text/bibliography; style=apa: {} text/bibliography; style=ieee: {} text/bibliography; style=bibtex: {} - "403": - description: Not allowed to view identifier + "410": + description: Failed to retrieve from S3 endpoint content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Identifier could not be found + "409": + description: Exported resource was not found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: "Identifier could not be exported, the requested style is not\ + \ known" content: application/json: schema: @@ -881,6 +868,18 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Identifier could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to find in data service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" put: tags: - identifier-endpoint @@ -904,20 +903,20 @@ paths: $ref: "#/components/schemas/IdentifierSaveDto" required: true responses: - "502": - description: Connection to search service failed + "404": + description: "Failed to find database, table or view" content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Insufficient access rights or authorities + "202": + description: Saved identifier content: application/json: schema: - $ref: "#/components/schemas/ApiErrorDto" - "404": - description: "Failed to find database, table or view" + $ref: "#/components/schemas/IdentifierDto" + "400": + description: Identifier form contains invalid request data content: application/json: schema: @@ -928,18 +927,18 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Identifier form contains invalid request data + "403": + description: Insufficient access rights or authorities content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "202": - description: Saved identifier + "502": + description: Connection to search service failed content: application/json: schema: - $ref: "#/components/schemas/IdentifierDto" + $ref: "#/components/schemas/ApiErrorDto" security: - bearerAuth: [] - basicAuth: [] @@ -957,12 +956,6 @@ 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 delete in search service content: @@ -977,6 +970,12 @@ paths: $ref: "#/components/schemas/ApiErrorDto" "202": description: Deleted identifier + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" "403": description: Deleting identifier not permitted content: @@ -1002,42 +1001,42 @@ paths: type: string format: uuid responses: - "502": - description: Connection to search service failed + "404": + description: "Failed to find database, table or view" content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Insufficient access rights or authorities + "400": + description: Identifier form contains invalid request data content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: "Failed to find database, table or view" + "202": + description: Published identifier content: application/json: schema: - $ref: "#/components/schemas/ApiErrorDto" + $ref: "#/components/schemas/IdentifierDto" "503": description: Failed to save in search service content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Identifier form contains invalid request data + "403": + description: Insufficient access rights or authorities content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "202": - description: Published identifier + "502": + description: Connection to search service failed content: application/json: schema: - $ref: "#/components/schemas/IdentifierDto" + $ref: "#/components/schemas/ApiErrorDto" security: - bearerAuth: [] - basicAuth: [] @@ -1063,8 +1062,8 @@ paths: $ref: "#/components/schemas/DatabaseModifyVisibilityDto" required: true responses: - "502": - description: Connection to search service failed + "400": + description: The visibility payload is malformed content: application/json: schema: @@ -1075,12 +1074,6 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: The visibility payload is malformed - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "403": description: Visibility modification is not permitted content: @@ -1093,6 +1086,12 @@ paths: application/json: schema: $ref: "#/components/schemas/DatabaseBriefDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" "404": description: Failed to find database in metadata database content: @@ -1123,12 +1122,6 @@ paths: type: string format: uuid responses: - "403": - description: Find view is not permitted - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "404": description: "Database, view or user could not be found" content: @@ -1141,6 +1134,12 @@ paths: application/json: schema: $ref: "#/components/schemas/ViewDto" + "403": + description: Find view is not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" security: - bearerAuth: [] - basicAuth: [] @@ -1171,12 +1170,6 @@ paths: $ref: "#/components/schemas/ViewUpdateDto" required: true responses: - "502": - description: Connection to search service failed - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "404": description: Database or View could not be found content: @@ -1201,6 +1194,12 @@ paths: '*/*': schema: $ref: "#/components/schemas/ViewBriefDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" "400": description: Update view query is malformed content: @@ -1230,22 +1229,22 @@ paths: type: string format: uuid responses: - "502": - description: Connection to search service failed + "404": + description: "Database, view or user could not be found" content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" "202": description: Delete view successfully - "503": - description: Failed to save in search service + "423": + description: Delete view resulted in an invalid query statement content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: "Database, view or user could not be found" + "503": + description: Failed to save in search service content: application/json: schema: @@ -1256,8 +1255,8 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "423": - description: Delete view resulted in an invalid query statement + "502": + description: Connection to search service failed content: application/json: schema: @@ -1295,18 +1294,18 @@ paths: type: string format: uuid responses: - "403": - description: Access to the database is forbidden - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "200": description: Find table successfully content: application/json: schema: $ref: "#/components/schemas/TableDto" + "403": + description: Access to the database is forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" "404": description: "Table, database or container could not be found" content: @@ -1342,14 +1341,8 @@ paths: $ref: "#/components/schemas/TableUpdateDto" required: true responses: - "502": - description: Connection to search service failed - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to save in search service + "400": + description: Update table visibility payload is malformed content: application/json: schema: @@ -1360,8 +1353,8 @@ paths: application/json: schema: $ref: "#/components/schemas/TableBriefDto" - "400": - description: Update table visibility payload is malformed + "503": + description: Failed to save in search service content: application/json: schema: @@ -1372,6 +1365,12 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" "403": description: Update table visibility not permitted content: @@ -1403,28 +1402,28 @@ paths: type: string format: uuid responses: - "502": - description: Connection to search service failed + "400": + description: Delete table query resulted in an invalid query statement content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Access to the database is forbidden + "202": + description: Delete table successfully + "503": + description: Failed to save in search service content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to save in search service + "403": + description: Access to the database is forbidden content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "202": - description: Delete table successfully - "400": - description: Delete table query resulted in an invalid query statement + "502": + description: Connection to search service failed content: application/json: schema: @@ -1461,32 +1460,32 @@ paths: type: string format: uuid responses: - "502": - description: Connection to search service failed + "403": + description: Not the owner content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "503": - description: Failed to save in search service + "404": + description: Failed to find database/table in metadata database content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Failed to map column statistic to known columns + "503": + description: Failed to save in search service content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Not the owner + "400": + description: Failed to map column statistic to known columns content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Failed to find database/table in metadata database + "502": + description: Connection to search service failed content: application/json: schema: @@ -1532,18 +1531,12 @@ paths: $ref: "#/components/schemas/ColumnSemanticsUpdateDto" required: true responses: - "502": - description: Connection to search service failed - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Access to the database is forbidden + "202": + description: Updated column semantics successfully content: application/json: schema: - $ref: "#/components/schemas/ApiErrorDto" + $ref: "#/components/schemas/ColumnDto" "404": description: Failed to find user/table/database/ontology in metadata database content: @@ -1556,12 +1549,18 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "202": - description: Updated column semantics successfully + "403": + description: Access to the database is forbidden content: application/json: schema: - $ref: "#/components/schemas/ColumnDto" + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" "400": description: Update semantic concept query is malformed or update unit of measurement query is malformed @@ -1594,18 +1593,12 @@ paths: $ref: "#/components/schemas/DatabaseTransferDto" required: true responses: - "502": - description: Connection to search service failed + "400": + description: Owner payload is malformed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "202": - description: Transfer of ownership was successful - content: - application/json: - schema: - $ref: "#/components/schemas/DatabaseBriefDto" "503": description: Failed to save in search service content: @@ -1618,8 +1611,8 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Owner payload is malformed + "502": + description: Connection to search service failed content: application/json: schema: @@ -1630,6 +1623,12 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Transfer of ownership was successful + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseBriefDto" security: - bearerAuth: [] - basicAuth: [] @@ -1650,26 +1649,26 @@ 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" "503": description: Failed to save in search service content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "200": - description: Refreshed database views metadata + "403": + description: Refresh view metadata is not permitted content: application/json: schema: - $ref: "#/components/schemas/DatabaseBriefDto" - "403": - description: Refresh view metadata is not permitted + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed content: application/json: schema: @@ -1700,14 +1699,8 @@ paths: type: string format: uuid responses: - "403": - description: Not allowed to refresh table metadata - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "502": - description: Connection to search service failed + "400": + description: Failed to parse payload at search service content: application/json: schema: @@ -1724,8 +1717,14 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Failed to parse payload at search service + "403": + description: Not allowed to refresh table metadata + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed content: application/json: schema: @@ -1754,12 +1753,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: View of image was successful content: @@ -1769,6 +1762,12 @@ paths: items: type: string format: byte + "404": + description: Database or user could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" security: - bearerAuth: [] - basicAuth: [] @@ -1793,14 +1792,20 @@ paths: $ref: "#/components/schemas/DatabaseModifyImageDto" required: true responses: + "403": + description: Modify of image is not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" "410": description: File was not found in the Storage Service content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "502": - description: Connection to search service failed + "404": + description: Database could not be found content: application/json: schema: @@ -1817,14 +1822,8 @@ paths: application/json: schema: $ref: "#/components/schemas/DatabaseBriefDto" - "404": - description: Database could not be found - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "403": - description: Modify of image is not permitted + "502": + description: Connection to search service failed content: application/json: schema: @@ -1948,12 +1947,6 @@ paths: $ref: "#/components/schemas/ImageCreateDto" required: true responses: - "400": - description: Image specification is invalid - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "409": description: Image already exists content: @@ -1966,6 +1959,12 @@ paths: application/json: schema: $ref: "#/components/schemas/ImageDto" + "400": + description: Image specification is invalid + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" security: - bearerAuth: [] - basicAuth: [] @@ -2054,8 +2053,8 @@ paths: $ref: "#/components/schemas/CreateIdentifierDto" required: true responses: - "502": - description: Connection to search service failed + "404": + description: "Failed to find database, table or view" content: application/json: schema: @@ -2066,26 +2065,26 @@ paths: application/json: schema: $ref: "#/components/schemas/IdentifierDto" - "403": - description: Insufficient access rights or authorities + "400": + description: Identifier form contains invalid request data content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: "Failed to find database, table or view" + "503": + description: Failed to save in search service 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: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Identifier form contains invalid request data + "502": + description: Connection to search service failed content: application/json: schema: @@ -2146,14 +2145,8 @@ paths: $ref: "#/components/schemas/CreateViewDto" required: true responses: - "423": - description: Create view resulted in an invalid query statement - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "502": - description: Connection to search service failed + "404": + description: Failed to find database/user in metadata database. content: application/json: schema: @@ -2164,8 +2157,8 @@ paths: application/json: schema: $ref: "#/components/schemas/ViewBriefDto" - "503": - description: Failed to save in search service + "423": + description: Create view resulted in an invalid query statement content: application/json: schema: @@ -2176,8 +2169,8 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Create view query is malformed + "503": + description: Failed to save in search service content: application/json: schema: @@ -2188,8 +2181,14 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Failed to find database/user in metadata database. + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Create view query is malformed content: application/json: schema: @@ -2220,12 +2219,6 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Database could not be found - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "200": description: List tables content: @@ -2234,6 +2227,12 @@ paths: type: array items: $ref: "#/components/schemas/TableBriefDto" + "404": + description: Database could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" security: - bearerAuth: [] - basicAuth: [] @@ -2257,24 +2256,12 @@ paths: $ref: "#/components/schemas/CreateTableDto" required: true responses: - "403": - description: Create table not permitted - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "502": - description: Connection to search service failed + "400": + description: Create table query is malformed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "201": - description: Created a new table - content: - application/json: - schema: - $ref: "#/components/schemas/TableBriefDto" "409": description: Create table conflicts with existing table name content: @@ -2287,14 +2274,26 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" + "201": + description: Created a new table + content: + application/json: + schema: + $ref: "#/components/schemas/TableBriefDto" "404": description: "Database, container or user could not be found" content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "400": - description: Create table query is malformed + "403": + description: Create table not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed content: application/json: schema: @@ -2338,6 +2337,12 @@ paths: $ref: "#/components/schemas/CreateContainerDto" required: true responses: + "409": + description: Container name already exists + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" "403": description: "Create container not permitted, need authority `create-container`" content: @@ -2356,12 +2361,6 @@ paths: application/json: schema: $ref: "#/components/schemas/ContainerDto" - "409": - description: Container name already exists - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "404": description: Container image or user could not be found content: @@ -2437,26 +2436,26 @@ paths: schema: type: string responses: - "400": - description: Filter params are invalid + "200": + description: Found entities content: application/json: schema: - $ref: "#/components/schemas/ApiErrorDto" + type: array + items: + $ref: "#/components/schemas/EntityDto" "417": description: Generated query or uri is malformed content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "200": - description: Found entities + "400": + description: Filter params are invalid content: application/json: schema: - type: array - items: - $ref: "#/components/schemas/EntityDto" + $ref: "#/components/schemas/ApiErrorDto" "404": description: Could not find ontology content: @@ -2506,18 +2505,18 @@ 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" + "404": + description: Could not find message + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" /api/license: get: tags: @@ -2549,18 +2548,18 @@ paths: schema: type: string responses: - "404": - description: Failed to find metadata for identifier - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "200": description: Retrieved metadata from identifier content: application/json: schema: $ref: "#/components/schemas/IdentifierDto" + "404": + description: Failed to find metadata for identifier + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" /api/database/{databaseId}: get: tags: @@ -2576,18 +2575,6 @@ paths: type: string format: uuid responses: - "403": - description: Not allowed to view database - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Database could not be found - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "200": description: Database found successfully headers: @@ -2604,6 +2591,18 @@ paths: application/json: schema: $ref: "#/components/schemas/DatabaseBriefDto" + "404": + description: Database could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Not allowed to view database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" security: - bearerAuth: [] - basicAuth: [] @@ -2635,12 +2634,6 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "417": - description: Generated query is malformed - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" "200": description: Suggested table semantics successfully content: @@ -2649,8 +2642,8 @@ paths: type: array items: $ref: "#/components/schemas/EntityDto" - "422": - description: Ontology does not have rdf or sparql endpoint + "417": + description: Generated query is malformed content: application/json: schema: @@ -2667,6 +2660,12 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" + "422": + description: Ontology does not have rdf or sparql endpoint + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" security: - bearerAuth: [] - basicAuth: [] @@ -2703,6 +2702,12 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find database/table in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" "200": description: Suggested table column semantics successfully content: @@ -2717,12 +2722,6 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "404": - description: Failed to find database/table in metadata database - content: - application/json: - schema: - $ref: "#/components/schemas/ApiErrorDto" security: - bearerAuth: [] - basicAuth: [] @@ -2773,14 +2772,14 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Deleted container "403": description: "Create container not permitted, need authority `delete-container`" content: application/json: schema: $ref: "#/components/schemas/ApiErrorDto" - "202": - description: Deleted container security: - bearerAuth: [] - basicAuth: [] @@ -2802,59 +2801,6 @@ paths: $ref: "#/components/schemas/ConceptDto" components: schemas: - 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 ApiErrorDto: required: - code @@ -2941,6 +2887,59 @@ components: 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 CreatorBriefDto: required: - creator_name @@ -4750,6 +4749,7 @@ components: - id - language - licenses + - links - owner - publication_year - publisher @@ -4765,6 +4765,8 @@ components: type: string format: uuid example: b97cd56b-66ca-4354-9e6c-f47210cfaaec + links: + $ref: "#/components/schemas/LinksDto" type: type: string example: database @@ -5078,6 +5080,21 @@ components: award_title: type: string example: EOSC-Life + LinksDto: + required: + - self + - self_html + type: object + properties: + self: + type: string + example: http://example.com/api/ + data: + type: string + example: http://example.com + self_html: + type: string + example: http://example.com RelatedIdentifierDto: required: - id @@ -6371,14 +6388,14 @@ components: type: string resumptionToken: type: string - parametersString: - type: string fromDate: type: string format: date-time untilDate: type: string format: date-time + parametersString: + type: string BannerMessageDto: required: - id diff --git a/.docs/.openapi/api.yaml b/.docs/.openapi/api.yaml index 883a0efffe0d6959a2453e61f01e087e9bc0cf22..0fcd84503c6bd92530804d6e3e02242fe205d689 100644 --- a/.docs/.openapi/api.yaml +++ b/.docs/.openapi/api.yaml @@ -186,6 +186,11 @@ paths: schema: type: string format: date-time + - name: Accept + in: header + required: true + schema: + type: string responses: '200': description: Retrieved view data @@ -202,6 +207,7 @@ paths: application/json: schema: type: string + text/csv: {} '400': description: Request pagination is malformed content: @@ -220,6 +226,12 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' + '406': + description: Failed to format data + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' '409': description: View schema could not be mapped content: @@ -274,6 +286,11 @@ paths: schema: type: string format: date-time + - name: Accept + in: header + required: true + schema: + type: string responses: '200': description: Retrieved view data @@ -290,6 +307,7 @@ paths: application/json: schema: type: string + text/csv: {} '400': description: Request pagination is malformed content: @@ -308,6 +326,12 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' + '406': + description: Failed to format data + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' '409': description: View schema could not be mapped content: @@ -365,6 +389,11 @@ paths: schema: type: integer format: int64 + - name: Accept + in: header + required: true + schema: + type: string responses: '200': description: Get table data @@ -381,6 +410,7 @@ paths: application/json: schema: type: string + text/csv: {} '400': description: Request pagination or table data select query is malformed content: @@ -399,6 +429,12 @@ 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 establish connection with the metadata service content: @@ -640,6 +676,11 @@ paths: schema: type: integer format: int64 + - name: Accept + in: header + required: true + schema: + type: string responses: '200': description: Get table data @@ -656,6 +697,7 @@ paths: application/json: schema: type: string + text/csv: {} '400': description: Request pagination or table data select query is malformed content: @@ -674,6 +716,12 @@ 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 establish connection with the metadata service content: @@ -708,6 +756,11 @@ paths: schema: type: string format: uuid + - name: Accept + in: header + required: true + schema: + type: string - name: timestamp in: query required: false @@ -748,6 +801,7 @@ paths: application/json: schema: type: string + text/csv: {} '400': description: Invalid pagination content: @@ -768,6 +822,12 @@ 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: @@ -801,6 +861,11 @@ paths: schema: type: string format: uuid + - name: Accept + in: header + required: true + schema: + type: string - name: timestamp in: query required: false @@ -841,6 +906,7 @@ paths: application/json: schema: type: string + text/csv: {} '400': description: Invalid pagination content: @@ -861,6 +927,12 @@ 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: @@ -1164,6 +1236,12 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' + '406': + description: Failed to format data + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' '417': description: Failed to insert query into query store of data database content: @@ -1185,70 +1263,6 @@ paths: security: - basicAuth: [] - bearerAuth: [] - '/api/database/{databaseId}/view/{viewId}/export': - get: - tags: - - view-endpoint - summary: Get view data - description: >- - Gets data from view with id as downloadable file. For tables in private - databases, the user needs to have at least *READ* access to the - associated database. - operationId: exportDataset - parameters: - - name: databaseId - in: path - required: true - schema: - type: string - format: uuid - - name: viewId - in: path - required: true - schema: - type: string - format: uuid - - name: timestamp - in: query - required: false - schema: - type: string - format: date-time - responses: - '200': - description: Exported view data - content: - application/json: - schema: - type: string - format: binary - '400': - description: Request pagination or view data select query is malformed - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' - '403': - description: Export view data not allowed - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' - '404': - description: Failed to find view in metadata database or export dataset - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' - '503': - description: Failed to establish connection with the metadata service - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' - security: - - basicAuth: [] - - bearerAuth: [] '/api/database/{databaseId}/table/{tableId}/history': get: tags: @@ -1314,70 +1328,6 @@ paths: security: - basicAuth: [] - bearerAuth: [] - '/api/database/{databaseId}/table/{tableId}/export': - get: - tags: - - table-endpoint - summary: Get table data - description: >- - Gets data from table with id as downloadable file. For tables in private - databases, the user needs to have at least *READ* access to the - associated database. - operationId: exportDataset_1 - parameters: - - name: databaseId - in: path - required: true - schema: - type: string - format: uuid - - name: tableId - in: path - required: true - schema: - type: string - format: uuid - - name: timestamp - in: query - required: false - schema: - type: string - format: date-time - responses: - '200': - description: Exported table data - content: - application/json: - schema: - type: string - format: binary - '400': - description: Request pagination or table data select query is malformed - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' - '403': - description: Export table data not allowed - 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' - '503': - description: Failed to establish connection with the metadata service - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' - security: - - basicAuth: [] - - bearerAuth: [] '/api/database/{databaseId}/subset/{subsetId}': get: tags: @@ -1403,11 +1353,6 @@ paths: schema: type: string format: uuid - - name: Accept - in: header - required: true - schema: - type: string - name: timestamp in: query required: false @@ -2282,7 +2227,6 @@ paths: application/ld+json: schema: $ref: '#/components/schemas/LdDatasetDto' - text/csv: {} text/xml: {} text/bibliography: {} text/bibliography; style=apa: {} @@ -5332,6 +5276,7 @@ components: - id - language - licenses + - links - owner - publication_year - publisher @@ -5347,6 +5292,8 @@ components: type: string format: uuid example: b97cd56b-66ca-4354-9e6c-f47210cfaaec + links: + $ref: '#/components/schemas/LinksDto' type: type: string example: database @@ -5681,6 +5628,21 @@ 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 + type: object + properties: + self: + type: string + example: 'http://example.com/api/' + data: + type: string + example: 'http://example.com' + self_html: + type: string + example: 'http://example.com' RelatedIdentifierDto: required: - id @@ -8414,14 +8376,14 @@ components: type: string resumptionToken: type: string - parametersString: - type: string fromDate: type: string format: date-time untilDate: type: string format: date-time + parametersString: + type: string BannerMessageDto: required: - id diff --git a/.docs/changelog.md b/.docs/changelog.md index 8c114c004061347b51db487ddafdae19a57721fe..941b3ccc59758e4bf709514ac296b738e13158cc 100644 --- a/.docs/changelog.md +++ b/.docs/changelog.md @@ -2,18 +2,20 @@ author: Martin Weise --- -## v1.7.1 (2025-03-04) - -#### Fixes - -* Fixed a bug where quick interaction with the UI caused the user to trigger the brute-force login detection - in [#501](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/501). +## v1.7.1 (2025-03-06) #### Features +* Added support to download `pandas` DataFrame by PID + in [#503](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/503). * Added the possibility to create and fill a table from a `pandas` DataFrame (or optionally just create the schema) in [#496](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/496). +#### Fixes + +* Fixed a bug where quick interaction with the UI caused the user to trigger the brute-force login detection + in [#501](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/501). + ## v1.7.0 (2025-03-03) [:simple-gitlab: GitLab Release](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/tags/v1.7.1) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8439dc1b4c2f24a8ca07f136b0afdd15fba26042..5dd7139b4565d5d70ebe3bf129429b064b47b074 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -232,7 +232,9 @@ build-images: - "apk add --no-cache make" - echo "$CI_REGISTRY_PASSWORD" | docker login --username "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY_URL script: - - "make build-images" + - 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 compose build -q --parallel build-helm: image: docker.io/docker:${DOCKER_VERSION}-dind diff --git a/dbrepo-analyse-service/Pipfile.lock b/dbrepo-analyse-service/Pipfile.lock index 94704d5c24469e8669f7037f90a622361f87a2cb..995400fd16e50f79ff7fe5b0b4114ef6c407041e 100644 --- a/dbrepo-analyse-service/Pipfile.lock +++ b/dbrepo-analyse-service/Pipfile.lock @@ -425,7 +425,7 @@ }, "dbrepo": { "hashes": [ - "sha256:4f5ee48e9a68a44c2d1184923b90729d724553862742738d8f942273a586eb3d" + "sha256:e70ea4f7030191eb80116e5d0a4b17b041c94c80359d5d8e707d62218edd9a54" ], "path": "./lib/dbrepo-1.7.1.tar.gz" }, diff --git a/dbrepo-analyse-service/lib/dbrepo-1.7.1-py3-none-any.whl b/dbrepo-analyse-service/lib/dbrepo-1.7.1-py3-none-any.whl index 8e77c6e1f6a01b3d9739280f29539985c359d2c8..61f52896c18ecbec8090177b38b8dbaeb0e1a95e 100644 Binary files a/dbrepo-analyse-service/lib/dbrepo-1.7.1-py3-none-any.whl and b/dbrepo-analyse-service/lib/dbrepo-1.7.1-py3-none-any.whl differ diff --git a/dbrepo-analyse-service/lib/dbrepo-1.7.1.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.7.1.tar.gz index ede846d6168615c3e3bac49872362163b0a9f005..6708e1d892771d6cdf9293a6e9f5197f4dd9e304 100644 Binary files a/dbrepo-analyse-service/lib/dbrepo-1.7.1.tar.gz and b/dbrepo-analyse-service/lib/dbrepo-1.7.1.tar.gz differ diff --git a/dbrepo-auth-service/listeners/target/create-event-listener.jar b/dbrepo-auth-service/listeners/target/create-event-listener.jar index b117c50b6646de91273c95dc5749cd54868012be..77b988f95baa69b04c7fa4fa6f9737335eef2711 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/Dockerfile b/dbrepo-dashboard-service/Dockerfile index e4d9d8f5056d01714c0fc15c3840f8bf05cac921..d5f64a82fb40c8823bbb7d0e5f8ac0a5426ce888 100644 --- a/dbrepo-dashboard-service/Dockerfile +++ b/dbrepo-dashboard-service/Dockerfile @@ -4,6 +4,5 @@ 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-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 7ca50f8aa864f88bd75d873c93e9caa736fde258..9ef410b0b681776fa53f51969b652cb0ca816308 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 @@ -11,7 +11,6 @@ import at.tuwien.api.error.ApiErrorDto; import at.tuwien.exception.*; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.mapper.MariaDbMapper; -import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.CacheService; import at.tuwien.service.DatabaseService; import at.tuwien.service.StorageService; @@ -33,10 +32,7 @@ import lombok.extern.log4j.Log4j2; import org.apache.spark.sql.Dataset; import org.apache.spark.sql.Row; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; +import org.springframework.http.*; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; @@ -44,7 +40,6 @@ import java.security.Principal; import java.sql.SQLException; import java.time.Instant; import java.util.List; -import java.util.Map; import java.util.UUID; @Log4j2 @@ -56,7 +51,6 @@ public class SubsetEndpoint extends RestEndpoint { private final CacheService cacheService; private final MariaDbMapper mariaDbMapper; private final SubsetService subsetService; - private final MetadataMapper metadataMapper; private final StorageService storageService; private final DatabaseService databaseService; private final EndpointValidator endpointValidator; @@ -64,12 +58,11 @@ public class SubsetEndpoint extends RestEndpoint { @Autowired public SubsetEndpoint(CacheService cacheService, MariaDbMapper mariaDbMapper, SubsetService subsetService, - MetadataMapper metadataMapper, StorageService storageService, DatabaseService databaseService, + StorageService storageService, DatabaseService databaseService, EndpointValidator endpointValidator, MetadataServiceGateway metadataServiceGateway) { this.cacheService = cacheService; this.mariaDbMapper = mariaDbMapper; this.subsetService = subsetService; - this.metadataMapper = metadataMapper; this.storageService = storageService; this.databaseService = databaseService; this.endpointValidator = endpointValidator; @@ -162,14 +155,12 @@ public class SubsetEndpoint extends RestEndpoint { }) public ResponseEntity<?> findById(@NotNull @PathVariable("databaseId") UUID databaseId, @NotNull @PathVariable("subsetId") UUID subsetId, - @NotNull @RequestHeader("Accept") String accept, @RequestParam(required = false) Instant timestamp, Principal principal) throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, - QueryNotFoundException, FormatNotAvailableException, StorageUnavailableException, UserNotFoundException, - MetadataServiceException, TableNotFoundException, QueryMalformedException, NotAllowedException { - log.debug("endpoint find subset in database, databaseId={}, subsetId={}, accept={}, timestamp={}", databaseId, - subsetId, accept, timestamp); + QueryNotFoundException, UserNotFoundException, MetadataServiceException, NotAllowedException { + log.debug("endpoint find subset in database, databaseId={}, subsetId={}, timestamp={}", databaseId, + subsetId, timestamp); final DatabaseDto database = cacheService.getDatabase(databaseId); endpointValidator.validateOnlyPrivateSchemaAccess(database, principal); final QueryDto subset; @@ -185,27 +176,7 @@ public class SubsetEndpoint extends RestEndpoint { timestamp = Instant.now(); log.debug("timestamp not set: default to {}", timestamp); } - if (accept == null || accept.isBlank()) { - accept = MediaType.APPLICATION_JSON_VALUE; - log.debug("accept header not set: default to {}", accept); - } - switch (accept) { - case MediaType.APPLICATION_JSON_VALUE: - log.trace("accept header matches json"); - return ResponseEntity.ok(subset); - case "text/csv": - log.trace("accept header matches csv"); - final String query = mariaDbMapper.rawSelectQuery(subset.getQuery(), timestamp, null, null); - final Dataset<Row> dataset = subsetService.getData(database, query); - final ExportResourceDto resource = storageService.transformDataset(dataset); - final HttpHeaders headers = new HttpHeaders(); - headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\""); - log.trace("export table resulted in resource {}", resource); - return ResponseEntity.ok() - .headers(headers) - .body(resource.getResource()); - } - throw new FormatNotAvailableException("Must provide either application/json or text/csv value for header 'Accept': provided " + accept + " instead"); + return ResponseEntity.ok(subset); } @PostMapping @@ -234,6 +205,11 @@ public class SubsetEndpoint extends RestEndpoint { content = {@Content( mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), + @ApiResponse(responseCode = "406", + description = "Failed to format data", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), @ApiResponse(responseCode = "417", description = "Failed to insert query into query store of data database", content = {@Content( @@ -250,18 +226,18 @@ public class SubsetEndpoint extends RestEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<List<Map<String, Object>>> create(@NotNull @PathVariable("databaseId") UUID databaseId, - @Valid @RequestBody SubsetDto data, - Principal principal, - @NotNull HttpServletRequest request, - @RequestParam(required = false) Instant timestamp, - @RequestParam(required = false) Long page, - @RequestParam(required = false) Long size) + public ResponseEntity<?> create(@NotNull @PathVariable("databaseId") UUID databaseId, + @Valid @RequestBody SubsetDto data, + Principal principal, + @NotNull HttpServletRequest request, + @RequestParam(required = false) Instant timestamp, + @RequestParam(required = false) Long page, + @RequestParam(required = false) Long size) throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, QueryNotFoundException, StorageUnavailableException, QueryMalformedException, StorageNotFoundException, QueryStoreInsertException, TableMalformedException, PaginationException, QueryNotSupportedException, NotAllowedException, UserNotFoundException, MetadataServiceException, TableNotFoundException, - ViewMalformedException, ViewNotFoundException, ImageNotFoundException { + ViewMalformedException, ViewNotFoundException, ImageNotFoundException, FormatNotAvailableException { log.debug("endpoint create subset in database, databaseId={}, page={}, size={}, timestamp={}", databaseId, page, size, timestamp); /* check */ @@ -291,7 +267,7 @@ public class SubsetEndpoint extends RestEndpoint { endpointValidator.validateOnlyPrivateSchemaAccess(database, principal); try { final UUID subsetId = subsetService.create(database, data, timestamp, userId); - return getData(databaseId, subsetId, principal, request, timestamp, page, size); + return getData(databaseId, subsetId, principal, "application/json", request, timestamp, page, size); } catch (SQLException e) { log.error("Failed to establish connection to database: {}", e.getMessage()); throw new DatabaseUnavailableException("Failed to establish connection to database: " + e.getMessage(), e); @@ -312,7 +288,8 @@ public class SubsetEndpoint extends RestEndpoint { @Header(name = "Access-Control-Expose-Headers", description = "Reverse proxy exposing of custom headers", schema = @Schema(implementation = String.class), required = true)}, content = {@Content( mediaType = "application/json", - schema = @Schema(implementation = List.class))}), + schema = @Schema(implementation = List.class)), + @Content(mediaType = "text/csv")}), @ApiResponse(responseCode = "400", description = "Invalid pagination", content = {@Content( @@ -328,24 +305,31 @@ public class SubsetEndpoint extends RestEndpoint { content = {@Content( mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), + @ApiResponse(responseCode = "406", + description = "Failed to format data", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), @ApiResponse(responseCode = "503", description = "Failed to communicate with database", content = {@Content( mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<List<Map<String, Object>>> getData(@NotNull @PathVariable("databaseId") UUID databaseId, - @NotNull @PathVariable("subsetId") UUID subsetId, - Principal principal, - @NotNull HttpServletRequest request, - @RequestParam(required = false) Instant timestamp, - @RequestParam(required = false) Long page, - @RequestParam(required = false) Long size) + public ResponseEntity<?> getData(@NotNull @PathVariable("databaseId") UUID databaseId, + @NotNull @PathVariable("subsetId") UUID subsetId, + Principal principal, + @NotNull @RequestHeader("Accept") String accept, + @NotNull HttpServletRequest request, + @RequestParam(required = false) Instant timestamp, + @RequestParam(required = false) Long page, + @RequestParam(required = false) Long size) throws PaginationException, DatabaseNotFoundException, RemoteUnavailableException, NotAllowedException, QueryNotFoundException, DatabaseUnavailableException, QueryMalformedException, UserNotFoundException, - MetadataServiceException, TableNotFoundException, ViewNotFoundException, ViewMalformedException { - log.debug("endpoint get subset data, databaseId={}, subsetId={}, principal.name={} page={}, size={}", - databaseId, subsetId, principal != null ? principal.getName() : null, page, size); + MetadataServiceException, TableNotFoundException, ViewNotFoundException, ViewMalformedException, + FormatNotAvailableException, StorageUnavailableException { + log.debug("endpoint get subset data, databaseId={}, subsetId={}, accept={} page={}, size={}", databaseId, + subsetId, accept, page, size); endpointValidator.validateDataParams(page, size); final DatabaseDto database = cacheService.getDatabase(databaseId); if (!database.getIsPublic()) { @@ -353,7 +337,9 @@ public class SubsetEndpoint extends RestEndpoint { log.error("Failed to re-execute query: no authentication found"); throw new NotAllowedException("Failed to re-execute query: no authentication found"); } - cacheService.getAccess(databaseId, getId(principal)); + if (!isSystem(principal)) { + cacheService.getAccess(databaseId, getId(principal)); + } } log.trace("visibility for database: is_public={}, is_schema_public={}", database.getIsPublic(), database.getIsSchemaPublic()); /* parameters */ @@ -369,6 +355,10 @@ public class SubsetEndpoint extends RestEndpoint { timestamp = Instant.now(); log.debug("timestamp not set: default to {}", timestamp); } + if (accept == null || accept.isBlank()) { + accept = MediaType.APPLICATION_JSON_VALUE; + log.debug("accept header not set: default to {}", accept); + } try { final HttpHeaders headers = new HttpHeaders(); headers.set("X-Id", "" + subsetId); @@ -382,16 +372,32 @@ public class SubsetEndpoint extends RestEndpoint { .build(); } subset.setIdentifiers(metadataServiceGateway.getIdentifiers(database.getId(), subset.getId())); - final String query = mariaDbMapper.rawSelectQuery(subset.getQuery(), timestamp, page, size); + final String query = mariaDbMapper.rawSelectQuery(subset.getQuery(), timestamp, + accept.equals("text/csv") ? null : page, + accept.equals("text/csv") ? null : size); final Dataset<Row> dataset = subsetService.getData(database, query); - final String viewName = metadataMapper.queryDtoToViewName(subset); + final String viewName = subset.getQueryHash(); databaseService.createView(database, viewName, subset.getQuery()); final ViewDto view = databaseService.inspectView(database, viewName); headers.set("Access-Control-Expose-Headers", "X-Id X-Headers"); headers.set("X-Headers", String.join(",", view.getColumns().stream().map(ViewColumnDto::getInternalName).toList())); - return ResponseEntity.status(request.getMethod().equals("POST") ? HttpStatus.CREATED : HttpStatus.OK) - .headers(headers) - .body(transform(dataset)); + final HttpStatusCode statusCode = request.getMethod().equals("POST") ? HttpStatus.CREATED : HttpStatus.OK; + switch (accept) { + case MediaType.APPLICATION_JSON_VALUE: + log.trace("accept header matches json"); + return ResponseEntity.status(statusCode) + .headers(headers) + .body(transform(dataset)); + case "text/csv": + log.trace("accept header matches csv"); + final ExportResourceDto resource = storageService.transformDataset(dataset); + headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\""); + return ResponseEntity.status(statusCode) + .headers(headers) + .body(storageService.transformDataset(dataset) + .getResource()); + } + throw new FormatNotAvailableException("Must provide either application/json or text/csv value for header 'Accept': provided " + accept + " instead"); } catch (SQLException e) { log.error("Failed to establish connection to database: {}", e.getMessage()); throw new DatabaseUnavailableException("Failed to establish connection to database: " + e.getMessage(), e); 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 6914726cb84a886d97210dce9f1f60ac19db53b5..8e1fef5bac3d5451b0938f337e623d7e0e39ab56 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 @@ -29,9 +29,9 @@ import lombok.extern.log4j.Log4j2; import org.apache.spark.sql.Dataset; import org.apache.spark.sql.Row; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.io.InputStreamResource; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; @@ -40,7 +40,6 @@ import java.security.Principal; import java.sql.SQLException; import java.time.Instant; import java.util.List; -import java.util.Map; import java.util.UUID; @Log4j2 @@ -228,7 +227,8 @@ public class TableEndpoint extends RestEndpoint { @Header(name = "Access-Control-Expose-Headers", description = "Expose `X-Count` custom header", schema = @Schema(implementation = String.class), required = true)}, content = {@Content( mediaType = "application/json", - schema = @Schema(implementation = List.class))}), + schema = @Schema(implementation = List.class)), + @Content(mediaType = "text/csv")}), @ApiResponse(responseCode = "400", description = "Request pagination or table data select query is malformed", content = {@Content( @@ -244,23 +244,30 @@ public class TableEndpoint extends RestEndpoint { content = {@Content( mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), + @ApiResponse(responseCode = "406", + description = "Failed to format data", + 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<List<Map<String, Object>>> getData(@NotNull @PathVariable("databaseId") UUID databaseId, - @NotNull @PathVariable("tableId") UUID tableId, - @RequestParam(required = false) Instant timestamp, - @RequestParam(required = false) Long page, - @RequestParam(required = false) Long size, - @NotNull HttpServletRequest request, - Principal principal) + public ResponseEntity<?> getData(@NotNull @PathVariable("databaseId") UUID databaseId, + @NotNull @PathVariable("tableId") UUID tableId, + @RequestParam(required = false) Instant timestamp, + @RequestParam(required = false) Long page, + @RequestParam(required = false) Long size, + @NotNull @RequestHeader("Accept") String accept, + @NotNull HttpServletRequest request, + Principal principal) throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, - PaginationException, MetadataServiceException, NotAllowedException, DatabaseNotFoundException { - log.debug("endpoint get table data, databaseId={}, tableId={}, timestamp={}, page={}, size={}", databaseId, - tableId, timestamp, page, size); + PaginationException, MetadataServiceException, NotAllowedException, DatabaseNotFoundException, + FormatNotAvailableException, StorageUnavailableException { + log.debug("endpoint get table data, databaseId={}, tableId={}, timestamp={}, page={}, size={}, accept={}", + databaseId, tableId, timestamp, page, size, accept); endpointValidator.validateDataParams(page, size); /* parameters */ if (page == null) { @@ -281,7 +288,9 @@ public class TableEndpoint extends RestEndpoint { log.error("Failed find table data: authentication required"); throw new NotAllowedException("Failed to find table data: authentication required"); } - cacheService.getAccess(databaseId, getId(principal)); + if (!isSystem(principal)) { + cacheService.getAccess(databaseId, getId(principal)); + } } final DatabaseDto database = cacheService.getDatabase(databaseId); try { @@ -296,11 +305,26 @@ public class TableEndpoint extends RestEndpoint { headers.set("Access-Control-Expose-Headers", "X-Headers"); headers.set("X-Headers", String.join(",", table.getColumns().stream().map(ColumnDto::getInternalName).toList())); final String query = mariaDbMapper.defaultRawSelectQuery(database.getInternalName(), - table.getInternalName(), timestamp, page, size); + table.getInternalName(), timestamp, + accept.equals("text/csv") ? null : page, + accept.equals("text/csv") ? null : size); final Dataset<Row> dataset = subsetService.getData(database, query); - return ResponseEntity.ok() - .headers(headers) - .body(transform(dataset)); + switch (accept) { + case MediaType.APPLICATION_JSON_VALUE: + log.trace("accept header matches json"); + return ResponseEntity.ok() + .headers(headers) + .body(transform(dataset)); + case "text/csv": + log.trace("accept header matches csv"); + final ExportResourceDto resource = storageService.transformDataset(dataset); + headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\""); + return ResponseEntity.status(HttpStatus.OK) + .headers(headers) + .body(storageService.transformDataset(dataset) + .getResource()); + } + throw new FormatNotAvailableException("Must provide either application/json or text/csv value for header 'Accept': provided " + accept + " instead"); } catch (SQLException | QueryMalformedException e) { log.error("Failed to establish connection to database: {}", e.getMessage()); throw new DatabaseUnavailableException("Failed to establish connection to database: " + e.getMessage(), e); @@ -586,72 +610,6 @@ public class TableEndpoint extends RestEndpoint { } } - @GetMapping("/{tableId}/export") - @Observed(name = "dbrepo_table_data_export") - @Operation(summary = "Get table data", - description = "Gets data from table with id as downloadable file. For tables in private databases, the user needs to have at least *READ* access to the associated database.", - security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")}) - @ApiResponses(value = { - @ApiResponse(responseCode = "200", - description = "Exported table data", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = InputStreamResource.class))}), - @ApiResponse(responseCode = "400", - description = "Request pagination or table data select query is malformed", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = ApiErrorDto.class))}), - @ApiResponse(responseCode = "403", - description = "Export table data not allowed", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = ApiErrorDto.class))}), - @ApiResponse(responseCode = "404", - description = "Failed to find table in metadata database", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = ApiErrorDto.class))}), - @ApiResponse(responseCode = "503", - description = "Failed to establish connection with the metadata service", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = ApiErrorDto.class))}), - }) - public ResponseEntity<InputStreamResource> exportDataset(@NotNull @PathVariable("databaseId") UUID databaseId, - @NotNull @PathVariable("tableId") UUID tableId, - @RequestParam(required = false) Instant timestamp, - Principal principal) - throws RemoteUnavailableException, TableNotFoundException, NotAllowedException, StorageUnavailableException, - QueryMalformedException, MetadataServiceException, DatabaseNotFoundException { - log.debug("endpoint export table data, databaseId={}, tableId={}, timestamp={}", databaseId, tableId, timestamp); - /* parameters */ - if (timestamp == null) { - timestamp = Instant.now(); - log.debug("timestamp not set: default to {}", timestamp); - } - final TableDto table = cacheService.getTable(databaseId, tableId); - if (!table.getIsPublic()) { - if (principal == null) { - log.error("Failed to export private table: principal is null"); - throw new NotAllowedException("Failed to export private table: principal is null"); - } - cacheService.getAccess(databaseId, getId(principal)); - } - final DatabaseDto database = cacheService.getDatabase(databaseId); - final String query = mariaDbMapper.defaultRawSelectQuery(database.getInternalName(), - table.getInternalName(), timestamp, null, null); - final Dataset<Row> dataset = subsetService.getData(cacheService.getDatabase(table.getDatabaseId()), - query); - final ExportResourceDto resource = storageService.transformDataset(dataset); - final HttpHeaders headers = new HttpHeaders(); - headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\""); - log.trace("export table resulted in resource {}", resource); - return ResponseEntity.ok() - .headers(headers) - .body(resource.getResource()); - } - @PostMapping("/{tableId}/data/import") @Observed(name = "dbrepo_table_data_import") @PreAuthorize("hasAuthority('insert-table-data')") 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 5c1fdb57dbc30b428d104e4c145f4a0064105f78..b4c7fa715f667d7edf2727e7248af696266bf5e5 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 @@ -25,9 +25,9 @@ import lombok.extern.log4j.Log4j2; import org.apache.spark.sql.Dataset; import org.apache.spark.sql.Row; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.io.InputStreamResource; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; @@ -36,7 +36,6 @@ import java.security.Principal; import java.sql.SQLException; import java.time.Instant; import java.util.List; -import java.util.Map; import java.util.UUID; @Log4j2 @@ -225,7 +224,8 @@ public class ViewEndpoint extends RestEndpoint { @Header(name = "Access-Control-Expose-Headers", description = "Expose `X-Count` custom header", schema = @Schema(implementation = String.class), required = true)}, content = {@Content( mediaType = "application/json", - schema = @Schema(implementation = List.class))}), + schema = @Schema(implementation = List.class)), + @Content(mediaType = "text/csv")}), @ApiResponse(responseCode = "400", description = "Request pagination is malformed", content = {@Content( @@ -241,6 +241,11 @@ public class ViewEndpoint extends RestEndpoint { content = {@Content( mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), + @ApiResponse(responseCode = "406", + description = "Failed to format data", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), @ApiResponse(responseCode = "409", description = "View schema could not be mapped", content = {@Content( @@ -252,17 +257,20 @@ public class ViewEndpoint extends RestEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<List<Map<String, Object>>> getData(@NotNull @PathVariable("databaseId") UUID databaseId, - @NotNull @PathVariable("viewId") UUID viewId, - @RequestParam(required = false) Long page, - @RequestParam(required = false) Long size, - @RequestParam(required = false) Instant timestamp, - @NotNull HttpServletRequest request, - Principal principal) + public ResponseEntity<?> getData(@NotNull @PathVariable("databaseId") UUID databaseId, + @NotNull @PathVariable("viewId") UUID viewId, + @RequestParam(required = false) Long page, + @RequestParam(required = false) Long size, + @RequestParam(required = false) Instant timestamp, + @NotNull HttpServletRequest request, + @NotNull @RequestHeader("Accept") String accept, + Principal principal) throws DatabaseUnavailableException, RemoteUnavailableException, ViewNotFoundException, PaginationException, - QueryMalformedException, NotAllowedException, MetadataServiceException, TableNotFoundException, DatabaseNotFoundException { - log.debug("endpoint get view data, databaseId={}, viewId={}, page={}, size={}, timestamp={}", databaseId, - viewId, page, size, timestamp); + QueryMalformedException, NotAllowedException, MetadataServiceException, TableNotFoundException, + DatabaseNotFoundException, ViewMalformedException, StorageUnavailableException, + FormatNotAvailableException { + log.debug("endpoint get view data, databaseId={}, viewId={}, page={}, size={}, accept={}, timestamp={}", + databaseId, viewId, page, size, accept, timestamp); endpointValidator.validateDataParams(page, size); /* parameters */ if (page == null) { @@ -283,7 +291,9 @@ public class ViewEndpoint extends RestEndpoint { log.error("Failed to get data from view: unauthorized"); throw new NotAllowedException("Failed to get data from view: unauthorized"); } - cacheService.getAccess(databaseId, getId(principal)); + if (!isSystem(principal)) { + cacheService.getAccess(databaseId, getId(principal)); + } } final DatabaseDto database = cacheService.getDatabase(databaseId); try { @@ -297,84 +307,32 @@ public class ViewEndpoint extends RestEndpoint { } headers.set("Access-Control-Expose-Headers", "X-Headers"); headers.set("X-Headers", String.join(",", view.getColumns().stream().map(ViewColumnDto::getInternalName).toList())); - final String query = mariaDbMapper.defaultRawSelectQuery(database.getInternalName(), - view.getInternalName(), timestamp, page, size); - final Dataset<Row> dataset = subsetService.getData(cacheService.getDatabase(databaseId), - query); - return ResponseEntity.ok() - .headers(headers) - .body(transform(dataset)); + final String query = mariaDbMapper.rawSelectQuery(view.getQuery(), timestamp, + accept.equals("text/csv") ? null : page, + accept.equals("text/csv") ? null : size); + final Dataset<Row> dataset = subsetService.getData(database, query); + final String viewName = view.getQueryHash(); + databaseService.createView(database, viewName, view.getQuery()); + switch (accept) { + case MediaType.APPLICATION_JSON_VALUE: + log.trace("accept header matches json"); + return ResponseEntity.ok() + .headers(headers) + .body(transform(dataset)); + case "text/csv": + log.trace("accept header matches csv"); + final ExportResourceDto resource = storageService.transformDataset(dataset); + headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\""); + return ResponseEntity.ok() + .headers(headers) + .body(storageService.transformDataset(dataset) + .getResource()); + } + throw new FormatNotAvailableException("Must provide either application/json or text/csv value for header 'Accept': provided " + accept + " instead"); } catch (SQLException e) { log.error("Failed to establish connection to database: {}", e.getMessage()); throw new DatabaseUnavailableException("Failed to establish connection to database: " + e.getMessage(), e); } } - @GetMapping("/{viewId}/export") - @Observed(name = "dbrepo_view_data_export") - @Operation(summary = "Get view data", - description = "Gets data from view with id as downloadable file. For tables in private databases, the user needs to have at least *READ* access to the associated database.", - security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")}) - @ApiResponses(value = { - @ApiResponse(responseCode = "200", - description = "Exported view data", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = InputStreamResource.class))}), - @ApiResponse(responseCode = "400", - description = "Request pagination or view data select query is malformed", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = ApiErrorDto.class))}), - @ApiResponse(responseCode = "403", - description = "Export view data not allowed", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = ApiErrorDto.class))}), - @ApiResponse(responseCode = "404", - description = "Failed to find view in metadata database or export dataset", - 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<InputStreamResource> exportDataset(@NotNull @PathVariable("databaseId") UUID databaseId, - @NotNull @PathVariable("viewId") UUID viewId, - @RequestParam(required = false) Instant timestamp, - Principal principal) - throws RemoteUnavailableException, ViewNotFoundException, NotAllowedException, MetadataServiceException, - StorageUnavailableException, QueryMalformedException, TableNotFoundException, DatabaseNotFoundException { - log.debug("endpoint export view data, databaseId={}, viewId={}", databaseId, viewId); - /* parameters */ - if (timestamp == null) { - timestamp = Instant.now(); - log.debug("timestamp not set: default to {}", timestamp); - } - /* parameters */ - final ViewDto view = cacheService.getView(databaseId, viewId); - if (!view.getIsPublic()) { - if (principal == null) { - log.error("Failed to export private view: principal is null"); - throw new NotAllowedException("Failed to export private view: principal is null"); - } - cacheService.getAccess(databaseId, getId(principal)); - } - final DatabaseDto database = cacheService.getDatabase(databaseId); - final String query = mariaDbMapper.defaultRawSelectQuery(database.getInternalName(), - view.getInternalName(), timestamp, null, null); - final Dataset<Row> dataset = subsetService.getData(cacheService.getDatabase(databaseId), - query); - final ExportResourceDto resource = storageService.transformDataset(dataset); - final HttpHeaders headers = new HttpHeaders(); - headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\""); - log.trace("export table resulted in resource {}", resource); - return ResponseEntity.ok() - .headers(headers) - .body(resource.getResource()); - } - } 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 b5f592d570cb73677baaa00666af945901e1d256..53c0858bbd98acd3bb250b0def751534bc920548 100644 --- a/dbrepo-data-service/rest-service/src/main/resources/application.yml +++ b/dbrepo-data-service/rest-service/src/main/resources/application.yml @@ -74,6 +74,7 @@ dbrepo: 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}" minConcurrent: "${MIN_CONCURRENT_CONSUMERS:2}" maxConcurrent: "${MAX_CONCURRENT_CONSUMERS:6}" 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 9cdb0d99c82e399c1d8297c1c71dd1f6dd963a31..b034b791242dd92c640b0b721afa86a8197a7afd 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 @@ -33,7 +33,6 @@ import java.security.Principal; import java.sql.SQLException; import java.time.Instant; import java.util.List; -import java.util.Map; import java.util.UUID; import static org.junit.jupiter.api.Assertions.*; @@ -145,16 +144,15 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - generic_findById(DATABASE_1_ID, QUERY_1_ID, "application/json", null, null); + generic_findById(DATABASE_1_ID, QUERY_1_ID, null, null); }); } @Test @WithMockUser(username = USER_1_USERNAME) public void findById_privateDataPrivateSchema_succeeds() throws DatabaseNotFoundException, SQLException, - RemoteUnavailableException, UserNotFoundException, QueryNotFoundException, MetadataServiceException, - DatabaseUnavailableException, TableNotFoundException, StorageUnavailableException, NotAllowedException, - QueryMalformedException, FormatNotAvailableException { + RemoteUnavailableException, UserNotFoundException, DatabaseUnavailableException, NotAllowedException, + QueryNotFoundException, MetadataServiceException { /* mock */ when(credentialService.getDatabase(DATABASE_1_ID)) @@ -163,15 +161,14 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { .thenReturn(QUERY_1_DTO); /* test */ - generic_findById(DATABASE_1_ID, QUERY_1_ID, "application/json", null, USER_1_PRINCIPAL); + generic_findById(DATABASE_1_ID, QUERY_1_ID, null, USER_1_PRINCIPAL); } @Test @WithMockUser(username = USER_1_USERNAME) public void findById_privateDataPrivateSchemaAcceptEmpty_succeeds() throws DatabaseNotFoundException, SQLException, - RemoteUnavailableException, UserNotFoundException, QueryNotFoundException, MetadataServiceException, - DatabaseUnavailableException, TableNotFoundException, StorageUnavailableException, NotAllowedException, - QueryMalformedException, FormatNotAvailableException { + RemoteUnavailableException, UserNotFoundException, DatabaseUnavailableException, NotAllowedException, + QueryNotFoundException, MetadataServiceException { /* mock */ when(credentialService.getDatabase(DATABASE_1_ID)) @@ -180,15 +177,14 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { .thenReturn(QUERY_1_DTO); /* test */ - generic_findById(DATABASE_1_ID, QUERY_1_ID, null, null, USER_1_PRINCIPAL); + generic_findById(DATABASE_1_ID, QUERY_1_ID, null, USER_1_PRINCIPAL); } @Test @WithMockUser(username = USER_3_USERNAME) public void findById_publicDataPrivateSchema_succeeds() throws DatabaseNotFoundException, SQLException, RemoteUnavailableException, UserNotFoundException, DatabaseUnavailableException, NotAllowedException, - StorageUnavailableException, QueryMalformedException, QueryNotFoundException, - FormatNotAvailableException, TableNotFoundException, MetadataServiceException { + QueryNotFoundException, MetadataServiceException { /* mock */ when(credentialService.getDatabase(DATABASE_3_ID)) @@ -197,32 +193,15 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { .thenReturn(QUERY_5_DTO); /* test */ - generic_findById(DATABASE_3_ID, QUERY_5_ID, "application/json", null, USER_3_PRINCIPAL); - } - - @Test - @WithAnonymousUser - public void findById_format_fails() throws DatabaseNotFoundException, RemoteUnavailableException, SQLException, - UserNotFoundException, QueryNotFoundException, MetadataServiceException { - - /* mock */ - when(credentialService.getDatabase(DATABASE_4_ID)) - .thenReturn(DATABASE_4_PRIVILEGED_DTO); - when(subsetService.findById(DATABASE_4_PRIVILEGED_DTO, QUERY_7_ID)) - .thenReturn(QUERY_7_DTO); - - /* test */ - assertThrows(FormatNotAvailableException.class, () -> { - generic_findById(DATABASE_4_ID, QUERY_7_ID, "application/pdf", null, null); - }); + generic_findById(DATABASE_3_ID, QUERY_5_ID, null, USER_3_PRINCIPAL); } @Test @WithMockUser(username = USER_1_USERNAME) - public void findById_privateDataPrivateSchemaAcceptCsv_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, - UserNotFoundException, DatabaseUnavailableException, StorageUnavailableException, QueryMalformedException, - QueryNotFoundException, FormatNotAvailableException, SQLException, MetadataServiceException, - TableNotFoundException, NotAllowedException { + public void findById_privateDataPrivateSchemaAcceptCsv_succeeds() throws DatabaseNotFoundException, + RemoteUnavailableException, UserNotFoundException, DatabaseUnavailableException, + StorageUnavailableException, QueryMalformedException, QueryNotFoundException, SQLException, + MetadataServiceException, TableNotFoundException, NotAllowedException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); /* mock */ @@ -236,7 +215,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { .thenReturn(EXPORT_RESOURCE_DTO); /* test */ - generic_findById(DATABASE_1_ID, QUERY_1_ID, "text/csv", null, USER_1_PRINCIPAL); + generic_findById(DATABASE_1_ID, QUERY_1_ID, null, USER_1_PRINCIPAL); } @Test @@ -250,7 +229,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - generic_findById(DATABASE_3_ID, QUERY_5_ID, "text/csv", Instant.now(), null); + generic_findById(DATABASE_3_ID, QUERY_5_ID, Instant.now(), null); }); } @@ -273,7 +252,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - generic_findById(DATABASE_3_ID, QUERY_5_ID, "text/csv", Instant.now(), null); + generic_findById(DATABASE_3_ID, QUERY_5_ID, Instant.now(), null); }); } @@ -289,7 +268,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(DatabaseNotFoundException.class, () -> { - generic_findById(DATABASE_3_ID, QUERY_5_ID, "application/json", null, null); + generic_findById(DATABASE_3_ID, QUERY_5_ID, null, null); }); } @@ -307,7 +286,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(DatabaseUnavailableException.class, () -> { - generic_findById(DATABASE_3_ID, QUERY_5_ID, "application/json", null, USER_3_PRINCIPAL); + generic_findById(DATABASE_3_ID, QUERY_5_ID, null, USER_3_PRINCIPAL); }); } @@ -318,7 +297,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { StorageNotFoundException, DatabaseUnavailableException, StorageUnavailableException, SQLException, QueryMalformedException, QueryNotFoundException, DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException, TableNotFoundException, ViewMalformedException, ViewNotFoundException, - ImageNotFoundException { + ImageNotFoundException, FormatNotAvailableException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); /* mock */ @@ -348,7 +327,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { PaginationException, StorageNotFoundException, DatabaseUnavailableException, StorageUnavailableException, QueryMalformedException, QueryNotFoundException, DatabaseNotFoundException, RemoteUnavailableException, SQLException, MetadataServiceException, TableNotFoundException, ViewMalformedException, - ViewNotFoundException, ImageNotFoundException { + ViewNotFoundException, ImageNotFoundException, FormatNotAvailableException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); /* mock */ @@ -398,7 +377,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { TableMalformedException, NotAllowedException, SQLException, QueryNotFoundException, PaginationException, DatabaseUnavailableException, StorageUnavailableException, QueryMalformedException, QueryNotSupportedException, StorageNotFoundException, TableNotFoundException, ViewMalformedException, - ViewNotFoundException, ImageNotFoundException { + ViewNotFoundException, ImageNotFoundException, FormatNotAvailableException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); /* mock */ @@ -426,7 +405,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { NotAllowedException, SQLException, QueryNotFoundException, DatabaseUnavailableException, StorageUnavailableException, QueryMalformedException, QueryNotSupportedException, PaginationException, StorageNotFoundException, TableNotFoundException, ViewMalformedException, ViewNotFoundException, - ImageNotFoundException { + ImageNotFoundException, FormatNotAvailableException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); /* mock */ @@ -478,7 +457,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { public void getData_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, NotAllowedException, SQLException, QueryNotFoundException, QueryMalformedException, DatabaseUnavailableException, PaginationException, MetadataServiceException, TableNotFoundException, - ViewNotFoundException, ViewMalformedException { + ViewNotFoundException, ViewMalformedException, StorageUnavailableException, FormatNotAvailableException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); /* mock */ @@ -498,16 +477,17 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { .thenReturn("GET"); /* test */ - final ResponseEntity<List<Map<String, Object>>> response = subsetEndpoint.getData(DATABASE_3_ID, QUERY_5_ID, null, httpServletRequest, null, null, null); + final ResponseEntity<?> response = subsetEndpoint.getData(DATABASE_3_ID, QUERY_5_ID, + null, "application/json", httpServletRequest, null, null, null); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); } @Test public void getData_head_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, - UserNotFoundException, NotAllowedException, SQLException, QueryNotFoundException, TableMalformedException, - QueryMalformedException, DatabaseUnavailableException, PaginationException, MetadataServiceException, - TableNotFoundException, ViewNotFoundException, ViewMalformedException { + UserNotFoundException, NotAllowedException, SQLException, QueryNotFoundException, QueryMalformedException, + DatabaseUnavailableException, PaginationException, MetadataServiceException, TableNotFoundException, + ViewNotFoundException, ViewMalformedException, StorageUnavailableException, FormatNotAvailableException { /* mock */ when(credentialService.getDatabase(DATABASE_3_ID)) @@ -520,7 +500,8 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { .thenReturn("HEAD"); /* test */ - final ResponseEntity<List<Map<String, Object>>> response = subsetEndpoint.getData(DATABASE_3_ID, QUERY_5_ID, null, httpServletRequest, null, null, null); + final ResponseEntity<?> response = subsetEndpoint.getData(DATABASE_3_ID, QUERY_5_ID, + null, "application/json", httpServletRequest, null, null, null); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getHeaders().get("X-Count")); assertEquals(1, response.getHeaders().get("X-Count").size()); @@ -532,7 +513,8 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { public void getData_private_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, DatabaseUnavailableException, NotAllowedException, QueryMalformedException, QueryNotFoundException, PaginationException, SQLException, MetadataServiceException, - TableNotFoundException, ViewNotFoundException, ViewMalformedException { + TableNotFoundException, ViewNotFoundException, ViewMalformedException, StorageUnavailableException, + FormatNotAvailableException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); /* mock */ @@ -552,7 +534,8 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { .thenReturn("GET"); /* test */ - final ResponseEntity<List<Map<String, Object>>> response = subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, null, null, null); + final ResponseEntity<?> response = subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, + USER_1_PRINCIPAL, "application/json", httpServletRequest, null, null, null); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); } @@ -568,7 +551,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, null, httpServletRequest, null, null, null); + subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, null, "application/json", httpServletRequest, null, null, null); }); } @@ -586,7 +569,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, null, null, null); + subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, "application/json", httpServletRequest, null, null, null); }); } @@ -595,7 +578,8 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { public void getData_privateHead_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, DatabaseUnavailableException, NotAllowedException, QueryMalformedException, QueryNotFoundException, PaginationException, SQLException, MetadataServiceException, - TableNotFoundException, ViewNotFoundException, ViewMalformedException { + TableNotFoundException, ViewNotFoundException, ViewMalformedException, StorageUnavailableException, + FormatNotAvailableException { /* mock */ when(credentialService.getDatabase(DATABASE_1_ID)) @@ -608,7 +592,8 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { .thenReturn("HEAD"); /* test */ - final ResponseEntity<List<Map<String, Object>>> response = subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, null, null, null); + final ResponseEntity<?> response = subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, + USER_1_PRINCIPAL, "GET", httpServletRequest, null, null, null); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getHeaders().get("X-Count")); assertEquals(1, response.getHeaders().get("X-Count").size()); @@ -734,14 +719,12 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { return response.getBody(); } - protected void generic_findById(UUID databaseId, UUID subsetId, String accept, Instant timestamp, - Principal principal) throws UserNotFoundException, DatabaseUnavailableException, - StorageUnavailableException, NotAllowedException, QueryMalformedException, QueryNotFoundException, - DatabaseNotFoundException, RemoteUnavailableException, FormatNotAvailableException, - MetadataServiceException, TableNotFoundException { + protected void generic_findById(UUID databaseId, UUID subsetId, Instant timestamp, Principal principal) + throws UserNotFoundException, DatabaseUnavailableException, NotAllowedException, QueryNotFoundException, + DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException { /* test */ - final ResponseEntity<?> response = subsetEndpoint.findById(databaseId, subsetId, accept, timestamp, principal); + final ResponseEntity<?> response = subsetEndpoint.findById(databaseId, subsetId, timestamp, principal); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); } 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 25f3b60ceac1f47225e73c237cefc215c21f1696..3a5a62731bc595c2e971a382cf6c3a1c1b5791aa 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 @@ -39,7 +39,6 @@ import java.sql.SQLException; import java.time.Instant; import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.*; @@ -292,7 +291,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void getData_publicDataPrivateSchema_succeeds() throws DatabaseUnavailableException, TableNotFoundException, QueryMalformedException, RemoteUnavailableException, PaginationException, MetadataServiceException, NotAllowedException, - DatabaseNotFoundException { + DatabaseNotFoundException, StorageUnavailableException, FormatNotAvailableException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); /* mock */ @@ -306,7 +305,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { .thenReturn("GET"); /* test */ - final ResponseEntity<List<Map<String, Object>>> response = tableEndpoint.getData(DATABASE_1_ID, TABLE_4_ID, null, null, null, httpServletRequest, null); + final ResponseEntity<?> response = tableEndpoint.getData(DATABASE_1_ID, TABLE_4_ID, null, null, null, "application/json", httpServletRequest, null); assertEquals(HttpStatus.OK, response.getStatusCode()); } @@ -315,7 +314,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void getData_head_succeeds() throws DatabaseUnavailableException, TableNotFoundException, SQLException, QueryMalformedException, RemoteUnavailableException, PaginationException, - MetadataServiceException, NotAllowedException, DatabaseNotFoundException { + MetadataServiceException, NotAllowedException, DatabaseNotFoundException, StorageUnavailableException, FormatNotAvailableException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); /* mock */ @@ -331,7 +330,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { .thenReturn("HEAD"); /* test */ - final ResponseEntity<List<Map<String, Object>>> response = tableEndpoint.getData(DATABASE_2_ID, TABLE_5_ID, null, null, null, httpServletRequest, null); + final ResponseEntity<?> response = tableEndpoint.getData(DATABASE_2_ID, TABLE_5_ID, null, null, null, "application/json", httpServletRequest, null); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getHeaders().get("Access-Control-Expose-Headers")); assertEquals("X-Count", response.getHeaders().get("Access-Control-Expose-Headers").get(0)); @@ -351,7 +350,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - tableEndpoint.getData(DATABASE_1_ID, TABLE_1_ID, null, null, null, httpServletRequest, null); + tableEndpoint.getData(DATABASE_1_ID, TABLE_1_ID, null, null, null, "application/json", httpServletRequest, null); }); } @@ -369,14 +368,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - tableEndpoint.getData(DATABASE_1_ID, TABLE_1_ID, null, null, null, httpServletRequest, USER_2_PRINCIPAL); + tableEndpoint.getData(DATABASE_1_ID, TABLE_1_ID, null, null, null, "application/json", httpServletRequest, USER_2_PRINCIPAL); }); } @Test @WithAnonymousUser public void getData_notAllowed_fails() throws TableNotFoundException, RemoteUnavailableException, - MetadataServiceException{ + MetadataServiceException { /* mock */ when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) @@ -386,7 +385,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - tableEndpoint.getData(DATABASE_3_ID, TABLE_8_ID, null, null, null, httpServletRequest, null); + tableEndpoint.getData(DATABASE_3_ID, TABLE_8_ID, null, null, null, "application/json", httpServletRequest, null); }); } @@ -408,7 +407,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(DatabaseUnavailableException.class, () -> { - tableEndpoint.getData(DATABASE_2_ID, TABLE_5_ID, null, null, null, httpServletRequest, null); + tableEndpoint.getData(DATABASE_2_ID, TABLE_5_ID, null, null, null, "application/json", httpServletRequest, null); }); } @@ -426,7 +425,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(RemoteUnavailableException.class, () -> { - tableEndpoint.getData(DATABASE_1_ID, TABLE_1_ID, null, null, null, httpServletRequest, USER_2_PRINCIPAL); + tableEndpoint.getData(DATABASE_1_ID, TABLE_1_ID, null, null, null, "application/json", httpServletRequest, USER_2_PRINCIPAL); }); } @@ -435,7 +434,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @MethodSource("anyAccess_parameters") public void getData_private_succeeds(String name, DatabaseAccessDto access) throws DatabaseUnavailableException, TableNotFoundException, QueryMalformedException, RemoteUnavailableException, PaginationException, - MetadataServiceException, NotAllowedException, DatabaseNotFoundException { + MetadataServiceException, NotAllowedException, DatabaseNotFoundException, StorageUnavailableException, FormatNotAvailableException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); /* mock */ @@ -451,7 +450,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { .thenReturn("GET"); /* test */ - final ResponseEntity<List<Map<String, Object>>> response = tableEndpoint.getData(DATABASE_1_ID, TABLE_1_ID, null, null, null, httpServletRequest, USER_2_PRINCIPAL); + final ResponseEntity<?> response = tableEndpoint.getData(DATABASE_1_ID, TABLE_1_ID, null, null, null, "application/json", httpServletRequest, USER_2_PRINCIPAL); assertEquals(HttpStatus.OK, response.getStatusCode()); } @@ -467,7 +466,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(TableNotFoundException.class, () -> { - tableEndpoint.getData(DATABASE_3_ID, TABLE_8_ID, null, null, null, httpServletRequest, null); + tableEndpoint.getData(DATABASE_3_ID, TABLE_8_ID, null, null, null, "application/json", httpServletRequest, null); }); } @@ -1323,8 +1322,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser - public void exportData_publicDataPrivateSchema_succeeds() throws TableNotFoundException, NotAllowedException, StorageUnavailableException, - QueryMalformedException, RemoteUnavailableException, MetadataServiceException, DatabaseNotFoundException { + public void getData_publicDataPrivateSchemaTextCsv_succeeds() throws TableNotFoundException, NotAllowedException, + StorageUnavailableException, QueryMalformedException, RemoteUnavailableException, MetadataServiceException, + DatabaseNotFoundException, DatabaseUnavailableException, FormatNotAvailableException, PaginationException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); /* mock */ @@ -1334,18 +1334,21 @@ public class TableEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_1_PRIVILEGED_DTO); when(subsetService.getData(any(DatabaseDto.class), anyString())) .thenReturn(mock); + when(httpServletRequest.getMethod()) + .thenReturn("GET"); /* test */ - final ResponseEntity<InputStreamResource> response = tableEndpoint.exportDataset(DATABASE_1_ID, TABLE_4_ID, null, null); + final ResponseEntity<?> response = tableEndpoint.getData(DATABASE_1_ID, TABLE_4_ID, null, null, null, "text/csv", httpServletRequest, null); assertEquals(HttpStatus.OK, response.getStatusCode()); } @ParameterizedTest @WithMockUser(username = USER_2_USERNAME) @MethodSource("anyAccess_parameters") - public void exportData_privateDataPrivateSchema_succeeds(String name, DatabaseAccessDto access) + public void getData_privateDataPrivateSchemaTextCsv_succeeds(String name, DatabaseAccessDto access) throws TableNotFoundException, NotAllowedException, StorageUnavailableException, QueryMalformedException, - RemoteUnavailableException, MetadataServiceException, DatabaseNotFoundException { + RemoteUnavailableException, MetadataServiceException, DatabaseNotFoundException, + DatabaseUnavailableException, FormatNotAvailableException, PaginationException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); /* mock */ @@ -1359,9 +1362,11 @@ public class TableEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_1_DTO); when(subsetService.getData(any(DatabaseDto.class), anyString())) .thenReturn(mock); + when(httpServletRequest.getMethod()) + .thenReturn("GET"); /* test */ - final ResponseEntity<InputStreamResource> response = tableEndpoint.exportDataset(DATABASE_1_ID, TABLE_1_ID, null, USER_2_PRINCIPAL); + final ResponseEntity<?> response = tableEndpoint.getData(DATABASE_1_ID, TABLE_1_ID, null, null, null, "text/csv", httpServletRequest, USER_2_PRINCIPAL); assertEquals(HttpStatus.OK, response.getStatusCode()); } @@ -1381,7 +1386,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - tableEndpoint.exportDataset(DATABASE_1_ID, TABLE_1_ID, null, null); + tableEndpoint.getData(DATABASE_1_ID, TABLE_1_ID, null, null, null, "text/csv", httpServletRequest, null); }); } 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 0393be3dad8da280f29cc1be9133ffa42c9f6cb2..23ad1b73e3db99c355d08aa8011ab658fb48e728 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 @@ -29,7 +29,6 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import java.sql.SQLException; import java.time.Instant; import java.util.List; -import java.util.Map; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.anyString; @@ -253,7 +252,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_1_PRIVILEGED_DTO); doNothing() .when(viewService) - .delete(DATABASE_1_PRIVILEGED_DTO,VIEW_1_DTO); + .delete(DATABASE_1_PRIVILEGED_DTO, VIEW_1_DTO); /* test */ assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { @@ -281,7 +280,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"}) public void getData_privateDataPrivateSchema_succeeds() throws RemoteUnavailableException, ViewNotFoundException, DatabaseUnavailableException, QueryMalformedException, PaginationException, NotAllowedException, - MetadataServiceException, TableNotFoundException, DatabaseNotFoundException { + MetadataServiceException, TableNotFoundException, DatabaseNotFoundException, ViewMalformedException, StorageUnavailableException, FormatNotAvailableException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); /* mock */ @@ -297,7 +296,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { .thenReturn("GET"); /* test */ - final ResponseEntity<List<Map<String, Object>>> response = viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, USER_1_PRINCIPAL); + final ResponseEntity<?> response = viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, "application/json", USER_1_PRINCIPAL); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); } @@ -323,7 +322,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, null); + viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, "application/json", null); }); } @@ -331,7 +330,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"}) public void getData_privateHead_succeeds() throws RemoteUnavailableException, ViewNotFoundException, SQLException, DatabaseUnavailableException, QueryMalformedException, PaginationException, - NotAllowedException, MetadataServiceException, TableNotFoundException, DatabaseNotFoundException { + NotAllowedException, MetadataServiceException, TableNotFoundException, DatabaseNotFoundException, ViewMalformedException, StorageUnavailableException, FormatNotAvailableException { /* mock */ when(credentialService.getView(DATABASE_1_ID, VIEW_3_ID)) @@ -346,7 +345,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { .thenReturn(VIEW_3_DATA_COUNT); /* test */ - final ResponseEntity<List<Map<String, Object>>> response = viewEndpoint.getData(DATABASE_1_ID, VIEW_3_ID, null, null, null, httpServletRequest, USER_1_PRINCIPAL); + final ResponseEntity<?> response = viewEndpoint.getData(DATABASE_1_ID, VIEW_3_ID, null, null, null, httpServletRequest, "application/json", USER_1_PRINCIPAL); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getHeaders().get("X-Count")); assertEquals(1, response.getHeaders().get("X-Count").size()); @@ -373,13 +372,13 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, USER_4_PRINCIPAL); + viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, "application/json", USER_4_PRINCIPAL); }); } @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"}) - public void getData_viewNotFound_fails() throws RemoteUnavailableException, ViewNotFoundException, + public void getData_viewNotFoundTextCsv_fails() throws RemoteUnavailableException, ViewNotFoundException, MetadataServiceException { /* mock */ @@ -389,7 +388,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(ViewNotFoundException.class, () -> { - viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, USER_4_PRINCIPAL); + viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, "text/csv", USER_4_PRINCIPAL); }); } @@ -407,13 +406,13 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, USER_4_PRINCIPAL); + viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, "application/json", USER_4_PRINCIPAL); }); } @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"view-database-view-data"}) - public void exportDataset_privateNoAccess_fails() throws RemoteUnavailableException, ViewNotFoundException, + public void getData_privateNoAccessTextCsv_fails() throws RemoteUnavailableException, ViewNotFoundException, NotAllowedException, MetadataServiceException { /* mock */ @@ -425,13 +424,13 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - viewEndpoint.exportDataset(DATABASE_1_ID, VIEW_1_ID, null, USER_4_PRINCIPAL); + viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, "text/csv", USER_4_PRINCIPAL); }); } @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"}) - public void exportDataset_viewNotFound_fails() throws RemoteUnavailableException, ViewNotFoundException, + public void getData_viewNotFound_fails() throws RemoteUnavailableException, ViewNotFoundException, MetadataServiceException { /* mock */ @@ -441,25 +440,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(ViewNotFoundException.class, () -> { - viewEndpoint.exportDataset(DATABASE_1_ID, VIEW_1_ID, null, USER_4_PRINCIPAL); - }); - } - - @Test - @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"}) - public void exportDataset_privateNoAccess_succeeds() throws RemoteUnavailableException, ViewNotFoundException, - NotAllowedException, MetadataServiceException { - - /* mock */ - when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID)) - .thenReturn(VIEW_1_DTO); - doThrow(NotAllowedException.class) - .when(credentialService) - .getAccess(DATABASE_1_ID, USER_4_ID); - - /* test */ - assertThrows(NotAllowedException.class, () -> { - viewEndpoint.exportDataset(DATABASE_1_ID, VIEW_1_ID, null, USER_4_PRINCIPAL); + viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, "application/json", USER_4_PRINCIPAL); }); } 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 ae03fdbf68cefc1db05455d0ec228ea00be1c12f..de1c875e0aef96a54f283e31a8ef90d9e8468de0 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,8 +1,6 @@ package at.tuwien.mvc; -import at.tuwien.api.database.query.ExecuteStatementDto; import at.tuwien.api.database.query.ImportDto; -import at.tuwien.api.database.query.QueryDto; import at.tuwien.api.database.query.QueryPersistDto; import at.tuwien.api.database.table.TupleDeleteDto; import at.tuwien.api.database.table.TupleDto; @@ -116,7 +114,7 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest { /* ignore */ } try { - subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, null, 0L, 10L); + subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, "application/json", httpServletRequest, null, 0L, 10L); } catch (Exception e) { /* ignore */ } @@ -126,7 +124,7 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest { /* ignore */ } try { - subsetEndpoint.findById(DATABASE_1_ID, QUERY_1_ID, "application/json", null, USER_1_PRINCIPAL); + subsetEndpoint.findById(DATABASE_1_ID, QUERY_1_ID, null, USER_1_PRINCIPAL); } catch (Exception e) { /* ignore */ } @@ -145,7 +143,7 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest { /* mock */ try { - tableEndpoint.getData(DATABASE_1_ID, TABLE_1_ID, null, null, null, httpServletRequest, null); + tableEndpoint.getData(DATABASE_1_ID, TABLE_1_ID, null, null, null, "application/json", httpServletRequest, null); } catch (Exception e) { /* ignore */ } @@ -169,11 +167,6 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest { } catch (Exception e) { /* ignore */ } - try { - tableEndpoint.exportDataset(DATABASE_1_ID, TABLE_1_ID, null, USER_1_PRINCIPAL); - } catch (Exception e) { - /* ignore */ - } try { tableEndpoint.importDataset(DATABASE_1_ID, TABLE_1_ID, ImportDto.builder().build(), USER_1_PRINCIPAL, TOKEN_ACCESS_TOKEN); } catch (Exception e) { @@ -182,8 +175,7 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest { /* test */ for (String metric : List.of("dbrepo_table_data_list", "dbrepo_table_data_create", "dbrepo_table_data_update", - "dbrepo_table_data_delete", "dbrepo_table_data_history", "dbrepo_table_data_export", - "dbrepo_table_data_import")) { + "dbrepo_table_data_delete", "dbrepo_table_data_history", "dbrepo_table_data_import")) { assertThat(registry) .hasObservationWithNameEqualTo(metric); } @@ -195,7 +187,7 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest { /* mock */ try { - viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, 0L, 10L, null, httpServletRequest, USER_1_PRINCIPAL); + viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, 0L, 10L, null, httpServletRequest, "application/json", USER_1_PRINCIPAL); } catch (Exception e) { /* ignore */ } 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 158c6743a4e7bac049cae0211fe764030ab4a3f0..37f6d367dc125a155dcdb7ae85c9bdf30cc8c6a2 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 @@ -36,21 +36,6 @@ public class SubsetEndpointMvcTest extends AbstractUnitTest { @Autowired private MockMvc mockMvc; - @Test - public void findById_noAcceptHeader_fails() throws Exception { - - /* mock */ - when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID)) - .thenReturn(DATABASE_3_PRIVILEGED_DTO); - when(subsetService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID)) - .thenReturn(QUERY_5_DTO); - - /* test */ - this.mockMvc.perform(get("/api/database/" + DATABASE_3_ID + "/subset/" + QUERY_5_ID)) - .andDo(print()) - .andExpect(status().isBadRequest()); - } - @Test public void findById_privateDataPublicSchema_jsonAcceptHeader_fails() throws Exception { 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 7bdf8fa14118f7f6cca621cf01e7567ce608dfdc..0bd399d454d4427440684a57d3f2611079279bca 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 @@ -6,7 +6,6 @@ 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.query.QueryDto; import at.tuwien.api.database.table.TableBriefDto; import at.tuwien.api.database.table.TableDto; import at.tuwien.api.database.table.columns.ColumnDto; @@ -27,10 +26,6 @@ public interface MetadataMapper { org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MetadataMapper.class); - default String queryDtoToViewName(QueryDto subset) { - return subset.getQueryHash(); - } - ContainerDto containerDtoToContainerDto(ContainerDto data); DatabaseBriefDto databaseDtoToDatabaseBriefDto(DatabaseDto data); 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 new file mode 100644 index 0000000000000000000000000000000000000000..b8448528bda815a6f0fa0faba462b2a37fae1b95 --- /dev/null +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/CredentialService.java @@ -0,0 +1,7 @@ +package at.tuwien.service; + +import at.tuwien.api.keycloak.TokenDto; + +public interface CredentialService { + TokenDto getAccessToken(String username, String password); +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..7cf7d1eff4394ae174b0e724fa8e34455b363578 --- /dev/null +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/CredentialServiceImpl.java @@ -0,0 +1,44 @@ +package at.tuwien.service.impl; + +import at.tuwien.api.keycloak.TokenDto; +import at.tuwien.gateway.KeycloakGateway; +import at.tuwien.service.CredentialService; +import com.github.benmanes.caffeine.cache.Cache; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Log4j2 +@Service +public class CredentialServiceImpl implements CredentialService { + + private final KeycloakGateway keycloakGateway; + private final Cache<String, TokenDto> tokenCache; + + @Autowired + public CredentialServiceImpl(KeycloakGateway keycloakGateway, Cache<String, TokenDto> tokenCache) { + this.tokenCache = tokenCache; + this.keycloakGateway = keycloakGateway; + } + + @Override + 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; + } + 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; + } + + /** + * Method for test cases to remove all caches. + */ + public void invalidateAll() { + tokenCache.invalidateAll(); + } + +} diff --git a/dbrepo-gateway-service/dbrepo.conf b/dbrepo-gateway-service/dbrepo.conf index 165aba7643fcda32b94784d757d93e253814a1e0..f181fdf7a70945280453f345f6a639921967abca 100644 --- a/dbrepo-gateway-service/dbrepo.conf +++ b/dbrepo-gateway-service/dbrepo.conf @@ -123,7 +123,7 @@ server { 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|export)" { + 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)" { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; @@ -132,7 +132,7 @@ server { 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|export)" { + 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" { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; @@ -168,6 +168,15 @@ server { proxy_read_timeout 90; } + 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-Proto $scheme; + proxy_pass http://metadata; + proxy_read_timeout 90; + } + location ~ "/pid/([0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})" { rewrite /pid/(.*) /api/identifier/$1 break; proxy_set_header Host $host; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDto.java index 57ecb5ad625017fec1571a1da53a83cbd5fcf852..0bc16d61cd9a1dc45c129184ec18cfb49ed0d754 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDto.java @@ -46,6 +46,9 @@ public class IdentifierDto { @Schema(example = "null") private UUID viewId; + @NotNull + private LinksDto links; + @NotNull @Schema(example = "database") private IdentifierTypeDto type; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/LinksDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/LinksDto.java new file mode 100644 index 0000000000000000000000000000000000000000..fcef2a659750d9cf6b78bdc54b4a627dbcc0935d --- /dev/null +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/LinksDto.java @@ -0,0 +1,32 @@ +package at.tuwien.api.identifier; + +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 LinksDto { + + @NotNull + @Schema(example = "http://example.com/api/") + private String self; + + @NotNull + @JsonProperty("self_html") + @Schema(example = "http://example.com") + private String selfHtml; + + @Schema(example = "http://example.com") + private String data; + +} diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java index 2d18ca0c49124539a6b9aa6072396aa247eb8167..74284789247ee20deac7df99c49a4f60e8cfa765 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java @@ -318,10 +318,27 @@ public interface MetadataMapper { Identifier identifierDtoToIdentifier(IdentifierDto data); @Mappings({ - @Mapping(target = "databaseId", source = "database.id") + @Mapping(target = "databaseId", source = "database.id"), + @Mapping(target = "links", expression = "java(identifierToLinksDto(data))"), }) IdentifierDto identifierToIdentifierDto(Identifier data); + default LinksDto identifierToLinksDto(Identifier data) { + final LinksDto links = LinksDto.builder() + .self("/api/identifier/" + data.getId()) + .selfHtml("/pid/" + data.getId()) + .build(); + switch (data.getType()) { + case VIEW -> + links.setData("/api/database/" + data.getDatabase().getId() + "/view/" + data.getViewId() + "/data"); + case TABLE -> + links.setData("/api/database/" + data.getDatabase().getId() + "/table/" + data.getTableId() + "/data"); + case SUBSET -> + links.setData("/api/database/" + data.getDatabase().getId() + "/subset/" + data.getQueryId() + "/data"); + } + return links; + } + @Mappings({ @Mapping(target = "databaseId", source = "database.id"), @Mapping(target = "ownedBy", source = "owner.id") diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java index 31dd1e542d53112ff42b49a6e5f6269255088ac6..96deaea775defd1562aba3601d9ba513b771f401 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java @@ -9,7 +9,6 @@ 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.identifier.IdentifierType; import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.mapper.MetadataMapper; @@ -126,7 +125,7 @@ public class IdentifierEndpoint extends AbstractEndpoint { } @GetMapping(value = "/{identifierId}", produces = {MediaType.APPLICATION_JSON_VALUE, "application/ld+json", - MediaType.TEXT_XML_VALUE, "text/csv", "text/bibliography", "text/bibliography; style=apa", + MediaType.TEXT_XML_VALUE, "text/bibliography", "text/bibliography; style=apa", "text/bibliography; style=ieee", "text/bibliography; style=bibtex"}) @Transactional(readOnly = true) @Observed(name = "dbrepo_identifier_find") @@ -138,7 +137,6 @@ public class IdentifierEndpoint extends AbstractEndpoint { content = { @Content(mediaType = "application/json", schema = @Schema(implementation = IdentifierDto.class)), @Content(mediaType = "application/ld+json", schema = @Schema(implementation = LdDatasetDto.class)), - @Content(mediaType = "text/csv"), @Content(mediaType = "text/xml"), @Content(mediaType = "text/bibliography"), @Content(mediaType = "text/bibliography; style=apa"), @@ -190,7 +188,7 @@ public class IdentifierEndpoint extends AbstractEndpoint { @RequestHeader(HttpHeaders.ACCEPT) String accept, Principal principal) throws IdentifierNotFoundException, DataServiceException, DataServiceConnectionException, MalformedException, FormatNotAvailableException, - QueryNotFoundException, NotAllowedException { + QueryNotFoundException, NotAllowedException, TableNotFoundException, ViewNotFoundException { log.debug("endpoint find identifier, identifierId={}, accept={}", identifierId, accept); if (accept == null) { accept = ""; @@ -212,13 +210,6 @@ public class IdentifierEndpoint extends AbstractEndpoint { case "application/ld+json": log.trace("accept header matches json-ld"); return ResponseEntity.ok(metadataMapper.identifierToLdDatasetDto(identifier, endpointConfig.getWebsiteUrl())); - case "text/csv": - log.trace("accept header matches csv"); - if (identifier.getType().equals(IdentifierType.DATABASE)) { - log.error("Failed to export dataset: identifier type is database"); - throw new FormatNotAvailableException("Failed to export dataset: identifier type is database"); - } - return ResponseEntity.ok(identifierService.exportResource(identifier)); case "text/xml": log.trace("accept header matches xml"); return ResponseEntity.ok(identifierService.exportMetadata(identifier)); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/IdentifierEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/IdentifierEndpointUnitTest.java index 1e003041027ed22072d167eae81fab3a5d32c813..59aca6a405cf0086fb1cc39e033d4865a33df082 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/IdentifierEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/IdentifierEndpointUnitTest.java @@ -365,20 +365,6 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { assertEquals(1, identifiers.size()); } - @Test - @WithAnonymousUser - public void find_textCsvDatabase_fails() throws IdentifierNotFoundException { - - /* mock */ - when(identifierService.find(IDENTIFIER_1_ID)) - .thenReturn(IDENTIFIER_1); - - /* test */ - assertThrows(FormatNotAvailableException.class, () -> { - identifierEndpoint.find(IDENTIFIER_1_ID, "text/csv", null); - }); - } - @Test @WithAnonymousUser public void find_draft_fails() throws IdentifierNotFoundException { @@ -410,7 +396,8 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_2_USERNAME) public void find_draft_succeeds() throws IdentifierNotFoundException, MalformedException, NotAllowedException, - DataServiceException, QueryNotFoundException, DataServiceConnectionException, FormatNotAvailableException { + DataServiceException, QueryNotFoundException, DataServiceConnectionException, FormatNotAvailableException, + TableNotFoundException, ViewNotFoundException { /* mock */ when(identifierService.find(IDENTIFIER_5_ID)) @@ -424,7 +411,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void find_defaultHtmlRespondsJson_succeeds() throws IdentifierNotFoundException, MalformedException, NotAllowedException, DataServiceException, QueryNotFoundException, DataServiceConnectionException, - FormatNotAvailableException { + FormatNotAvailableException, TableNotFoundException, ViewNotFoundException { /* mock */ when(identifierService.find(IDENTIFIER_1_ID)) @@ -438,7 +425,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_4_USERNAME) public void find_json0_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException, NotAllowedException { + FormatNotAvailableException, NotAllowedException, TableNotFoundException, ViewNotFoundException { final String accept = "application/json"; final IdentifierDto compare = objectMapper.readValue(FileUtils.readFileToString(new File("src/test/resources/json/metadata0.json"), StandardCharsets.UTF_8), IdentifierDto.class); @@ -468,7 +455,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void find_json1_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException, NotAllowedException { + FormatNotAvailableException, NotAllowedException, TableNotFoundException, ViewNotFoundException { final String accept = "application/json"; final IdentifierDto compare = objectMapper.readValue(FileUtils.readFileToString(new File("src/test/resources/json/metadata1.json"), StandardCharsets.UTF_8), IdentifierDto.class); @@ -514,34 +501,11 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { assertEquals(compare.getCreators().get(0).getNameIdentifierScheme(), creator0.getNameIdentifierScheme()); } - @Test - @WithAnonymousUser - public void find_csv_succeeds() throws IOException, MalformedException, DataServiceException, - DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException, NotAllowedException { - final String accept = "text/csv"; - final InputStreamResource compare = new InputStreamResource(FileUtils.openInputStream(new File("src/test/resources/csv/keyboard.csv"))); - final InputStreamResource mock = new InputStreamResource(FileUtils.openInputStream(new File("src/test/resources/csv/keyboard.csv"))); - - /* mock */ - when(identifierService.find(IDENTIFIER_2_ID)) - .thenReturn(IDENTIFIER_2); - when(identifierService.exportResource(IDENTIFIER_2)) - .thenReturn(mock); - - /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_2_ID, accept, null); - assertEquals(HttpStatus.OK, response.getStatusCode()); - final InputStreamResource body = (InputStreamResource) response.getBody(); - assertNotNull(body); - assertEquals(inputStreamToString(compare.getInputStream()), inputStreamToString(body.getInputStream())); - } - @Test @WithAnonymousUser public void find_bibliography_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException, NotAllowedException { + FormatNotAvailableException, NotAllowedException, TableNotFoundException, ViewNotFoundException { final String accept = "text/bibliography"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa1.txt"), StandardCharsets.UTF_8); @@ -584,7 +548,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_4_USERNAME) public void find_bibliographyApa0_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException, NotAllowedException { + FormatNotAvailableException, NotAllowedException, TableNotFoundException, ViewNotFoundException { final String accept = "text/bibliography; style=apa"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa0.txt"), StandardCharsets.UTF_8); @@ -607,7 +571,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void find_bibliographyApa1_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException, NotAllowedException { + FormatNotAvailableException, NotAllowedException, TableNotFoundException, ViewNotFoundException { final String accept = "text/bibliography; style=apa"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa1.txt"), StandardCharsets.UTF_8); @@ -630,7 +594,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_2_USERNAME) public void find_draftBibliographyApa2_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException, NotAllowedException { + FormatNotAvailableException, NotAllowedException, TableNotFoundException, ViewNotFoundException { final String accept = "text/bibliography; style=apa"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa2.txt"), StandardCharsets.UTF_8); @@ -653,7 +617,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void find_bibliographyApa3_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException, NotAllowedException { + FormatNotAvailableException, NotAllowedException, TableNotFoundException, ViewNotFoundException { final String accept = "text/bibliography; style=apa"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa3.txt"), StandardCharsets.UTF_8); @@ -676,7 +640,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void find_bibliographyApa4_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException, NotAllowedException { + FormatNotAvailableException, NotAllowedException, TableNotFoundException, ViewNotFoundException { final String accept = "text/bibliography; style=apa"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa4.txt"), StandardCharsets.UTF_8); @@ -699,7 +663,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_4_USERNAME) public void find_bibliographyIeee0_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException, NotAllowedException { + FormatNotAvailableException, NotAllowedException, TableNotFoundException, ViewNotFoundException { final String accept = "text/bibliography; style=ieee"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_ieee0.txt"), StandardCharsets.UTF_8); @@ -722,7 +686,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void find_bibliographyIeee1_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException, NotAllowedException { + FormatNotAvailableException, NotAllowedException, TableNotFoundException, ViewNotFoundException { final String accept = "text/bibliography; style=ieee"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_ieee1.txt"), StandardCharsets.UTF_8); @@ -745,7 +709,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_2_USERNAME) public void find_bibliographyIeee2_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException, NotAllowedException { + FormatNotAvailableException, NotAllowedException, TableNotFoundException, ViewNotFoundException { final String accept = "text/bibliography; style=ieee"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_ieee2.txt"), StandardCharsets.UTF_8); @@ -768,7 +732,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void find_bibliographyIeee3_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException, NotAllowedException { + FormatNotAvailableException, NotAllowedException, TableNotFoundException, ViewNotFoundException { final String accept = "text/bibliography; style=ieee"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_ieee3.txt"), StandardCharsets.UTF_8); @@ -791,7 +755,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_4_USERNAME) public void find_bibliographyBibtex0_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException, NotAllowedException { + FormatNotAvailableException, NotAllowedException, TableNotFoundException, ViewNotFoundException { final String accept = "text/bibliography; style=bibtex"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_bibtex0.txt"), StandardCharsets.UTF_8); @@ -814,7 +778,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void find_bibliographyBibtex1_succeeds() throws MalformedException, IOException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException, NotAllowedException { + FormatNotAvailableException, NotAllowedException, TableNotFoundException, ViewNotFoundException { final String accept = "text/bibliography; style=bibtex"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_bibtex1.txt"), StandardCharsets.UTF_8); @@ -837,7 +801,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_2_USERNAME) public void find_bibliographyBibtex2_succeeds() throws MalformedException, DataServiceException, IOException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException, NotAllowedException { + FormatNotAvailableException, NotAllowedException, TableNotFoundException, ViewNotFoundException { final String accept = "text/bibliography; style=bibtex"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_bibtex2.txt"), StandardCharsets.UTF_8); @@ -860,7 +824,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void find_bibliographyBibtex3_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException, IOException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException, NotAllowedException { + FormatNotAvailableException, NotAllowedException, TableNotFoundException, ViewNotFoundException { final String accept = "text/bibliography; style=bibtex"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_bibtex3.txt"), StandardCharsets.UTF_8); @@ -882,7 +846,8 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser public void find_jsonLd_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException, - QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException, NotAllowedException { + QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException, NotAllowedException, + TableNotFoundException, ViewNotFoundException { final String accept = "application/ld+json"; /* mock */ @@ -914,7 +879,8 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser public void find_move_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException, - QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException, NotAllowedException { + QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException, NotAllowedException, + TableNotFoundException, ViewNotFoundException { /* mock */ when(identifierService.find(IDENTIFIER_1_ID)) @@ -1065,7 +1031,8 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser public void find_json_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException, - FormatNotAvailableException, QueryNotFoundException, IdentifierNotFoundException, NotAllowedException { + FormatNotAvailableException, QueryNotFoundException, IdentifierNotFoundException, NotAllowedException, + TableNotFoundException, ViewNotFoundException { final String accept = "application/json"; /* mock */ @@ -1093,7 +1060,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void find_xml_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException, IOException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException, - NotAllowedException { + NotAllowedException, TableNotFoundException, ViewNotFoundException { final InputStreamResource resource = new InputStreamResource(FileUtils.openInputStream( new File("src/test/resources/xml/datacite-example-dataset-v4.xml"))); @@ -1108,9 +1075,9 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser - public void find_httpRedirect_succeeds() throws MalformedException, DataServiceException, - DataServiceConnectionException, FormatNotAvailableException, QueryNotFoundException, - IdentifierNotFoundException, NotAllowedException { + public void find_httpRedirect_succeeds() throws MalformedException, DataServiceException, QueryNotFoundException, + DataServiceConnectionException, FormatNotAvailableException, IdentifierNotFoundException, + NotAllowedException, TableNotFoundException, ViewNotFoundException { /* test */ final ResponseEntity<?> response = generic_find(null, null); @@ -1509,14 +1476,13 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { protected ResponseEntity<?> generic_find(String accept, InputStreamResource resource) throws MalformedException, DataServiceException, DataServiceConnectionException, FormatNotAvailableException, - QueryNotFoundException, IdentifierNotFoundException, NotAllowedException { + QueryNotFoundException, IdentifierNotFoundException, NotAllowedException, TableNotFoundException, + ViewNotFoundException { /* mock */ when(identifierService.find(IDENTIFIER_1_ID)) .thenReturn(IDENTIFIER_1); if (resource != null) { - when(identifierService.exportResource(IDENTIFIER_1)) - .thenReturn(resource); when(identifierService.exportMetadata(IDENTIFIER_1)) .thenReturn(resource); } @@ -1525,10 +1491,6 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { return identifierEndpoint.find(IDENTIFIER_1_ID, accept, null); } - protected static String inputStreamToString(InputStream inputStream) throws IOException { - return IOUtils.toString(inputStream, StandardCharsets.UTF_8); - } - protected void generic_delete() throws NotAllowedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, IdentifierNotFoundException, SearchServiceException, SearchServiceConnectionException { 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/tuwien/gateway/DataServiceGatewayUnitTest.java index 5508a6245e40021cf307d474bc056dfc64861920..af1ecc9f1c69b6f2acaf3176575045bf14ad8322 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/tuwien/gateway/DataServiceGatewayUnitTest.java @@ -1,6 +1,5 @@ package at.tuwien.gateway; -import at.tuwien.ExportResourceDto; import at.tuwien.api.database.AccessTypeDto; import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.database.ViewDto; @@ -812,75 +811,6 @@ public class DataServiceGatewayUnitTest extends AbstractUnitTest { }); } - @Test - public void exportQuery_succeeds() throws DataServiceException, DataServiceConnectionException, - QueryNotFoundException { - - /* mock */ - when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ExportResourceDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .build()); - - /* test */ - dataServiceGateway.exportQuery(DATABASE_1_ID, QUERY_1_ID); - } - - @Test - public void exportQuery_connection_fails() { - - /* mock */ - doThrow(HttpServerErrorException.class) - .when(dataServiceRestTemplate) - .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ExportResourceDto.class)); - - /* test */ - assertThrows(DataServiceConnectionException.class, () -> { - dataServiceGateway.exportQuery(DATABASE_1_ID, QUERY_1_ID); - }); - } - - @Test - public void exportQuery_unauthorized_fails() { - - /* mock */ - doThrow(HttpClientErrorException.Unauthorized.class) - .when(dataServiceRestTemplate) - .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ExportResourceDto.class)); - - /* test */ - assertThrows(DataServiceException.class, () -> { - dataServiceGateway.exportQuery(DATABASE_1_ID, QUERY_1_ID); - }); - } - - @Test - public void exportQuery_notFound_fails() { - - /* mock */ - doThrow(HttpClientErrorException.NotFound.class) - .when(dataServiceRestTemplate) - .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ExportResourceDto.class)); - - /* test */ - assertThrows(QueryNotFoundException.class, () -> { - dataServiceGateway.exportQuery(DATABASE_1_ID, QUERY_1_ID); - }); - } - - @Test - public void exportQuery_responseCode_fails() { - - /* mock */ - when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ExportResourceDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT) - .build()); - - /* test */ - assertThrows(DataServiceException.class, () -> { - dataServiceGateway.exportQuery(DATABASE_1_ID, QUERY_1_ID); - }); - } - @Test public void getTableSchemas_succeeds() throws DataServiceException, DataServiceConnectionException, TableNotFoundException { diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java index d6b5da373cd08436c1ab1a42031952f05faf6d12..6d7480ba8034a9108492ab0816005f4a92f8046c 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java @@ -29,7 +29,9 @@ public class InternalRequestInterceptor implements ClientHttpRequestInterceptor public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { final HttpHeaders headers = request.getHeaders(); - headers.setAccept(List.of(MediaType.APPLICATION_JSON)); + if (headers.get("Accept") == null) { + headers.setAccept(List.of(MediaType.APPLICATION_JSON)); + } final TokenDto token = credentialService.getAccessToken(gatewayConfig.getSystemUsername(), gatewayConfig.getSystemPassword()); headers.setBearerAuth(token.getAccessToken()); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java index 5bb0303e16c14145f1e08ee913b4c4dcabdead61..3996448d212bed80364bdc2ac4d5ab62da3e1863 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java @@ -1,9 +1,8 @@ package at.tuwien.gateway; -import at.tuwien.ExportResourceDto; import at.tuwien.api.database.AccessTypeDto; -import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.database.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; @@ -145,19 +144,6 @@ public interface DataServiceGateway { QueryDto findQuery(UUID databaseId, UUID queryId) throws DataServiceConnectionException, DataServiceException, QueryNotFoundException; - /** - * Exports a given query. - * - * @param databaseId The database id. - * @param queryId The query id. - * @return The exported resource, if successful. - * @throws DataServiceConnectionException The connection to the data service could not be established. - * @throws DataServiceException The data service responded unexpectedly. - * @throws QueryNotFoundException The given query was not found in the query store. - */ - ExportResourceDto exportQuery(UUID databaseId, UUID queryId) throws DataServiceConnectionException, - DataServiceException, QueryNotFoundException; - /** * Obtain table schemas from a given database. * diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DataServiceGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DataServiceGatewayImpl.java index 8feed3b291444ea674317673d74fa59bba4b5cad..ba855feda32000f1c4f0265c2b194c7e9e4e8237 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DataServiceGatewayImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DataServiceGatewayImpl.java @@ -1,6 +1,5 @@ package at.tuwien.gateway.impl; -import at.tuwien.ExportResourceDto; import at.tuwien.api.database.*; import at.tuwien.api.database.internal.CreateDatabaseDto; import at.tuwien.api.database.query.QueryDto; @@ -315,31 +314,6 @@ public class DataServiceGatewayImpl implements DataServiceGateway { return response.getBody(); } - @Override - public ExportResourceDto exportQuery(UUID databaseId, UUID queryId) throws DataServiceConnectionException, - DataServiceException, QueryNotFoundException { - final ResponseEntity<ExportResourceDto> response; - final String path = "/api/database/" + databaseId + "/subset/" + queryId; - log.trace("export subset at endpoint {} with path {}", gatewayConfig.getDataEndpoint(), path); - try { - response = restTemplate.exchange(path, HttpMethod.GET, HttpEntity.EMPTY, ExportResourceDto.class); - } catch (HttpServerErrorException e) { - log.error("Failed to export query: {}", e.getMessage()); - throw new DataServiceConnectionException("Failed to export query: " + e.getMessage(), e); - } catch (HttpClientErrorException.NotFound e) { - log.error("Failed to export query: not found: {}", e.getMessage()); - throw new QueryNotFoundException("Failed to export query: not found: " + e.getMessage(), e); - } catch (HttpClientErrorException.Unauthorized e) { - log.error("Failed to export query: {}", e.getMessage()); - throw new DataServiceException("Failed to export query: " + e.getMessage(), e); - } - if (!response.getStatusCode().equals(HttpStatus.OK)) { - log.error("Failed to export query: wrong http code: {}", response.getStatusCode()); - throw new DataServiceException("Failed to export query: wrong http code: " + response.getStatusCode()); - } - return response.getBody(); - } - @Override public List<TableDto> getTableSchemas(UUID databaseId) throws DataServiceConnectionException, DataServiceException, TableNotFoundException { diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/IdentifierService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/IdentifierService.java index 605ded7d37faad52fc7119f4dd0a958c199b68b8..8c9a3088fe96844df0628ba95d71c0356ebc2b33 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/IdentifierService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/IdentifierService.java @@ -161,19 +161,6 @@ public interface IdentifierService { */ String exportBibliography(Identifier identifier, BibliographyTypeDto style) throws MalformedException; - /** - * Exports an identifier to XML - * - * @param identifier The identifier. - * @return The XML resource, if successful. - * @throws DataServiceException - * @throws DataServiceConnectionException - * @throws IdentifierNotFoundException - * @throws QueryNotFoundException - */ - InputStreamResource exportResource(Identifier identifier) throws DataServiceException, DataServiceConnectionException, - IdentifierNotFoundException, QueryNotFoundException; - /** * Soft-deletes an identifier for a given id in the metadata database. Does not actually remove the entity from the * database, but sets it as deleted. diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java index 0c8ce27d1214b1ac47c6756d7f5d3fbe4c77adcd..5ab9cc26a226374d817966e880a684393c36cf08 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java @@ -196,13 +196,6 @@ public class DataCiteIdentifierServiceImpl implements IdentifierService { return identifierService.exportBibliography(identifier, style); } - @Override - @Transactional(readOnly = true) - public InputStreamResource exportResource(Identifier identifier) throws DataServiceException, - DataServiceConnectionException, IdentifierNotFoundException, QueryNotFoundException { - return identifierService.exportResource(identifier); - } - @Override @Transactional public void delete(Identifier identifier) throws DataServiceException, DataServiceConnectionException, diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java index b1d1f45932c61bb755a615f22a6a919297ffec46..8af7023c8cb48b64078457c409b8e14ece6187b7 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java @@ -1,6 +1,5 @@ package at.tuwien.service.impl; -import at.tuwien.ExportResourceDto; import at.tuwien.api.database.query.QueryDto; import at.tuwien.api.identifier.BibliographyTypeDto; import at.tuwien.api.identifier.CreateIdentifierDto; @@ -356,14 +355,6 @@ public class IdentifierServiceImpl implements IdentifierService { return body; } - @Override - @Transactional(readOnly = true) - public InputStreamResource exportResource(Identifier identifier) throws DataServiceException, - DataServiceConnectionException, QueryNotFoundException { - final ExportResourceDto exportResource = dataServiceGateway.exportQuery(identifier.getDatabase().getId(), identifier.getQueryId()); - return exportResource.getResource(); - } - @Override @Transactional public void delete(Identifier identifier) throws DataServiceException, DataServiceConnectionException, diff --git a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java index 1f4cc4e6691c5108f2fb61e806dc9e488b926f68..490c902295d9c50977caa0ab2b66a462ba6d514b 100644 --- a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java +++ b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java @@ -6201,6 +6201,10 @@ public abstract class BaseTest { public static final IdentifierDto IDENTIFIER_1_DTO = IdentifierDto.builder() .id(IDENTIFIER_1_ID) .databaseId(DATABASE_1_ID) + .links(LinksDto.builder() + .self("/api/identifier/" + IDENTIFIER_1_ID) + .selfHtml("/pid/" + IDENTIFIER_1_ID) + .build()) .queryId(QUERY_1_ID) .descriptions(new LinkedList<>(List.of(IDENTIFIER_1_DESCRIPTION_1_DTO))) .titles(new LinkedList<>(List.of(IDENTIFIER_1_TITLE_1_DTO, IDENTIFIER_1_TITLE_2_DTO))) @@ -6488,6 +6492,11 @@ public abstract class BaseTest { .id(IDENTIFIER_5_ID) .databaseId(DATABASE_2_ID) .queryId(QUERY_2_ID) + .links(LinksDto.builder() + .self("/api/identifier/" + IDENTIFIER_5_ID) + .selfHtml("/pid/" + IDENTIFIER_5_ID) + .data("/api/database/" + DATABASE_2_ID + "/subset/" + QUERY_2_ID + "/data") + .build()) .descriptions(new LinkedList<>(List.of(IDENTIFIER_5_DESCRIPTION_1_DTO))) .titles(new LinkedList<>(List.of(IDENTIFIER_5_TITLE_1_DTO))) .doi(IDENTIFIER_5_DOI) @@ -6769,6 +6778,11 @@ public abstract class BaseTest { .id(IDENTIFIER_6_ID) .databaseId(DATABASE_3_ID) .queryId(QUERY_3_ID) + .links(LinksDto.builder() + .self("/api/identifier/" + IDENTIFIER_6_ID) + .selfHtml("/pid/" + IDENTIFIER_6_ID) + .data("/api/database/" + DATABASE_3_ID + "/subset/" + QUERY_3_ID + "/data") + .build()) .descriptions(new LinkedList<>(List.of(IDENTIFIER_6_DESCRIPTION_1_DTO))) .titles(new LinkedList<>(List.of(IDENTIFIER_6_TITLE_1_DTO))) .doi(IDENTIFIER_6_DOI) @@ -6878,6 +6892,10 @@ public abstract class BaseTest { public static 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) + .build()) .descriptions(new LinkedList<>()) .titles(new LinkedList<>()) .doi(IDENTIFIER_7_DOI) @@ -6986,6 +7004,11 @@ public abstract class BaseTest { .id(IDENTIFIER_2_ID) .queryId(QUERY_1_ID) .databaseId(DATABASE_1_ID) + .links(LinksDto.builder() + .self("/api/identifier/" + IDENTIFIER_2_ID) + .selfHtml("/pid/" + IDENTIFIER_2_ID) + .data("/api/database/" + DATABASE_1_ID + "/subset/" + QUERY_1_ID + "/data") + .build()) .descriptions(new LinkedList<>()) .titles(new LinkedList<>()) .doi(IDENTIFIER_2_DOI) @@ -7085,6 +7108,11 @@ public abstract class BaseTest { .id(IDENTIFIER_3_ID) .databaseId(DATABASE_1_ID) .viewId(VIEW_1_ID) + .links(LinksDto.builder() + .self("/api/identifier/" + IDENTIFIER_3_ID) + .selfHtml("/pid/" + IDENTIFIER_3_ID) + .data("/api/database/" + DATABASE_1_ID + "/view/" + VIEW_1_ID + "/data") + .build()) .descriptions(new LinkedList<>()) .titles(new LinkedList<>()) .doi(IDENTIFIER_3_DOI) @@ -7185,6 +7213,11 @@ public abstract class BaseTest { .id(IDENTIFIER_4_ID) .databaseId(DATABASE_1_ID) .tableId(TABLE_1_ID) + .links(LinksDto.builder() + .self("/api/identifier/" + IDENTIFIER_4_ID) + .selfHtml("/pid/" + IDENTIFIER_4_ID) + .data("/api/database/" + DATABASE_1_ID + "/table/" + TABLE_1_ID + "/data") + .build()) .descriptions(new LinkedList<>()) .titles(new LinkedList<>()) .doi(IDENTIFIER_4_DOI) diff --git a/dbrepo-search-service/Pipfile.lock b/dbrepo-search-service/Pipfile.lock index ac2d0e3f70431e171ffda6524d193727056840b4..e520c5d0f8890461117ca6d7ab6645de932c2261 100644 --- a/dbrepo-search-service/Pipfile.lock +++ b/dbrepo-search-service/Pipfile.lock @@ -373,7 +373,7 @@ }, "dbrepo": { "hashes": [ - "sha256:4f5ee48e9a68a44c2d1184923b90729d724553862742738d8f942273a586eb3d" + "sha256:e70ea4f7030191eb80116e5d0a4b17b041c94c80359d5d8e707d62218edd9a54" ], "path": "./lib/dbrepo-1.7.1.tar.gz" }, diff --git a/dbrepo-search-service/init/Pipfile.lock b/dbrepo-search-service/init/Pipfile.lock index 39a52462e0daa22c8052517b0617cb350e9a9408..7e637809c29b2223d18dc64896ae84432efbf7c5 100644 --- a/dbrepo-search-service/init/Pipfile.lock +++ b/dbrepo-search-service/init/Pipfile.lock @@ -259,7 +259,7 @@ }, "dbrepo": { "hashes": [ - "sha256:4f5ee48e9a68a44c2d1184923b90729d724553862742738d8f942273a586eb3d" + "sha256:e70ea4f7030191eb80116e5d0a4b17b041c94c80359d5d8e707d62218edd9a54" ], "path": "./lib/dbrepo-1.7.1.tar.gz" }, diff --git a/dbrepo-search-service/init/lib/dbrepo-1.7.1-py3-none-any.whl b/dbrepo-search-service/init/lib/dbrepo-1.7.1-py3-none-any.whl index 8e77c6e1f6a01b3d9739280f29539985c359d2c8..61f52896c18ecbec8090177b38b8dbaeb0e1a95e 100644 Binary files a/dbrepo-search-service/init/lib/dbrepo-1.7.1-py3-none-any.whl and b/dbrepo-search-service/init/lib/dbrepo-1.7.1-py3-none-any.whl differ diff --git a/dbrepo-search-service/init/lib/dbrepo-1.7.1.tar.gz b/dbrepo-search-service/init/lib/dbrepo-1.7.1.tar.gz index ede846d6168615c3e3bac49872362163b0a9f005..6708e1d892771d6cdf9293a6e9f5197f4dd9e304 100644 Binary files a/dbrepo-search-service/init/lib/dbrepo-1.7.1.tar.gz and b/dbrepo-search-service/init/lib/dbrepo-1.7.1.tar.gz differ diff --git a/dbrepo-search-service/lib/dbrepo-1.7.1-py3-none-any.whl b/dbrepo-search-service/lib/dbrepo-1.7.1-py3-none-any.whl index 8e77c6e1f6a01b3d9739280f29539985c359d2c8..61f52896c18ecbec8090177b38b8dbaeb0e1a95e 100644 Binary files a/dbrepo-search-service/lib/dbrepo-1.7.1-py3-none-any.whl and b/dbrepo-search-service/lib/dbrepo-1.7.1-py3-none-any.whl differ diff --git a/dbrepo-search-service/lib/dbrepo-1.7.1.tar.gz b/dbrepo-search-service/lib/dbrepo-1.7.1.tar.gz index ede846d6168615c3e3bac49872362163b0a9f005..6708e1d892771d6cdf9293a6e9f5197f4dd9e304 100644 Binary files a/dbrepo-search-service/lib/dbrepo-1.7.1.tar.gz and b/dbrepo-search-service/lib/dbrepo-1.7.1.tar.gz differ diff --git a/dbrepo-ui/composables/query-service.ts b/dbrepo-ui/composables/query-service.ts index 5a86c09d1b1b7017e362a62c0cc5df33c545fd6c..2b33fa8849c6d7bba4509720c2083f4d65562ff1 100644 --- a/dbrepo-ui/composables/query-service.ts +++ b/dbrepo-ui/composables/query-service.ts @@ -64,7 +64,7 @@ export const useQueryService = (): any => { } console.debug('export query with id', queryId, 'in database with id', databaseId) return new Promise<any>((resolve, reject) => { - axios.get<any>(`/api/database/${databaseId}/subset/${queryId}`, config) + axios.get<any>(`/api/database/${databaseId}/subset/${queryId}/data`, config) .then((response) => { console.info('Exported query with id', queryId, 'in database with id', databaseId) resolve(response.data) diff --git a/dbrepo-ui/composables/table-service.ts b/dbrepo-ui/composables/table-service.ts index 45ee0a7b934cb92c2d275b3cb1a23738d4fc0809..c9dfeb62fcd42c603ef86d67b52332fea04ac2a2 100644 --- a/dbrepo-ui/composables/table-service.ts +++ b/dbrepo-ui/composables/table-service.ts @@ -132,7 +132,7 @@ export const useTableService = (): any => { } console.debug('export data for table with id', tableId, 'in database with id', databaseId); return new Promise<QueryResultDto>((resolve, reject) => { - axios.get<QueryResultDto>(`/api/database/${databaseId}/table/${tableId}/export`, config) + axios.get<QueryResultDto>(`/api/database/${databaseId}/table/${tableId}/data`, config) .then((response) => { console.info('Exported data for table') resolve(response.data) diff --git a/dbrepo-ui/composables/view-service.ts b/dbrepo-ui/composables/view-service.ts index 9029a553ac782248d33707380f2ed72efcfc8032..3e775e2b14d51b83c7332bf7311de99a7a25d24e 100644 --- a/dbrepo-ui/composables/view-service.ts +++ b/dbrepo-ui/composables/view-service.ts @@ -114,7 +114,7 @@ export const useViewService = (): any => { } console.debug('export data for view with id', viewId, 'in database with id', databaseId); return new Promise<QueryResultDto>((resolve, reject) => { - axios.get<QueryResultDto>(`/api/database/${databaseId}/view/${viewId}/export`, config) + axios.get<QueryResultDto>(`/api/database/${databaseId}/view/${viewId}/data`, config) .then((response) => { console.info('Exported data for view with id', viewId, 'in database with id', databaseId) resolve(response.data) diff --git a/docker-compose.yml b/docker-compose.yml index e8c5cd8de7795d1bcced37da11b80b94dc404315..84905a7d057f6ea27dae62f7402eaa53f0d92cb7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -539,6 +539,7 @@ services: AUTH_SERVICE_CLIENT: "${AUTH_SERVICE_CLIENT:-dbrepo-client}" AUTH_SERVICE_CLIENT_SECRET: "${AUTH_SERVICE_CLIENT:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG}" AUTH_SERVICE_ENDPOINT: "${AUTH_SERVICE_ENDPOINT:-http://auth-service:8080}" + BASE_URL: "${BASE_URL:-http://localhost}" BROKER_EXCHANGE_NAME: "${BROKER_EXCHANGE_NAME:-dbrepo}" BROKER_QUEUE_NAME: "${BROKER_QUEUE_NAME:-dbrepo}" BROKER_HOST: "${BROKER_ENDPOINT:-broker-service}" diff --git a/helm/dbrepo/charts/seaweedfs-4.2.1.tgz b/helm/dbrepo/charts/seaweedfs-4.2.1.tgz index f68e0bea5c235a15b317317f1e757fe29be1c73c..b26358e59779d3206d9c834f59b08e7f2f84149b 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/create-event-listener.jar b/helm/dbrepo/files/create-event-listener.jar index b117c50b6646de91273c95dc5749cd54868012be..77b988f95baa69b04c7fa4fa6f9737335eef2711 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/gateway-configmap.yaml b/helm/dbrepo/templates/gateway-configmap.yaml index 076e305014cef07a50a427679cd1f75b10b67f4e..0587cbac175d9c70e2ba43ff0a3095bd0dc5b519 100644 --- a/helm/dbrepo/templates/gateway-configmap.yaml +++ b/helm/dbrepo/templates/gateway-configmap.yaml @@ -20,7 +20,7 @@ data: listen 8080 default_server; server_name _; - location /dashboard/ { + location /dashboard { rewrite ^/dashboard/(.*) /$1 break; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; @@ -31,7 +31,7 @@ data: } # Proxy Grafana Live WebSocket connections. - location /dashboard/api/live/ { + location /dashboard/api/live { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; @@ -93,7 +93,7 @@ data: 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|export)" { + 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)" { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; @@ -102,7 +102,7 @@ data: 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|export)" { + 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" { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; @@ -138,6 +138,15 @@ data: proxy_read_timeout 90; } + 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-Proto $scheme; + proxy_pass http://metadata-service; + proxy_read_timeout 90; + } + location ~ "/pid/([0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})" { rewrite /pid/(.*) /api/identifier/$1 break; proxy_set_header Host $host; diff --git a/helm/seaweedfs/charts/mariadb-20.2.4.tgz b/helm/seaweedfs/charts/mariadb-20.2.4.tgz deleted file mode 100644 index eb0f7bcfab6286495ed5338abdb8221b1f89805c..0000000000000000000000000000000000000000 Binary files a/helm/seaweedfs/charts/mariadb-20.2.4.tgz and /dev/null differ diff --git a/helm/seaweedfs/charts/postgresql-16.4.9.tgz b/helm/seaweedfs/charts/postgresql-16.4.9.tgz deleted file mode 100644 index 4bb0578224f0d8817e757a759547b171798bd407..0000000000000000000000000000000000000000 Binary files a/helm/seaweedfs/charts/postgresql-16.4.9.tgz and /dev/null differ diff --git a/lib/python/README.md b/lib/python/README.md index 11506a7bf059630b65ed703d4674cde8cf3642e9..1a15df15c79acd1dba9ea26ab14c09cbb2419927 100644 --- a/lib/python/README.md +++ b/lib/python/README.md @@ -44,6 +44,7 @@ client = RestClient(endpoint="https://test.dbrepo.tuwien.ac.at", username="foo", password="bar") df = pd.DataFrame(data={'x_coord': 16.52617, 'component': 'Feinstaub (PM10)', 'unit': 'µg/m³', ...}) +df = df.set_index(['x_coord']) client.create_table(database_id="e0d82287-9099-4077-8f69-3c19fc3bc145", name="Sensor", is_public=True, is_schema_public=True, dataframe=df) @@ -51,6 +52,14 @@ client.create_table(database_id="e0d82287-9099-4077-8f69-3c19fc3bc145", ... or just create the table schema by setting `create_table(..., withData=False)`. +In both cases it is important to set the index to existing columns that uniquely +identify a row. You can specify multiple columns: + +```python +... +df = df.set_index(['some_column', 'some_other_column']) +``` + ## Supported Features & Best-Practices - Manage user diff --git a/lib/python/coverage.xml b/lib/python/coverage.xml index ac21b0bc1ed6b9f659ba578333c89e481c34ca8f..b23a031c5fe13102ab04331b3ef60329ee9353c0 100644 --- a/lib/python/coverage.xml +++ b/lib/python/coverage.xml @@ -1,41 +1,41 @@ <?xml version="1.0" ?> -<coverage version="7.6.10" timestamp="1740478405603" lines-valid="1820" lines-covered="1743" line-rate="0.9577" branches-covered="0" branches-valid="0" branch-rate="0" complexity="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 --> <!-- 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.9134" branch-rate="0" complexity="0"> + <package name="dbrepo" line-rate="0.9102" branch-rate="0" complexity="0"> <classes> - <class name="RestClient.py" filename="dbrepo/RestClient.py" complexity="0" line-rate="0.9248" branch-rate="0"> + <class name="RestClient.py" filename="dbrepo/RestClient.py" complexity="0" line-rate="0.9102" branch-rate="0"> <methods/> <lines> <line number="1" hits="1"/> <line number="2" hits="1"/> <line number="3" hits="1"/> - <line number="5" hits="1"/> + <line number="4" hits="1"/> <line number="6" hits="1"/> <line number="7" hits="1"/> - <line number="9" hits="1"/> + <line number="8" hits="1"/> <line number="10" hits="1"/> <line number="11" hits="1"/> - <line number="15" hits="1"/> - <line number="19" hits="1"/> - <line number="31" hits="1"/> + <line number="14" hits="1"/> + <line number="16" hits="1"/> + <line number="20" hits="1"/> <line number="32" hits="1"/> <line number="33" hits="1"/> <line number="34" hits="1"/> - <line number="36" hits="1"/> - <line number="41" hits="1"/> + <line number="35" hits="1"/> + <line number="37" hits="1"/> <line number="42" hits="1"/> <line number="43" hits="1"/> <line number="44" hits="1"/> <line number="45" hits="1"/> - <line number="47" hits="1"/> + <line number="46" hits="1"/> <line number="48" hits="1"/> - <line number="51" hits="1"/> - <line number="53" hits="1"/> + <line number="49" hits="1"/> + <line number="52" hits="1"/> <line number="54" hits="1"/> <line number="55" hits="1"/> <line number="56" hits="1"/> @@ -46,7 +46,7 @@ <line number="61" hits="1"/> <line number="62" hits="1"/> <line number="63" hits="1"/> - <line number="64" hits="1"/> + <line number="65" hits="1"/> <line number="66" hits="1"/> <line number="67" hits="1"/> <line number="68" hits="1"/> @@ -58,28 +58,28 @@ <line number="74" hits="1"/> <line number="75" hits="1"/> <line number="76" hits="1"/> - <line number="77" hits="1"/> - <line number="80" hits="1"/> + <line number="79" hits="1"/> + <line number="85" hits="1"/> <line number="86" hits="1"/> <line number="87" hits="1"/> <line number="88" hits="1"/> <line number="89" hits="1"/> - <line number="90" hits="1"/> - <line number="92" hits="1"/> + <line number="91" hits="1"/> + <line number="99" hits="1"/> <line number="100" hits="1"/> <line number="101" hits="1"/> <line number="102" hits="1"/> <line number="103" hits="1"/> <line number="104" hits="1"/> - <line number="105" hits="1"/> - <line number="108" hits="1"/> + <line number="107" hits="1"/> + <line number="115" hits="1"/> <line number="116" hits="1"/> <line number="117" hits="1"/> <line number="118" hits="1"/> <line number="119" hits="1"/> <line number="120" hits="1"/> - <line number="121" hits="1"/> - <line number="124" hits="1"/> + <line number="123" hits="1"/> + <line number="133" hits="1"/> <line number="134" hits="1"/> <line number="135" hits="1"/> <line number="136" hits="1"/> @@ -89,10 +89,10 @@ <line number="140" hits="1"/> <line number="141" hits="1"/> <line number="142" hits="1"/> - <line number="143" hits="1"/> - <line number="146" hits="1"/> + <line number="145" hits="1"/> + <line number="165" hits="1"/> <line number="166" hits="1"/> - <line number="167" hits="1"/> + <line number="169" hits="1"/> <line number="170" hits="1"/> <line number="171" hits="1"/> <line number="172" hits="1"/> @@ -102,15 +102,15 @@ <line number="176" hits="1"/> <line number="177" hits="1"/> <line number="178" hits="1"/> - <line number="179" hits="1"/> - <line number="182" hits="1"/> + <line number="181" hits="1"/> + <line number="189" hits="1"/> <line number="190" hits="1"/> <line number="191" hits="1"/> <line number="192" hits="1"/> <line number="193" hits="1"/> <line number="194" hits="1"/> - <line number="195" hits="1"/> - <line number="198" hits="1"/> + <line number="197" hits="1"/> + <line number="206" hits="1"/> <line number="207" hits="1"/> <line number="208" hits="1"/> <line number="209" hits="1"/> @@ -118,21 +118,21 @@ <line number="211" hits="1"/> <line number="212" hits="1"/> <line number="213" hits="1"/> - <line number="214" hits="1"/> - <line number="217" hits="1"/> + <line number="216" hits="1"/> + <line number="224" hits="1"/> <line number="225" hits="1"/> <line number="226" hits="1"/> <line number="227" hits="1"/> <line number="228" hits="1"/> <line number="229" hits="1"/> - <line number="230" hits="1"/> - <line number="233" hits="1"/> + <line number="232" hits="1"/> + <line number="239" hits="1"/> <line number="240" hits="1"/> <line number="241" hits="1"/> <line number="242" hits="1"/> <line number="243" hits="1"/> - <line number="244" hits="1"/> - <line number="247" hits="1"/> + <line number="246" hits="1"/> + <line number="257" hits="1"/> <line number="258" hits="1"/> <line number="259" hits="1"/> <line number="260" hits="1"/> @@ -142,10 +142,10 @@ <line number="264" hits="1"/> <line number="265" hits="1"/> <line number="266" hits="1"/> - <line number="267" hits="1"/> - <line number="270" hits="1"/> + <line number="269" hits="1"/> + <line number="289" hits="1"/> <line number="290" hits="1"/> - <line number="291" hits="1"/> + <line number="293" hits="1"/> <line number="294" hits="1"/> <line number="295" hits="1"/> <line number="296" hits="1"/> @@ -161,10 +161,10 @@ <line number="306" hits="1"/> <line number="307" hits="1"/> <line number="308" hits="1"/> - <line number="309" hits="1"/> - <line number="312" hits="1"/> + <line number="311" hits="1"/> + <line number="335" hits="1"/> <line number="336" hits="1"/> - <line number="337" hits="1"/> + <line number="341" hits="1"/> <line number="342" hits="1"/> <line number="343" hits="1"/> <line number="344" hits="1"/> @@ -176,10 +176,10 @@ <line number="350" hits="1"/> <line number="351" hits="1"/> <line number="352" hits="1"/> - <line number="353" hits="1"/> - <line number="356" hits="1"/> + <line number="355" hits="1"/> + <line number="372" hits="1"/> <line number="373" hits="1"/> - <line number="374" hits="1"/> + <line number="375" hits="1"/> <line number="376" hits="1"/> <line number="377" hits="1"/> <line number="378" hits="1"/> @@ -190,11 +190,11 @@ <line number="383" hits="1"/> <line number="384" hits="1"/> <line number="385" hits="1"/> - <line number="386" hits="1"/> + <line number="387" hits="1"/> <line number="388" hits="1"/> <line number="389" hits="1"/> - <line number="390" hits="1"/> - <line number="393" hits="1"/> + <line number="392" hits="1"/> + <line number="408" hits="1"/> <line number="409" hits="1"/> <line number="410" hits="1"/> <line number="411" hits="1"/> @@ -207,11 +207,11 @@ <line number="418" hits="1"/> <line number="419" hits="1"/> <line number="420" hits="1"/> - <line number="421" hits="1"/> + <line number="422" hits="1"/> <line number="423" hits="1"/> - <line number="424" hits="1"/> - <line number="426" hits="1"/> - <line number="429" hits="1"/> + <line number="425" hits="1"/> + <line number="428" hits="1"/> + <line number="443" hits="1"/> <line number="444" hits="1"/> <line number="445" hits="1"/> <line number="446" hits="1"/> @@ -228,19 +228,18 @@ <line number="457" hits="1"/> <line number="458" hits="1"/> <line number="459" hits="1"/> - <line number="460" hits="1"/> + <line number="461" hits="1"/> <line number="462" hits="1"/> <line number="463" hits="1"/> - <line number="464" hits="1"/> - <line number="467" hits="1"/> + <line number="466" hits="1"/> + <line number="489" hits="1"/> + <line number="490" hits="1"/> <line number="491" hits="1"/> - <line number="492" hits="1"/> + <line number="494" hits="1"/> <line number="495" hits="1"/> <line number="496" hits="1"/> <line number="497" hits="1"/> - <line number="498" hits="1"/> - <line number="499" hits="1"/> - <line number="500" hits="1"/> + <line number="498" hits="0"/> <line number="501" hits="1"/> <line number="502" hits="1"/> <line number="503" hits="1"/> @@ -251,33 +250,33 @@ <line number="508" hits="1"/> <line number="509" hits="1"/> <line number="510" hits="1"/> + <line number="511" hits="1"/> + <line number="512" hits="1"/> <line number="513" hits="1"/> - <line number="525" hits="1"/> - <line number="526" hits="1"/> - <line number="527" hits="1"/> - <line number="528" hits="1"/> + <line number="514" hits="1"/> + <line number="517" hits="1"/> <line number="529" hits="1"/> <line number="530" hits="1"/> <line number="531" hits="1"/> <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="550" hits="1"/> - <line number="551" hits="1"/> - <line number="552" hits="1"/> - <line number="553" hits="1"/> + <line number="538" hits="1"/> + <line number="541" hits="1"/> <line number="554" hits="1"/> <line number="555" hits="1"/> <line number="556" hits="1"/> <line number="557" hits="1"/> <line number="558" hits="1"/> <line number="559" hits="1"/> + <line number="560" hits="1"/> + <line number="561" hits="1"/> <line number="562" hits="1"/> - <line number="576" hits="1"/> - <line number="577" hits="1"/> - <line number="578" hits="1"/> - <line number="579" hits="1"/> + <line number="563" hits="1"/> + <line number="566" hits="1"/> <line number="580" hits="1"/> <line number="581" hits="1"/> <line number="582" hits="1"/> @@ -289,11 +288,11 @@ <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="606" hits="1"/> - <line number="607" hits="1"/> - <line number="608" hits="1"/> - <line number="609" hits="1"/> + <line number="594" hits="1"/> + <line number="597" hits="1"/> <line number="610" hits="1"/> <line number="611" hits="1"/> <line number="612" hits="1"/> @@ -301,11 +300,11 @@ <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="633" hits="1"/> - <line number="634" hits="1"/> - <line number="635" hits="1"/> - <line number="636" hits="1"/> + <line number="620" hits="1"/> + <line number="623" hits="1"/> <line number="637" hits="1"/> <line number="638" hits="1"/> <line number="639" hits="1"/> @@ -316,47 +315,46 @@ <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="660" hits="1"/> - <line number="661" hits="1"/> - <line number="662" hits="1"/> - <line number="663" hits="1"/> + <line number="650" hits="1"/> + <line number="653" hits="1"/> <line number="664" hits="1"/> <line number="665" hits="1"/> <line number="666" hits="1"/> <line number="667" hits="1"/> + <line number="668" hits="1"/> + <line number="669" hits="1"/> <line number="670" hits="1"/> - <line number="683" hits="1"/> - <line number="684" hits="1"/> - <line number="685" hits="1"/> - <line number="686" hits="1"/> + <line number="671" hits="1"/> + <line number="674" 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="710" hits="1"/> - <line number="711" hits="1"/> - <line number="713" hits="1"/> + <line number="696" hits="1"/> + <line number="699" hits="1"/> <line number="714" hits="1"/> <line number="715" hits="1"/> - <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="743" hits="1"/> - <line number="744" hits="1"/> - <line number="747" hits="1"/> + <line number="724" hits="1"/> + <line number="727" 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"/> @@ -366,14 +364,14 @@ <line number="760" hits="1"/> <line number="761" hits="1"/> <line number="762" hits="1"/> + <line number="763" hits="1"/> + <line number="764" hits="1"/> <line number="765" hits="1"/> - <line number="780" hits="1"/> - <line number="781" hits="1"/> - <line number="782" hits="1"/> - <line number="783" hits="1"/> - <line number="784" hits="1"/> - <line number="785" hits="1"/> - <line number="786" hits="1"/> + <line number="766" hits="1"/> + <line number="767" hits="1"/> + <line number="768" hits="1"/> + <line number="769" hits="1"/> + <line number="772" hits="1"/> <line number="787" hits="1"/> <line number="788" hits="1"/> <line number="789" hits="1"/> @@ -384,14 +382,14 @@ <line number="794" hits="1"/> <line number="795" hits="1"/> <line number="796" hits="1"/> + <line number="797" hits="1"/> + <line number="798" hits="1"/> <line number="799" 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="800" hits="1"/> + <line number="801" hits="1"/> + <line number="802" hits="1"/> + <line number="803" hits="1"/> + <line number="806" hits="1"/> <line number="824" hits="1"/> <line number="825" hits="1"/> <line number="826" hits="1"/> @@ -403,15 +401,15 @@ <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="858" hits="1"/> - <line number="859" hits="1"/> - <line number="860" hits="1"/> - <line number="861" hits="1"/> - <line number="862" hits="1"/> - <line number="863" hits="1"/> - <line number="864" hits="1"/> + <line number="840" hits="1"/> + <line number="841" hits="1"/> + <line number="843" hits="1"/> + <line number="846" hits="1"/> <line number="865" hits="1"/> <line number="866" hits="1"/> <line number="867" hits="1"/> @@ -423,144 +421,145 @@ <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"/> + <line number="879" hits="1"/> <line number="880" 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="881" hits="1"/> + <line number="882" hits="1"/> + <line number="884" hits="1"/> + <line number="887" hits="1"/> <line number="901" hits="1"/> <line number="902" hits="1"/> <line number="903" hits="1"/> <line number="904" hits="1"/> <line number="905" hits="1"/> + <line number="906" hits="1"/> <line number="907" hits="1"/> + <line number="908" hits="1"/> + <line number="909" hits="1"/> <line number="910" hits="1"/> - <line number="926" hits="0"/> + <line number="911" hits="1"/> + <line number="912" hits="1"/> + <line number="914" hits="1"/> + <line number="917" hits="1"/> <line number="927" hits="0"/> <line number="928" hits="0"/> <line number="929" hits="0"/> + <line number="930" hits="0"/> <line number="932" hits="0"/> <line number="933" hits="0"/> <line number="934" hits="0"/> <line number="935" hits="0"/> - <line number="936" hits="0"/> - <line number="937" hits="0"/> - <line number="938" hits="0"/> - <line number="939" hits="0"/> - <line number="940" hits="0"/> - <line number="941" hits="0"/> - <line number="943" hits="0"/> - <line number="946" hits="1"/> + <line number="938" hits="1"/> + <line number="955" hits="0"/> + <line number="956" hits="0"/> + <line number="959" hits="0"/> <line number="960" hits="0"/> <line number="961" hits="0"/> <line number="962" hits="0"/> + <line number="963" hits="0"/> + <line number="964" hits="0"/> + <line number="965" hits="0"/> + <line number="966" hits="0"/> + <line number="967" hits="0"/> <line number="968" hits="0"/> - <line number="969" hits="0"/> <line number="970" hits="0"/> - <line number="971" hits="0"/> - <line number="972" hits="0"/> - <line number="973" hits="0"/> - <line number="974" hits="0"/> - <line number="975" hits="0"/> - <line number="976" hits="0"/> - <line number="977" hits="0"/> - <line number="980" hits="1"/> - <line number="992" hits="0"/> + <line number="973" hits="1"/> + <line number="987" hits="0"/> <line number="993" hits="0"/> <line number="994" hits="0"/> + <line number="995" hits="0"/> + <line number="996" hits="0"/> + <line number="997" hits="0"/> <line number="998" hits="0"/> <line number="999" hits="0"/> <line number="1000" hits="0"/> <line number="1001" hits="0"/> <line number="1002" hits="0"/> - <line number="1003" hits="0"/> - <line number="1004" hits="0"/> - <line number="1005" hits="0"/> - <line number="1006" hits="0"/> - <line number="1007" hits="0"/> - <line number="1010" hits="1"/> - <line number="1025" hits="1"/> - <line number="1026" hits="1"/> - <line number="1027" hits="1"/> - <line number="1028" hits="1"/> - <line number="1029" hits="1"/> - <line number="1030" hits="1"/> - <line number="1031" hits="1"/> - <line number="1032" hits="1"/> + <line number="1005" hits="1"/> + <line number="1017" hits="0"/> + <line number="1021" hits="0"/> + <line number="1022" hits="0"/> + <line number="1023" hits="0"/> + <line number="1024" hits="0"/> + <line number="1025" hits="0"/> + <line number="1026" hits="0"/> + <line number="1027" hits="0"/> + <line number="1028" hits="0"/> + <line number="1029" hits="0"/> + <line number="1030" hits="0"/> <line number="1033" hits="1"/> - <line number="1034" hits="1"/> - <line number="1035" hits="1"/> - <line number="1037" hits="1"/> - <line number="1038" hits="1"/> - <line number="1039" hits="1"/> - <line number="1042" hits="1"/> + <line number="1048" hits="1"/> + <line number="1049" hits="1"/> + <line number="1050" hits="1"/> + <line number="1051" hits="1"/> + <line number="1052" hits="1"/> + <line number="1053" hits="1"/> + <line number="1054" hits="1"/> + <line number="1055" hits="1"/> + <line number="1056" hits="1"/> <line number="1057" hits="1"/> <line number="1058" hits="1"/> - <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"/> - <line number="1067" hits="1"/> - <line number="1068" hits="1"/> - <line number="1070" hits="1"/> - <line number="1073" 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"/> + <line number="1086" hits="1"/> <line number="1087" hits="1"/> <line number="1088" hits="1"/> <line number="1089" hits="1"/> <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"/> - <line number="1098" hits="1"/> - <line number="1100" hits="1"/> - <line number="1103" hits="1"/> + <line number="1110" hits="1"/> + <line number="1111" hits="1"/> + <line number="1112" hits="1"/> + <line number="1113" hits="1"/> + <line number="1114" hits="1"/> + <line number="1115" hits="1"/> + <line number="1116" hits="1"/> + <line number="1117" hits="1"/> + <line number="1118" hits="1"/> + <line number="1119" hits="1"/> <line number="1120" hits="1"/> <line number="1121" hits="1"/> - <line number="1122" hits="1"/> <line number="1123" hits="1"/> - <line number="1124" hits="1"/> - <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="1138" hits="1"/> - <line number="1141" 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="1149" hits="1"/> + <line number="1150" hits="1"/> + <line number="1151" 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="1164" hits="1"/> - <line number="1165" hits="1"/> - <line number="1166" hits="1"/> - <line number="1167" hits="1"/> - <line number="1168" hits="1"/> - <line number="1169" hits="1"/> - <line number="1170" hits="1"/> - <line number="1172" hits="1"/> - <line number="1175" 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"/> <line number="1187" hits="1"/> <line number="1188" hits="1"/> <line number="1189" hits="1"/> @@ -568,102 +567,104 @@ <line number="1191" hits="1"/> <line number="1192" hits="1"/> <line number="1193" hits="1"/> - <line number="1194" hits="1"/> <line number="1195" hits="1"/> - <line number="1196" hits="1"/> - <line number="1199" hits="1"/> + <line number="1198" hits="1"/> + <line number="1210" hits="1"/> + <line number="1211" hits="1"/> + <line number="1212" hits="1"/> + <line number="1213" hits="1"/> + <line number="1214" hits="1"/> + <line number="1215" hits="1"/> <line number="1216" hits="1"/> <line number="1217" hits="1"/> <line number="1218" hits="1"/> <line number="1219" hits="1"/> - <line number="1220" hits="1"/> - <line number="1221" hits="1"/> <line number="1222" hits="1"/> - <line number="1223" hits="1"/> - <line number="1224" hits="1"/> - <line number="1225" hits="1"/> - <line number="1226" hits="1"/> - <line number="1227" hits="1"/> - <line number="1228" hits="1"/> - <line number="1230" hits="1"/> - <line number="1231" hits="1"/> - <line number="1232" hits="1"/> - <line number="1235" hits="1"/> - <line number="1252" hits="1"/> + <line number="1239" hits="1"/> + <line number="1240" hits="1"/> + <line number="1241" hits="1"/> + <line number="1242" hits="1"/> + <line number="1243" hits="1"/> + <line number="1244" hits="1"/> + <line number="1245" hits="1"/> + <line number="1246" hits="1"/> + <line number="1247" hits="1"/> + <line number="1248" hits="1"/> + <line number="1249" hits="1"/> + <line number="1250" hits="1"/> + <line number="1251" hits="1"/> <line number="1253" hits="1"/> <line number="1254" hits="1"/> <line number="1255" hits="1"/> - <line number="1256" hits="1"/> - <line number="1257" hits="1"/> <line number="1258" hits="1"/> - <line number="1259" hits="1"/> - <line number="1260" hits="1"/> - <line number="1261" hits="1"/> - <line number="1262" hits="1"/> - <line number="1263" hits="1"/> - <line number="1264" hits="1"/> - <line number="1266" hits="1"/> - <line number="1267" hits="1"/> - <line number="1268" hits="1"/> - <line number="1271" hits="1"/> + <line number="1275" hits="1"/> + <line number="1276" hits="1"/> + <line number="1277" hits="1"/> + <line number="1278" hits="1"/> + <line number="1279" hits="1"/> + <line number="1280" hits="1"/> + <line number="1281" hits="1"/> + <line number="1282" hits="1"/> + <line number="1283" hits="1"/> + <line number="1284" hits="1"/> <line number="1285" hits="1"/> <line number="1286" hits="1"/> <line number="1287" hits="1"/> - <line number="1288" hits="1"/> <line number="1289" hits="1"/> <line number="1290" hits="1"/> <line number="1291" hits="1"/> - <line number="1292" hits="1"/> - <line number="1293" hits="1"/> <line number="1294" hits="1"/> - <line number="1295" hits="1"/> - <line number="1296" hits="1"/> - <line number="1298" hits="1"/> - <line number="1299" hits="1"/> - <line number="1300" hits="1"/> - <line number="1303" hits="1"/> + <line number="1308" hits="1"/> + <line number="1309" hits="1"/> + <line number="1310" hits="1"/> + <line number="1311" hits="1"/> + <line number="1312" hits="1"/> + <line number="1313" hits="1"/> + <line number="1314" hits="1"/> + <line number="1315" hits="1"/> + <line number="1316" hits="1"/> + <line number="1317" hits="1"/> + <line number="1318" hits="1"/> + <line number="1319" hits="1"/> + <line number="1321" hits="1"/> + <line number="1322" hits="1"/> + <line number="1323" hits="1"/> <line number="1326" hits="1"/> - <line number="1327" hits="1"/> - <line number="1328" hits="1"/> - <line number="1329" hits="1"/> - <line number="1330" hits="1"/> - <line number="1331" hits="1"/> - <line number="1332" hits="1"/> - <line number="1333" hits="1"/> - <line number="1335" hits="1"/> - <line number="1336" hits="1"/> - <line number="1337" hits="1"/> - <line number="1338" hits="1"/> - <line number="1339" hits="1"/> - <line number="1340" hits="1"/> - <line number="1341" hits="1"/> - <line number="1342" hits="1"/> - <line number="1343" hits="1"/> - <line number="1344" hits="1"/> - <line number="1345" hits="1"/> - <line number="1346" hits="1"/> - <line number="1347" hits="1"/> - <line number="1348" hits="1"/> <line number="1349" hits="1"/> <line number="1350" hits="1"/> + <line number="1351" hits="1"/> + <line number="1352" hits="1"/> <line number="1353" hits="1"/> + <line number="1354" hits="1"/> + <line number="1355" hits="1"/> + <line number="1356" hits="1"/> + <line number="1357" hits="1"/> + <line number="1358" hits="1"/> + <line number="1360" hits="1"/> + <line number="1361" hits="1"/> + <line number="1362" hits="1"/> + <line number="1363" hits="1"/> + <line number="1364" hits="1"/> + <line number="1365" hits="1"/> + <line number="1366" hits="1"/> + <line number="1367" hits="1"/> + <line number="1368" hits="1"/> + <line number="1369" hits="1"/> + <line number="1370" hits="1"/> <line number="1371" hits="1"/> <line number="1372" hits="1"/> <line number="1373" hits="1"/> <line number="1374" hits="1"/> <line number="1375" hits="1"/> - <line number="1376" hits="1"/> - <line number="1377" hits="1"/> <line number="1378" hits="1"/> - <line number="1379" hits="1"/> - <line number="1380" hits="1"/> - <line number="1381" hits="1"/> - <line number="1382" hits="1"/> - <line number="1383" hits="1"/> - <line number="1384" hits="1"/> - <line number="1385" hits="1"/> - <line number="1386" hits="1"/> - <line number="1389" hits="1"/> + <line number="1396" hits="1"/> + <line number="1397" hits="1"/> + <line number="1398" hits="1"/> + <line number="1399" hits="1"/> + <line number="1400" hits="1"/> + <line number="1401" hits="1"/> + <line number="1402" hits="1"/> + <line number="1403" hits="1"/> <line number="1404" hits="1"/> <line number="1405" hits="1"/> <line number="1406" hits="1"/> @@ -671,13 +672,13 @@ <line number="1408" hits="1"/> <line number="1409" hits="1"/> <line number="1410" hits="1"/> - <line number="1411" hits="1"/> - <line number="1412" hits="1"/> <line number="1413" hits="1"/> - <line number="1414" hits="1"/> - <line number="1415" hits="1"/> - <line number="1416" hits="1"/> - <line number="1419" hits="1"/> + <line number="1428" hits="1"/> + <line number="1429" hits="1"/> + <line number="1430" hits="1"/> + <line number="1431" hits="1"/> + <line number="1432" hits="1"/> + <line number="1433" hits="1"/> <line number="1434" hits="1"/> <line number="1435" hits="1"/> <line number="1436" hits="1"/> @@ -685,14 +686,12 @@ <line number="1438" hits="1"/> <line number="1439" hits="1"/> <line number="1440" hits="1"/> - <line number="1441" hits="1"/> - <line number="1442" hits="1"/> <line number="1443" hits="1"/> - <line number="1444" hits="1"/> - <line number="1445" hits="1"/> - <line number="1446" hits="1"/> - <line number="1447" hits="1"/> - <line number="1450" hits="1"/> + <line number="1458" hits="1"/> + <line number="1459" hits="1"/> + <line number="1460" hits="1"/> + <line number="1461" hits="1"/> + <line number="1462" hits="1"/> <line number="1463" hits="1"/> <line number="1464" hits="1"/> <line number="1465" hits="1"/> @@ -702,209 +701,207 @@ <line number="1469" hits="1"/> <line number="1470" hits="1"/> <line number="1471" hits="1"/> - <line number="1472" hits="1"/> - <line number="1473" hits="1"/> <line number="1474" hits="1"/> - <line number="1477" hits="1"/> + <line number="1487" hits="1"/> + <line number="1488" hits="1"/> + <line number="1489" hits="1"/> + <line number="1490" hits="1"/> + <line number="1491" hits="1"/> + <line number="1492" hits="1"/> + <line number="1493" hits="1"/> + <line number="1494" hits="1"/> <line number="1495" hits="1"/> <line number="1496" hits="1"/> <line number="1497" hits="1"/> <line number="1498" hits="1"/> - <line number="1499" hits="1"/> - <line number="1500" hits="1"/> <line number="1501" hits="1"/> - <line number="1502" hits="1"/> - <line number="1503" hits="1"/> - <line number="1504" hits="1"/> - <line number="1505" hits="1"/> - <line number="1506" hits="1"/> - <line number="1507" hits="1"/> - <line number="1508" hits="1"/> - <line number="1509" hits="1"/> - <line number="1510" hits="1"/> - <line number="1513" hits="1"/> - <line number="1549" hits="1"/> - <line number="1550" hits="1"/> - <line number="1555" hits="1"/> - <line number="1556" hits="1"/> - <line number="1557" hits="1"/> - <line number="1558" hits="1"/> - <line number="1559" hits="1"/> - <line number="1560" hits="1"/> - <line number="1561" hits="1"/> - <line number="1562" hits="1"/> - <line number="1563" hits="1"/> - <line number="1564" hits="1"/> - <line number="1565" hits="1"/> - <line number="1566" hits="1"/> - <line number="1568" hits="1"/> - <line number="1569" hits="1"/> - <line number="1570" hits="1"/> + <line number="1519" hits="1"/> + <line number="1520" hits="1"/> + <line number="1521" hits="1"/> + <line number="1522" hits="1"/> + <line number="1523" hits="1"/> + <line number="1524" hits="1"/> + <line number="1525" hits="1"/> + <line number="1526" hits="1"/> + <line number="1527" hits="1"/> + <line number="1528" hits="1"/> + <line number="1529" hits="1"/> + <line number="1530" hits="1"/> + <line number="1531" hits="1"/> + <line number="1532" hits="1"/> + <line number="1533" hits="1"/> + <line number="1534" hits="1"/> + <line number="1537" hits="1"/> <line number="1573" hits="1"/> - <line number="1610" hits="1"/> - <line number="1611" hits="1"/> - <line number="1617" hits="1"/> - <line number="1618" hits="1"/> - <line number="1619" hits="1"/> - <line number="1620" hits="1"/> - <line number="1621" hits="1"/> - <line number="1622" hits="1"/> - <line number="1623" hits="1"/> - <line number="1624" hits="1"/> - <line number="1625" hits="1"/> - <line number="1626" hits="1"/> - <line number="1627" hits="1"/> - <line number="1628" hits="1"/> - <line number="1630" hits="1"/> - <line number="1631" hits="1"/> - <line number="1632" hits="1"/> + <line number="1574" hits="1"/> + <line number="1579" hits="1"/> + <line number="1580" hits="1"/> + <line number="1581" hits="1"/> + <line number="1582" hits="1"/> + <line number="1583" hits="1"/> + <line number="1584" hits="1"/> + <line number="1585" hits="1"/> + <line number="1586" hits="1"/> + <line number="1587" hits="1"/> + <line number="1588" hits="1"/> + <line number="1589" hits="1"/> + <line number="1590" hits="1"/> + <line number="1592" hits="1"/> + <line number="1593" hits="1"/> + <line number="1594" hits="1"/> + <line number="1597" hits="1"/> + <line number="1634" hits="1"/> <line number="1635" hits="1"/> + <line number="1641" hits="1"/> + <line number="1642" hits="1"/> + <line number="1643" hits="1"/> + <line number="1644" hits="1"/> + <line number="1645" hits="1"/> + <line number="1646" hits="1"/> + <line number="1647" hits="1"/> + <line number="1648" hits="1"/> + <line number="1649" hits="1"/> <line number="1650" hits="1"/> <line number="1651" hits="1"/> <line number="1652" hits="1"/> - <line number="1653" hits="1"/> <line number="1654" hits="1"/> <line number="1655" hits="1"/> <line number="1656" hits="1"/> - <line number="1657" hits="1"/> - <line number="1658" hits="1"/> <line number="1659" hits="1"/> - <line number="1660" hits="1"/> - <line number="1661" hits="1"/> - <line number="1662" hits="1"/> - <line number="1664" hits="1"/> - <line number="1665" hits="1"/> - <line number="1666" hits="1"/> - <line number="1669" hits="1"/> + <line number="1674" hits="1"/> <line number="1675" hits="1"/> <line number="1676" hits="1"/> <line number="1677" hits="1"/> <line number="1678" hits="1"/> <line number="1679" hits="1"/> <line number="1680" hits="1"/> + <line number="1681" hits="1"/> + <line number="1682" hits="1"/> <line number="1683" hits="1"/> - <line number="1689" hits="0"/> - <line number="1690" hits="0"/> - <line number="1691" hits="0"/> - <line number="1692" hits="0"/> - <line number="1693" hits="0"/> - <line number="1694" hits="0"/> - <line number="1697" hits="1"/> + <line number="1684" hits="1"/> + <line number="1685" hits="1"/> + <line number="1686" hits="1"/> + <line number="1688" hits="1"/> + <line number="1689" hits="1"/> + <line number="1690" hits="1"/> + <line number="1693" hits="1"/> + <line number="1699" hits="1"/> + <line number="1700" hits="1"/> + <line number="1701" hits="1"/> + <line number="1702" hits="1"/> <line number="1703" hits="1"/> <line number="1704" hits="1"/> - <line number="1705" hits="1"/> - <line number="1706" hits="1"/> <line number="1707" hits="1"/> - <line number="1708" hits="1"/> - <line number="1711" hits="1"/> + <line number="1713" hits="0"/> + <line number="1714" hits="0"/> + <line number="1715" hits="0"/> + <line number="1716" hits="0"/> + <line number="1717" hits="0"/> + <line number="1718" hits="0"/> + <line number="1721" hits="1"/> + <line number="1727" hits="1"/> + <line number="1728" hits="1"/> + <line number="1729" hits="1"/> <line number="1730" hits="1"/> <line number="1731" hits="1"/> <line number="1732" hits="1"/> - <line number="1733" hits="1"/> - <line number="1734" hits="1"/> <line number="1735" hits="1"/> - <line number="1736" hits="1"/> - <line number="1737" hits="1"/> - <line number="1738" hits="1"/> - <line number="1739" hits="1"/> - <line number="1740" hits="1"/> - <line number="1741" hits="1"/> - <line number="1742" hits="1"/> - <line number="1743" hits="1"/> - <line number="1744" hits="1"/> - <line number="1745" hits="1"/> - <line number="1746" hits="1"/> - <line number="1747" hits="1"/> - <line number="1748" hits="1"/> - <line number="1749" hits="1"/> - <line number="1750" hits="1"/> - <line number="1751" hits="1"/> - <line number="1752" hits="1"/> - <line number="1753" hits="1"/> <line number="1754" hits="1"/> <line number="1755" hits="1"/> <line number="1756" hits="1"/> <line number="1757" hits="1"/> + <line number="1758" hits="1"/> <line number="1759" hits="1"/> + <line number="1760" hits="1"/> + <line number="1761" hits="1"/> <line number="1762" hits="1"/> - <line number="1773" hits="0"/> - <line number="1774" hits="0"/> - <line number="1775" hits="0"/> - <line number="1776" hits="0"/> - <line number="1777" hits="0"/> - <line number="1778" hits="0"/> - <line number="1779" hits="0"/> - <line number="1780" hits="0"/> + <line number="1763" hits="1"/> + <line number="1764" hits="1"/> + <line number="1765" hits="1"/> + <line number="1766" hits="1"/> + <line number="1767" hits="1"/> + <line number="1768" hits="1"/> + <line number="1769" hits="1"/> + <line number="1770" hits="1"/> + <line number="1771" hits="1"/> + <line number="1772" hits="1"/> + <line number="1773" hits="1"/> + <line number="1774" hits="1"/> + <line number="1775" hits="1"/> + <line number="1776" hits="1"/> + <line number="1777" hits="1"/> + <line number="1778" hits="1"/> + <line number="1779" hits="1"/> + <line number="1780" hits="1"/> + <line number="1781" hits="1"/> <line number="1783" hits="1"/> - <line number="1794" hits="0"/> - <line number="1795" hits="0"/> - <line number="1796" hits="0"/> + <line number="1786" hits="1"/> <line number="1797" hits="0"/> <line number="1798" hits="0"/> <line number="1799" hits="0"/> <line number="1800" hits="0"/> <line number="1801" hits="0"/> - <line number="1804" hits="1"/> - <line number="1810" hits="1"/> - <line number="1811" hits="1"/> - <line number="1812" hits="1"/> - <line number="1813" hits="1"/> - <line number="1814" hits="1"/> - <line number="1815" hits="0"/> - <line number="1818" hits="1"/> - <line number="1824" hits="1"/> - <line number="1825" hits="1"/> - <line number="1826" hits="1"/> - <line number="1827" hits="1"/> - <line number="1828" hits="1"/> + <line number="1802" hits="0"/> + <line number="1803" hits="0"/> + <line number="1804" hits="0"/> + <line number="1807" hits="1"/> + <line number="1818" hits="0"/> + <line number="1819" hits="0"/> + <line number="1820" hits="0"/> + <line number="1821" hits="0"/> + <line number="1822" hits="0"/> + <line number="1823" hits="0"/> + <line number="1824" hits="0"/> + <line number="1826" hits="0"/> + <line number="1827" hits="0"/> <line number="1829" hits="0"/> - <line number="1833" hits="1"/> + <line number="1830" hits="0"/> + <line number="1832" hits="0"/> + <line number="1833" hits="0"/> + <line number="1834" hits="0"/> + <line number="1835" hits="0"/> + <line number="1836" hits="0"/> + <line number="1837" hits="0"/> + <line number="1840" hits="1"/> + <line number="1851" hits="1"/> + <line number="1852" hits="1"/> <line number="1853" hits="1"/> <line number="1854" hits="1"/> - <line number="1856" hits="1"/> - <line number="1857" hits="1"/> - <line number="1858" hits="1"/> - <line number="1859" hits="1"/> - <line number="1860" hits="1"/> + <line number="1855" hits="1"/> + <line number="1856" hits="0"/> + <line number="1857" hits="0"/> + <line number="1858" hits="0"/> <line number="1861" hits="1"/> - <line number="1862" hits="1"/> - <line number="1863" hits="1"/> - <line number="1864" hits="1"/> - <line number="1865" hits="1"/> - <line number="1866" hits="1"/> <line number="1867" hits="1"/> <line number="1868" hits="1"/> <line number="1869" hits="1"/> - </lines> - </class> - <class name="UploadClient.py" filename="dbrepo/UploadClient.py" complexity="0" line-rate="0.52" branch-rate="0"> - <methods/> - <lines> - <line number="1" hits="1"/> - <line number="2" hits="1"/> - <line number="3" hits="1"/> - <line number="4" hits="1"/> - <line number="5" hits="1"/> - <line number="7" hits="1"/> - <line number="8" hits="1"/> - <line number="10" hits="1"/> - <line number="12" hits="1"/> - <line number="16" hits="1"/> - <line number="24" hits="1"/> - <line number="26" hits="1"/> - <line number="27" hits="0"/> - <line number="29" hits="1"/> - <line number="30" hits="0"/> - <line number="31" hits="0"/> - <line number="32" hits="0"/> - <line number="33" hits="0"/> - <line number="34" hits="0"/> - <line number="35" hits="0"/> - <line number="36" hits="0"/> - <line number="37" hits="0"/> - <line number="38" hits="0"/> - <line number="39" hits="0"/> - <line number="40" hits="0"/> + <line number="1870" hits="1"/> + <line number="1871" hits="1"/> + <line number="1872" hits="0"/> + <line number="1875" hits="1"/> + <line number="1881" hits="1"/> + <line number="1882" hits="1"/> + <line number="1883" hits="1"/> + <line number="1884" hits="1"/> + <line number="1885" hits="1"/> + <line number="1886" hits="0"/> + <line number="1889" hits="1"/> + <line number="1909" hits="1"/> + <line number="1910" hits="1"/> + <line number="1912" hits="1"/> + <line number="1913" hits="1"/> + <line number="1914" hits="1"/> + <line number="1915" hits="1"/> + <line number="1916" hits="1"/> + <line number="1917" hits="1"/> + <line number="1918" hits="1"/> + <line number="1919" hits="1"/> + <line number="1920" hits="1"/> + <line number="1921" hits="1"/> + <line number="1922" hits="1"/> + <line number="1923" hits="1"/> + <line number="1924" hits="1"/> + <line number="1925" hits="1"/> </lines> </class> <class name="__init__.py" filename="dbrepo/__init__.py" complexity="0" line-rate="1" branch-rate="0"> @@ -913,7 +910,7 @@ </class> </classes> </package> - <package name="dbrepo.api" line-rate="1" branch-rate="0" complexity="0"> + <package name="dbrepo.api" line-rate="0.959" branch-rate="0" complexity="0"> <classes> <class name="__init__.py" filename="dbrepo/api/__init__.py" complexity="0" line-rate="1" branch-rate="0"> <methods/> @@ -941,81 +938,79 @@ <line number="26" hits="1"/> <line number="27" hits="1"/> <line number="28" hits="1"/> - <line number="29" hits="1"/> - <line number="30" hits="1"/> <line number="31" hits="1"/> <line number="32" hits="1"/> <line number="33" hits="1"/> - <line number="36" hits="1"/> - <line number="37" hits="1"/> + <line number="34" hits="1"/> + <line number="35" hits="1"/> <line number="38" hits="1"/> <line number="39" hits="1"/> <line number="40" hits="1"/> - <line number="43" hits="1"/> - <line number="44" hits="1"/> + <line number="41" hits="1"/> + <line number="42" hits="1"/> <line number="45" hits="1"/> <line number="46" hits="1"/> <line number="47" hits="1"/> <line number="50" hits="1"/> <line number="51" hits="1"/> <line number="52" hits="1"/> + <line number="53" hits="1"/> + <line number="54" hits="1"/> <line number="55" hits="1"/> <line number="56" hits="1"/> <line number="57" hits="1"/> <line number="58" hits="1"/> - <line number="59" hits="1"/> - <line number="60" hits="1"/> <line number="61" hits="1"/> <line number="62" hits="1"/> <line number="63" hits="1"/> - <line number="66" hits="1"/> + <line number="64" hits="1"/> <line number="67" hits="1"/> <line number="68" hits="1"/> <line number="69" hits="1"/> + <line number="70" hits="1"/> + <line number="71" hits="1"/> <line number="72" hits="1"/> <line number="73" hits="1"/> - <line number="74" hits="1"/> - <line number="75" hits="1"/> <line number="76" hits="1"/> <line number="77" hits="1"/> <line number="78" hits="1"/> + <line number="79" hits="1"/> + <line number="80" hits="1"/> <line number="81" hits="1"/> <line number="82" hits="1"/> <line number="83" hits="1"/> - <line number="84" hits="1"/> - <line number="85" hits="1"/> <line number="86" hits="1"/> <line number="87" hits="1"/> <line number="88" hits="1"/> + <line number="89" hits="1"/> + <line number="90" hits="1"/> <line number="91" hits="1"/> <line number="92" hits="1"/> - <line number="93" hits="1"/> - <line number="94" hits="1"/> <line number="95" hits="1"/> <line number="96" hits="1"/> <line number="97" hits="1"/> <line number="98" hits="1"/> <line number="99" hits="1"/> - <line number="102" hits="1"/> - <line number="103" hits="1"/> + <line number="100" hits="1"/> + <line number="101" hits="1"/> <line number="104" hits="1"/> <line number="105" hits="1"/> <line number="106" hits="1"/> <line number="107" hits="1"/> <line number="108" hits="1"/> + <line number="109" hits="1"/> + <line number="110" hits="1"/> <line number="111" hits="1"/> - <line number="112" hits="1"/> - <line number="113" hits="1"/> <line number="114" hits="1"/> <line number="115" hits="1"/> <line number="116" hits="1"/> <line number="117" hits="1"/> <line number="118" hits="1"/> + <line number="119" hits="1"/> + <line number="120" hits="1"/> <line number="121" hits="1"/> <line number="122" hits="1"/> <line number="123" hits="1"/> - <line number="124" hits="1"/> - <line number="125" hits="1"/> <line number="126" hits="1"/> <line number="127" hits="1"/> <line number="128" hits="1"/> @@ -1026,26 +1021,28 @@ <line number="135" hits="1"/> <line number="136" hits="1"/> <line number="137" hits="1"/> + <line number="138" hits="1"/> + <line number="139" hits="1"/> <line number="140" hits="1"/> - <line number="141" hits="1"/> - <line number="142" hits="1"/> <line number="143" hits="1"/> <line number="144" hits="1"/> - <line number="145" hits="1"/> - <line number="146" hits="1"/> <line number="147" hits="1"/> - <line number="150" hits="1"/> + <line number="148" hits="1"/> <line number="151" hits="1"/> - <line number="154" hits="1"/> <line number="155" hits="1"/> + <line number="156" hits="1"/> <line number="158" hits="1"/> + <line number="159" hits="1"/> + <line number="161" hits="1"/> <line number="162" hits="1"/> - <line number="163" hits="1"/> <line number="165" hits="1"/> - <line number="166" hits="1"/> - <line number="168" hits="1"/> <line number="169" hits="1"/> + <line number="170" hits="1"/> + <line number="171" hits="1"/> <line number="172" hits="1"/> + <line number="173" hits="1"/> + <line number="174" hits="1"/> + <line number="175" hits="1"/> <line number="176" hits="1"/> <line number="177" hits="1"/> <line number="178" hits="1"/> @@ -1069,14 +1066,14 @@ <line number="196" hits="1"/> <line number="197" hits="1"/> <line number="198" hits="1"/> - <line number="199" hits="1"/> - <line number="200" hits="1"/> <line number="201" hits="1"/> - <line number="202" hits="1"/> - <line number="203" hits="1"/> - <line number="204" hits="1"/> <line number="205" hits="1"/> + <line number="206" hits="1"/> + <line number="207" hits="1"/> <line number="208" hits="1"/> + <line number="209" hits="1"/> + <line number="210" hits="1"/> + <line number="211" hits="1"/> <line number="212" hits="1"/> <line number="213" hits="1"/> <line number="214" hits="1"/> @@ -1254,171 +1251,171 @@ <line number="386" hits="1"/> <line number="387" hits="1"/> <line number="388" hits="1"/> - <line number="389" hits="1"/> - <line number="390" hits="1"/> <line number="391" hits="1"/> <line number="392" hits="1"/> <line number="393" hits="1"/> - <line number="394" hits="1"/> - <line number="395" hits="1"/> - <line number="398" hits="1"/> - <line number="399" hits="1"/> + <line number="396" hits="1"/> + <line number="397" hits="1"/> <line number="400" hits="1"/> - <line number="403" hits="1"/> + <line number="401" hits="1"/> <line number="404" hits="1"/> - <line number="407" hits="1"/> <line number="408" hits="1"/> + <line number="409" hits="1"/> + <line number="410" hits="1"/> <line number="411" hits="1"/> + <line number="414" hits="1"/> <line number="415" hits="1"/> <line number="416" hits="1"/> <line number="417" hits="1"/> - <line number="418" hits="1"/> + <line number="420" hits="1"/> <line number="421" hits="1"/> - <line number="422" hits="1"/> - <line number="423" hits="1"/> <line number="424" hits="1"/> + <line number="425" hits="1"/> + <line number="426" hits="1"/> <line number="427" hits="1"/> <line number="428" hits="1"/> <line number="431" hits="1"/> <line number="432" hits="1"/> <line number="433" hits="1"/> <line number="434" hits="1"/> - <line number="435" hits="1"/> + <line number="437" hits="1"/> <line number="438" hits="1"/> - <line number="439" hits="1"/> - <line number="440" hits="1"/> <line number="441" hits="1"/> + <line number="442" hits="1"/> + <line number="443" hits="1"/> <line number="444" hits="1"/> <line number="445" hits="1"/> + <line number="446" hits="1"/> + <line number="447" hits="1"/> <line number="448" hits="1"/> - <line number="449" hits="1"/> - <line number="450" hits="1"/> <line number="451" hits="1"/> <line number="452" hits="1"/> <line number="453" hits="1"/> <line number="454" hits="1"/> <line number="455" hits="1"/> - <line number="458" hits="1"/> - <line number="459" hits="1"/> + <line number="456" hits="1"/> + <line number="457" hits="1"/> <line number="460" hits="1"/> <line number="461" hits="1"/> - <line number="462" hits="1"/> - <line number="463" hits="1"/> <line number="464" hits="1"/> + <line number="465" hits="1"/> + <line number="466" hits="1"/> <line number="467" hits="1"/> - <line number="468" hits="1"/> + <line number="470" hits="1"/> <line number="471" hits="1"/> <line number="472" hits="1"/> <line number="473" hits="1"/> <line number="474" hits="1"/> - <line number="477" hits="1"/> - <line number="478" hits="1"/> + <line number="475" hits="1"/> + <line number="476" hits="1"/> <line number="479" hits="1"/> <line number="480" hits="1"/> - <line number="481" hits="1"/> - <line number="482" hits="1"/> <line number="483" hits="1"/> - <line number="486" hits="1"/> - <line number="487" hits="1"/> - <line number="490" hits="1"/> - <line number="491" hits="1"/> + <line number="484" hits="1"/> + <line number="485" hits="1"/> + <line number="488" hits="1"/> + <line number="489" hits="1"/> <line number="492" hits="1"/> + <line number="493" hits="1"/> + <line number="494" hits="1"/> <line number="495" hits="1"/> <line number="496" hits="1"/> - <line number="499" hits="1"/> + <line number="497" hits="1"/> <line number="500" hits="1"/> <line number="501" hits="1"/> <line number="502" hits="1"/> - <line number="503" hits="1"/> - <line number="504" hits="1"/> + <line number="505" hits="1"/> + <line number="506" hits="1"/> <line number="507" hits="1"/> - <line number="508" hits="1"/> - <line number="509" hits="1"/> - <line number="512" hits="1"/> - <line number="513" 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="521" hits="1"/> - <line number="522" hits="1"/> + <line number="519" hits="1"/> + <line number="520" 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"/> <line number="530" hits="1"/> <line number="531" hits="1"/> <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="544" hits="1"/> - <line number="545" hits="1"/> - <line number="546" hits="1"/> - <line number="547" hits="1"/> <line number="548" hits="1"/> + <line number="549" hits="1"/> + <line number="550" hits="1"/> <line number="551" hits="1"/> - <line number="555" hits="1"/> - <line number="556" hits="1"/> - <line number="557" hits="1"/> + <line number="554" hits="1"/> <line number="558" hits="1"/> - <line number="561" hits="1"/> + <line number="559" hits="1"/> + <line number="560" 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"/> <line number="570" hits="1"/> <line number="571" hits="1"/> <line number="572" hits="1"/> <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"/> <line number="596" hits="1"/> <line number="597" hits="1"/> <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="605" hits="1"/> - <line number="606" 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="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="620" hits="1"/> <line number="621" hits="1"/> - <line number="622" hits="1"/> - <line number="623" 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"/> <line number="631" hits="1"/> <line number="632" hits="1"/> <line number="633" hits="1"/> @@ -1435,15 +1432,15 @@ <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="651" hits="1"/> - <line number="652" 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"/> <line number="660" hits="1"/> <line number="661" hits="1"/> <line number="662" hits="1"/> @@ -1464,19 +1461,19 @@ <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"/> <line number="698" hits="1"/> <line number="699" hits="1"/> @@ -1484,12 +1481,12 @@ <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"/> <line number="713" hits="1"/> <line number="714" hits="1"/> @@ -1497,13 +1494,11 @@ <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="727" hits="1"/> + <line number="725" hits="1"/> <line number="728" hits="1"/> <line number="729" hits="1"/> <line number="730" hits="1"/> @@ -1512,96 +1507,83 @@ <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"/> <line number="741" hits="1"/> <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="753" hits="1"/> + <line number="751" hits="1"/> <line number="754" hits="1"/> <line number="755" hits="1"/> <line number="756" hits="1"/> <line number="757" hits="1"/> <line number="760" hits="1"/> <line number="761" hits="1"/> - <line number="762" hits="1"/> - <line number="763" hits="1"/> + <line number="764" hits="1"/> + <line number="765" hits="1"/> <line number="766" hits="1"/> <line number="767" hits="1"/> - <line number="770" hits="1"/> - <line number="771" hits="1"/> + <line number="768" hits="1"/> + <line number="769" hits="1"/> <line number="772" hits="1"/> <line number="773" hits="1"/> <line number="774" hits="1"/> <line number="775" hits="1"/> <line number="778" hits="1"/> <line number="779" hits="1"/> - <line number="780" hits="1"/> - <line number="781" hits="1"/> + <line number="782" hits="1"/> + <line number="783" hits="1"/> <line number="784" hits="1"/> <line number="785" hits="1"/> - <line number="788" hits="1"/> + <line number="786" hits="1"/> <line number="789" hits="1"/> - <line number="790" hits="1"/> - <line number="791" hits="1"/> - <line number="792" hits="1"/> + <line number="793" hits="1"/> + <line number="794" hits="1"/> <line number="795" hits="1"/> - <line number="796" hits="1"/> - <line number="799" hits="1"/> + <line number="798" hits="1"/> + <line number="802" hits="1"/> <line number="803" hits="1"/> - <line number="804" hits="1"/> - <line number="805" hits="1"/> <line number="806" hits="1"/> + <line number="807" hits="1"/> + <line number="808" hits="1"/> <line number="809" hits="1"/> + <line number="810" 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="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="828" hits="1"/> - <line number="829" 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="845" hits="1"/> - <line number="846" hits="1"/> - <line number="847" hits="1"/> + <line number="844" hits="1"/> <line number="848" hits="1"/> <line number="849" hits="1"/> <line number="850" hits="1"/> <line number="851" hits="1"/> - <line number="852" hits="1"/> - <line number="853" hits="1"/> <line number="854" hits="1"/> - <line number="855" hits="1"/> - <line number="856" hits="1"/> - <line number="857" hits="1"/> <line number="858" hits="1"/> <line number="859" hits="1"/> - <line number="860" hits="1"/> - <line number="861" hits="1"/> <line number="862" hits="1"/> - <line number="863" hits="1"/> - <line number="864" hits="1"/> - <line number="865" hits="1"/> <line number="866" hits="1"/> <line number="867" hits="1"/> <line number="868" hits="1"/> @@ -1615,62 +1597,73 @@ <line number="876" hits="1"/> <line number="877" hits="1"/> <line number="878" hits="1"/> + <line number="879" hits="1"/> + <line number="880" hits="1"/> <line number="881" hits="1"/> - <line number="885" hits="1"/> + <line number="882" hits="1"/> + <line number="883" 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"/> + <line number="903" hits="1"/> <line number="904" hits="1"/> + <line number="905" hits="1"/> + <line number="906" hits="1"/> + <line number="907" hits="1"/> <line number="908" hits="1"/> <line number="909" hits="1"/> + <line number="910" hits="1"/> <line number="911" hits="1"/> <line number="912" hits="1"/> + <line number="913" hits="1"/> <line number="914" hits="1"/> <line number="915" hits="1"/> + <line number="916" hits="1"/> <line number="917" hits="1"/> <line number="918" hits="1"/> + <line number="919" hits="1"/> + <line number="920" hits="1"/> <line number="921" hits="1"/> - <line number="925" hits="1"/> + <line number="922" hits="1"/> + <line number="923" hits="1"/> <line number="926" 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="936" hits="1"/> - <line number="937" hits="1"/> - <line number="939" hits="1"/> - <line number="940" hits="1"/> + <line number="933" hits="1"/> + <line number="934" hits="1"/> + <line number="935" hits="1"/> + <line number="938" hits="1"/> <line number="942" hits="1"/> <line number="943" hits="1"/> <line number="945" hits="1"/> <line number="946" hits="1"/> <line number="949" hits="1"/> - <line number="950" hits="1"/> - <line number="951" 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="958" hits="1"/> <line number="959" hits="1"/> <line number="960" hits="1"/> - <line number="961" hits="1"/> - <line number="964" hits="1"/> - <line number="965" hits="1"/> - <line number="968" hits="1"/> - <line number="969" hits="1"/> + <line number="962" hits="1"/> + <line number="963" hits="1"/> + <line number="966" hits="1"/> <line number="970" hits="1"/> + <line number="971" hits="1"/> <line number="973" hits="1"/> <line number="974" hits="1"/> - <line number="975" hits="1"/> + <line number="977" hits="1"/> <line number="978" hits="1"/> <line number="979" hits="1"/> <line number="980" hits="1"/> @@ -1683,30 +1676,20 @@ <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="997" hits="1"/> + <line number="995" hits="1"/> <line number="998" hits="1"/> <line number="999" hits="1"/> - <line number="1000" hits="1"/> - <line number="1001" hits="1"/> <line number="1002" hits="1"/> <line number="1003" hits="1"/> <line number="1004" hits="1"/> - <line number="1005" hits="1"/> - <line number="1006" hits="1"/> <line number="1007" hits="1"/> <line number="1008" hits="1"/> <line number="1009" hits="1"/> - <line number="1010" hits="1"/> - <line number="1011" hits="1"/> <line number="1012" hits="1"/> <line number="1013" hits="1"/> - <line number="1014" hits="1"/> - <line number="1015" hits="1"/> <line number="1016" hits="1"/> <line number="1017" hits="1"/> <line number="1018" hits="1"/> @@ -1715,6 +1698,8 @@ <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"/> @@ -1722,8 +1707,6 @@ <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"/> @@ -1732,6 +1715,8 @@ <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"/> @@ -1749,9 +1734,9 @@ <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"/> <line number="1067" hits="1"/> <line number="1068" hits="1"/> <line number="1069" hits="1"/> @@ -1763,9 +1748,9 @@ <line number="1075" hits="1"/> <line number="1076" hits="1"/> <line number="1077" hits="1"/> + <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"/> @@ -1781,23 +1766,32 @@ <line number="1095" hits="1"/> <line number="1096" hits="1"/> <line number="1097" hits="1"/> + <line number="1098" hits="1"/> + <line number="1099" hits="1"/> <line number="1100" hits="1"/> <line number="1101" hits="1"/> <line number="1102" hits="1"/> - <line number="1103" hits="1"/> + <line number="1105" hits="1"/> <line number="1106" hits="1"/> <line number="1107" hits="1"/> <line number="1108" hits="1"/> <line number="1109" hits="1"/> <line number="1110" hits="1"/> + <line number="1111" hits="1"/> + <line number="1112" hits="1"/> <line number="1113" hits="1"/> - <line number="1117" hits="1"/> + <line number="1114" hits="1"/> + <line number="1115" hits="1"/> <line number="1118" hits="1"/> <line number="1119" hits="1"/> <line number="1120" hits="1"/> <line number="1121" hits="1"/> + <line number="1122" hits="1"/> + <line number="1123" hits="1"/> <line number="1124" hits="1"/> <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"/> @@ -1810,17 +1804,42 @@ <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="1149" hits="1"/> - <line number="1152" hits="1"/> - <line number="1153" hits="1"/> - <line number="1154" hits="1"/> + <line number="1151" 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="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="1169" hits="1"/> + <line number="1170" hits="1"/> + <line number="1171" hits="1"/> + <line number="1172" hits="1"/> + <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="1184" hits="1"/> + <line number="1185" hits="1"/> + <line number="1186" hits="1"/> + <line number="1187" hits="1"/> + <line number="1190" hits="1"/> + <line number="1191" hits="1"/> + <line number="1192" hits="1"/> + <line number="1193" hits="1"/> + <line number="1194" hits="1"/> </lines> </class> <class name="exceptions.py" filename="dbrepo/api/exceptions.py" complexity="0" line-rate="1" branch-rate="0"> @@ -1860,6 +1879,108 @@ <line number="110" hits="1"/> </lines> </class> + <class name="mapper.py" filename="dbrepo/api/mapper.py" complexity="0" line-rate="0.5567" branch-rate="0"> + <methods/> + <lines> + <line number="1" hits="1"/> + <line number="3" hits="1"/> + <line number="4" hits="1"/> + <line number="5" hits="1"/> + <line number="7" hits="1"/> + <line number="9" hits="1"/> + <line number="12" hits="1"/> + <line number="13" hits="1"/> + <line number="14" hits="0"/> + <line number="15" hits="1"/> + <line number="16" hits="1"/> + <line number="17" hits="0"/> + <line number="18" hits="1"/> + <line number="20" hits="1"/> + <line number="21" hits="0"/> + <line number="22" hits="1"/> + <line number="23" hits="1"/> + <line number="24" hits="1"/> + <line number="26" hits="1"/> + <line number="28" hits="1"/> + <line number="29" hits="0"/> + <line number="31" hits="1"/> + <line number="32" hits="1"/> + <line number="33" hits="0"/> + <line number="34" hits="1"/> + <line number="38" hits="1"/> + <line number="39" hits="1"/> + <line number="40" hits="0"/> + <line number="42" hits="0"/> + <line number="44" hits="0"/> + <line number="45" hits="0"/> + <line number="46" hits="0"/> + <line number="47" hits="1"/> + <line number="50" hits="1"/> + <line number="51" hits="1"/> + <line number="52" hits="1"/> + <line number="53" hits="1"/> + <line number="57" hits="1"/> + <line number="58" hits="1"/> + <line number="59" hits="1"/> + <line number="60" hits="1"/> + <line number="63" hits="1"/> + <line number="64" hits="0"/> + <line number="65" hits="0"/> + <line number="66" hits="0"/> + <line number="67" hits="0"/> + <line number="68" hits="0"/> + <line number="70" hits="0"/> + <line number="71" hits="0"/> + <line number="72" hits="1"/> + <line number="73" hits="1"/> + <line number="74" hits="1"/> + <line number="75" hits="1"/> + <line number="76" hits="0"/> + <line number="77" hits="0"/> + <line number="78" hits="0"/> + <line number="79" hits="0"/> + <line number="80" hits="1"/> + <line number="81" hits="1"/> + <line number="82" hits="1"/> + <line number="83" hits="1"/> + <line number="84" hits="1"/> + <line number="85" hits="0"/> + <line number="86" hits="0"/> + <line number="87" hits="0"/> + <line number="88" hits="0"/> + <line number="89" hits="0"/> + <line number="90" hits="0"/> + <line number="91" hits="0"/> + <line number="92" hits="0"/> + <line number="93" hits="0"/> + <line number="94" hits="1"/> + <line number="95" hits="1"/> + <line number="96" hits="1"/> + <line number="97" hits="1"/> + <line number="98" hits="0"/> + <line number="99" hits="0"/> + <line number="100" hits="0"/> + <line number="101" hits="1"/> + <line number="102" hits="1"/> + <line number="103" hits="1"/> + <line number="104" hits="1"/> + <line number="106" hits="0"/> + <line number="107" hits="0"/> + <line number="108" hits="0"/> + <line number="109" hits="0"/> + <line number="110" hits="0"/> + <line number="111" hits="0"/> + <line number="112" hits="0"/> + <line number="113" hits="0"/> + <line number="115" hits="0"/> + <line number="116" hits="1"/> + <line number="117" hits="1"/> + <line number="119" hits="1"/> + <line number="120" hits="1"/> + <line number="121" hits="0"/> + <line number="122" hits="1"/> + </lines> + </class> </classes> </package> </packages> diff --git a/lib/python/dbrepo/RestClient.py b/lib/python/dbrepo/RestClient.py index f2a93151ecff15ece92618ddf30d9d7bfa0f1dcd..3459543d838cc76ee125f2ad84165caf9bced574 100644 --- a/lib/python/dbrepo/RestClient.py +++ b/lib/python/dbrepo/RestClient.py @@ -826,7 +826,7 @@ class RestClient: if page is not None and size is not None: params.append(('page', page)) params.append(('size', size)) - response = self._wrapper(method="get", url=url, params=params) + response = self._wrapper(method="get", url=url, params=params, headers={'Accept': 'application/json'}) if response.status_code == 200: return DataFrame.from_records(response.json()) if response.status_code == 400: @@ -869,7 +869,7 @@ class RestClient: params.append(('size', size)) if timestamp is not None: params.append(('timestamp', timestamp.strftime("%Y-%m-%dT%H:%M:%SZ"))) - response = self._wrapper(method="get", url=url, params=params) + response = self._wrapper(method="get", url=url, params=params, headers={'Accept': 'application/json'}) if response.status_code == 200: return DataFrame.from_records(response.json()) if response.status_code == 400: @@ -1393,11 +1393,10 @@ class RestClient: :raises ServiceError: If something went wrong with obtaining the information in the data service. :raises ResponseCodeError: If something went wrong with the retrieval. """ - headers = {} url = f'/api/database/{database_id}/subset/{subset_id}/data' if page is not None and size is not None: url += f'?page={page}&size={size}' - response = self._wrapper(method="get", url=url, headers=headers) + response = self._wrapper(method="get", url=url, headers={'Accept': 'application/json'}) if response.status_code == 200: return DataFrame.from_records(response.json()) if response.status_code == 400: @@ -1786,7 +1785,7 @@ class RestClient: def get_identifier(self, identifier_id: str) -> Identifier: """ - Get list of identifiers, filter by the remaining optional arguments. + Get the identifier by given id. :param identifier_id: The identifier id. @@ -1805,6 +1804,39 @@ class RestClient: raise ResponseCodeError(f'Failed to get identifier: response code: {response.status_code} is not ' f'200 (OK): {response.text}') + def get_identifier_data(self, identifier_id: str) -> DataFrame: + """ + Get the identifier data by given id. + + :param identifier_id: The identifier id. + + :returns: The identifier, if successful. + + :raises NotExistsError: If the identifier does not exist. + :raises ResponseCodeError: If something went wrong with the retrieval of the identifier. + """ + url = f'/api/identifier/{identifier_id}' + response = self._wrapper(method="get", url=url, headers={'Accept': 'application/json'}) + if response.status_code == 200: + body = response.json() + identifier = Identifier.model_validate(body) + if identifier.type == IdentifierType.VIEW: + return self.get_view_data(database_id=identifier.database_id, view_id=identifier.view_id, page=0, + size=10000) + elif identifier.type == IdentifierType.TABLE: + return self.get_table_data(database_id=identifier.database_id, table_id=identifier.table_id, page=0, + size=10000) + elif identifier.type == IdentifierType.SUBSET: + return self.get_subset_data(database_id=identifier.database_id, subset_id=identifier.query_id, page=0, + size=10000) + raise FormatNotAvailable(f'Failed to get identifier data: type is database') + if response.status_code == 404: + raise NotExistsError(f'Failed to get identifier data: not found') + if response.status_code == 406: + raise NotExistsError(f'Failed to get identifier data: type database') + raise ResponseCodeError(f'Failed to get identifier data: response code: {response.status_code} is not ' + f'200 (OK): {response.text}') + def get_image(self, image_id: str) -> Image: """ Get container image. diff --git a/lib/python/dbrepo/api/dto.py b/lib/python/dbrepo/api/dto.py index 526ba29bf7d4dfea5983bce99c84c2e67e8befe4..356f9b220095970886e524e8cccefdd49ea823c7 100644 --- a/lib/python/dbrepo/api/dto.py +++ b/lib/python/dbrepo/api/dto.py @@ -653,6 +653,7 @@ class IdentifierSave(CreateIdentifier): class Identifier(BaseModel): id: str database_id: str + links: Links type: IdentifierType owner: UserBrief status: IdentifierStatusType @@ -988,6 +989,12 @@ class Query(BaseModel): identifiers: List[IdentifierBrief] = field(default_factory=list) +class Links(BaseModel): + self: str + self_html: str + data: Optional[str] = None + + class UpdateQuery(BaseModel): persist: bool diff --git a/lib/python/tests/test_unit_identifier.py b/lib/python/tests/test_unit_identifier.py index 9ac386437c29f4c65f6879d1a1f0c98641652652..137a513d4666ad097094f67d6fd4dcff80fc1d3b 100644 --- a/lib/python/tests/test_unit_identifier.py +++ b/lib/python/tests/test_unit_identifier.py @@ -7,7 +7,7 @@ from dbrepo.api.dto import Identifier, IdentifierType, SaveIdentifierTitle, Crea IdentifierDescription, SaveIdentifierDescription, Language, SaveIdentifierFunder, SaveRelatedIdentifier, \ RelatedIdentifierRelation, RelatedIdentifierType, IdentifierFunder, RelatedIdentifier, UserBrief, \ IdentifierStatusType, CreateIdentifierCreator, CreateIdentifierTitle, CreateIdentifierFunder, \ - CreateRelatedIdentifier, CreateIdentifierDescription, SaveIdentifierCreator + CreateRelatedIdentifier, CreateIdentifierDescription, SaveIdentifierCreator, Links from dbrepo.api.exceptions import MalformedError, ForbiddenError, NotExistsError, AuthenticationError, \ ServiceConnectionError, ServiceError, ResponseCodeError, FormatNotAvailable, RequestError @@ -19,6 +19,9 @@ class IdentifierUnitTest(unittest.TestCase): exp = Identifier(id="f6171539-a479-4829-9b9b-a6b474e1c7d3", database_id="6bd39359-b154-456d-b9c2-caa516a45732", view_id="e5229d24-584a-43e8-b9f6-d349c3053f9c", + links=Links(self="/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3", + self_html="/pid/f6171539-a479-4829-9b9b-a6b474e1c7d3", + data="/api/database/6bd39359-b154-456d-b9c2-caa516a45732/view/e5229d24-584a-43e8-b9f6-d349c3053f9c/data"), publication_year=2024, publisher='TU Wien', type=IdentifierType.VIEW, @@ -172,6 +175,9 @@ class IdentifierUnitTest(unittest.TestCase): publisher='TU Wien', type=IdentifierType.VIEW, language=Language.EN, + links=Links(self="/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3", + self_html="/pid/f6171539-a479-4829-9b9b-a6b474e1c7d3", + data="/api/database/6bd39359-b154-456d-b9c2-caa516a45732/view/e5229d24-584a-43e8-b9f6-d349c3053f9c/data"), descriptions=[IdentifierDescription(id="d8bdc933-655c-46bd-9903-ede3928a304b", description='Test Description')], titles=[IdentifierTitle(id="f6171539-a479-4829-9b9b-a6b474e1c7d3", @@ -275,6 +281,9 @@ class IdentifierUnitTest(unittest.TestCase): publisher='TU Wien', type=IdentifierType.VIEW, language=Language.EN, + links=Links(self="/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3", + self_html="/pid/f6171539-a479-4829-9b9b-a6b474e1c7d3", + data="/api/database/6bd39359-b154-456d-b9c2-caa516a45732/view/e5229d24-584a-43e8-b9f6-d349c3053f9c/data"), descriptions=[IdentifierDescription(id="d8bdc933-655c-46bd-9903-ede3928a304b", description='Test Description')], titles=[IdentifierTitle(id="f6171539-a479-4829-9b9b-a6b474e1c7d3", @@ -517,6 +526,9 @@ class IdentifierUnitTest(unittest.TestCase): publisher='TU Wien', type=IdentifierType.VIEW, language=Language.EN, + links=Links(self="/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3", + self_html="/pid/f6171539-a479-4829-9b9b-a6b474e1c7d3", + data="/api/database/6bd39359-b154-456d-b9c2-caa516a45732/view/e5229d24-584a-43e8-b9f6-d349c3053f9c/data"), descriptions=[IdentifierDescription(id="d8bdc933-655c-46bd-9903-ede3928a304b", description='Test Description')], titles=[IdentifierTitle(id="f6171539-a479-4829-9b9b-a6b474e1c7d3", title='Test Title')], @@ -530,7 +542,8 @@ class IdentifierUnitTest(unittest.TestCase): status=IdentifierStatusType.PUBLISHED, owner=UserBrief(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise')) # mock - mock.put('/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3/publish', json=exp.model_dump(), status_code=202) + mock.put('/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3/publish', json=exp.model_dump(), + status_code=202) # test client = RestClient(username="a", password="b") response = client.publish_identifier(identifier_id="f6171539-a479-4829-9b9b-a6b474e1c7d3") @@ -545,6 +558,9 @@ class IdentifierUnitTest(unittest.TestCase): publisher='TU Wien', type=IdentifierType.VIEW, language=Language.EN, + links=Links(self="/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3", + self_html="/pid/f6171539-a479-4829-9b9b-a6b474e1c7d3", + data="/api/database/6bd39359-b154-456d-b9c2-caa516a45732/view/e5229d24-584a-43e8-b9f6-d349c3053f9c/data"), descriptions=[IdentifierDescription(id="d8bdc933-655c-46bd-9903-ede3928a304b", description='Test Description')], titles=[IdentifierTitle(id="f6171539-a479-4829-9b9b-a6b474e1c7d3", title='Test Title')], @@ -558,7 +574,8 @@ class IdentifierUnitTest(unittest.TestCase): status=IdentifierStatusType.PUBLISHED, owner=UserBrief(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise')) # mock - mock.put('/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3/publish', json=exp.model_dump(), status_code=400) + mock.put('/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3/publish', json=exp.model_dump(), + status_code=400) # test try: RestClient(username="a", password="b").publish_identifier( @@ -575,6 +592,9 @@ class IdentifierUnitTest(unittest.TestCase): publisher='TU Wien', type=IdentifierType.VIEW, language=Language.EN, + links=Links(self="/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3", + self_html="/pid/f6171539-a479-4829-9b9b-a6b474e1c7d3", + data="/api/database/6bd39359-b154-456d-b9c2-caa516a45732/view/e5229d24-584a-43e8-b9f6-d349c3053f9c/data"), descriptions=[IdentifierDescription(id="d8bdc933-655c-46bd-9903-ede3928a304b", description='Test Description')], titles=[IdentifierTitle(id="f6171539-a479-4829-9b9b-a6b474e1c7d3", title='Test Title')], @@ -588,7 +608,8 @@ class IdentifierUnitTest(unittest.TestCase): status=IdentifierStatusType.PUBLISHED, owner=UserBrief(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise')) # mock - mock.put('/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3/publish', json=exp.model_dump(), status_code=403) + mock.put('/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3/publish', json=exp.model_dump(), + status_code=403) # test try: RestClient(username="a", password="b").publish_identifier( @@ -605,6 +626,9 @@ class IdentifierUnitTest(unittest.TestCase): publisher='TU Wien', type=IdentifierType.VIEW, language=Language.EN, + links=Links(self="/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3", + self_html="/pid/f6171539-a479-4829-9b9b-a6b474e1c7d3", + data="/api/database/6bd39359-b154-456d-b9c2-caa516a45732/view/e5229d24-584a-43e8-b9f6-d349c3053f9c/data"), descriptions=[IdentifierDescription(id="d8bdc933-655c-46bd-9903-ede3928a304b", description='Test Description')], titles=[IdentifierTitle(id="f6171539-a479-4829-9b9b-a6b474e1c7d3", title='Test Title')], @@ -618,7 +642,8 @@ class IdentifierUnitTest(unittest.TestCase): status=IdentifierStatusType.PUBLISHED, owner=UserBrief(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise')) # mock - mock.put('/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3/publish', json=exp.model_dump(), status_code=404) + mock.put('/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3/publish', json=exp.model_dump(), + status_code=404) # test try: RestClient(username="a", password="b").publish_identifier( @@ -635,6 +660,9 @@ class IdentifierUnitTest(unittest.TestCase): publisher='TU Wien', type=IdentifierType.VIEW, language=Language.EN, + links=Links(self="/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3", + self_html="/pid/f6171539-a479-4829-9b9b-a6b474e1c7d3", + data="/api/database/6bd39359-b154-456d-b9c2-caa516a45732/view/e5229d24-584a-43e8-b9f6-d349c3053f9c/data"), descriptions=[IdentifierDescription(id="d8bdc933-655c-46bd-9903-ede3928a304b", description='Test Description')], titles=[IdentifierTitle(id="f6171539-a479-4829-9b9b-a6b474e1c7d3", title='Test Title')], @@ -648,7 +676,8 @@ class IdentifierUnitTest(unittest.TestCase): status=IdentifierStatusType.PUBLISHED, owner=UserBrief(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise')) # mock - mock.put('/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3/publish', json=exp.model_dump(), status_code=502) + mock.put('/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3/publish', json=exp.model_dump(), + status_code=502) # test try: RestClient(username="a", password="b").publish_identifier( @@ -665,6 +694,9 @@ class IdentifierUnitTest(unittest.TestCase): publisher='TU Wien', type=IdentifierType.VIEW, language=Language.EN, + links=Links(self="/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3", + self_html="/pid/f6171539-a479-4829-9b9b-a6b474e1c7d3", + data="/api/database/6bd39359-b154-456d-b9c2-caa516a45732/view/e5229d24-584a-43e8-b9f6-d349c3053f9c/data"), descriptions=[IdentifierDescription(id="d8bdc933-655c-46bd-9903-ede3928a304b", description='Test Description')], titles=[IdentifierTitle(id="f6171539-a479-4829-9b9b-a6b474e1c7d3", title='Test Title')], @@ -678,7 +710,8 @@ class IdentifierUnitTest(unittest.TestCase): status=IdentifierStatusType.PUBLISHED, owner=UserBrief(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise')) # mock - mock.put('/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3/publish', json=exp.model_dump(), status_code=503) + mock.put('/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3/publish', json=exp.model_dump(), + status_code=503) # test try: RestClient(username="a", password="b").publish_identifier( @@ -695,6 +728,9 @@ class IdentifierUnitTest(unittest.TestCase): publisher='TU Wien', type=IdentifierType.VIEW, language=Language.EN, + links=Links(self="/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3", + self_html="/pid/f6171539-a479-4829-9b9b-a6b474e1c7d3", + data="/api/database/6bd39359-b154-456d-b9c2-caa516a45732/view/e5229d24-584a-43e8-b9f6-d349c3053f9c/data"), descriptions=[IdentifierDescription(id="d8bdc933-655c-46bd-9903-ede3928a304b", description='Test Description')], titles=[IdentifierTitle(id="f6171539-a479-4829-9b9b-a6b474e1c7d3", title='Test Title')], @@ -708,7 +744,8 @@ class IdentifierUnitTest(unittest.TestCase): status=IdentifierStatusType.PUBLISHED, owner=UserBrief(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise')) # mock - mock.put('/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3/publish', json=exp.model_dump(), status_code=200) + mock.put('/api/identifier/f6171539-a479-4829-9b9b-a6b474e1c7d3/publish', json=exp.model_dump(), + status_code=200) # test try: RestClient(username="a", password="b").publish_identifier(