Skip to content

Commit

Permalink
Merge branch 'main' into grad-release
Browse files Browse the repository at this point in the history
  • Loading branch information
cditcher committed Dec 13, 2024
2 parents a8d333c + 81a8e7a commit 02c6487
Show file tree
Hide file tree
Showing 15 changed files with 198 additions and 25 deletions.
4 changes: 4 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ updates:
schedule:
interval: "daily"
target-branch: "grad-release"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,6 @@ jobs:
# now hit it with a zap scan
- name: ZAP Scan
uses: zaproxy/action-api-scan@v0.7.0
uses: zaproxy/action-api-scan@v0.9.0
with:
target: 'https://${{ env.REPO_NAME }}-${{ env.OPENSHIFT_NAMESPACE }}.apps.silver.devops.gov.bc.ca/api/v1/api-docs'
2 changes: 1 addition & 1 deletion .github/workflows/build.from.main.branch.deploy.to.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,6 @@ jobs:
# now hit it with a zap scan
- name: ZAP Scan
uses: zaproxy/action-api-scan@v0.7.0
uses: zaproxy/action-api-scan@v0.9.0
with:
target: 'https://${{ env.REPO_NAME }}-${{ env.OPENSHIFT_NAMESPACE }}.apps.silver.devops.gov.bc.ca/api/v1/api-docs'
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,6 @@ jobs:
# now hit it with a zap scan
- name: ZAP Scan
uses: zaproxy/action-api-scan@v0.7.0
uses: zaproxy/action-api-scan@v0.9.0
with:
target: 'https://${{ env.REPO_NAME }}-${{ env.OPENSHIFT_NAMESPACE }}.apps.silver.devops.gov.bc.ca/api/v1/api-docs'
2 changes: 1 addition & 1 deletion api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>ca.bc.gov.educ</groupId>
<artifactId>educ-grad-student-api</artifactId>
<version>1.8.67</version>
<version>1.8.69</version>
<name>educ-grad-student-api</name>
<description>Student Demographics API for GRAD team</description>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,10 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons

// username
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth instanceof JwtAuthenticationToken) {
JwtAuthenticationToken authenticationToken = (JwtAuthenticationToken) auth;
if (auth instanceof JwtAuthenticationToken authenticationToken) {
Jwt jwt = (Jwt) authenticationToken.getCredentials();
String username = JwtUtil.getName(jwt);
if (username != null) {
ThreadLocalStateUtil.setCurrentUser(username);
}
String username = JwtUtil.getName(jwt, request);
ThreadLocalStateUtil.setCurrentUser(username);
}

return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ public enum TraxEventType {
NEWSTUDENT,
UPD_DEMOG,
UPD_GRAD,
UPD_STD_STATUS,
XPROGRAM,
ASSESSMENT,
COURSE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class GraduationStudentRecord extends BaseModel {
private String schoolOfRecord;
private UUID schoolOfRecordId;
private String schoolName;
private String studentGrade;
private String studentGrade;
private String studentStatus;
private String studentStatusName;
private UUID studentID;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,8 @@ protected void onPersist() {
if (this.createDate == null) {
this.createDate = LocalDateTime.now();
}
if(this.updateDate == null) {
this.updateDate = LocalDateTime.now();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,60 @@ INSERT INTO GRADUATION_STUDENT_RECORD_HISTORY (
@Query(value= INSERT_INTO_GRADUATION_STUDENT_RECORD_HISTORY_BY_BATCH_ID_AND_STUDENT_ID_IN_SQL, nativeQuery=true)
Integer insertGraduationStudentRecordHistoryByBatchIdAndStudentIDs(@Param(value = "batchId") Long batchId, @Param(value = "studentIDs") List<UUID> studentIDs, @Param(value = "activityCode") String activityCode, @Param(value = "updateUser") String updateUser);

String INSERT_INTO_GRADUATION_STUDENT_RECORD_HISTORY_BY_STUDENT_ID_IN_SQL = """
INSERT INTO GRADUATION_STUDENT_RECORD_HISTORY (
GRADUATION_STUDENT_RECORD_HISTORY_ID,
HISTORY_ACTIVITY_CODE,
GRADUATION_STUDENT_RECORD_ID,
GRADUATION_PROGRAM_CODE,
GPA,
STUDENT_STATUS_CODE,
HONOURS_STANDING,
PROGRAM_COMPLETION_DATE,
RECALCULATE_GRAD_STATUS,
SCHOOL_OF_RECORD,
STUDENT_GRADE,
SCHOOL_AT_GRADUATION,
CREATE_USER,
CREATE_DATE,
UPDATE_USER,
UPDATE_DATE,
RECALCULATE_PROJECTED_GRAD,
BATCH_ID,
CONSUMER_EDUC_REQT_MET,
STUDENT_CITIZENSHIP_CODE,
ADULT_START_DATE,
SCHOOL_OF_RECORD_ID,
SCHOOL_AT_GRADUATION_ID
) SELECT
SYS_GUID(),
:activityCode,
GRADUATION_STUDENT_RECORD_ID,
GRADUATION_PROGRAM_CODE,
GPA,
STUDENT_STATUS_CODE,
HONOURS_STANDING,
PROGRAM_COMPLETION_DATE,
RECALCULATE_GRAD_STATUS,
SCHOOL_OF_RECORD,
STUDENT_GRADE,
SCHOOL_AT_GRADUATION,
CREATE_USER,
CREATE_DATE,
UPDATE_USER,
SYSDATE,
RECALCULATE_PROJECTED_GRAD,
BATCH_ID,
CONSUMER_EDUC_REQT_MET,
STUDENT_CITIZENSHIP_CODE,
ADULT_START_DATE,
SCHOOL_OF_RECORD_ID,
SCHOOL_AT_GRADUATION_ID
FROM GRADUATION_STUDENT_RECORD
WHERE GRADUATION_STUDENT_RECORD_ID = :studentID
""";
@Modifying
@Query(value= INSERT_INTO_GRADUATION_STUDENT_RECORD_HISTORY_BY_STUDENT_ID_IN_SQL, nativeQuery=true)
Integer insertGraduationStudentRecordHistoryByStudentId(@Param(value = "studentID") UUID studentID, @Param(value = "activityCode") String activityCode);

}
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,13 @@ public GraduationStudentRecord updateGraduationStatusByFields(OngoingUpdateReque
gradEntity.setUpdateDate(null);
gradEntity.setUpdateUser(null);
validateStudentStatusAndResetBatchFlags(gradEntity);
gradEntity = graduationStatusRepository.saveAndFlush(gradEntity);
historyService.createStudentHistory(gradEntity, UPDATE_ONGOING_HISTORY_ACTIVITY_CODE);
if (isBatchFlagUpdatesOnly(eventType)) {
gradEntity = saveBatchFlagsWithAuditHistory(gradEntity.getStudentID(), gradEntity.getRecalculateGradStatus(),
gradEntity.getRecalculateProjectedGrad(), UPDATE_ONGOING_HISTORY_ACTIVITY_CODE);
} else {
gradEntity = graduationStatusRepository.saveAndFlush(gradEntity);
historyService.createStudentHistory(gradEntity, UPDATE_ONGOING_HISTORY_ACTIVITY_CODE);
}
if (constants.isStudentGuidPenXrefEnabled() && StringUtils.isNotBlank(requestDTO.getPen())) {
saveStudentGuidPenXref(gradEntity.getStudentID(), requestDTO.getPen());
}
Expand All @@ -130,6 +135,10 @@ public GraduationStudentRecord updateGraduationStatusByFields(OngoingUpdateReque
return null;
}

private boolean isBatchFlagUpdatesOnly(TraxEventType eventType) {
return TraxEventType.NEWSTUDENT != eventType && TraxEventType.UPD_GRAD != eventType;
}

@Transactional
@Retry(name = "generalpostcall")
public StudentOptionalProgram saveStudentOptionalProgram(StudentOptionalProgramRequestDTO studentOptionalProgramReq, String accessToken) {
Expand Down Expand Up @@ -214,6 +223,15 @@ private void saveStudentGuidPenXref(UUID studentId, String pen) {
}
}

/**
* Update Batch Flags in Graduation Status for Ongoing Updates
*/
private GraduationStudentRecordEntity saveBatchFlagsWithAuditHistory(UUID studentID, String recalculateGradStatus, String recalculateProjectedGrad, String historyActivityCode) {
graduationStatusRepository.updateGradStudentRecalculationAllFlags(studentID, recalculateGradStatus, recalculateProjectedGrad);
gradStudentRecordHistoryRepository.insertGraduationStudentRecordHistoryByStudentId(studentID, historyActivityCode);
return graduationStatusRepository.findByStudentID(studentID);
}

@Transactional
public void deleteGraduationStatus(UUID studentID) {
// graduation_student_record
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

import static ca.bc.gov.educ.api.gradstudent.constant.EventStatus.DB_COMMITTED;

Expand Down Expand Up @@ -82,16 +81,15 @@ public class GraduationStatusService extends GradBaseService {
final HistoryService historyService;
final GradValidation validation;
final EducGradStudentApiConstants constants;
final GraduationStudentRecordSearchRepository graduationStudentRecordSearchRepository;

@Autowired
GraduationStudentRecordSearchRepository graduationStudentRecordSearchRepository;

@Autowired
public GraduationStatusService(WebClient webClient, GraduationStudentRecordRepository graduationStatusRepository, StudentStatusRepository studentStatusRepository, GradStatusEventRepository gradStatusEventRepository, StudentNonGradReasonRepository studentNonGradReasonRepository, GraduationStatusTransformer graduationStatusTransformer, StudentOptionalProgramRepository gradStudentOptionalProgramRepository, GradStudentOptionalProgramTransformer gradStudentOptionalProgramTransformer, StudentCareerProgramRepository gradStudentCareerProgramRepository, GradStudentCareerProgramTransformer gradStudentCareerProgramTransformer, StudentNonGradReasonTransformer studentNonGradReasonTransformer, GradStudentService gradStudentService, HistoryService historyService, GradValidation validation, EducGradStudentApiConstants constants) {
public GraduationStatusService(WebClient webClient, GraduationStudentRecordRepository graduationStatusRepository, StudentStatusRepository studentStatusRepository, GradStatusEventRepository gradStatusEventRepository, StudentNonGradReasonRepository studentNonGradReasonRepository, GraduationStatusTransformer graduationStatusTransformer, StudentOptionalProgramRepository gradStudentOptionalProgramRepository, GraduationStudentRecordSearchRepository graduationStudentRecordSearchRepository, GradStudentOptionalProgramTransformer gradStudentOptionalProgramTransformer, StudentCareerProgramRepository gradStudentCareerProgramRepository, GradStudentCareerProgramTransformer gradStudentCareerProgramTransformer, StudentNonGradReasonTransformer studentNonGradReasonTransformer, GradStudentService gradStudentService, HistoryService historyService, GradValidation validation, EducGradStudentApiConstants constants) {
this.webClient = webClient;
this.graduationStatusRepository = graduationStatusRepository;
this.studentStatusRepository = studentStatusRepository;
this.gradStatusEventRepository = gradStatusEventRepository;
this.graduationStudentRecordSearchRepository = graduationStudentRecordSearchRepository;
this.graduationStatusTransformer = graduationStatusTransformer;
this.gradStudentOptionalProgramRepository = gradStudentOptionalProgramRepository;
this.gradStudentOptionalProgramTransformer = gradStudentOptionalProgramTransformer;
Expand Down Expand Up @@ -202,7 +200,7 @@ public Pair<GraduationStudentRecord, GradStatusEvent> saveGraduationStatus(UUID
if(batchId != null) {
resetBatchFlags(gradEntity, false);
}

gradEntity.setUpdateUser(null);
gradEntity = graduationStatusRepository.saveAndFlush(gradEntity);
historyService.createStudentHistory(gradEntity, GRAD_ALG);
final GradStatusEvent gradStatusEvent = createGradStatusEvent(gradEntity.getUpdateUser(), gradEntity,
Expand Down Expand Up @@ -399,8 +397,8 @@ public GraduationStudentRecordSearchResult searchGraduationStudentRecords(final
Specification<GraduationStudentRecordSearchEntity> spec = new GraduationStudentRecordSearchSpecification(searchCriteria);
List<GraduationStudentRecordSearchEntity> results = graduationStudentRecordSearchRepository.findAll(Specification.where(spec));
List<UUID> students = new ArrayList<>();
if (results != null && !results.isEmpty()) {
students = results.stream().map(GraduationStudentRecordSearchEntity::getStudentID).collect(Collectors.toList());
if (!results.isEmpty()) {
students = results.stream().map(GraduationStudentRecordSearchEntity::getStudentID).toList();
}
searchResult.setStudentIDs(students);
return searchResult;
Expand Down Expand Up @@ -1102,6 +1100,7 @@ public Pair<GraduationStudentRecord, GradStatusEvent> undoCompletionStudent(UUID
gradEntity.setGpa(null);
gradEntity.setSchoolAtGrad(null);
gradEntity.setUpdateUser(null);
gradEntity.setUpdateDate(null);
gradEntity = graduationStatusRepository.save(gradEntity);
historyService.createStudentHistory(gradEntity, USER_UNDO_CMPL);
final GradStatusEvent gradStatusEvent = createGradStatusEvent(gradEntity.getUpdateUser(), gradEntity,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class EducGradStudentApiConstants {
public static final String API_NAME = "GRAD-STUDENT-API";
public static final String STREAM_NAME="GRAD_STATUS_EVENT_STREAM";
public static final String CORRELATION_ID = "correlationID";
public static final String USERNAME = "username";

//API end-point Mapping constants
public static final String API_ROOT_MAPPING = "";
Expand Down
34 changes: 34 additions & 0 deletions api/src/main/java/ca/bc/gov/educ/api/gradstudent/util/JwtUtil.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package ca.bc.gov.educ.api.gradstudent.util;

import jakarta.servlet.http.HttpServletRequest;
import lombok.val;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.oauth2.jwt.Jwt;

Expand Down Expand Up @@ -54,6 +56,38 @@ public static String getName(Jwt jwt) {
return sb.toString();
}

/**
* Gets name string
* => If it is service account, get it from request header. Otherwise, get it from jwt
*
* @param jwt the JWT
* @param request the Request Header
* @return the username string
*/
public static String getName(Jwt jwt, HttpServletRequest request) {
StringBuilder sb = new StringBuilder();
if (isServiceAccount(jwt.getClaims())) {
sb.append(getUserNameString(request));
} else {
String givenName = (String) jwt.getClaims().get("given_name");
if (StringUtils.isNotBlank(givenName)) {
sb.append(givenName.charAt(0));
}
String familyName = (String) jwt.getClaims().get("family_name");
sb.append(familyName);
}
return sb.toString();
}

private static String getUserNameString(HttpServletRequest request) {
val username = request.getHeader(EducGradStudentApiConstants.USERNAME);
if (StringUtils.isNotBlank(username)) {
return username;
} else {
return "Batch Process";
}
}

private static boolean isServiceAccount(Map<String, Object> claims) {
return !claims.containsKey("family_name");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ public void testGraduationStudentRecordAsOngoingUpdateForStudentStatus() {
OngoingUpdateRequestDTO requestDTO = new OngoingUpdateRequestDTO();
requestDTO.setPen(pen);
requestDTO.setStudentID(studentID.toString());
requestDTO.setEventType(TraxEventType.UPD_STD_STATUS);
requestDTO.setEventType(TraxEventType.UPD_GRAD);

OngoingUpdateFieldDTO field = OngoingUpdateFieldDTO.builder()
.type(FieldType.STRING).name(FieldName.STUDENT_STATUS).value(newStatus)
Expand Down Expand Up @@ -322,6 +322,68 @@ public void testGraduationStudentRecordAsOngoingUpdateForStudentStatus() {
assertThat(result.getRecalculateGradStatus()).isNull();
}

@Test
public void testGraduationStudentRecordAsOngoingUpdateForBatchFlags() {
// ID
UUID studentID = UUID.randomUUID();
String pen = "123456789";
String mincode = "12345678";

GraduationStudentRecordEntity graduationStatusEntity = new GraduationStudentRecordEntity();
graduationStatusEntity.setStudentID(studentID);
graduationStatusEntity.setPen(pen);
graduationStatusEntity.setStudentStatus("CUR");
graduationStatusEntity.setRecalculateGradStatus(null);
graduationStatusEntity.setRecalculateProjectedGrad("Y");
graduationStatusEntity.setProgram("2018-EN");
graduationStatusEntity.setSchoolOfRecord(mincode);
graduationStatusEntity.setSchoolAtGrad(mincode);
graduationStatusEntity.setGpa("4");
graduationStatusEntity.setProgramCompletionDate(new Date(System.currentTimeMillis()));

OngoingUpdateRequestDTO requestDTO = new OngoingUpdateRequestDTO();
requestDTO.setPen(pen);
requestDTO.setStudentID(studentID.toString());
requestDTO.setEventType(TraxEventType.COURSE);

OngoingUpdateFieldDTO field1 = OngoingUpdateFieldDTO.builder()
.type(FieldType.STRING).name(FieldName.RECALC_GRAD_ALG).value("Y")
.build();
requestDTO.getUpdateFields().add(field1);

OngoingUpdateFieldDTO field2 = OngoingUpdateFieldDTO.builder()
.type(FieldType.STRING).name(FieldName.RECALC_TVR).value("NULL")
.build();
requestDTO.getUpdateFields().add(field2);

GraduationStudentRecordEntity savedGraduationStatus = new GraduationStudentRecordEntity();
BeanUtils.copyProperties(graduationStatusEntity, savedGraduationStatus);
savedGraduationStatus.setRecalculateGradStatus("Y");
savedGraduationStatus.setRecalculateProjectedGrad(null);

when(graduationStatusRepository.findById(studentID)).thenReturn(Optional.of(graduationStatusEntity));
when(graduationStatusRepository.findByStudentID(studentID)).thenReturn(savedGraduationStatus);
when(graduationStatusRepository.saveAndFlush(graduationStatusEntity)).thenReturn(savedGraduationStatus);

when(this.webClient.delete()).thenReturn(this.requestHeadersUriMock);
when(this.requestHeadersUriMock.uri(String.format(constants.getDeleteStudentAchievements(),studentID))).thenReturn(this.requestHeadersMock);
when(this.requestHeadersMock.headers(any(Consumer.class))).thenReturn(this.requestBodyMock);
when(this.requestBodyMock.retrieve()).thenReturn(this.responseMock);
when(this.responseMock.bodyToMono(Integer.class)).thenReturn(Mono.just(0));

var result = dataConversionService.updateGraduationStatusByFields(requestDTO, "accessToken");

assertThat(result).isNotNull();
assertThat(result.getStudentID()).isEqualTo(graduationStatusEntity.getStudentID());
assertThat(result.getPen()).isEqualTo(graduationStatusEntity.getPen());

assertThat(result.getSchoolOfRecord()).isEqualTo(graduationStatusEntity.getSchoolOfRecord());
assertThat(result.getGpa()).isEqualTo(graduationStatusEntity.getGpa());

assertThat(result.getRecalculateGradStatus()).isEqualTo("Y");
assertThat(result.getRecalculateProjectedGrad()).isNull();
}

@Test
public void testGraduationStudentRecordAsOngoingUpdateForStudentMergedStatus() {
// ID
Expand All @@ -345,7 +407,7 @@ public void testGraduationStudentRecordAsOngoingUpdateForStudentMergedStatus() {
OngoingUpdateRequestDTO requestDTO = new OngoingUpdateRequestDTO();
requestDTO.setPen(pen);
requestDTO.setStudentID(studentID.toString());
requestDTO.setEventType(TraxEventType.UPD_STD_STATUS);
requestDTO.setEventType(TraxEventType.UPD_GRAD);

OngoingUpdateFieldDTO field = OngoingUpdateFieldDTO.builder()
.type(FieldType.STRING).name(FieldName.STUDENT_STATUS).value(newStatus)
Expand Down Expand Up @@ -407,7 +469,7 @@ public void testGraduationStudentRecordAsOngoingUpdateForStudentArchivedStatus()
OngoingUpdateRequestDTO requestDTO = new OngoingUpdateRequestDTO();
requestDTO.setPen(pen);
requestDTO.setStudentID(studentID.toString());
requestDTO.setEventType(TraxEventType.UPD_STD_STATUS);
requestDTO.setEventType(TraxEventType.UPD_GRAD);

OngoingUpdateFieldDTO field = OngoingUpdateFieldDTO.builder()
.type(FieldType.STRING).name(FieldName.STUDENT_STATUS).value(newStatus)
Expand Down

0 comments on commit 02c6487

Please sign in to comment.