diff --git a/api/src/main/java/ca/bc/gov/educ/api/edx/controller/v1/EdxSagaController.java b/api/src/main/java/ca/bc/gov/educ/api/edx/controller/v1/EdxSagaController.java index a12c2737..cb1db163 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/edx/controller/v1/EdxSagaController.java +++ b/api/src/main/java/ca/bc/gov/educ/api/edx/controller/v1/EdxSagaController.java @@ -73,7 +73,7 @@ public EdxSagaController(EdxActivationCodeSagaDataPayloadValidator edxActivation @Override public ResponseEntity edxSchoolUserActivationInvite(EdxUserSchoolActivationInviteSagaData edxUserActivationInviteSagaData) { - validatePayload(() -> getEdxActivationCodeSagaDataPayLoadValidator().validateEdxActivationCodeSagaDataPayload(edxUserActivationInviteSagaData)); + validatePayload(() -> getEdxActivationCodeSagaDataPayLoadValidator().validateEdxSchoolUserActivationCodeSagaDataPayload(edxUserActivationInviteSagaData)); RequestUtil.setAuditColumnsForCreate(edxUserActivationInviteSagaData); return this.processEdxSchoolUserActivationLinkSaga(EDX_SCHOOL_USER_ACTIVATION_INVITE_SAGA, edxUserActivationInviteSagaData); } diff --git a/api/src/main/java/ca/bc/gov/educ/api/edx/struct/v1/EdxUserSchoolActivationInviteSagaData.java b/api/src/main/java/ca/bc/gov/educ/api/edx/struct/v1/EdxUserSchoolActivationInviteSagaData.java index 818463da..35b8ff38 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/edx/struct/v1/EdxUserSchoolActivationInviteSagaData.java +++ b/api/src/main/java/ca/bc/gov/educ/api/edx/struct/v1/EdxUserSchoolActivationInviteSagaData.java @@ -7,10 +7,12 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.Null; +import jakarta.validation.constraints.Size; import lombok.Data; import lombok.EqualsAndHashCode; -import jakarta.validation.constraints.*; import java.io.Serializable; import java.time.LocalDateTime; import java.util.List; @@ -21,25 +23,19 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class EdxUserSchoolActivationInviteSagaData extends BaseRequest implements Serializable { private static final long serialVersionUID = -7847063658732692951L; - @NotNull(message = "schoolID cannot be null") UUID schoolID; - @NotNull(message = "School Name cannot be null") String schoolName; - - @NotEmpty(message = "Activation Roles cannot be null or empty") + private List edxActivationRoleCodes; @Size(max = 255) - @NotNull(message = "First Name cannot be null") String firstName; @Size(max = 255) - @NotNull(message = "Last Name cannot be null") String lastName; @Size(max = 255) - @NotNull(message = "Email cannot be null") @Email(message = "Email address should be a valid email address") String email; diff --git a/api/src/main/java/ca/bc/gov/educ/api/edx/validator/EdxActivationCodeSagaDataPayloadValidator.java b/api/src/main/java/ca/bc/gov/educ/api/edx/validator/EdxActivationCodeSagaDataPayloadValidator.java index c211b5f2..117952c9 100644 --- a/api/src/main/java/ca/bc/gov/educ/api/edx/validator/EdxActivationCodeSagaDataPayloadValidator.java +++ b/api/src/main/java/ca/bc/gov/educ/api/edx/validator/EdxActivationCodeSagaDataPayloadValidator.java @@ -22,25 +22,68 @@ public class EdxActivationCodeSagaDataPayloadValidator { private static final String EDX_ACTIVATION_ROLE_CODE = "edxActivationRoleCode"; private final ApplicationProperties props; + public static final String DISTRICT_ID = "districtID"; + public static final String DISTRICT_NAME = "districtName"; + + public static final String SCHOOL_ID = "schoolID"; + public static final String SCHOOL_NAME = "schoolName"; + public static final String FIRST_NAME = "firstName"; + public static final String LAST_NAME = "lastName"; + public static final String EMAIL = "email"; + public EdxActivationCodeSagaDataPayloadValidator(EdxRoleRepository edxRoleRepository, ApplicationProperties props) { this.edxRoleRepository = edxRoleRepository; this.props = props; } - public List validateEdxActivationCodeSagaDataPayload(EdxUserSchoolActivationInviteSagaData edxUserActivationInviteSagaData) { - return new ArrayList<>(validateEdxActivationCodes(edxUserActivationInviteSagaData.getEdxActivationRoleCodes())); + public List validateEdxSchoolUserActivationCodeSagaDataPayload(EdxUserSchoolActivationInviteSagaData edxUserActivationInviteSagaData) { + final List apiValidationErrors = new ArrayList<>(); + apiValidationErrors.addAll(validatePayload(edxUserActivationInviteSagaData)); + apiValidationErrors.addAll(validateEdxActivationCodes(edxUserActivationInviteSagaData.getEdxActivationRoleCodes())); + return apiValidationErrors; } public List validateDistrictUserEdxActivationCodeSagaDataPayload(EdxUserDistrictActivationInviteSagaData edxDistrictUserActivationInviteSagaData) { return new ArrayList<>(validateEdxActivationCodes(edxDistrictUserActivationInviteSagaData.getEdxActivationRoleCodes())); } + public List validatePayload(EdxUserSchoolActivationInviteSagaData edxUserSchoolActivationInviteSagaData) { + final List apiValidationErrors = new ArrayList<>(); + + if(edxUserSchoolActivationInviteSagaData.getSchoolID() == null) { + apiValidationErrors.add(createFieldError(SCHOOL_ID, edxUserSchoolActivationInviteSagaData.getSchoolID(), "School ID cannot be null")); + } + + if(edxUserSchoolActivationInviteSagaData.getSchoolName() == null) { + apiValidationErrors.add(createFieldError(SCHOOL_NAME, edxUserSchoolActivationInviteSagaData.getSchoolName(), "School Name cannot be null")); + } + + if(edxUserSchoolActivationInviteSagaData.getFirstName() == null) { + apiValidationErrors.add(createFieldError(FIRST_NAME, edxUserSchoolActivationInviteSagaData.getFirstName(), "First Name cannot be null")); + } + + if(edxUserSchoolActivationInviteSagaData.getLastName() == null) { + apiValidationErrors.add(createFieldError(LAST_NAME, edxUserSchoolActivationInviteSagaData.getLastName(), "Last Name cannot be null")); + } + + if(edxUserSchoolActivationInviteSagaData.getEmail() == null) { + apiValidationErrors.add(createFieldError(EMAIL, edxUserSchoolActivationInviteSagaData.getEmail(), "Email cannot be null")); + } + + return apiValidationErrors; + } + + private List validateEdxActivationCodes(List roles) { final List apiValidationErrors = new ArrayList<>(); - for(var role: roles) { - if (!props.getAllowRolesList().contains(role)) { - apiValidationErrors.add(createFieldError(EDX_ACTIVATION_ROLE_CODE, role, "edxActivationRoleCode is not valid according to the allow list.")); - break; + if(roles.isEmpty()){ + apiValidationErrors.add(createFieldError(EDX_ACTIVATION_ROLE_CODE, null, "Roles list cannot be empty.")); + }else { + for (var role : roles) { + if (!props.getAllowRolesList().contains(role)) { + apiValidationErrors.add(createFieldError(EDX_ACTIVATION_ROLE_CODE, role, "edxActivationRoleCode is not valid according to the allow list.")); + break; + } } } return apiValidationErrors; @@ -51,7 +94,7 @@ public List validateEdxActivationCodeRelinkSchoolSagaDataPayload(Edx if(StringUtils.isBlank(edxUserActivationRelinkSagaData.getEdxUserId())){ apiValidationErrors.add(createFieldError("edxUserID", edxUserActivationRelinkSagaData.getEdxUserId(), "EDX User ID must be provided for re-link")); } - apiValidationErrors.addAll(validateEdxActivationCodeSagaDataPayload(edxUserActivationRelinkSagaData)); + apiValidationErrors.addAll(validateEdxSchoolUserActivationCodeSagaDataPayload(edxUserActivationRelinkSagaData)); return apiValidationErrors; } diff --git a/api/src/test/java/ca/bc/gov/educ/api/edx/controller/EdxSagaControllerTest.java b/api/src/test/java/ca/bc/gov/educ/api/edx/controller/EdxSagaControllerTest.java index afd56415..ec0e355f 100644 --- a/api/src/test/java/ca/bc/gov/educ/api/edx/controller/EdxSagaControllerTest.java +++ b/api/src/test/java/ca/bc/gov/educ/api/edx/controller/EdxSagaControllerTest.java @@ -133,7 +133,7 @@ void testEdxSchoolUserActivationInvite_GivenInputWithMissingLastNameRequiredFiel .content(jsonString) .accept(MediaType.APPLICATION_JSON) .with(jwt().jwt((jwt) -> jwt.claim("scope", "SCHOOL_USER_ACTIVATION_INVITE_SAGA")))) - .andExpect(jsonPath("$.message", is("Validation error"))) + .andExpect(jsonPath("$.message", is("Payload contains invalid data."))) .andExpect(jsonPath("$.subErrors[0].message", is("Last Name cannot be null"))) .andDo(print()).andExpect(status().isBadRequest()); } @@ -148,7 +148,7 @@ void testEdxSchoolUserActivationInvite_GivenInputWithMissingFirstNameRequiredFie .content(jsonString) .accept(MediaType.APPLICATION_JSON) .with(jwt().jwt((jwt) -> jwt.claim("scope", "SCHOOL_USER_ACTIVATION_INVITE_SAGA")))) - .andExpect(jsonPath("$.message", is("Validation error"))) + .andExpect(jsonPath("$.message", is("Payload contains invalid data."))) .andExpect(jsonPath("$.subErrors[0].message", is("First Name cannot be null"))) .andDo(print()).andExpect(status().isBadRequest()); } @@ -163,7 +163,7 @@ void testEdxSchoolUserActivationInvite_GivenInputWithMissingEmailRequiredField_S .content(jsonString) .accept(MediaType.APPLICATION_JSON) .with(jwt().jwt((jwt) -> jwt.claim("scope", "SCHOOL_USER_ACTIVATION_INVITE_SAGA")))) - .andExpect(jsonPath("$.message", is("Validation error"))) + .andExpect(jsonPath("$.message", is("Payload contains invalid data."))) .andExpect(jsonPath("$.subErrors[0].message", is("Email cannot be null"))) .andDo(print()).andExpect(status().isBadRequest()); } @@ -178,7 +178,7 @@ void testEdxSchoolUserActivationInvite_GivenInputWithMissingSchoolNameRequiredFi .content(jsonString) .accept(MediaType.APPLICATION_JSON) .with(jwt().jwt((jwt) -> jwt.claim("scope", "SCHOOL_USER_ACTIVATION_INVITE_SAGA")))) - .andExpect(jsonPath("$.message", is("Validation error"))) + .andExpect(jsonPath("$.message", is("Payload contains invalid data."))) .andExpect(jsonPath("$.subErrors[0].message", is("School Name cannot be null"))) .andDo(print()).andExpect(status().isBadRequest()); } @@ -193,8 +193,8 @@ void testEdxSchoolUserActivationInvite_GivenInputWithMissingSchoolIDRequiredFiel .content(jsonString) .accept(MediaType.APPLICATION_JSON) .with(jwt().jwt((jwt) -> jwt.claim("scope", "SCHOOL_USER_ACTIVATION_INVITE_SAGA")))) - .andExpect(jsonPath("$.message", is("Validation error"))) - .andExpect(jsonPath("$.subErrors[0].message", is("schoolID cannot be null"))) + .andExpect(jsonPath("$.message", is("Payload contains invalid data."))) + .andExpect(jsonPath("$.subErrors[0].message", is("School ID cannot be null"))) .andDo(print()).andExpect(status().isBadRequest()); } @@ -208,8 +208,8 @@ void testEdxSchoolUserActivationInvite_GivenInputWithMissingRoleIdsRequiredField .content(jsonString) .accept(MediaType.APPLICATION_JSON) .with(jwt().jwt((jwt) -> jwt.claim("scope", "SCHOOL_USER_ACTIVATION_INVITE_SAGA")))) - .andExpect(jsonPath("$.message", is("Validation error"))) - .andExpect(jsonPath("$.subErrors[0].message", is("Activation Roles cannot be null or empty"))) + .andExpect(jsonPath("$.message", is("Payload contains invalid data."))) + .andExpect(jsonPath("$.subErrors[0].message", is("Roles list cannot be empty."))) .andDo(print()).andExpect(status().isBadRequest()); } @@ -264,7 +264,7 @@ void testEdxSchoolUserActivationRelink_GivenInputWithMissingLastNameRequiredFiel .content(jsonString) .accept(MediaType.APPLICATION_JSON) .with(jwt().jwt((jwt) -> jwt.claim("scope", "SCHOOL_USER_ACTIVATION_INVITE_SAGA")))) - .andExpect(jsonPath("$.message", is("Validation error"))) + .andExpect(jsonPath("$.message", is("Payload contains invalid data."))) .andExpect(jsonPath("$.subErrors[0].message", is("Last Name cannot be null"))) .andDo(print()).andExpect(status().isBadRequest()); } @@ -279,7 +279,7 @@ void testEdxSchoolUserActivationRelink_GivenInputWithMissingFirstNameRequiredFie .content(jsonString) .accept(MediaType.APPLICATION_JSON) .with(jwt().jwt((jwt) -> jwt.claim("scope", "SCHOOL_USER_ACTIVATION_INVITE_SAGA")))) - .andExpect(jsonPath("$.message", is("Validation error"))) + .andExpect(jsonPath("$.message", is("Payload contains invalid data."))) .andExpect(jsonPath("$.subErrors[0].message", is("First Name cannot be null"))) .andDo(print()).andExpect(status().isBadRequest()); } @@ -294,7 +294,7 @@ void testEdxSchoolUserActivationRelink_GivenInputWithMissingEmailRequiredField_S .content(jsonString) .accept(MediaType.APPLICATION_JSON) .with(jwt().jwt((jwt) -> jwt.claim("scope", "SCHOOL_USER_ACTIVATION_INVITE_SAGA")))) - .andExpect(jsonPath("$.message", is("Validation error"))) + .andExpect(jsonPath("$.message", is("Payload contains invalid data."))) .andExpect(jsonPath("$.subErrors[0].message", is("Email cannot be null"))) .andDo(print()).andExpect(status().isBadRequest()); } @@ -309,7 +309,7 @@ void testEdxSchoolUserActivationRelink_GivenInputWithMissingSchoolNameRequiredFi .content(jsonString) .accept(MediaType.APPLICATION_JSON) .with(jwt().jwt((jwt) -> jwt.claim("scope", "SCHOOL_USER_ACTIVATION_INVITE_SAGA")))) - .andExpect(jsonPath("$.message", is("Validation error"))) + .andExpect(jsonPath("$.message", is("Payload contains invalid data."))) .andExpect(jsonPath("$.subErrors[0].message", is("School Name cannot be null"))) .andDo(print()).andExpect(status().isBadRequest()); } @@ -324,8 +324,8 @@ void testEdxSchoolUserActivationRelink_GivenInputWithMissingSchoolIDRequiredFiel .content(jsonString) .accept(MediaType.APPLICATION_JSON) .with(jwt().jwt((jwt) -> jwt.claim("scope", "SCHOOL_USER_ACTIVATION_INVITE_SAGA")))) - .andExpect(jsonPath("$.message", is("Validation error"))) - .andExpect(jsonPath("$.subErrors[0].message", is("schoolID cannot be null"))) + .andExpect(jsonPath("$.message", is("Payload contains invalid data."))) + .andExpect(jsonPath("$.subErrors[0].message", is("School ID cannot be null"))) .andDo(print()).andExpect(status().isBadRequest()); } @@ -339,8 +339,8 @@ void testEdxSchoolUserActivationRelink_GivenInputWithMissingRoleIdsRequiredField .content(jsonString) .accept(MediaType.APPLICATION_JSON) .with(jwt().jwt((jwt) -> jwt.claim("scope", "SCHOOL_USER_ACTIVATION_INVITE_SAGA")))) - .andExpect(jsonPath("$.message", is("Validation error"))) - .andExpect(jsonPath("$.subErrors[0].message", is("Activation Roles cannot be null or empty"))) + .andExpect(jsonPath("$.message", is("Payload contains invalid data."))) + .andExpect(jsonPath("$.subErrors[0].message", is("Roles list cannot be empty."))) .andDo(print()).andExpect(status().isBadRequest()); }