Skip to content

Commit

Permalink
Merge pull request #263 from bcgov/feature/sagaClean
Browse files Browse the repository at this point in the history
Create school SAGA revisions
  • Loading branch information
arcshiftsolutions authored Oct 25, 2023
2 parents 1821e4a + 0f4bd23 commit d5150f0
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 215 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,7 @@
import ca.bc.gov.educ.api.edx.service.v1.SagaService;
import ca.bc.gov.educ.api.edx.struct.v1.*;
import ca.bc.gov.educ.api.edx.utils.RequestUtil;
import ca.bc.gov.educ.api.edx.validator.CreateSecureExchangeSagaPayloadValidator;
import ca.bc.gov.educ.api.edx.validator.EdxActivationCodeSagaDataPayloadValidator;
import ca.bc.gov.educ.api.edx.validator.EdxUserPayloadValidator;
import ca.bc.gov.educ.api.edx.validator.SecureExchangeCommentSagaValidator;
import ca.bc.gov.educ.api.edx.validator.SecureExchangePayloadValidator;
import ca.bc.gov.educ.api.edx.validator.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.AccessLevel;
import lombok.Getter;
Expand All @@ -32,7 +28,6 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;

import static ca.bc.gov.educ.api.edx.constants.SagaEnum.*;
Expand Down Expand Up @@ -121,9 +116,9 @@ public ResponseEntity<String> edxDistrictUserActivationRelink(EdxUserDistrictAct

@Override
public ResponseEntity<String> createSchool(CreateSchoolSagaData edxSchoolCreationSagaData) {
Optional<EdxUser> userOptional = edxSchoolCreationSagaData.getInitialEdxUser();
if (userOptional.isPresent()) {
validatePayload(() -> getEdxUserPayLoadValidator().validateEdxUserPayload(userOptional.get(), true));
EdxUser edxUser = edxSchoolCreationSagaData.getInitialEdxUser();
if (edxUser != null) {
validatePayload(() -> getEdxUserPayLoadValidator().validateEdxUserPayload(edxUser, true));
}
return this.processNewSchoolSaga(CREATE_NEW_SCHOOL_SAGA, edxSchoolCreationSagaData);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public interface SagaDataMapper {
@Mapping(target = "sagaCompensated", ignore = true)
@Mapping(target = "retryCount", ignore = true)
@Mapping(target = "payload", expression = "java(ca.bc.gov.educ.api.edx.utils.JsonUtil.getJsonStringFromObject(sagaData))")
@Mapping(target = "emailId", expression = "java(sagaData.getInitialEdxUser().isPresent() ? sagaData.getInitialEdxUser().get().getEmail() : \"\")")
@Mapping(target = "emailId", expression = "java(sagaData.getInitialEdxUser() != null ? sagaData.getInitialEdxUser().getEmail() : \"\")")
@Mapping(target = "edxUserId", ignore = true)
@Mapping(target = "schoolID", source = "sagaData.school.schoolId")
@Mapping(target = "districtID", source = "sagaData.school.districtId")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,44 +1,33 @@
package ca.bc.gov.educ.api.edx.orchestrator;

import static ca.bc.gov.educ.api.edx.constants.EventOutcome.INITIAL_USER_FOUND;
import static ca.bc.gov.educ.api.edx.constants.EventOutcome.INITIAL_USER_INVITED;
import static ca.bc.gov.educ.api.edx.constants.EventOutcome.NO_INITIAL_USER_FOUND;
import static ca.bc.gov.educ.api.edx.constants.EventOutcome.PRIMARY_ACTIVATION_CODE_SENT;
import static ca.bc.gov.educ.api.edx.constants.EventOutcome.SCHOOL_CREATED;
import static ca.bc.gov.educ.api.edx.constants.EventOutcome.SCHOOL_PRIMARY_CODE_CREATED;
import static ca.bc.gov.educ.api.edx.constants.EventType.CREATE_SCHOOL;
import static ca.bc.gov.educ.api.edx.constants.EventType.CREATE_SCHOOL_PRIMARY_CODE;
import static ca.bc.gov.educ.api.edx.constants.EventType.INVITE_INITIAL_USER;
import static ca.bc.gov.educ.api.edx.constants.EventType.ONBOARD_INITIAL_USER;
import static ca.bc.gov.educ.api.edx.constants.EventType.SEND_PRIMARY_ACTIVATION_CODE;
import static ca.bc.gov.educ.api.edx.constants.SagaStatusEnum.IN_PROGRESS;
import static ca.bc.gov.educ.api.edx.constants.SagaEnum.CREATE_NEW_SCHOOL_SAGA;
import static ca.bc.gov.educ.api.edx.constants.TopicsEnum.EDX_API_TOPIC;
import static ca.bc.gov.educ.api.edx.constants.TopicsEnum.INSTITUTE_API_TOPIC;
import static lombok.AccessLevel.PRIVATE;

import org.springframework.stereotype.Component;

import com.fasterxml.jackson.core.JsonProcessingException;

import ca.bc.gov.educ.api.edx.messaging.MessagePublisher;
import ca.bc.gov.educ.api.edx.messaging.jetstream.Publisher;
import ca.bc.gov.educ.api.edx.model.v1.SagaEntity;
import ca.bc.gov.educ.api.edx.model.v1.SagaEventStatesEntity;
import ca.bc.gov.educ.api.edx.orchestrator.base.BaseOrchestrator;
import ca.bc.gov.educ.api.edx.service.v1.CreateSchoolOrchestratorService;
import ca.bc.gov.educ.api.edx.service.v1.EdxSchoolUserActivationInviteOrchestratorService;
import ca.bc.gov.educ.api.edx.service.v1.EdxUsersService;
import ca.bc.gov.educ.api.edx.service.v1.SagaService;
import ca.bc.gov.educ.api.edx.struct.v1.CreateSchoolSagaData;
import ca.bc.gov.educ.api.edx.struct.v1.Event;
import ca.bc.gov.educ.api.edx.struct.v1.School;
import ca.bc.gov.educ.api.edx.utils.JsonUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import static ca.bc.gov.educ.api.edx.constants.EventOutcome.*;
import static ca.bc.gov.educ.api.edx.constants.EventType.*;
import static ca.bc.gov.educ.api.edx.constants.SagaEnum.CREATE_NEW_SCHOOL_SAGA;
import static ca.bc.gov.educ.api.edx.constants.SagaStatusEnum.IN_PROGRESS;
import static ca.bc.gov.educ.api.edx.constants.TopicsEnum.EDX_API_TOPIC;
import static ca.bc.gov.educ.api.edx.constants.TopicsEnum.INSTITUTE_API_TOPIC;
import static lombok.AccessLevel.PRIVATE;

@Component
@Slf4j
public class CreateSchoolOrchestrator extends BaseOrchestrator<CreateSchoolSagaData> {
public class CreateSchoolOrchestrator extends SchoolUserActivationBaseOrchestrator<CreateSchoolSagaData> {

@Getter(PRIVATE)
private final Publisher publisher;
Expand All @@ -48,26 +37,29 @@ public class CreateSchoolOrchestrator extends BaseOrchestrator<CreateSchoolSagaD

@Getter(PRIVATE)
private final CreateSchoolOrchestratorService orchestratorService;
@Getter(PRIVATE)
private final EdxSchoolUserActivationInviteOrchestratorService edxSchoolUserActivationInviteOrchestratorService;


protected CreateSchoolOrchestrator(SagaService sagaService, MessagePublisher messagePublisher, CreateSchoolOrchestratorService orchestratorService, Publisher publisher, EdxUsersService edxUsersService) {
super(sagaService, messagePublisher, CreateSchoolSagaData.class, CREATE_NEW_SCHOOL_SAGA.toString(), EDX_API_TOPIC.toString());
protected CreateSchoolOrchestrator(SagaService sagaService, MessagePublisher messagePublisher, CreateSchoolOrchestratorService orchestratorService, Publisher publisher, EdxUsersService edxUsersService, EdxSchoolUserActivationInviteOrchestratorService edxSchoolUserActivationInviteOrchestratorService) {
super(sagaService, messagePublisher, CreateSchoolSagaData.class, CREATE_NEW_SCHOOL_SAGA.toString(), EDX_API_TOPIC.toString(), edxSchoolUserActivationInviteOrchestratorService);
this.publisher = publisher;
this.edxUsersService = edxUsersService;
this.orchestratorService = orchestratorService;
this.edxSchoolUserActivationInviteOrchestratorService = edxSchoolUserActivationInviteOrchestratorService;
}

@Override
public void populateStepsToExecuteMap() {
this.stepBuilder()
.begin(CREATE_SCHOOL, this::createSchool)
.step(CREATE_SCHOOL, SCHOOL_CREATED, ONBOARD_INITIAL_USER, this::checkForInitialUser)
.step(CREATE_SCHOOL, SCHOOL_CREATED, ONBOARD_INITIAL_USER, this::storeInitialUserIfFound)
.step(ONBOARD_INITIAL_USER, INITIAL_USER_FOUND, CREATE_SCHOOL_PRIMARY_CODE, this::createPrimaryCode)
.end(ONBOARD_INITIAL_USER, NO_INITIAL_USER_FOUND, this::completeCreateSchoolSagaWithNoUser)
.or()
.step(CREATE_SCHOOL_PRIMARY_CODE, SCHOOL_PRIMARY_CODE_CREATED, SEND_PRIMARY_ACTIVATION_CODE, this::sendPrimaryCode)
.step(SEND_PRIMARY_ACTIVATION_CODE, PRIMARY_ACTIVATION_CODE_SENT, INVITE_INITIAL_USER, this::inviteInitialUser)
.end(INVITE_INITIAL_USER, INITIAL_USER_INVITED);
.step(SEND_PRIMARY_ACTIVATION_CODE, PRIMARY_ACTIVATION_CODE_SENT, CREATE_PERSONAL_ACTIVATION_CODE, this::createPersonalActivationCode)
.step(CREATE_PERSONAL_ACTIVATION_CODE, PERSONAL_ACTIVATION_CODE_CREATED, SEND_EDX_SCHOOL_USER_ACTIVATION_EMAIL, this::sendEdxUserActivationEmail)
.end(SEND_EDX_SCHOOL_USER_ACTIVATION_EMAIL, EDX_SCHOOL_USER_ACTIVATION_EMAIL_SENT);
}

public void createSchool(Event event, SagaEntity saga, CreateSchoolSagaData sagaData) throws JsonProcessingException {
Expand All @@ -89,7 +81,7 @@ public void createSchool(Event event, SagaEntity saga, CreateSchoolSagaData saga
log.info("message sent to INSTITUTE_API_TOPIC for CREATE_SCHOOL Event. :: {}", saga.getSagaId());
}

public void checkForInitialUser(Event event, SagaEntity saga, CreateSchoolSagaData sagaData) throws JsonProcessingException {
public void storeInitialUserIfFound(Event event, SagaEntity saga, CreateSchoolSagaData sagaData) throws JsonProcessingException {
final SagaEventStatesEntity eventStates = this.createEventState(saga, event.getEventType(), event.getEventOutcome(), event.getEventPayload());
saga.setSagaState(ONBOARD_INITIAL_USER.toString());
this.getSagaService().updateAttachedSagaWithEvents(saga, eventStates);
Expand All @@ -100,9 +92,9 @@ public void checkForInitialUser(Event event, SagaEntity saga, CreateSchoolSagaDa
.eventPayload(JsonUtil.getJsonStringFromObject(sagaData))
.sagaId(saga.getSagaId());

if (sagaData.getInitialEdxUser().isPresent()) {
if (sagaData.getInitialEdxUser() != null) {
School createdSchoolFromInstitute = JsonUtil.getJsonObjectFromString(School.class, event.getEventPayload());
this.orchestratorService.attachInstituteSchoolToSaga(createdSchoolFromInstitute.getSchoolId(), saga);
this.orchestratorService.attachSchoolAndUserInviteToSaga(createdSchoolFromInstitute.getSchoolId(), sagaData, saga);
nextEventBuilder.eventOutcome(INITIAL_USER_FOUND);
} else {
nextEventBuilder.eventOutcome(NO_INITIAL_USER_FOUND);
Expand Down Expand Up @@ -145,21 +137,6 @@ public void sendPrimaryCode(Event event, SagaEntity saga, CreateSchoolSagaData s
log.info("message sent to EDX_API_TOPIC for SEND_PRIMARY_ACTIVATION_CODE Event. :: {}", saga.getSagaId());
}

private void inviteInitialUser(Event event, SagaEntity saga, CreateSchoolSagaData sagaData) throws JsonProcessingException {
final SagaEventStatesEntity eventStates = this.createEventState(saga, event.getEventType(), event.getEventOutcome(), event.getEventPayload());
saga.setSagaState(INVITE_INITIAL_USER.toString());
this.getSagaService().updateAttachedSagaWithEvents(saga, eventStates);

this.orchestratorService.startEdxSchoolUserInviteSaga(sagaData);

final Event nextEvent = Event.builder().sagaId(saga.getSagaId())
.eventType(INVITE_INITIAL_USER).eventOutcome(INITIAL_USER_INVITED)
.eventPayload(JsonUtil.getJsonStringFromObject(sagaData))
.build();
this.postMessageToTopic(this.getTopicToSubscribe(), nextEvent);
log.info("message sent to EDX_API_TOPIC for INVITE_INITIAL_USER Event. :: {}", saga.getSagaId());
}

private void completeCreateSchoolSagaWithNoUser(final Event event, final SagaEntity saga, final CreateSchoolSagaData sagaData) {
log.info("CREATE_NEW_SCHOOL_SAGA has ended with NO_INITIAL_USER_FOUND :: {}", saga.getSagaId());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import ca.bc.gov.educ.api.edx.orchestrator.base.BaseOrchestrator;
import ca.bc.gov.educ.api.edx.service.v1.EdxSchoolUserActivationInviteOrchestratorService;
import ca.bc.gov.educ.api.edx.service.v1.SagaService;
import ca.bc.gov.educ.api.edx.struct.v1.CreateSchoolSagaData;
import ca.bc.gov.educ.api.edx.struct.v1.EdxUserSchoolActivationInviteSagaData;
import ca.bc.gov.educ.api.edx.struct.v1.Event;
import ca.bc.gov.educ.api.edx.utils.JsonUtil;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,49 +1,33 @@
package ca.bc.gov.educ.api.edx.service.v1;

import static ca.bc.gov.educ.api.edx.constants.InstituteTypeCode.SCHOOL;
import static ca.bc.gov.educ.api.edx.constants.SagaEnum.EDX_SCHOOL_USER_ACTIVATION_INVITE_SAGA;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.fasterxml.jackson.core.JsonProcessingException;

import ca.bc.gov.educ.api.edx.constants.SagaStatusEnum;
import ca.bc.gov.educ.api.edx.exception.SagaRuntimeException;
import ca.bc.gov.educ.api.edx.mappers.v1.SagaDataMapper;
import ca.bc.gov.educ.api.edx.model.v1.EdxActivationCodeEntity;
import ca.bc.gov.educ.api.edx.model.v1.SagaEntity;
import ca.bc.gov.educ.api.edx.orchestrator.EdxSchoolUserActivationInviteOrchestrator;
import ca.bc.gov.educ.api.edx.props.EmailProperties;
import ca.bc.gov.educ.api.edx.repository.EdxActivationCodeRepository;
import ca.bc.gov.educ.api.edx.rest.RestUtils;
import ca.bc.gov.educ.api.edx.struct.v1.CreateSchoolSagaData;
import ca.bc.gov.educ.api.edx.struct.v1.EdxPrimaryActivationCode;
import ca.bc.gov.educ.api.edx.struct.v1.EdxUser;
import ca.bc.gov.educ.api.edx.struct.v1.EdxUserSchoolActivationInviteSagaData;
import ca.bc.gov.educ.api.edx.struct.v1.EmailNotification;
import ca.bc.gov.educ.api.edx.struct.v1.School;
import ca.bc.gov.educ.api.edx.struct.v1.*;
import ca.bc.gov.educ.api.edx.utils.JsonUtil;
import ca.bc.gov.educ.api.edx.utils.RequestUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import jakarta.persistence.EntityNotFoundException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;

import static ca.bc.gov.educ.api.edx.constants.InstituteTypeCode.SCHOOL;

@Service
@Slf4j
public class CreateSchoolOrchestratorService {

private static final SagaDataMapper SAGA_DATA_MAPPER = SagaDataMapper.mapper;

protected final SagaService sagaService;

private final EdxSchoolUserActivationInviteOrchestrator activationInviteOrchestrator;

private final EdxActivationCodeRepository edxActivationCodeRepository;

private final EdxUsersService service;
Expand All @@ -58,20 +42,18 @@ public CreateSchoolOrchestratorService(
EdxUsersService service,
EmailProperties emailProperties,
EmailNotificationService emailNotificationService,
EdxSchoolUserActivationInviteOrchestrator activationInviteOrchestrator,
RestUtils restUtils
) {
this.sagaService = sagaService;
this.edxActivationCodeRepository = edxActivationCodeRepository;
this.service = service;
this.emailProperties = emailProperties;
this.emailNotificationService = emailNotificationService;
this.activationInviteOrchestrator = activationInviteOrchestrator;
this.restUtils = restUtils;
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void attachInstituteSchoolToSaga(String schoolId, SagaEntity saga)
public void attachSchoolAndUserInviteToSaga(String schoolId, CreateSchoolSagaData createSchoolSagaData, SagaEntity saga)
throws JsonProcessingException {
List<School> result = this.restUtils.getSchoolById(saga.getSagaId(), schoolId);

Expand All @@ -82,9 +64,17 @@ public void attachInstituteSchoolToSaga(String schoolId, SagaEntity saga)

School school = result.get(0);
saga.setSchoolID(UUID.fromString(school.getSchoolId()));
CreateSchoolSagaData payload = JsonUtil.getJsonObjectFromString(CreateSchoolSagaData.class, saga.getPayload());
payload.setSchool(school);
saga.setPayload(JsonUtil.getJsonStringFromObject(payload));
createSchoolSagaData.setSchool(school);
EdxUser user = createSchoolSagaData.getInitialEdxUser();
List<String> roles = List.of("EDX_SCHOOL_ADMIN");
createSchoolSagaData.setSchoolID(UUID.fromString(school.getSchoolId()));
createSchoolSagaData.setSchoolName(school.getDisplayName());
createSchoolSagaData.setFirstName(user.getFirstName());
createSchoolSagaData.setLastName(user.getLastName());
createSchoolSagaData.setEmail(user.getEmail());
createSchoolSagaData.setEdxActivationRoleCodes(roles);

saga.setPayload(JsonUtil.getJsonStringFromObject(createSchoolSagaData));
this.sagaService.updateAttachedEntityDuringSagaProcess(saga);
}

Expand All @@ -100,7 +90,7 @@ public void createPrimaryActivationCode(CreateSchoolSagaData sagaData) {

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void sendPrimaryActivationCodeNotification(CreateSchoolSagaData sagaData) {
EdxUser user = sagaData.getInitialEdxUser().orElseThrow();
EdxUser user = sagaData.getInitialEdxUser();
School school = sagaData.getSchool();
UUID schoolId = UUID.fromString(school.getSchoolId());

Expand All @@ -124,43 +114,4 @@ public void sendPrimaryActivationCodeNotification(CreateSchoolSagaData sagaData)
this.emailNotificationService.sendEmail(emailNotification);
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void startEdxSchoolUserInviteSaga(CreateSchoolSagaData sagaData) {
EdxUserSchoolActivationInviteSagaData inviteSagaData = new EdxUserSchoolActivationInviteSagaData();
EdxUser user = sagaData.getInitialEdxUser().orElseThrow();
School school = sagaData.getSchool();
List<String> roles = List.of("EDX_SCHOOL_ADMIN");
List<String> statusFilters = List.of(SagaStatusEnum.IN_PROGRESS.toString(), SagaStatusEnum.STARTED.toString());
String sagaName = EDX_SCHOOL_USER_ACTIVATION_INVITE_SAGA.toString();

inviteSagaData.setSchoolID(UUID.fromString(school.getSchoolId()));
inviteSagaData.setSchoolName(school.getDisplayName());
inviteSagaData.setFirstName(user.getFirstName());
inviteSagaData.setLastName(user.getLastName());
inviteSagaData.setEmail(user.getEmail());
inviteSagaData.setEdxActivationRoleCodes(roles);
RequestUtil.setAuditColumnsForCreate(inviteSagaData);

final Optional<SagaEntity> sagaInProgress = sagaService.
findAllActiveUserActivationInviteSagasBySchoolIDAndEmailId(
inviteSagaData.getSchoolID(),
inviteSagaData.getEmail(),
sagaName,
statusFilters);

if (sagaInProgress.isEmpty()) {
try {
SagaEntity sagaEntity = SAGA_DATA_MAPPER.toModel(String.valueOf(sagaName), inviteSagaData);
final SagaEntity saga = this.activationInviteOrchestrator.createSaga(sagaEntity);
this.activationInviteOrchestrator.startSaga(saga);
} catch (JsonProcessingException e) {
throw new SagaRuntimeException(e);
}
}
}

public EdxActivationCodeEntity findPrimaryCode(String schoolId) {
return this.service.findPrimaryEdxActivationCode(SCHOOL, schoolId);
}

}
Loading

0 comments on commit d5150f0

Please sign in to comment.