Skip to content

Commit

Permalink
Merge pull request #71 from virtualidentityag/develop
Browse files Browse the repository at this point in the history
staging
  • Loading branch information
tkuzynow authored Jul 18, 2024
2 parents 54c9080 + 82ef075 commit 02fc476
Show file tree
Hide file tree
Showing 11 changed files with 451 additions and 19 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/dockerImage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
- name: Setup JVM
uses: actions/setup-java@v1
with:
java-version: 11.0.10
java-version: 11.0.15
java-package: jdk
architecture: x64

Expand Down
43 changes: 33 additions & 10 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
<version>2.7.18</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>

Expand All @@ -41,15 +41,15 @@
<commons-validator.version>1.7</commons-validator.version>
<liquibase-maven-plugin.version>4.8.0</liquibase-maven-plugin.version>
<javax.ws.rs-api.version>2.1.1</javax.ws.rs-api.version>
<spring-boot-starter-web.version>2.6.6</spring-boot-starter-web.version>
<spring-security-core.version>5.7.5</spring-security-core.version>
<spring-beans.version>5.2.20.RELEASE</spring-beans.version>
<spring-webmvc.version>5.2.20.RELEASE</spring-webmvc.version>
<spring-core.version>5.2.20.RELEASE</spring-core.version>
<spring-boot-starter-web.version>2.7.18</spring-boot-starter-web.version>
<spring-security-core.version>5.7.12</spring-security-core.version>
<spring-beans.version>5.3.31</spring-beans.version>
<spring-webmvc.version>5.3.35</spring-webmvc.version>
<spring-core.version>5.3.35</spring-core.version>
<json-smart.version>2.4.7</json-smart.version>
<spring-context-support.version>5.3.23</spring-context-support.version>
<spring-context-support.version>5.3.35</spring-context-support.version>
<ehcache.version>2.10.9.2</ehcache.version>
<spring-boot-starter-data-mongodb.version>2.7.5</spring-boot-starter-data-mongodb.version>
<spring-boot-starter-data-mongodb.version>2.7.18</spring-boot-starter-data-mongodb.version>
<spring-data-mongodb.version>3.3.5</spring-data-mongodb.version>
</properties>

Expand Down Expand Up @@ -125,7 +125,7 @@
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-search-orm</artifactId>
<version>5.11.10.Final</version>
<version>5.11.12.Final</version>
</dependency>

<!-- Swagger/OpenAPI dependencies -->
Expand Down Expand Up @@ -216,7 +216,6 @@
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<version>4.8.0</version>
</dependency>

<!-- mongo dependencies -->
Expand Down Expand Up @@ -345,6 +344,12 @@
<groupId>org.powermock</groupId>
<scope>test</scope>
<version>${powermock.version}</version>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<artifactId>powermock-api-mockito2</artifactId>
Expand Down Expand Up @@ -455,6 +460,24 @@
</configuration>
</plugin>

<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>5.30.0</version>
<configuration>
<activeRecipes>
<recipe>org.openrewrite.java.spring.boot2.UpgradeSpringBoot_2_7</recipe>
</activeRecipes>
</configuration>
<dependencies>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-spring</artifactId>
<version>5.9.0</version>
</dependency>
</dependencies>
</plugin>

<!-- json-schema.org pojo generation -->
<plugin>
<groupId>org.jsonschema2pojo</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ private boolean agencyTopicsRelationExists(Integer agencyId, Integer topicId) {
private List<Integer> findAllAgenciesForConsultingType(Integer consultingTypeId) {
return agencyServiceJdbcTemplate.query(
"SELECT id from agency WHERE consulting_type = ?",
new Object[] {consultingTypeId},
(RowMapper<Integer>) (resultSet, rowNum) -> resultSet.getInt("id"));
(RowMapper<Integer>) (resultSet, rowNum) -> resultSet.getInt("id"),
new Object[] {consultingTypeId});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.keycloak.representations.idm.RoleRepresentation;
import org.springframework.boot.configurationprocessor.json.JSONException;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
Expand Down Expand Up @@ -265,7 +264,7 @@ private String getCreateRoleBody(String roleName) {
JSONObject body = new JSONObject();
body.put("name", roleName);
return body.toString();
} catch (JSONException e) {
} catch (Exception e) {
return null;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.keycloak.representations.idm.UserRepresentation;
import org.springframework.boot.configurationprocessor.json.JSONException;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
Expand Down Expand Up @@ -207,7 +206,7 @@ private Object getResetUserCredentialsBody(String password) {
body.put("value", password);
body.put("temporary", false);
return body.toString();
} catch (JSONException e) {
} catch (Exception e) {
return null;
}
}
Expand Down
154 changes: 154 additions & 0 deletions src/main/java/com/vi/migrationtool/keycloak/TenantUpdateService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package com.vi.migrationtool.keycloak;

import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

@Slf4j
@Service
@RequiredArgsConstructor
public class TenantUpdateService {

private static final int USER_PAGE_SIZE = 300;
private static final String TENANT_ID = "tenantId";
private static final String SUCCESSFULLY_SET_TENANT_ID_FOR_WITH_ID_TO =
"Successfully set tenantId for {} with id {} to {}";

private final KeycloakUserService keycloakUserService;

private final KeycloakLoginService keycloakLoginService;

private final JdbcTemplate userServiceJdbcTemplate;

private HttpHeaders authenticateInKeycloak() {
var httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
KeycloakLoginResponseDTO loginResponse = keycloakLoginService.loginAdminUser();
httpHeaders.setBearerAuth(loginResponse.getAccessToken());
return httpHeaders;
}

public void updateAdviceSeekersTenant(List<UserTenant> adviceSeekerToTargetTenantCollection) {
var httpHeaders = authenticateInKeycloak();
if (adviceSeekerToTargetTenantCollection.isEmpty()) {
log.info("No advice seeker found with different tenantId");
return;
}
for (int i = 0; i < adviceSeekerToTargetTenantCollection.size(); i++) {
var adviceSeekerTenant = adviceSeekerToTargetTenantCollection.get(i);
if (i % USER_PAGE_SIZE == 0) {
httpHeaders = authenticateInKeycloak();
}
log.info(
"Attempt to set tenantId for adviceseeker with id {} to {}",
adviceSeekerTenant.getUserId(),
adviceSeekerTenant.getTenantId());

keycloakUserService.updateUserCustomAttributeWithoutLogin(
TENANT_ID, adviceSeekerTenant.getTenantId(), adviceSeekerTenant.getUserId(), httpHeaders);

updateTables(adviceSeekerTenant);
log.info(
SUCCESSFULLY_SET_TENANT_ID_FOR_WITH_ID_TO,
"advice seeker, user and keycloak user",
adviceSeekerTenant.getUserId(),
adviceSeekerTenant.getTenantId());
}
}

private void updateTables(UserTenant adviceSeekerTenant) {
userServiceJdbcTemplate.update(
"UPDATE user SET tenant_id = ? WHERE user_id = ?",
adviceSeekerTenant.getTenantId(),
adviceSeekerTenant.getUserId());

userServiceJdbcTemplate.update(
"UPDATE session SET tenant_id = ? WHERE user_id = ?",
adviceSeekerTenant.getTenantId(),
adviceSeekerTenant.getUserId());
}

public void updateConsultantsTenant(List<UserTenant> consultantTargetTenants) {

if (consultantTargetTenants.isEmpty()) {
log.info("No consultant found with different tenantId");
return;
}
var httpHeaders = authenticateInKeycloak();
for (int i = 0; i < consultantTargetTenants.size(); i++) {
if (i % USER_PAGE_SIZE == 0) {
httpHeaders = authenticateInKeycloak();
}
var consultantTenant = consultantTargetTenants.get(i);

log.info(
"Attempt to set tenantId for {} with id {} to {}",
"consultant",
consultantTenant.getUserId(),
consultantTenant.getTenantId());

keycloakUserService.updateUserCustomAttributeWithoutLogin(
TENANT_ID, consultantTenant.getTenantId(), consultantTenant.getUserId(), httpHeaders);

userServiceJdbcTemplate.update(
"UPDATE consultant_agency SET tenant_id = ? WHERE consultant_id = ?",
consultantTenant.getTenantId(),
consultantTenant.getUserId());

userServiceJdbcTemplate.update(
"UPDATE consultant SET tenant_id = ? WHERE consultant_id = ?",
consultantTenant.getTenantId(),
consultantTenant.getUserId());

userServiceJdbcTemplate.update(
"UPDATE session SET tenant_id = ? WHERE consultant_id = ?",
consultantTenant.getTenantId(),
consultantTenant.getUserId());

log.info(
SUCCESSFULLY_SET_TENANT_ID_FOR_WITH_ID_TO,
"consultant, consultant_agency, session and keycloak user",
consultantTenant.getUserId(),
consultantTenant.getTenantId());
}
}

public void updateAdminTenant(List<UserTenant> adminTargetTenants) {

if (adminTargetTenants.isEmpty()) {
log.info("No admin found with different tenantId");
return;
}
var httpHeaders = authenticateInKeycloak();
for (int i = 0; i < adminTargetTenants.size(); i++) {
if (i % USER_PAGE_SIZE == 0) {
httpHeaders = authenticateInKeycloak();
}
var adminTenant = adminTargetTenants.get(i);

log.info(
"Attempt to set tenantId for {} with id {} to {}",
"consultant",
adminTenant.getUserId(),
adminTenant.getTenantId());

keycloakUserService.updateUserCustomAttributeWithoutLogin(
TENANT_ID, adminTenant.getTenantId(), adminTenant.getUserId(), httpHeaders);

userServiceJdbcTemplate.update(
"UPDATE admin SET tenant_id = ? WHERE admin_id = ?",
adminTenant.getTenantId(),
adminTenant.getUserId());

log.info(
SUCCESSFULLY_SET_TENANT_ID_FOR_WITH_ID_TO,
"admin table and keycloak user",
adminTenant.getUserId(),
adminTenant.getTenantId());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.vi.migrationtool.tenantservice;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.vi.migrationtool.common.MigrationTasks;
import com.vi.migrationtool.config.BeanAwareSpringLiquibase;
import com.vi.migrationtool.keycloak.KeycloakLoginService;
import com.vi.migrationtool.keycloak.TenantUpdateService;
import java.util.List;
import liquibase.database.Database;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.helper.Validate;
import org.springframework.jdbc.core.JdbcTemplate;

@Slf4j
@Setter
public class MergeTenantsMigrationTask extends MigrationTasks {

String tenantMigrationConfiguration;
private KeycloakLoginService keycloakLoginService;

@Override
public void execute(Database database) {
Validate.notNull(
tenantMigrationConfiguration, "Tenant migration configuration must not be null");
var tenantServiceJdbcTemplate =
BeanAwareSpringLiquibase.getNamedBean("tenantServiceJdbcTemplate", JdbcTemplate.class);
var userServiceJdbcTemplate =
BeanAwareSpringLiquibase.getNamedBean("userServiceJdbcTemplate", JdbcTemplate.class);

var tenantUpdateService =
BeanAwareSpringLiquibase.getNamedBean("tenantUpdateService", TenantUpdateService.class);

var agencyServiceJdbcTemplate =
BeanAwareSpringLiquibase.getNamedBean("agencyServiceJdbcTemplate", JdbcTemplate.class);

this.keycloakLoginService =
BeanAwareSpringLiquibase.getNamedBean("keycloakLoginService", KeycloakLoginService.class);

var objectMapper =
new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
var migrations = readMigrations(objectMapper);

TenantMigrationService tenantMigrationService =
new TenantMigrationService(
tenantServiceJdbcTemplate,
userServiceJdbcTemplate,
agencyServiceJdbcTemplate,
tenantUpdateService);

log.info("Read migration configuration: {}", migrations);

performMigrations(migrations, tenantMigrationService);
}

private void performMigrations(
List<TenantMigrationConfiguration> migrations,
TenantMigrationService tenantMigrationService) {
migrations.stream()
.forEach(
migration -> {
log.info(
"Migrating tenants from {} to {}",
migration.getSourceTenantId(),
migration.getTargetTenantId());
tenantMigrationService.performMigration(migration);
});
}

private List<TenantMigrationConfiguration> readMigrations(ObjectMapper objectMapper) {
try {
TypeReference<List<TenantMigrationConfiguration>> typeReference =
new TypeReference<List<TenantMigrationConfiguration>>() {};
return objectMapper.readValue(tenantMigrationConfiguration, typeReference);
} catch (JsonProcessingException e) {
throw new IllegalStateException("Could not process json file ", e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.vi.migrationtool.tenantservice;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@AllArgsConstructor
@Getter
@NoArgsConstructor
@Setter
public class TenantMigrationConfiguration {

private Long sourceTenantId;
private Long targetTenantId;
private boolean deleteSourceTenant;
}
Loading

0 comments on commit 02fc476

Please sign in to comment.