Skip to content

Commit

Permalink
[MODCON-38] - Process USER_UPDATED event to update username if changed
Browse files Browse the repository at this point in the history
  • Loading branch information
Dzmitry_Butramyou committed Jul 11, 2023
1 parent acb05c9 commit d92b8ef
Show file tree
Hide file tree
Showing 17 changed files with 163 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.util.stream.Stream;

import static org.folio.consortia.messaging.listener.ConsortiaUserEventListener.USER_CREATED_LISTENER_ID;
import static org.folio.consortia.messaging.listener.ConsortiaUserEventListener.USER_UPDATED_LISTENER_ID;
import static org.folio.consortia.messaging.listener.ConsortiaUserEventListener.USER_DELETED_LISTENER_ID;

@Component
Expand All @@ -47,8 +48,10 @@ public class KafkaService {
@Getter
public enum Topic {
USER_CREATED("USER_CREATED"),
USER_UPDATED("USER_UPDATED"),
USER_DELETED("USER_DELETED"),
CONSORTIUM_PRIMARY_AFFILIATION_CREATED("Default", "CONSORTIUM_PRIMARY_AFFILIATION_CREATED"),
CONSORTIUM_PRIMARY_AFFILIATION_UPDATED("Default", "CONSORTIUM_PRIMARY_AFFILIATION_UPDATED"),
CONSORTIUM_PRIMARY_AFFILIATION_DELETED("Default", "CONSORTIUM_PRIMARY_AFFILIATION_DELETED");
private String nameSpace;
private final String topicName;
Expand Down Expand Up @@ -78,6 +81,7 @@ public void createKafkaTopics() {
*/
public void restartEventListeners() {
restartEventListener(USER_CREATED_LISTENER_ID);
restartEventListener(USER_UPDATED_LISTENER_ID);
restartEventListener(USER_DELETED_LISTENER_ID);
}

Expand All @@ -98,6 +102,7 @@ private List<NewTopic> tenantSpecificTopics(String tenant) {
eventsNameStreamBuilder.add(consEventType);
}
eventsNameStreamBuilder.add(ConsortiaOutputEventType.CONSORTIUM_PRIMARY_AFFILIATION_CREATED);
eventsNameStreamBuilder.add(ConsortiaOutputEventType.CONSORTIUM_PRIMARY_AFFILIATION_UPDATED);
eventsNameStreamBuilder.add(ConsortiaOutputEventType.CONSORTIUM_PRIMARY_AFFILIATION_DELETED);
return eventsNameStreamBuilder.build()
.map(Enum::name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class UserTenantEntity extends AuditableEntity {
private TenantEntity tenant;

private Boolean isPrimary;
private String centralTenantId;

@Override
public boolean equals(Object o) {
Expand All @@ -45,11 +46,12 @@ public boolean equals(Object o) {
&& Objects.equals(userId, that.userId)
&& Objects.equals(username, that.username)
&& Objects.equals(tenant, that.tenant)
&& Objects.equals(isPrimary, that.isPrimary);
&& Objects.equals(isPrimary, that.isPrimary)
&& Objects.equals(centralTenantId, that.centralTenantId);
}

@Override
public int hashCode() {
return Objects.hash(id, userId, username, tenant, isPrimary);
return Objects.hash(id, userId, username, tenant, isPrimary, centralTenantId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@

public enum ConsortiaInputEventType {
USER_CREATED,
USER_UPDATED,
USER_DELETED
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@

public enum ConsortiaOutputEventType {
CONSORTIUM_PRIMARY_AFFILIATION_CREATED,
CONSORTIUM_PRIMARY_AFFILIATION_UPDATED,
CONSORTIUM_PRIMARY_AFFILIATION_DELETED
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
public class ConsortiaUserEventListener {

public static final String USER_CREATED_LISTENER_ID = "user-created-listener-id";
public static final String USER_UPDATED_LISTENER_ID = "user-updated-listener-id";
public static final String USER_DELETED_LISTENER_ID = "user-deleted-listener-id";
private final UserAffiliationService userAffiliationService;
private final ConsortiaConfigurationService configurationService;
Expand All @@ -43,6 +44,20 @@ public void handleUserCreating(String data, MessageHeaders messageHeaders) {
}
}

@KafkaListener(
id = USER_UPDATED_LISTENER_ID,
topicPattern = "#{folioKafkaProperties.listener['user-updated'].topicPattern}",
concurrency = "#{folioKafkaProperties.listener['user-updated'].concurrency}",
containerFactory = "kafkaListenerContainerFactory")
public void handleUserUpdating(String data, MessageHeaders messageHeaders) {
// to update affiliation in central tenant schema
String centralTenantId = getCentralTenantByIdByHeader(messageHeaders);
if (StringUtils.isNotBlank(centralTenantId)) {
runInFolioContext(createFolioExecutionContext(messageHeaders, folioMetadata, centralTenantId), () ->
userAffiliationService.updatePrimaryUserAffiliation(data));
}
}

@KafkaListener(
id = USER_DELETED_LISTENER_ID,
topicPattern = "#{folioKafkaProperties.listener['user-deleted'].topicPattern}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ public interface UserTenantRepository extends JpaRepository<UserTenantEntity, UU
@Query("DELETE FROM UserTenantEntity ut WHERE ut.userId= ?1 AND ut.isPrimary= true")
void deleteByUserIdAndIsPrimaryTrue(UUID userId);

@Modifying
@Query("UPDATE UserTenantEntity ut SET ut.username= ?1 WHERE ut.userId= ?2")
void setUsernameByUserId(String username, UUID userId);

@Query("SELECT ut FROM UserTenantEntity ut WHERE ut.userId NOT IN (SELECT ut.userId FROM UserTenantEntity ut WHERE ut.userId= ?1 AND ut.isPrimary=true) AND ut.userId= ?1")
List<UserTenantEntity> getByUserIdAndIsPrimaryFalse(UUID userId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ public interface UserAffiliationService {
*/
void createPrimaryUserAffiliation(String userEvent);

/**
* Update primary affiliation for user
* @param userEvent - user event object from kafka
*/
void updatePrimaryUserAffiliation(String userEvent);

/**
* Delete primary affiliation for user
* @param userEvent - user event object from kafka
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ public interface UserTenantService {
*/
UserTenant createPrimaryUserTenantAffiliation(UUID consortiumId, TenantEntity consortiaTenant, String userId, String username);

/**
* Update username fields of user_tenant based on kafka userEventDto.
*
* @param userId id of existing user
* @param username the new name of existing user
*/
void updateUsernameInPrimaryUserTenantAffiliation(UUID userId, String username);

/**
* Deletes user_tenant by userId and tenantId.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public Tenant save(UUID consortiumId, UUID adminUserId, Tenant tenantDto) {
try (var context = new FolioExecutionContextSetter(contextHelper.getSystemUserFolioExecutionContext(tenantDto.getId()))) {
configurationClient.saveConfiguration(createConsortiaConfigurationBody(centralTenantId));
if (!tenantDto.getIsCentral()) {
createUserTenantWithDummyUser(tenantDto.getId());
createUserTenantWithDummyUser(tenantDto.getId(), centralTenantId);
createShadowAdminUserWithPermissions(shadowAdminUser); //NOSONAR
}
syncPrimaryAffiliationClient.syncPrimaryAffiliations(consortiumId.toString(), tenantDto.getId(), centralTenantId);
Expand Down Expand Up @@ -160,13 +160,15 @@ private Tenant saveTenant(UUID consortiumId, Tenant tenantDto) {
this tenant and will allow cross-tenant request.
@param tenantId tenant id
@param centralTenantId central tenant id
*/
private UserTenant createUserTenantWithDummyUser(String tenantId) {
private UserTenant createUserTenantWithDummyUser(String tenantId, String centralTenantId) {
UserTenant userTenant = new UserTenant();
userTenant.setId(UUID.randomUUID());
userTenant.setTenantId(tenantId);
userTenant.setUserId(UUID.randomUUID());
userTenant.setUsername(DUMMY_USERNAME);
userTenant.setCentralTenantId(centralTenantId);

log.info("Creating userTenant with dummy user with id {}.", userTenant.getId());
userTenantsClient.postUserTenant(userTenant);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.folio.consortia.domain.dto.PrimaryAffiliationEvent;
import org.folio.consortia.domain.dto.UserEvent;
import org.folio.consortia.domain.dto.UserTenant;
import org.folio.consortia.domain.dto.UserTenantCollection;
import org.folio.consortia.service.TenantService;
import org.folio.consortia.service.UserAffiliationService;
import org.folio.consortia.service.UserTenantService;
Expand Down Expand Up @@ -78,6 +79,44 @@ public void createPrimaryUserAffiliation(String eventPayload) {
}
}

@Override
@SneakyThrows
@Transactional
public void updatePrimaryUserAffiliation(String eventPayload) {
FolioExecutionContext currentContext = (FolioExecutionContext) folioExecutionContext.getInstance();
String centralTenantId = folioExecutionContext.getTenantId();
try {
var userEvent = objectMapper.readValue(eventPayload, UserEvent.class);
log.info("Received event for update primary affiliation for user: {} and tenant: {}", userEvent.getUserDto().getId(), userEvent.getTenantId());

var consortiaTenant = tenantService.getByTenantId(userEvent.getTenantId());
if (consortiaTenant == null) {
log.warn("Tenant {} not exists in consortia", userEvent.getTenantId());
return;
}
UUID userId = getUserId(userEvent);
String newUsername = userEvent.getUserDto().getUsername();

UserTenantCollection userTenantCollection = userTenantService.getByUserId(consortiaTenant.getConsortiumId(), userId, 0, Integer.MAX_VALUE);
boolean isUsernameChanged = userTenantCollection.getUserTenants().stream()
.anyMatch(userTenant -> ObjectUtils.notEqual(userTenant.getUsername(), newUsername));

if (isUsernameChanged) {
userTenantService.updateUsernameInPrimaryUserTenantAffiliation(userId, newUsername);
log.info("Username in primary affiliation has been updated for the user: {}", userEvent.getUserDto().getId());
}

PrimaryAffiliationEvent affiliationEvent = createPrimaryAffiliationEvent(userEvent);
String data = objectMapper.writeValueAsString(affiliationEvent);

try (var context = new FolioExecutionContextSetter(prepareContextForTenant(centralTenantId, folioModuleMetadata, currentContext))) {
kafkaService.send(KafkaService.Topic.CONSORTIUM_PRIMARY_AFFILIATION_UPDATED, consortiaTenant.getConsortiumId().toString(), data);
}
} catch (Exception e) {
log.error("Exception occurred while updating primary affiliation", e);
}
}

@Override
@SneakyThrows
@Transactional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ public UserTenant createPrimaryUserTenantAffiliation(UUID consortiumId, TenantEn
return userTenant;
}

@Override
public void updateUsernameInPrimaryUserTenantAffiliation(UUID userId, String username) {
userTenantRepository.setUsernameByUserId(username, userId);
}

@Override
@Transactional
public void deleteByUserIdAndTenantId(UUID consortiumId, String tenantId, UUID userId) {
Expand Down
4 changes: 4 additions & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ folio:
concurrency: ${KAFKA_EVENTS_CONCURRENCY:5}
topic-pattern: ${KAFKA_EVENTS_CONSUMER_PATTERN:(${folio.environment}\.)[a-zA-z0-9-]+\.\w+\.USER_DELETED}
group-id: ${folio.environment}-mod-consortia-group
user-updated:
concurrency: ${KAFKA_EVENTS_CONCURRENCY:5}
topic-pattern: ${KAFKA_EVENTS_CONSUMER_PATTERN:(${folio.environment}\.)[a-zA-z0-9-]+\.\w+\.USER_UPDATED}
group-id: ${folio.environment}-mod-consortia-group
tenant:
validation:
enabled: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,10 @@
<column name="updated_date" type="timestamp without time zone"/>
</addColumn>
</changeSet>

<changeSet id="MODCON-38@@add-central-tenant-id-field" author="d.butramyou">
<addColumn tableName="user_tenant">
<column name="central_tenant_id" type="text"/>
</addColumn>
</changeSet>
</databaseChangeLog>
2 changes: 2 additions & 0 deletions src/main/resources/swagger.api/schemas/userTenant.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ UserTenant:
type: string
isPrimary:
type: boolean
centralTenantId:
type: string
additionalProperties: false
required:
- userId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import static org.folio.spring.integration.XOkapiHeaders.TOKEN;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.times;
Expand All @@ -19,6 +20,8 @@
import java.util.UUID;

import org.folio.consortia.config.kafka.KafkaService;
import org.folio.consortia.domain.dto.UserTenant;
import org.folio.consortia.domain.dto.UserTenantCollection;
import org.folio.consortia.repository.TenantRepository;
import org.folio.consortia.service.impl.UserAffiliationServiceImpl;
import org.folio.spring.DefaultFolioExecutionContext;
Expand All @@ -36,6 +39,7 @@

class UserAffiliationServiceTest {
private static final String userCreatedEventSample = getMockDataAsString("mockdata/kafka/create_primary_affiliation_request.json");
private static final String userUpdatedEventSample = getMockDataAsString("mockdata/kafka/update_primary_affiliation_request.json");
private static final String userDeletedEventSample = getMockDataAsString("mockdata/kafka/delete_primary_affiliation_request.json");
@Mock
private FolioModuleMetadata folioModuleMetadata;
Expand Down Expand Up @@ -132,6 +136,34 @@ void primaryAffiliationAlreadyExists() {
verify(kafkaService, times(0)).send(any(), anyString(), any());
}

@Test
void primaryAffiliationSuccessfullyUpdatedTest() {
UserTenant userTenant = new UserTenant();
userTenant.setUserId(UUID.randomUUID());
userTenant.setUsername("TestUser");
UserTenantCollection userTenantCollection = new UserTenantCollection();
userTenantCollection.setUserTenants(List.of(userTenant));
userTenantCollection.setTotalRecords(1);

var te = createTenantEntity();

when(tenantService.getByTenantId(anyString())).thenReturn(te);
doNothing().when(consortiumService).checkConsortiumExistsOrThrow(any());
when(folioExecutionContext.getInstance()).thenReturn(folioExecutionContext);
when(folioExecutionContext.getTenantId()).thenReturn("diku");
Map<String, Collection<String>> map = createOkapiHeaders();
when(folioExecutionContext.getOkapiHeaders()).thenReturn(map);

when(userTenantService.getByUserId(any(), any(), eq(0), eq(Integer.MAX_VALUE))).thenReturn(userTenantCollection);

folioExecutionContext = new DefaultFolioExecutionContext(folioModuleMetadata, map);
try (var fec = new FolioExecutionContextSetter(folioExecutionContext)) {
userAffiliationService.updatePrimaryUserAffiliation(userUpdatedEventSample);
}

verify(kafkaService, times(1)).send(any(), anyString(), any());
}

@Test
void primaryAffiliationSuccessfullyDeletedTest() {
var te = createTenantEntity();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,16 @@ void shouldSavePrimaryAffiliation() {
assertNull(result);
}

@Test
void shouldUpdateUsernameInPrimaryAffiliation() {
var userEvent = createUserEvent();
doNothing().when(userTenantRepository).setUsernameByUserId(anyString(), any());

userTenantService.updateUsernameInPrimaryUserTenantAffiliation(UUID.fromString(userEvent.getUserDto().getId()), "newUsername");

verify(userTenantRepository, times(1)).setUsernameByUserId(anyString(), any());
}

@Test
void shouldDeletePrimaryAffiliation() {
var userEvent = createUserEvent();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"id": "03670ef4-3fcc-41d9-98a2-4375b2420f65",
"action": "Edit",
"tenantId": "diku",
"performedBy": "d900646f-4cfe-54fa-b6ac-fd646620eb28",
"eventDate": 1681984177363,
"actionDate": 1681984177324,
"userDto": {
"username": "newTestUser",
"id": "148f7c24-54fc-4d7f-afff-da2dfcd902e3",
"active": true,
"departments": [],
"proxyFor": [],
"createdDate": 1681984177336,
"updatedDate": 1681984177336
}
}

0 comments on commit d92b8ef

Please sign in to comment.