diff --git a/dbrepo-analyse-service/Pipfile.lock b/dbrepo-analyse-service/Pipfile.lock index ae160f77733183750c665ce9c9053d76b34a18e0..a6a76cc576f22319ee91a03e367e6e790ae03121 100644 --- a/dbrepo-analyse-service/Pipfile.lock +++ b/dbrepo-analyse-service/Pipfile.lock @@ -175,20 +175,20 @@ }, "boto3": { "hashes": [ - "sha256:159898f51c2997a12541c0e02d6e5a8fe2993ddb307b9478fd9a339f98b57e00", - "sha256:d0ca7a58ce25701a52232cc8df9d87854824f1f2964b929305722ebc7959d5a9" + "sha256:258ab77225a81d3cf3029c9afe9920cd9dec317689dfadec6f6f0a23130bb60a", + "sha256:eb21380d73fec6645439c0d802210f72a0cdb3295b02953f246ff53f512faa8f" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.36.0" + "version": "==1.36.1" }, "botocore": { "hashes": [ - "sha256:0232029ff9ae3f5b50cdb25cbd257c16f87402b6d31a05bd6483638ee6434c4b", - "sha256:b54b11f0cfc47fc1243ada0f7f461266c279968487616720fa8ebb02183917d7" + "sha256:dec513b4eb8a847d79bbefdcdd07040ed9d44c20b0001136f0890a03d595705a", + "sha256:f789a6f272b5b3d8f8756495019785e33868e5e00dd9662a3ee7959ac939bb12" ], "markers": "python_version >= '3.8'", - "version": "==1.36.0" + "version": "==1.36.1" }, "certifi": { "hashes": [ @@ -412,7 +412,7 @@ }, "dbrepo": { "hashes": [ - "sha256:0d11a0e0ec942d5b0ddfadd9e9007ce6dab9c5b9cc433e0f53b4fafcfc597bef" + "sha256:a08b6eb49c108466b231c1b2cae5be501043fe4208a782899ce103105e22e3c6" ], "path": "./lib/dbrepo-1.6.1.tar.gz" }, @@ -1427,11 +1427,11 @@ }, "referencing": { "hashes": [ - "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c", - "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de" + "sha256:363d9c65f080d0d70bc41c721dce3c7f3e77fc09f269cd5c8813da18069a6794", + "sha256:ca2e6492769e3602957e9b831b94211599d2aade9477f5d44110d2530cf9aade" ], - "markers": "python_version >= '3.8'", - "version": "==0.35.1" + "markers": "python_version >= '3.9'", + "version": "==0.36.1" }, "requests": { "hashes": [ @@ -1553,11 +1553,11 @@ }, "s3transfer": { "hashes": [ - "sha256:6563eda054c33bdebef7cbf309488634651c47270d828e594d151cd289fb7cf7", - "sha256:f43b03931c198743569bbfb6a328a53f4b2b4ec723cd7c01fab68e3119db3f8b" + "sha256:3f25c900a367c8b7f7d8f9c34edc87e300bde424f779dc9f0a8ae4f9df9264f6", + "sha256:8fa0aa48177be1f3425176dfe1ab85dcd3d962df603c3dbfc585e6bf857ef0ff" ], "markers": "python_version >= '3.8'", - "version": "==0.11.0" + "version": "==0.11.1" }, "setuptools": { "hashes": [ @@ -1612,7 +1612,7 @@ "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d" ], - "markers": "python_version >= '3.9'", + "markers": "python_version >= '3.10'", "version": "==2.3.0" }, "werkzeug": { @@ -2236,7 +2236,7 @@ "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d" ], - "markers": "python_version >= '3.9'", + "markers": "python_version >= '3.10'", "version": "==2.3.0" }, "wrapt": { diff --git a/dbrepo-analyse-service/lib/dbrepo-1.6.1.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.6.1.tar.gz index 5ce8fdab038ca28aa52e5c8544ce3bcfee7ca3fa..7e4d5a2470276918716a153487671274665749a6 100644 Binary files a/dbrepo-analyse-service/lib/dbrepo-1.6.1.tar.gz and b/dbrepo-analyse-service/lib/dbrepo-1.6.1.tar.gz differ diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java index 707df1600c8252b80c4e091e8dfb945e0975c1d4..46072e83dc14af22d09923d3e9462a53506aa4f8 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java @@ -10,6 +10,7 @@ import lombok.*; import lombok.extern.jackson.Jacksonized; import java.util.List; +import java.util.UUID; @Getter @Setter @@ -53,6 +54,6 @@ public class DatabaseBriefDto { @NotNull @JsonProperty("owner_id") - private UserBriefDto ownerId; + private UUID ownerId; } 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 fe8e4385e2857be757ebc72904ef76c988b8fa57..c5482f70411433f5df08bd0281a60c75d132bf26 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 @@ -907,6 +907,9 @@ public interface MetadataMapper { return database; } + @Mappings({ + @Mapping(target = "ownerId", source = "owner.id") + }) DatabaseBriefDto databaseToDatabaseBriefDto(Database data); AccessType accessTypeDtoToAccessType(AccessTypeDto data); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/SearchServiceGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/SearchServiceGatewayUnitTest.java index 0fbe9be24351f7ecb6e27cc2c2a0e5375cb5a3ee..b1ce21d4e5e8315b08087dc0d85712509a07973e 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/SearchServiceGatewayUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/SearchServiceGatewayUnitTest.java @@ -35,7 +35,7 @@ public class SearchServiceGatewayUnitTest extends AbstractUnitTest { private SearchServiceGateway searchServiceGateway; @Test - public void save_succeeds() throws DatabaseNotFoundException, SearchServiceException, + public void update_succeeds() throws DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException { final ResponseEntity<DatabaseDto> mock = ResponseEntity.accepted() .build(); @@ -45,11 +45,11 @@ public class SearchServiceGatewayUnitTest extends AbstractUnitTest { .thenReturn(mock); /* test */ - searchServiceGateway.save(DATABASE_1); + searchServiceGateway.update(DATABASE_1); } @Test - public void save_badRequest_fails() { + public void update_badRequest_fails() { final ResponseEntity<DatabaseDto> mock = ResponseEntity.status(HttpStatus.BAD_REQUEST) .build(); @@ -59,12 +59,12 @@ public class SearchServiceGatewayUnitTest extends AbstractUnitTest { /* test */ assertThrows(SearchServiceException.class, () -> { - searchServiceGateway.save(DATABASE_1); + searchServiceGateway.update(DATABASE_1); }); } @Test - public void save_unexpectedResponse_fails() { + public void update_unexpectedResponse_fails() { final ResponseEntity<DatabaseDto> mock = ResponseEntity.status(HttpStatus.OK) .build(); @@ -74,12 +74,12 @@ public class SearchServiceGatewayUnitTest extends AbstractUnitTest { /* test */ assertThrows(SearchServiceException.class, () -> { - searchServiceGateway.save(DATABASE_1); + searchServiceGateway.update(DATABASE_1); }); } @Test - public void save_unavailable_fails() { + public void update_unavailable_fails() { /* mock */ doThrow(HttpServerErrorException.ServiceUnavailable.class) @@ -88,12 +88,12 @@ public class SearchServiceGatewayUnitTest extends AbstractUnitTest { /* test */ assertThrows(SearchServiceConnectionException.class, () -> { - searchServiceGateway.save(DATABASE_1); + searchServiceGateway.update(DATABASE_1); }); } @Test - public void save_notFound_fails() { + public void update_notFound_fails() { /* mock */ doThrow(HttpClientErrorException.NotFound.class) @@ -102,7 +102,7 @@ public class SearchServiceGatewayUnitTest extends AbstractUnitTest { /* test */ assertThrows(DatabaseNotFoundException.class, () -> { - searchServiceGateway.save(DATABASE_1); + searchServiceGateway.update(DATABASE_1); }); } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DataCiteIdentifierServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DataCiteIdentifierServicePersistenceTest.java index 01a990cef3bec4ae4997f44d854ef6df2c9be22d..182fe8e14ac5cd63ad1752fec07ee9b511ba8726 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DataCiteIdentifierServicePersistenceTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DataCiteIdentifierServicePersistenceTest.java @@ -1,19 +1,20 @@ package at.tuwien.service; -import at.tuwien.api.datacite.DataCiteBody; -import at.tuwien.api.datacite.doi.DataCiteDoi; import at.tuwien.api.identifier.BibliographyTypeDto; -import at.tuwien.entities.database.Database; import at.tuwien.entities.identifier.Creator; import at.tuwien.entities.identifier.Identifier; import at.tuwien.entities.identifier.IdentifierStatusType; import at.tuwien.entities.identifier.NameIdentifierSchemeType; -import at.tuwien.exception.*; import at.tuwien.repository.ContainerRepository; import at.tuwien.repository.DatabaseRepository; import at.tuwien.repository.LicenseRepository; import at.tuwien.repository.UserRepository; import at.tuwien.test.AbstractUnitTest; +import at.tuwien.api.datacite.DataCiteBody; +import at.tuwien.api.datacite.doi.DataCiteDoi; +import at.tuwien.entities.database.Database; +import at.tuwien.exception.*; +import at.tuwien.gateway.SearchServiceGateway; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -47,7 +48,7 @@ import static org.mockito.Mockito.when; public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest { @MockBean - private SearchService searchService; + private SearchServiceGateway searchServiceGateway; @MockBean @Qualifier("dataCiteRestTemplate") @@ -139,7 +140,7 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest { /* mock */ when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(dataCiteBodyParameterizedTypeReference))) .thenReturn(mock); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ @@ -154,7 +155,7 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest { doThrow(HttpClientErrorException.BadRequest.class) .when(restTemplate) .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(dataCiteBodyParameterizedTypeReference)); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ @@ -171,7 +172,7 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest { doThrow(RestClientException.class) .when(restTemplate) .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(dataCiteBodyParameterizedTypeReference)); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ @@ -330,7 +331,7 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest { IdentifierNotFoundException, SearchServiceException, SearchServiceConnectionException { /* mock */ - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceUnitTest.java index 6cf8fa05702560a1e5e799b78588591167ce11bf..1b6570abd821337fe032bead021cf9d5a4b9fc8c 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceUnitTest.java @@ -8,6 +8,7 @@ import at.tuwien.entities.database.table.Table; import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; +import at.tuwien.gateway.SearchServiceGateway; import at.tuwien.repository.DatabaseRepository; import at.tuwien.test.AbstractUnitTest; import lombok.extern.log4j.Log4j2; @@ -32,7 +33,7 @@ import static org.mockito.Mockito.*; public class DatabaseServiceUnitTest extends AbstractUnitTest { @MockBean - private SearchService searchService; + private SearchServiceGateway searchServiceGateway; @MockBean private DataServiceGateway dataServiceGateway; @@ -108,7 +109,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { /* mock */ when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ @@ -125,8 +126,8 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); doThrow(DatabaseNotFoundException.class) - .when(searchService) - .save(any(Database.class)); + .when(searchServiceGateway) + .update(any(Database.class)); /* test */ assertThrows(DatabaseNotFoundException.class, () -> { @@ -143,8 +144,8 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); doThrow(SearchServiceConnectionException.class) - .when(searchService) - .save(any(Database.class)); + .when(searchServiceGateway) + .update(any(Database.class)); /* test */ assertThrows(SearchServiceConnectionException.class, () -> { @@ -162,7 +163,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { .thenReturn(List.of()); when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ @@ -181,8 +182,8 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); doThrow(SearchServiceConnectionException.class) - .when(searchService) - .save(any(Database.class)); + .when(searchServiceGateway) + .update(any(Database.class)); /* test */ assertThrows(SearchServiceConnectionException.class, () -> { @@ -201,8 +202,8 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); doThrow(DatabaseNotFoundException.class) - .when(searchService) - .save(any(Database.class)); + .when(searchServiceGateway) + .update(any(Database.class)); /* test */ assertThrows(DatabaseNotFoundException.class, () -> { @@ -220,7 +221,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { .thenReturn(List.of(VIEW_1_DTO, VIEW_2_DTO, VIEW_3_DTO, VIEW_4_DTO)); /* <<< */ when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ @@ -238,7 +239,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { .thenReturn(List.of(VIEW_1_DTO, VIEW_2_DTO, VIEW_3_DTO)); /* <<< */ when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ @@ -256,7 +257,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { .thenReturn(List.of()); when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ @@ -274,7 +275,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { .thenReturn(List.of(TABLE_1_DTO, TABLE_2_DTO, TABLE_3_DTO, TABLE_4_DTO)); when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ @@ -292,7 +293,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { .thenReturn(List.of(TABLE_1_DTO, TABLE_2_DTO, TABLE_3_DTO, TABLE_4_DTO, TABLE_5_DTO)); when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ @@ -410,8 +411,8 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { /* mock */ doThrow(SearchServiceException.class) - .when(searchService) - .save(DATABASE_1); + .when(searchServiceGateway) + .update(DATABASE_1); /* test */ assertThrows(SearchServiceException.class, () -> { @@ -425,8 +426,8 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { /* mock */ doThrow(DatabaseNotFoundException.class) - .when(searchService) - .save(DATABASE_1); + .when(searchServiceGateway) + .update(DATABASE_1); /* test */ assertThrows(DatabaseNotFoundException.class, () -> { @@ -440,8 +441,8 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { /* mock */ doThrow(SearchServiceConnectionException.class) - .when(searchService) - .save(DATABASE_1); + .when(searchServiceGateway) + .update(DATABASE_1); /* test */ assertThrows(SearchServiceConnectionException.class, () -> { @@ -467,8 +468,8 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { /* mock */ doThrow(SearchServiceException.class) - .when(searchService) - .save(DATABASE_1); + .when(searchServiceGateway) + .update(DATABASE_1); /* test */ assertThrows(SearchServiceException.class, () -> { @@ -482,8 +483,8 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { /* mock */ doThrow(DatabaseNotFoundException.class) - .when(searchService) - .save(DATABASE_1); + .when(searchServiceGateway) + .update(DATABASE_1); /* test */ assertThrows(DatabaseNotFoundException.class, () -> { @@ -497,8 +498,8 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { /* mock */ doThrow(SearchServiceConnectionException.class) - .when(searchService) - .save(DATABASE_1); + .when(searchServiceGateway) + .update(DATABASE_1); /* test */ assertThrows(SearchServiceConnectionException.class, () -> { @@ -515,7 +516,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { ContainerNotFoundException, SearchServiceException, SearchServiceConnectionException { /* mock */ - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/IdentifierServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/IdentifierServicePersistenceTest.java index fd9eab3516951a303e795646b375a5af3abf476b..0c87dcdd692533cd751401f9be37fee69b5186cc 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/IdentifierServicePersistenceTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/IdentifierServicePersistenceTest.java @@ -12,8 +12,10 @@ import at.tuwien.entities.database.Database; import at.tuwien.entities.identifier.*; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; +import at.tuwien.gateway.SearchServiceGateway; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -45,7 +47,7 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest { private DataServiceGateway dataServiceGateway; @MockBean - private SearchService searchService; + private SearchServiceGateway searchServiceGateway; @MockBean @Qualifier("restTemplate") @@ -173,7 +175,7 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest { /* mock */ when(dataServiceGateway.findQuery(IDENTIFIER_5_DATABASE_ID, IDENTIFIER_5_QUERY_ID)) .thenReturn(QUERY_2_DTO); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_2_DTO); /* test */ @@ -283,7 +285,7 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest { SearchServiceConnectionException { /* mock */ - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java index fe8ca04fe76519d4c970968ce4e4bfcedbfdb435..3126f9e9f42b36fb8dc09dfa3f8e60c88d851722 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java @@ -13,6 +13,7 @@ import at.tuwien.entities.database.table.constraints.primaryKey.PrimaryKey; import at.tuwien.entities.database.table.constraints.unique.Unique; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; +import at.tuwien.gateway.SearchServiceGateway; import at.tuwien.repository.ContainerRepository; import at.tuwien.repository.DatabaseRepository; import at.tuwien.repository.LicenseRepository; @@ -44,7 +45,7 @@ import static org.mockito.Mockito.when; public class TableServicePersistenceTest extends AbstractUnitTest { @MockBean - private SearchService searchService; + private SearchServiceGateway searchServiceGateway; @MockBean private UserService userService; @@ -110,7 +111,7 @@ public class TableServicePersistenceTest extends AbstractUnitTest { doNothing() .when(dataServiceGateway) .createTable(DATABASE_1_ID, request); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java index 83bdfa7e704dcc84e46f68879203993856ff489b..d975e808e3dd03e3b4fd0f27d3af4b60f4fec7a1 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java @@ -15,6 +15,7 @@ import at.tuwien.entities.database.table.columns.TableColumnType; import at.tuwien.entities.database.table.constraints.Constraints; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; +import at.tuwien.gateway.SearchServiceGateway; import at.tuwien.repository.DatabaseRepository; import at.tuwien.test.AbstractUnitTest; import lombok.extern.log4j.Log4j2; @@ -44,7 +45,7 @@ public class TableServiceUnitTest extends AbstractUnitTest { private DatabaseRepository databaseRepository; @MockBean - private SearchService searchService; + private SearchServiceGateway searchServiceGateway; @MockBean private UserService userService; @@ -133,7 +134,7 @@ public class TableServiceUnitTest extends AbstractUnitTest { .thenReturn(TABLE_8_STATISTIC_DTO); when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ @@ -151,8 +152,8 @@ public class TableServiceUnitTest extends AbstractUnitTest { when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); doThrow(DatabaseNotFoundException.class) - .when(searchService) - .save(any(Database.class)); + .when(searchServiceGateway) + .update(any(Database.class)); /* test */ assertThrows(DatabaseNotFoundException.class, () -> { @@ -171,8 +172,8 @@ public class TableServiceUnitTest extends AbstractUnitTest { when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); doThrow(SearchServiceConnectionException.class) - .when(searchService) - .save(any(Database.class)); + .when(searchServiceGateway) + .update(any(Database.class)); /* test */ assertThrows(SearchServiceConnectionException.class, () -> { @@ -222,7 +223,7 @@ public class TableServiceUnitTest extends AbstractUnitTest { .thenReturn(CONCEPT_1); when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ @@ -254,7 +255,7 @@ public class TableServiceUnitTest extends AbstractUnitTest { .thenReturn(CONCEPT_1_ENTITY_DTO); when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ @@ -277,7 +278,7 @@ public class TableServiceUnitTest extends AbstractUnitTest { .createTable(eq(DATABASE_1_ID), any(TableCreateDto.class)); when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ @@ -314,7 +315,7 @@ public class TableServiceUnitTest extends AbstractUnitTest { .createTable(eq(DATABASE_1_ID), any(TableCreateDto.class)); when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ @@ -367,7 +368,7 @@ public class TableServiceUnitTest extends AbstractUnitTest { .createTable(eq(DATABASE_1_ID), any(TableCreateDto.class)); when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ @@ -390,7 +391,7 @@ public class TableServiceUnitTest extends AbstractUnitTest { doNothing() .when(dataServiceGateway) .createTable(DATABASE_1_ID, TABLE_3_CREATE_DTO); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ @@ -411,7 +412,7 @@ public class TableServiceUnitTest extends AbstractUnitTest { doThrow(DataServiceException.class) .when(dataServiceGateway) .createTable(DATABASE_1_ID, TABLE_5_CREATE_DTO); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ @@ -509,7 +510,7 @@ public class TableServiceUnitTest extends AbstractUnitTest { doNothing() .when(dataServiceGateway) .deleteTable(DATABASE_1_ID, TABLE_1_ID); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ @@ -525,7 +526,7 @@ public class TableServiceUnitTest extends AbstractUnitTest { doNothing() .when(dataServiceGateway) .deleteTable(DATABASE_1_ID, TABLE_4_ID); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java index a0b840b6218d769318dfc60cebd36fb329f0d637..8ca002472a085a58ea5ee58fff8a2a0614c94fd9 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java @@ -2,8 +2,10 @@ package at.tuwien.service; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.View; +import at.tuwien.entities.database.ViewColumn; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; +import at.tuwien.gateway.SearchServiceGateway; import at.tuwien.repository.ContainerRepository; import at.tuwien.repository.DatabaseRepository; import at.tuwien.repository.LicenseRepository; @@ -54,7 +56,7 @@ public class ViewServicePersistenceTest extends AbstractUnitTest { private DataServiceGateway dataServiceGateway; @MockBean - private SearchService searchService; + private SearchServiceGateway searchServiceGateway; @BeforeEach public void beforeEach() { @@ -86,7 +88,7 @@ public class ViewServicePersistenceTest extends AbstractUnitTest { doNothing() .when(dataServiceGateway) .deleteView(DATABASE_1_ID, VIEW_1_ID); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceUnitTest.java index 1a4e9359f383a4f12da160a51430fc25f6b17881..cd9fe03c655d33b014239af4f05f0f0ae9b6d1e9 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceUnitTest.java @@ -1,12 +1,13 @@ package at.tuwien.service; +import at.tuwien.repository.DatabaseRepository; +import at.tuwien.test.AbstractUnitTest; import at.tuwien.api.database.ViewCreateDto; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.View; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; -import at.tuwien.repository.DatabaseRepository; -import at.tuwien.test.AbstractUnitTest; +import at.tuwien.gateway.SearchServiceGateway; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -17,6 +18,7 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.testcontainers.junit.jupiter.Testcontainers; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; @@ -32,7 +34,7 @@ public class ViewServiceUnitTest extends AbstractUnitTest { private DataServiceGateway dataServiceGateway; @MockBean - private SearchService searchService; + private SearchServiceGateway searchServiceGateway; @MockBean private DatabaseRepository databaseRepository; @@ -59,7 +61,7 @@ public class ViewServiceUnitTest extends AbstractUnitTest { .thenReturn(VIEW_1_DTO); when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ @@ -114,7 +116,7 @@ public class ViewServiceUnitTest extends AbstractUnitTest { .deleteView(DATABASE_1_ID, VIEW_1_ID); when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); - when(searchService.save(any(Database.class))) + when(searchServiceGateway.update(any(Database.class))) .thenReturn(DATABASE_1_DTO); /* test */ @@ -162,8 +164,8 @@ public class ViewServiceUnitTest extends AbstractUnitTest { when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); doThrow(SearchServiceException.class) - .when(searchService) - .save(any(Database.class)); + .when(searchServiceGateway) + .update(any(Database.class)); /* test */ assertThrows(SearchServiceException.class, () -> { @@ -182,8 +184,8 @@ public class ViewServiceUnitTest extends AbstractUnitTest { when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); doThrow(SearchServiceConnectionException.class) - .when(searchService) - .save(any(Database.class)); + .when(searchServiceGateway) + .update(any(Database.class)); /* test */ assertThrows(SearchServiceConnectionException.class, () -> { @@ -202,8 +204,8 @@ public class ViewServiceUnitTest extends AbstractUnitTest { when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); doThrow(DatabaseNotFoundException.class) - .when(searchService) - .save(any(Database.class)); + .when(searchServiceGateway) + .update(any(Database.class)); /* test */ assertThrows(DatabaseNotFoundException.class, () -> { diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/SearchServiceGateway.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/SearchServiceGateway.java index 08a106e545bff218acf88d68e7f75a5b6a3ca3c7..f5e2f49c02023fe9145f137089e4550c9ae5b769 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/SearchServiceGateway.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/SearchServiceGateway.java @@ -6,7 +6,7 @@ import at.tuwien.exception.*; public interface SearchServiceGateway { - DatabaseDto save(Database database) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException; + DatabaseDto update(Database database) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException; void delete(Long databaseId) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException; } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/SearchServiceGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/SearchServiceGatewayImpl.java index d44df25a9205085e0787cbce2c5dc437002fb082..0f14b8d34826fe94829146f53a0cc22fb9e97333 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/SearchServiceGatewayImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/SearchServiceGatewayImpl.java @@ -35,7 +35,7 @@ public class SearchServiceGatewayImpl implements SearchServiceGateway { } @Override - public DatabaseDto save(Database database) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException { + public DatabaseDto update(Database database) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException { final ResponseEntity<DatabaseDto> response; final HttpHeaders headers = new HttpHeaders(); headers.set("Accept", "application/json"); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/SearchService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/SearchService.java deleted file mode 100644 index 004df5d99da169a7edf718a6ee1aee546f8d8827..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/SearchService.java +++ /dev/null @@ -1,16 +0,0 @@ -package at.tuwien.service; - -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.entities.database.Database; -import at.tuwien.exception.DatabaseNotFoundException; -import at.tuwien.exception.SearchServiceConnectionException; -import at.tuwien.exception.SearchServiceException; - -public interface SearchService { - - DatabaseDto save(Database database) throws SearchServiceException, DatabaseNotFoundException, - SearchServiceConnectionException; - - void delete(Long databaseId) throws SearchServiceException, DatabaseNotFoundException, - SearchServiceConnectionException; -} diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java index b4d36edf91630b652eda1c02d7cc748224a09668..1c302c206871234da50f2cc9de234d7c94a84d66 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java @@ -6,11 +6,11 @@ import at.tuwien.entities.database.DatabaseAccess; import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; +import at.tuwien.gateway.SearchServiceGateway; import at.tuwien.mapper.MetadataMapper; import at.tuwien.repository.DatabaseRepository; import at.tuwien.service.AccessService; import at.tuwien.service.DatabaseService; -import at.tuwien.service.SearchService; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -23,21 +23,21 @@ import java.util.Optional; @Service public class AccessServiceImpl implements AccessService { - private final SearchService searchService; private final MetadataMapper metadataMapper; private final DatabaseService databaseService; private final DatabaseRepository databaseRepository; private final DataServiceGateway dataServiceGateway; + private final SearchServiceGateway searchServiceGateway; @Autowired - public AccessServiceImpl(SearchService searchService, MetadataMapper metadataMapper, - DatabaseService databaseService, DatabaseRepository databaseRepository, - DataServiceGateway dataServiceGateway) { - this.searchService = searchService; + public AccessServiceImpl(MetadataMapper metadataMapper, DatabaseService databaseService, + DatabaseRepository databaseRepository, DataServiceGateway dataServiceGateway, + SearchServiceGateway searchServiceGateway) { this.metadataMapper = metadataMapper; this.databaseService = databaseService; this.databaseRepository = databaseRepository; this.dataServiceGateway = dataServiceGateway; + this.searchServiceGateway = searchServiceGateway; } @Override @@ -79,7 +79,7 @@ public class AccessServiceImpl implements AccessService { .add(access); database = databaseRepository.save(database); /* create in search service */ - searchService.save(database); + searchServiceGateway.update(database); log.info("Created access to database with id {}", database.getId()); return access; } @@ -104,7 +104,7 @@ public class AccessServiceImpl implements AccessService { .setType(metadataMapper.accessTypeDtoToAccessType(access)); database = databaseRepository.save(database); /* update in search service */ - searchService.save(database); + searchServiceGateway.update(database); log.info("Updated access to database with id {}", database.getId()); } @@ -120,7 +120,7 @@ public class AccessServiceImpl implements AccessService { .remove(find(database, user)); databaseRepository.save(database); /* update in search service */ - searchService.save(databaseService.findById(database.getId())); + searchServiceGateway.update(databaseService.findById(database.getId())); log.info("Deleted access to database with id {}", database.getId()); } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java index d06c67b7b8ce837e254042728fd3d5c8056e97bf..7415ded56a8a2a926742ef3b44b025f7fb535baa 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java @@ -20,10 +20,10 @@ import at.tuwien.entities.database.table.constraints.unique.Unique; import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; +import at.tuwien.gateway.SearchServiceGateway; import at.tuwien.mapper.MetadataMapper; import at.tuwien.repository.DatabaseRepository; import at.tuwien.service.DatabaseService; -import at.tuwien.service.SearchService; import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.RandomStringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -39,18 +39,18 @@ import java.util.UUID; @Service public class DatabaseServiceImpl implements DatabaseService { - private final SearchService searchService; private final MetadataMapper metadataMapper; private final DatabaseRepository databaseRepository; private final DataServiceGateway dataServiceGateway; + private final SearchServiceGateway searchServiceGateway; @Autowired - public DatabaseServiceImpl(SearchService searchService, MetadataMapper metadataMapper, - DatabaseRepository databaseRepository, DataServiceGateway dataServiceGateway) { - this.searchService = searchService; + public DatabaseServiceImpl(MetadataMapper metadataMapper, DatabaseRepository databaseRepository, + DataServiceGateway dataServiceGateway, SearchServiceGateway searchServiceGateway) { this.metadataMapper = metadataMapper; this.databaseRepository = databaseRepository; this.dataServiceGateway = dataServiceGateway; + this.searchServiceGateway = searchServiceGateway; } @Override @@ -137,7 +137,7 @@ public class DatabaseServiceImpl implements DatabaseService { .toList()); final Database database = databaseRepository.save(entity1); /* create in search service */ - searchService.save(database); + searchServiceGateway.update(database); log.info("Created database with id {}", database.getId()); return database; } @@ -171,7 +171,7 @@ public class DatabaseServiceImpl implements DatabaseService { .forEach(table -> table.setIsSchemaPublic(data.getIsSchemaPublic())); database = databaseRepository.save(database); /* update in open search service */ - searchService.save(database); + searchServiceGateway.update(database); log.info("Updated database visibility of database with id {}", database.getId()); return database; } @@ -187,7 +187,7 @@ public class DatabaseServiceImpl implements DatabaseService { database.setContactPerson(user.getId()); database = databaseRepository.save(database); /* save in search service */ - searchService.save(database); + searchServiceGateway.update(database); log.info("Updated database owner of database with id {}", database); return database; } @@ -200,7 +200,7 @@ public class DatabaseServiceImpl implements DatabaseService { database.setImage(image); database = databaseRepository.save(database); /* save in search service */ - searchService.save(database); + searchServiceGateway.update(database); log.info("Updated database owner of database with id {} & search database", database.getId()); return database; } @@ -317,7 +317,7 @@ public class DatabaseServiceImpl implements DatabaseService { /* update in metadata database */ database = databaseRepository.save(database); /* save in search service */ - searchService.save(database); + searchServiceGateway.update(database); log.info("Updated table metadata of database with id {} & search database", database.getId()); return database; } @@ -344,7 +344,7 @@ public class DatabaseServiceImpl implements DatabaseService { /* update in metadata database */ database = databaseRepository.save(database); /* save in search service */ - searchService.save(database); + searchServiceGateway.update(database); log.info("Updated view metadata of database with id {} & search database", database.getId()); return database; } 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 e482cfd3c64e81cda98d0dda1ed29279e384d975..39e4824706a6d89a3588c6748c46ee2c3935b63e 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 @@ -16,10 +16,10 @@ import at.tuwien.entities.identifier.IdentifierTitle; import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; +import at.tuwien.gateway.SearchServiceGateway; import at.tuwien.mapper.MetadataMapper; import at.tuwien.repository.IdentifierRepository; import at.tuwien.service.IdentifierService; -import at.tuwien.service.SearchService; import at.tuwien.service.ViewService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; @@ -42,24 +42,24 @@ import java.util.stream.Stream; public class IdentifierServiceImpl implements IdentifierService { private final ViewService viewService; - private final SearchService searchService; private final MetadataConfig metadataConfig; private final MetadataMapper metadataMapper; private final TemplateEngine templateEngine; private final DataServiceGateway dataServiceGateway; private final IdentifierRepository identifierRepository; + private final SearchServiceGateway searchServiceGateway; - public IdentifierServiceImpl(ViewService viewService, SearchService searchService, TemplateEngine templateEngine, - MetadataMapper metadataMapper, MetadataConfig metadataConfig, - DataServiceGateway dataServiceGateway, IdentifierRepository identifierRepository) { + public IdentifierServiceImpl(ViewService viewService, TemplateEngine templateEngine, MetadataMapper metadataMapper, + MetadataConfig metadataConfig, DataServiceGateway dataServiceGateway, + IdentifierRepository identifierRepository, SearchServiceGateway searchServiceGateway) { this.viewService = viewService; - this.searchService = searchService; this.metadataConfig = metadataConfig; this.metadataMapper = metadataMapper; this.templateEngine = templateEngine; this.dataServiceGateway = dataServiceGateway; this.identifierRepository = identifierRepository; + this.searchServiceGateway = searchServiceGateway; } @Override @@ -153,7 +153,7 @@ public class IdentifierServiceImpl implements IdentifierService { identifier.setStatus(IdentifierStatusType.PUBLISHED); identifier = identifierRepository.save(identifier); /* update in search service */ - searchService.save(identifier.getDatabase()); + searchServiceGateway.update(identifier.getDatabase()); log.info("Published identifier with id {}", identifier.getId()); return identifier; } @@ -314,7 +314,7 @@ public class IdentifierServiceImpl implements IdentifierService { identifier.getDatabase() .getIdentifiers() .add(out); - searchService.save(identifier.getDatabase()); + searchServiceGateway.update(identifier.getDatabase()); return out; } @@ -378,7 +378,7 @@ public class IdentifierServiceImpl implements IdentifierService { identifier.getDatabase() .getIdentifiers() .remove(identifier); - searchService.save(identifier.getDatabase()); + searchServiceGateway.update(identifier.getDatabase()); log.info("Deleted identifier with id {}", identifier.getId()); } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/SearchServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/SearchServiceImpl.java deleted file mode 100644 index ef9840cbbae8e38962a3b60a6249ffb73743054a..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/SearchServiceImpl.java +++ /dev/null @@ -1,49 +0,0 @@ -package at.tuwien.service.impl; - -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.entities.database.Database; -import at.tuwien.exception.DatabaseNotFoundException; -import at.tuwien.exception.SearchServiceConnectionException; -import at.tuwien.exception.SearchServiceException; -import at.tuwien.gateway.SearchServiceGateway; -import at.tuwien.service.SearchService; -import lombok.extern.log4j.Log4j2; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Log4j2 -@Service -public class SearchServiceImpl implements SearchService { - - private final SearchServiceGateway searchServiceGateway; - - @Autowired - public SearchServiceImpl(SearchServiceGateway searchServiceGateway) { - this.searchServiceGateway = searchServiceGateway; - } - - @Override - public DatabaseDto save(Database database) throws SearchServiceException, DatabaseNotFoundException, - SearchServiceConnectionException { - if (!database.getIsPublic() || !database.getIsSchemaPublic()) { - log.warn("Database with id {} cannot be saved to be visible in search", database.getId()); - return null; - } - database.setTables(database.getTables() - .stream() - .filter(t -> t.getIsPublic() || t.getIsSchemaPublic()) - .toList()); - database.setViews(database.getViews() - .stream() - .filter(v -> v.getIsPublic() || v.getIsSchemaPublic()) - .toList()); - return searchServiceGateway.save(database); - } - - @Override - public void delete(Long databaseId) throws SearchServiceException, DatabaseNotFoundException, - SearchServiceConnectionException { - searchServiceGateway.delete(databaseId); - } - -} diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java index 6239d95c9e346f675e3c32395fd50c5ffe0e8b91..52a9a63667c8faa22bdd142d5161f04e85d70513 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java @@ -15,6 +15,7 @@ import at.tuwien.entities.database.table.columns.TableColumnUnit; import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; +import at.tuwien.gateway.SearchServiceGateway; import at.tuwien.mapper.MetadataMapper; import at.tuwien.repository.DatabaseRepository; import at.tuwien.service.*; @@ -37,26 +38,26 @@ public class TableServiceImpl implements TableService { private final UnitService unitService; private final RabbitConfig rabbitConfig; private final EntityService entityService; - private final SearchService searchService; private final ConceptService conceptService; private final MetadataMapper metadataMapper; private final DataServiceGateway dataServiceGateway; private final DatabaseRepository databaseRepository; + private final SearchServiceGateway searchServiceGateway; @Autowired public TableServiceImpl(UserService userService, UnitService unitService, RabbitConfig rabbitConfig, - EntityService entityService, SearchService searchService, ConceptService conceptService, - MetadataMapper metadataMapper, DataServiceGateway dataServiceGateway, - DatabaseRepository databaseRepository) { + EntityService entityService, ConceptService conceptService, MetadataMapper metadataMapper, + DataServiceGateway dataServiceGateway, DatabaseRepository databaseRepository, + SearchServiceGateway searchServiceGateway) { this.userService = userService; this.unitService = unitService; this.rabbitConfig = rabbitConfig; this.entityService = entityService; - this.searchService = searchService; this.conceptService = conceptService; this.metadataMapper = metadataMapper; this.dataServiceGateway = dataServiceGateway; this.databaseRepository = databaseRepository; + this.searchServiceGateway = searchServiceGateway; } @Override @@ -172,7 +173,7 @@ public class TableServiceImpl implements TableService { throw new TableNotFoundException("Failed to find created table"); } /* update in search service */ - searchService.save(entity); + searchServiceGateway.update(entity); log.info("Created table with id {}", optional.get().getId()); return optional.get(); } @@ -190,7 +191,7 @@ public class TableServiceImpl implements TableService { .remove(table); final Database database = databaseRepository.save(table.getDatabase()); /* update in search service */ - searchService.save(database); + searchServiceGateway.update(database); log.info("Deleted table with id {}", table.getId()); } @@ -217,7 +218,7 @@ public class TableServiceImpl implements TableService { tableEntity.setDescription(data.getDescription()); final Database database = databaseRepository.save(table.getDatabase()); /* update in search service */ - searchService.save(database); + searchServiceGateway.update(database); log.info("Updated table with id {}", table.getId()); return tableEntity; } @@ -257,7 +258,7 @@ public class TableServiceImpl implements TableService { .set(table.getColumns().indexOf(column), column); final Database database = databaseRepository.save(table.getDatabase()); /* update in open search service */ - searchService.save(database); + searchServiceGateway.update(database); log.info("Updated table column semantics"); return column; } @@ -309,7 +310,7 @@ public class TableServiceImpl implements TableService { .set(database.getTables().indexOf(table), table); databaseRepository.save(database); /* update in open search service */ - searchService.save(database); + searchServiceGateway.update(database); log.info("Updated statistics for the table and {} column(s)", table.getColumns().size()); log.trace("updated statistics: {}", table); } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java index 2f8e7671ed41667d4891aba73e6cf1b3ae6d0cea..b0a8f017962ccc808d8f3d1a37ae584fb1106316 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java @@ -8,9 +8,9 @@ import at.tuwien.entities.database.View; import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; +import at.tuwien.gateway.SearchServiceGateway; import at.tuwien.mapper.MetadataMapper; import at.tuwien.repository.DatabaseRepository; -import at.tuwien.service.SearchService; import at.tuwien.service.ViewService; import com.google.common.hash.Hashing; import lombok.extern.log4j.Log4j2; @@ -27,18 +27,18 @@ import java.util.Optional; @Service public class ViewServiceImpl implements ViewService { - private final SearchService searchService; private final MetadataMapper metadataMapper; private final DataServiceGateway dataServiceGateway; private final DatabaseRepository databaseRepository; + private final SearchServiceGateway searchServiceGateway; @Autowired public ViewServiceImpl(MetadataMapper metadataMapper, DataServiceGateway dataServiceGateway, - DatabaseRepository databaseRepository, SearchService searchService) { + DatabaseRepository databaseRepository, SearchServiceGateway searchServiceGateway) { this.metadataMapper = metadataMapper; this.dataServiceGateway = dataServiceGateway; this.databaseRepository = databaseRepository; - this.searchService = searchService; + this.searchServiceGateway = searchServiceGateway; } @Override @@ -81,7 +81,7 @@ public class ViewServiceImpl implements ViewService { .remove(view); final Database database = databaseRepository.save(view.getDatabase()); /* update in search service */ - searchService.save(database); + searchServiceGateway.update(database); log.info("Deleted view with id {}", view.getId()); } @@ -129,7 +129,7 @@ public class ViewServiceImpl implements ViewService { throw new MalformedException("Failed to find created view"); } /* update in search service */ - searchService.save(database); + searchServiceGateway.update(database); log.info("Created view with id {}", optional.get().getId()); return optional.get(); } @@ -151,7 +151,7 @@ public class ViewServiceImpl implements ViewService { tmpView.setIsSchemaPublic(data.getIsSchemaPublic()); database = databaseRepository.save(database); /* update in search service */ - searchService.save(database); + searchServiceGateway.update(database); log.info("Updated view with id {}", tmpView.getId()); return optional.get(); } diff --git a/dbrepo-search-service/Pipfile.lock b/dbrepo-search-service/Pipfile.lock index e700161ce55394f4a9edf485b4f10c7c00c49572..c0508dd3daf66ff03c848411ae47f1698da81014 100644 --- a/dbrepo-search-service/Pipfile.lock +++ b/dbrepo-search-service/Pipfile.lock @@ -360,7 +360,7 @@ }, "dbrepo": { "hashes": [ - "sha256:0d11a0e0ec942d5b0ddfadd9e9007ce6dab9c5b9cc433e0f53b4fafcfc597bef" + "sha256:a08b6eb49c108466b231c1b2cae5be501043fe4208a782899ce103105e22e3c6" ], "path": "./lib/dbrepo-1.6.1.tar.gz" }, @@ -1330,11 +1330,11 @@ }, "referencing": { "hashes": [ - "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c", - "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de" + "sha256:363d9c65f080d0d70bc41c721dce3c7f3e77fc09f269cd5c8813da18069a6794", + "sha256:ca2e6492769e3602957e9b831b94211599d2aade9477f5d44110d2530cf9aade" ], - "markers": "python_version >= '3.8'", - "version": "==0.35.1" + "markers": "python_version >= '3.9'", + "version": "==0.36.1" }, "requests": { "hashes": [ diff --git a/dbrepo-search-service/app.py b/dbrepo-search-service/app.py index 797b30f1b91d1b106fe7159de908d032faa6de60..f9e2dbcc77ac11a6f7c8175e2b0d868f848c98af 100644 --- a/dbrepo-search-service/app.py +++ b/dbrepo-search-service/app.py @@ -7,16 +7,17 @@ from typing import List, Any import requests from dbrepo.api.dto import Database, ApiError from flasgger import LazyJSONEncoder, Swagger, swag_from -from flask import Flask, request +from flask import Flask, request, Response from flask_cors import CORS from flask_httpauth import HTTPTokenAuth, HTTPBasicAuth, MultiAuth from jwt.exceptions import JWTDecodeError from opensearchpy import NotFoundError from prometheus_flask_exporter import PrometheusMetrics from pydantic import ValidationError +from pydantic.deprecated.json import pydantic_encoder from clients.keycloak_client import User, KeycloakClient -from clients.opensearch_client import OpenSearchClient +from clients.opensearch_client import OpenSearchClient, flatten logging.addLevelName(level=logging.NOTSET, levelName='TRACE') logging.basicConfig(level=logging.DEBUG) @@ -124,18 +125,6 @@ template = { } } }, - "SearchResultDto": { - "required": ["results"], - "type": "object", - "properties": { - "results": { - "type": "array", - "items": { - "type": "object" - } - } - } - }, "SearchRequestDto": { "required": ["search_term", "field_value_pairs"], "type": "object", @@ -209,13 +198,13 @@ app.json_encoder = LazyJSONEncoder @token_auth.verify_token -def verify_token(token: str): +def verify_token(token: str) -> bool | User: if token is None or token == "": return False try: client = KeycloakClient() return client.verify_jwt(access_token=token) - except JWTDecodeError as error: + except JWTDecodeError: return False @@ -260,10 +249,10 @@ def general_filter(index, results): "table": ["id", "name", "description"], "identifier": ["id", "type", "creator"], "user": ["id", "username"], - "database": ["id", "name", "is_public", "details"], + "database": ["id", "name", "is_public", "is_schema_public", "details"], "concept": ["uri", "name"], "unit": [], - "view": ["id", "name", "creator", " created"], + "view": ["id", "name", "creator"], } if index not in important_keys.keys(): raise KeyError(f"Failed to find index {index} in: {important_keys.keys()}") @@ -290,7 +279,7 @@ def get_index(index: str): :param index: desired index :return: list of the results """ - logging.info(f'Searching for index: {index}') + logging.debug(f'endpoint get search type: {index}') results = OpenSearchClient().query_index_by_term_opensearch("*", "contains") try: results = general_filter(index, results) @@ -299,7 +288,7 @@ def get_index(index: str): max_pages = math.ceil(len(results) / results_per_page) page = min(request.args.get("page", 1, type=int), max_pages) results = results[(results_per_page * (page - 1)): (results_per_page * page)] - return dict({"results": results}), 200 + return Response(dumps(results, default=pydantic_encoder)), 200, {'Content-Type': 'application/json'} except KeyError: return ApiError(status='NOT_FOUND', message=f'Failed to find get index: {index}', code='search.index.missing').model_dump(), 404 @@ -314,11 +303,11 @@ def get_fields(field_type: str): :param field_type: The search type :return: """ - logging.info(f'Searching in index database for type: {field_type}') + logging.debug(f'endpoint get search type fields: {field_type}') try: fields = OpenSearchClient().get_fields_for_index(field_type) logging.debug(f'get fields for field_type {field_type} resulted in {len(fields)} field(s)') - return fields, 200 + return Response(dumps(fields, default=pydantic_encoder)), 200, {'Content-Type': 'application/json'} except NotFoundError: return ApiError(status='NOT_FOUND', message=f'Failed to find fields for search type {field_type}', code='search.type.missing').model_dump(), 404 @@ -332,15 +321,19 @@ def get_fuzzy_search(): Main endpoint for fuzzy searching. :return: """ - search_term: str = request.args.get('q') + search_term: str | None = request.args.get('q') logging.debug(f'endpoint get fuzzy search, q={search_term}') if search_term is None or len(search_term) == 0: return ApiError(status='BAD_REQUEST', message='Provide a search term with ?q=term', code='search.fuzzy.invalid').model_dump(), 400 logging.debug(f"search request query: {search_term}") - results = OpenSearchClient().fuzzy_search(search_term, - KeycloakClient().userId(request.headers.get('Authorization'))) - return dict({"results": results}), 200 + user_id, error, status = KeycloakClient().userId(request.headers.get('Authorization')) + if error is not None and status is not None: + return error, status + results: [Database] = OpenSearchClient().fuzzy_search(search_term=search_term, + user_id=user_id, + user_token=request.headers.get('Authorization')) + return Response(dumps(results, default=pydantic_encoder)), 200, {'Content-Type': 'application/json'} @app.route("/api/search/<string:field_type>", methods=["POST"], endpoint="search_post_general_search") @@ -354,30 +347,32 @@ def post_general_search(field_type): if request.content_type != "application/json": return ApiError(status='UNSUPPORTED_MEDIA_TYPE', message='Content type needs to be application/json', code='search.general.media').model_dump(), 415 - req_body = request.json - logging.debug(f'endpoint get general search, field_type={field_type}') - logging.debug(f'=====> {request}') + value_pairs = request.json + logging.debug(f'endpoint get general search, field_type={field_type}, value_pairs={value_pairs}') t1 = request.args.get("t1") if not str(t1).isdigit(): t1 = None t2 = request.args.get("t2") if not str(t2).isdigit(): t2 = None - if t1 is not None and t2 is not None and "unit.uri" in req_body and "concept.uri" in req_body: - response = OpenSearchClient().unit_independent_search(t1, t2, req_body, KeycloakClient().userId( - request.headers.get('Authorization'))) + user_id, error, status = KeycloakClient().userId(request.headers.get('Authorization')) + if error is not None and status is not None: + return error, status + if t1 is not None and t2 is not None and "unit.uri" in value_pairs and "concept.uri" in value_pairs: + response: [Database] = OpenSearchClient().unit_independent_search(t1, t2, value_pairs, user_id) else: - response = OpenSearchClient().general_search(field_type, req_body, - KeycloakClient().userId(request.headers.get('Authorization'))) + response: [Database] = OpenSearchClient().general_search(field_type=field_type, + field_value_pairs=value_pairs, + user_id=user_id, + user_token=request.headers.get('Authorization')) # filter by type + tables = [table for table in flatten([database.tables for database in response]) if + table.is_public or table.is_schema_public or (user_id is not None and table.owner.id == user_id)] + views = [view for view in flatten([database.views for database in response]) if + view.is_public or view.is_schema_public or (user_id is not None and view.owner.id == user_id)] if field_type == 'table': - tmp = [] - for database in response: - if database["tables"] is not None: - for table in database["tables"]: - table["is_public"] = database["is_public"] - tmp.append(table) - response = tmp + logging.debug(f'filtered to {len(tables)} tables') + response = tables if field_type == 'identifier': tmp = [] for database in response: @@ -397,12 +392,7 @@ def post_general_search(field_type): tmp.append(view['identifier']) response = tmp elif field_type == 'column': - response = [x for xs in response for x in xs["tables"]] - for table in response: - for column in table["columns"]: - column["table_id"] = table["id"] - column["database_id"] = table["database_id"] - response = [x for xs in response for x in xs["columns"]] + response = flatten([table.columns for table in tables]) elif field_type == 'concept': tmp = [] tables = [x for xs in response for x in xs["tables"]] @@ -418,15 +408,15 @@ def post_general_search(field_type): tmp.append(column["unit"]) response = tmp elif field_type == 'view': - response = [x for xs in response for x in xs["views"]] - return dict({'results': response, 'type': field_type}), 200 + response = views + return Response(dumps(response, default=pydantic_encoder)), 200, {'Content-Type': 'application/json'} @app.route("/api/search/database/<int:database_id>", methods=["PUT"], endpoint="search_put_database") @metrics.gauge(name='dbrepo_search_update_database', description='Time needed to update a database in the search database') @auth.login_required(role=['update-search-index']) -def update_database(database_id: int) -> Database | ApiError: +def update_database(database_id: int): logging.debug(f"updating database with id: {database_id}") try: payload: Database = Database.model_validate(request.json) @@ -435,7 +425,7 @@ def update_database(database_id: int) -> Database | ApiError: return ApiError(status='BAD_REQUEST', message=f'Malformed payload: {e}', code='search.general.missing').model_dump(), 400 database = OpenSearchClient().update_database(database_id, payload) - logging.info(f"Updated database with id : {database_id}") + logging.info(f"Updated database with id: {database_id}") return database.model_dump(), 202 @@ -446,7 +436,7 @@ def update_database(database_id: int) -> Database | ApiError: def delete_database(database_id: int): try: OpenSearchClient().delete_database(database_id) - return dumps({}), 202 + return Response(dumps({})), 202 except NotFoundError: return ApiError(status='NOT_FOUND', message='Failed to find database', code='search.database.missing').model_dump(), 404 diff --git a/dbrepo-search-service/init/Pipfile.lock b/dbrepo-search-service/init/Pipfile.lock index a8257b53df3cc300043d7aeb6412481708b9b1ff..8d0c1995c070e8f9bd04de2bac81139c56c420c2 100644 --- a/dbrepo-search-service/init/Pipfile.lock +++ b/dbrepo-search-service/init/Pipfile.lock @@ -254,7 +254,7 @@ }, "dbrepo": { "hashes": [ - "sha256:0d11a0e0ec942d5b0ddfadd9e9007ce6dab9c5b9cc433e0f53b4fafcfc597bef" + "sha256:a08b6eb49c108466b231c1b2cae5be501043fe4208a782899ce103105e22e3c6" ], "path": "./lib/dbrepo-1.6.1.tar.gz" }, diff --git a/dbrepo-search-service/init/app.py b/dbrepo-search-service/init/app.py index 9fe915f92c50d2b712058783d4eecf1b087cc8f7..f8f671bade77541508aec72cd19066157cd162f3 100644 --- a/dbrepo-search-service/init/app.py +++ b/dbrepo-search-service/init/app.py @@ -1,12 +1,11 @@ import json -import os import logging +import os +from logging.config import dictConfig from typing import List import opensearchpy.exceptions from dbrepo.RestClient import RestClient -from logging.config import dictConfig - from dbrepo.api.dto import Database from opensearchpy import OpenSearch @@ -46,6 +45,8 @@ class App: search_username: str = None search_password: str = None search_instance: OpenSearch = None + system_username: str = None + system_password: str = None def __init__(self): self.metadata_service_endpoint = os.getenv("METADATA_SERVICE_ENDPOINT", "http://metadata-service:8080") @@ -53,6 +54,8 @@ class App: self.search_port = int(os.getenv("OPENSEARCH_PORT", "9200")) self.search_username = os.getenv("OPENSEARCH_USERNAME", "admin") self.search_password = os.getenv("OPENSEARCH_PASSWORD", "admin") + self.system_username = os.getenv("SYSTEM_USERNAME", "admin") + self.system_password = os.getenv("SYSTEM_PASSWORD", "admin") def _instance(self) -> OpenSearch: """ @@ -84,7 +87,8 @@ class App: def fetch_databases(self) -> List[Database]: logging.debug(f"fetching database from endpoint: {self.metadata_service_endpoint}") - client = RestClient(endpoint=self.metadata_service_endpoint) + client = RestClient(endpoint=self.metadata_service_endpoint, username=self.system_username, + password=self.system_password) databases = [] for index, database in enumerate(client.get_databases()): logging.debug(f"fetching database {index}/{len(databases)} details for database id: {database.id}") @@ -93,16 +97,17 @@ class App: return databases def save_databases(self, databases: List[Database]): - logging.debug(f"save {len(databases)} database(s)") + index = f'database' + logging.debug(f"save {len(databases)} database(s) in index: {index}") for doc in databases: doc: Database = doc try: - self._instance().delete(index="database", id=doc.id) - logging.debug(f"deleted database with id {doc.id}") + self._instance().delete(index=index, id=doc.id) + logging.debug(f"truncated database with id {doc.id} in index: {index}") except opensearchpy.NotFoundError: - logging.warning(f"Database with id {doc.id} does not exist, skip.") - self._instance().create(index="database", id=doc.id, body=doc.model_dump()) - logging.debug(f"created database with id {doc.id}") + pass + self._instance().create(index=index, id=doc.id, body=doc.model_dump()) + logging.info(f"Saved database with id {doc.id} in index: {index}") if __name__ == "__main__": diff --git a/dbrepo-search-service/init/clients/keycloak_client.py b/dbrepo-search-service/init/clients/keycloak_client.py index b12c3779f5d8a8385440a99b20c2d5a021b25011..2e15d00a9b272233feb7bab4cf6166c63b151e04 100644 --- a/dbrepo-search-service/init/clients/keycloak_client.py +++ b/dbrepo-search-service/init/clients/keycloak_client.py @@ -3,13 +3,15 @@ from dataclasses import dataclass from typing import List import requests +from dbrepo.api.dto import ApiError from flask import current_app from jwt import jwk_from_pem, JWT +from jwt.exceptions import JWTDecodeError @dataclass(init=True, eq=True) class User: - sub: str + id: str username: str roles: List[str] @@ -31,14 +33,22 @@ class KeycloakClient: raise AssertionError("Failed to obtain user token(s)") return response.json()["access_token"] - def verify_jwt(self, access_token: str) -> User: + def verify_jwt(self, access_token: str) -> ApiError | User: public_key = jwk_from_pem(str(current_app.config["JWT_PUBKEY"]).encode('utf-8')) payload = JWT().decode(message=access_token, key=public_key, do_time_check=True) - return User(username=payload.get('client_id'), roles=payload.get('realm_access')["roles"]) - - def userId(self, request) -> str | None: - # get the auth token - auth_header = request.headers.get('Authorization') - if auth_header: - return self.verify_jwt(auth_header.split(" ")[1]).sub - return None + return User(id=payload.get('uid'), username=payload.get('client_id'), + roles=payload.get('realm_access')["roles"]) + + def userId(self, auth_header: str | None) -> (str | None, ApiError, int): + if auth_header is None: + return None, None, None + try: + user = self.verify_jwt(auth_header.split(" ")[1]) + logging.debug(f'mapped JWT to user.id {user.id}') + return user.id, None, None + except JWTDecodeError as e: + logging.error(f'Failed to decode JWT: {e}') + if str(e) == 'JWT Expired': + return None, ApiError(status='UNAUTHORIZED', message=f'Token expired', + code='search.user.unauthorized').model_dump(), 401 + return None, ApiError(status='FORBIDDEN', message=str(e), code='search.user.forbidden').model_dump(), 403 diff --git a/dbrepo-search-service/init/clients/opensearch_client.py b/dbrepo-search-service/init/clients/opensearch_client.py index 69f6ab7f4cd671fc816cfe0dab6fc777134f5271..35c26f03f5f684adc2652c199db7f99afd6cfc13 100644 --- a/dbrepo-search-service/init/clients/opensearch_client.py +++ b/dbrepo-search-service/init/clients/opensearch_client.py @@ -7,7 +7,9 @@ from collections.abc import MutableMapping from json import dumps, load from dbrepo.api.dto import Database +from dbrepo.api.exceptions import ForbiddenError, NotExistsError from opensearchpy import OpenSearch, NotFoundError +from requests import head from omlib.constants import OM_IDS from omlib.measure import om @@ -20,16 +22,22 @@ class OpenSearchClient: The client to communicate with the OpenSearch database. """ host: str = None + instance: OpenSearch = None + metadata_endpoint: str = None + password: str = None port: int = None + system_username: str = None + system_password: str = None username: str = None - password: str = None - instance: OpenSearch = None def __init__(self, host: str = None, port: int = None, username: str = None, password: str = None): self.host = os.getenv('OPENSEARCH_HOST', host) + self.metadata_endpoint = os.getenv('METADATA_SERVICE_ENDPOINT', 'http://metadata-service:8080') + self.password = os.getenv('OPENSEARCH_PASSWORD', password) self.port = int(os.getenv('OPENSEARCH_PORT', port)) + self.system_username = os.getenv('SYSTEM_USERNAME', 'admin') + self.system_password = os.getenv('SYSTEM_PASSWORD', 'admin') self.username = os.getenv('OPENSEARCH_USERNAME', username) - self.password = os.getenv('OPENSEARCH_PASSWORD', password) def _instance(self) -> OpenSearch: """ @@ -56,9 +64,7 @@ class OpenSearchClient: logging.debug(f"updating database with id: {database_id} in search database") self._instance().index(index="database", id=database_id, body=dumps(data.model_dump())) response: dict = self._instance().get(index="database", id=database_id) - database = Database.model_validate(response["_source"]) - logging.info(f"Updated database with id {database_id} in index 'database'") - return database + return Database.model_validate(response["_source"]) def delete_database(self, database_id: int) -> None: """ @@ -130,32 +136,50 @@ class OpenSearchClient: fields_list.append(entry) return fields_list - def fuzzy_search(self, search_term: str = None, userId: str | None = None) -> [Database]: - logging.info(f"Performing fuzzy search") - fuzzy_body = { - "query": { - "multi_match": { - "query": search_term, - "fuzziness": "AUTO", - "fuzzy_transpositions": True, - "minimum_should_match": 3 - } - } - } - logging.debug(f'search body: {fuzzy_body}') + def fuzzy_search(self, search_term: str, user_id: str | None = None, user_token: str | None = None) -> [Database]: response = self._instance().search( index="database", - body=fuzzy_body + body={ + "query": { + "multi_match": { + "query": search_term, + "fuzziness": "AUTO", + "prefix_length": 2 + } + } + } ) results: [Database] = [] - if "hits" in results and "hits" in response["hits"]: + if "hits" in response and "hits" in response["hits"]: results = [Database.model_validate(hit["_source"]) for hit in response["hits"]["hits"]] - results = [database for database in results if database.is_public or database.is_schema_public or ( - userId is not None and database.owner.id == userId)] - return results + logging.debug(f'found {len(results)} results') + return self.filter_results(results, user_id, user_token) - def general_search(self, field_type: str = None, field_value_pairs: dict = None, userId: str | None = None) -> [ + def filter_results(self, results: [Database], user_id: str | None = None, user_token: str | None = None) -> [ Database]: + filtered: [Database] = [] + for database in results: + if database.is_public or database.is_schema_public: + logging.debug(f'database with id {database.id} is public or has public schema') + filtered.append(database) + elif user_id is not None and user_token is not None: + try: + url = f'{self.metadata_endpoint}/api/database/{database.id}/access/{user_id}' + logging.debug(f'requesting access from url: {url}') + response = head(url=url, auth=(self.system_username, self.system_password)) + if response.status_code == 200: + logging.debug(f'database with id {database.id} is draft and access was found') + filtered.append(database) + else: + logging.warning( + f'database with id {database.id} is not accessible: code {response.status_code}') + except (ForbiddenError, NotExistsError) as e: + logging.warning(f'database with id {database.id} is draft but no access was found') + logging.debug(f'filtered {len(filtered)} results') + return filtered + + def general_search(self, field_type: str = None, field_value_pairs: dict = None, user_id: str | None = None, + user_token: str | None = None) -> [Database]: """ Main method for searching stuff in the opensearch db @@ -197,11 +221,10 @@ class OpenSearchClient: body=dumps(body) ) results: [Database] = [] - if "hits" in results and "hits" in response["hits"]: + if "hits" in response and "hits" in response["hits"]: results = [Database.model_validate(hit["_source"]) for hit in response["hits"]["hits"]] - results = [database for database in results if database.is_public or database.is_schema_public or ( - userId is not None and database.owner.id == userId)] - return results + logging.debug(f'found {len(results)} results') + return self.filter_results(results, user_id, user_token) def unit_independent_search(self, t1: float, t2: float, field_value_pairs: dict, userId: str | None = None) -> [ Database]: diff --git a/dbrepo-search-service/init/database.json b/dbrepo-search-service/init/database.json index 363624ff059daa02d4edb58f3f6bce1b5b4664dd..59cbd78438a5fff391d1237c70a0384d7b397a83 100644 --- a/dbrepo-search-service/init/database.json +++ b/dbrepo-search-service/init/database.json @@ -572,37 +572,6 @@ } } }, - "owner": { - "properties": { - "id": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "qualified_name": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "username": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - } - } - }, "tables": { "properties": { "columns": { @@ -640,6 +609,12 @@ "is_null_allowed": { "type": "boolean" }, + "is_public": { + "type": "boolean" + }, + "is_schema_public": { + "type": "boolean" + }, "mean": { "type": "float" }, @@ -827,55 +802,6 @@ "num_rows": { "type": "long" }, - "owner": { - "properties": { - "id": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "qualified_name": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "name": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "orcid": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "username": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - } - } - }, "queue_name": { "type": "text", "fields": { @@ -933,6 +859,9 @@ "is_public": { "type": "boolean" }, + "is_schema_public": { + "type": "boolean" + }, "name": { "type": "text", "fields": { diff --git a/dbrepo-search-service/init/lib/dbrepo-1.6.1.tar.gz b/dbrepo-search-service/init/lib/dbrepo-1.6.1.tar.gz index 5ce8fdab038ca28aa52e5c8544ce3bcfee7ca3fa..7e4d5a2470276918716a153487671274665749a6 100644 Binary files a/dbrepo-search-service/init/lib/dbrepo-1.6.1.tar.gz and b/dbrepo-search-service/init/lib/dbrepo-1.6.1.tar.gz differ diff --git a/dbrepo-search-service/lib/dbrepo-1.6.1.tar.gz b/dbrepo-search-service/lib/dbrepo-1.6.1.tar.gz index 5ce8fdab038ca28aa52e5c8544ce3bcfee7ca3fa..7e4d5a2470276918716a153487671274665749a6 100644 Binary files a/dbrepo-search-service/lib/dbrepo-1.6.1.tar.gz and b/dbrepo-search-service/lib/dbrepo-1.6.1.tar.gz differ diff --git a/dbrepo-search-service/os-yml/get_fuzzy_search.yml b/dbrepo-search-service/os-yml/get_fuzzy_search.yml index bc54419eb9735fe731fb12a5e911070ebc29f80e..db2ef87b3268f10329ba11117ee323208d940af5 100644 --- a/dbrepo-search-service/os-yml/get_fuzzy_search.yml +++ b/dbrepo-search-service/os-yml/get_fuzzy_search.yml @@ -19,6 +19,9 @@ responses: content: application/json: schema: - $ref: '#/components/schemas/SearchResultDto' + type: array + properties: + id: + type: string 415: description: Wrong accept type diff --git a/dbrepo-ui/components/search/AdvancedSearch.vue b/dbrepo-ui/components/search/AdvancedSearch.vue index b312b2dc5291812fd98930e8585b50e389c341c5..8197cd3fb8a960f44440cc8238c0a1a42cb7f57e 100644 --- a/dbrepo-ui/components/search/AdvancedSearch.vue +++ b/dbrepo-ui/components/search/AdvancedSearch.vue @@ -384,8 +384,8 @@ export default { this.loading = true const searchService = useSearchService() searchService.general_search(this.searchType, this.advancedSearchData) - .then(({results, type}) => { - this.$emit('search-result', {results, type}) + .then((results) => { + this.$emit('search-result', results) }) .finally(() => { this.loading = false @@ -443,7 +443,7 @@ export default { return } this.resetAdvancedSearchFields() - this.$emit('search-result', { results: [], type: this.searchType }) + this.$emit('search-result', []) const searchService = useSearchService() this.loadingFields = true searchService.fields(this.searchType) diff --git a/dbrepo-ui/composables/search-service.ts b/dbrepo-ui/composables/search-service.ts index 62be8b9bc7160f70e33969970fbbba1c500d288f..b61f8358cf74167d1fef5c6f2de54ef017d4c7aa 100644 --- a/dbrepo-ui/composables/search-service.ts +++ b/dbrepo-ui/composables/search-service.ts @@ -18,11 +18,11 @@ export const useSearchService = (): any => { }) } - async function fuzzy_search(term: string): Promise<SearchResultDto> { + async function fuzzy_search(term: string): Promise<DatabaseDto[]> { const axios = useAxiosInstance() console.debug('fuzzy search for term', term) - return new Promise<SearchResultDto>((resolve, reject) => { - axios.get<SearchResultDto>(`/api/search?q=${term}`) + return new Promise<DatabaseDto[]>((resolve, reject) => { + axios.get<DatabaseDto[]>(`/api/search?q=${term}`) .then((response) => { console.info('Searched for term', term) resolve(response.data) diff --git a/dbrepo-ui/pages/search.vue b/dbrepo-ui/pages/search.vue index b13a0f0fc2d7985775fe8c3c450c0acb8785bbd0..b23c896448e12845d0d4b3f92ce0284b5886bd55 100644 --- a/dbrepo-ui/pages/search.vue +++ b/dbrepo-ui/pages/search.vue @@ -27,7 +27,8 @@ v-if="isDatabaseSearch" :loading="loading" :databases="results" /> - <div> + <div + v-else> <v-card v-for="(result, idx) in results" :key="idx" @@ -38,10 +39,13 @@ <v-divider class="mx-4" /> <v-card-title class="text-primary text-decoration-underline"> - <a v-if="link(result)" :href="link(result)"> + <a + v-if="link(result)" + :href="link(result)"> {{ title(result) }} </a> - <span v-else> + <span + v-else> {{ title(result) }} </span> </v-card-title> @@ -66,23 +70,15 @@ </v-card-text> </v-card> </div> - <v-dialog - v-model="createDbDialog" - persistent - max-width="640"> - <DatabaseCreate @close="closed" /> - </v-dialog> </div> </template> <script> -import DatabaseCreate from '@/components/database/DatabaseCreate.vue' import AdvancedSearch from '@/components/search/AdvancedSearch.vue' import { useUserStore } from '@/stores/user' export default { components: { - DatabaseCreate, AdvancedSearch }, data () { @@ -90,7 +86,6 @@ export default { results: [], type: 'database', loading: false, - createDbDialog: null, userStore: useUserStore() } }, @@ -136,10 +131,13 @@ export default { if (!queryKeys || queryKeys.length !== 1 || !queryKeys.includes('q')) { return } + if (!this.q) { + return + } this.loading = true const searchService = useSearchService() searchService.fuzzy_search(this.q) - .then(({results}) => { + .then((results) => { this.results = results this.loading = false }) @@ -294,19 +292,8 @@ export default { } return tags }, - closed (event) { - this.dialog = false - if (event.success) { - this.$router.push(`/database/${event.database_id}/info`) - } - }, - onSearchResult ({results, type}) { + onSearchResult (results) { this.results = results - if (!type) { - return - } - console.debug('search for type', type, ':', results) - this.type = type }, capitalizeFirstLetter(string) { if (!string) { diff --git a/docker-compose.yml b/docker-compose.yml index 7159ff58cbb59eec4d114603c71c5ea4c52d51b1..315f6bf1884c1e49d2ac870ab53f50d7a6b8c449 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -303,12 +303,14 @@ services: AUTH_SERVICE_CLIENT_SECRET: ${AUTH_SERVICE_CLIENT_SECRET:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG} AUTH_SERVICE_ENDPOINT: ${AUTH_SERVICE_ENDPOINT:-http://auth-service:8080} COLLECTION: ${COLLECTION:-['database','table','column','identifier','unit','concept','user','view']} + LOG_LEVEL: ${LOG_LEVEL:-info} METADATA_SERVICE_ENDPOINT: ${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080} OPENSEARCH_HOST: ${OPENSEARCH_HOST:-search-db} OPENSEARCH_PORT: ${OPENSEARCH_PORT:-9200} OPENSEARCH_USERNAME: ${SEARCH_DB_USERNAME:-admin} OPENSEARCH_PASSWORD: ${SEARCH_DB_PASSWORD:-admin} - LOG_LEVEL: ${LOG_LEVEL:-info} + SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}" + SYSTEM_PASSWORD: "${SYSTEM_PASSWORD:-admin}" healthcheck: test: curl -sSL localhost:8080/health | grep 'UP' || exit 1 interval: 10s @@ -402,11 +404,14 @@ services: context: ./dbrepo-search-service/init network: host environment: + LOG_LEVEL: ${LOG_LEVEL:-info} METADATA_SERVICE_ENDPOINT: ${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080} OPENSEARCH_HOST: ${OPENSEARCH_HOST:-search-db} OPENSEARCH_PORT: ${OPENSEARCH_PORT:-9200} OPENSEARCH_USERNAME: ${SEARCH_DB_USERNAME:-admin} OPENSEARCH_PASSWORD: ${SEARCH_DB_PASSWORD:-admin} + SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}" + SYSTEM_PASSWORD: "${SYSTEM_PASSWORD:-admin}" depends_on: dbrepo-search-db: condition: service_healthy diff --git a/lib/python/dbrepo/api/dto.py b/lib/python/dbrepo/api/dto.py index dc7f0e191210b70978ec7b26834293705d3012e9..fa7eb063fc453c3dd8fabef04f141d07012c94a3 100644 --- a/lib/python/dbrepo/api/dto.py +++ b/lib/python/dbrepo/api/dto.py @@ -5,7 +5,7 @@ from dataclasses import field from enum import Enum from typing import List, Optional, Annotated -from pydantic import BaseModel, PlainSerializer, Field +from pydantic import BaseModel, PlainSerializer Timestamp = Annotated[ datetime.datetime, PlainSerializer(lambda v: v.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z', return_type=str) @@ -987,9 +987,10 @@ class DatabaseBrief(BaseModel): internal_name: str description: Optional[str] = None is_public: bool + is_schema_public: bool identifiers: Optional[List[Identifier]] = field(default_factory=list) contact: UserBrief - owner: UserBrief + owner_id: str class Unique(BaseModel):