Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add scheduler for purging expired EdxUser School/Districts #226

Merged
merged 4 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
Expand All @@ -24,4 +25,6 @@ public interface EdxUserDistrictRepository extends JpaRepository<EdxUserDistrict
WHERE permission.EDX_PERMISSION_CODE = :permissionCode"""
, nativeQuery = true)
List<EdxUserDistrictEntity> findDistrictsByPermission(String permissionCode);

List<EdxUserDistrictEntity> findAllByExpiryDateBefore(LocalDateTime dateTime);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
Expand All @@ -26,4 +27,6 @@ public interface EdxUserSchoolRepository extends JpaRepository<EdxUserSchoolEnti

List<EdxUserSchoolEntity> findAllBySchoolIDIn(List<UUID> schoolIDs);

List<EdxUserSchoolEntity> findAllByExpiryDateBefore(LocalDateTime dateTime);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package ca.bc.gov.educ.api.edx.schedulers;

import ca.bc.gov.educ.api.edx.model.v1.EdxUserDistrictEntity;
import ca.bc.gov.educ.api.edx.model.v1.EdxUserSchoolEntity;
import ca.bc.gov.educ.api.edx.repository.*;
import net.javacrumbs.shedlock.core.LockAssert;
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

@Component
public class EdxUserScheduler {
private final EdxUserSchoolRepository edxUserSchoolRepository;
private final EdxUserDistrictRepository edxUserDistrictRepository;

public EdxUserScheduler(
EdxUserSchoolRepository edxUserSchoolRepository,
EdxUserDistrictRepository edxUserDistrictRepository
) {
this.edxUserSchoolRepository = edxUserSchoolRepository;
this.edxUserDistrictRepository = edxUserDistrictRepository;
}

@Scheduled(cron = "${scheduled.jobs.purge.edx.users.cron}")
@SchedulerLock(name = "PurgeEdxUsers", lockAtLeastFor = "PT4H", lockAtMostFor = "PT4H")
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void purgeExpiredEdxUsers() {
LockAssert.assertLocked();
final LocalDateTime now = LocalDateTime.now();
List<EdxUserSchoolEntity> expiredSchoolUsers = this.edxUserSchoolRepository.findAllByExpiryDateBefore(now);
List<EdxUserDistrictEntity> expiredDistrictUsers = this.edxUserDistrictRepository.findAllByExpiryDateBefore(now);

this.edxUserSchoolRepository.deleteAll(expiredSchoolUsers);
this.edxUserDistrictRepository.deleteAll(expiredDistrictUsers);
}
}
13 changes: 12 additions & 1 deletion api/src/test/java/ca/bc/gov/educ/api/edx/BaseEdxAPITest.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ public void before() {
this.secureExchangeAPITestUtils.cleanDB();
}


protected EdxUserEntity createUserEntity(EdxUserRepository edxUserRepository, EdxPermissionRepository edxPermissionRepository, EdxRoleRepository edxRoleRepository, EdxUserSchoolRepository edxUserSchoolRepository, EdxUserDistrictRepository edxUserDistrictRepository) {
var entity = edxUserRepository.save(getEdxUserEntity());

Expand Down Expand Up @@ -217,13 +216,25 @@ protected EdxUserSchool createEdxUserSchool(EdxUser edxUsr) {
return edxUserSchool;
}

protected EdxUserSchool createEdxUserSchool(EdxUser edxUsr, LocalDateTime expiryDate) {
EdxUserSchool edxUserSchool = this.createEdxUserSchool(edxUsr);
edxUserSchool.setExpiryDate(expiryDate.toString());
return edxUserSchool;
}

protected EdxUserDistrict createEdxUserDistrict(EdxUser edxUsr) {
EdxUserDistrict edxUserDistrict = new EdxUserDistrict();
edxUserDistrict.setEdxUserID(edxUsr.getEdxUserID());
edxUserDistrict.setDistrictID(UUID.randomUUID().toString());
return edxUserDistrict;
}

protected EdxUserDistrict createEdxUserDistrict(EdxUser edxUsr, LocalDateTime expiryDate) {
EdxUserDistrict edxUserDistrict = this.createEdxUserDistrict(edxUsr);
edxUserDistrict.setExpiryDate(expiryDate.toString());
return edxUserDistrict;
}

protected List<EdxActivationCodeEntity> createActivationCodeTableDataForSchoolUser(EdxActivationCodeRepository edxActivationCodeRepository, EdxPermissionRepository edxPermissionRepository, EdxRoleRepository edxRoleRepository, EdxActivationRoleRepository edxActivationRoleRepository, boolean isActive, UUID validationCode, Integer numberOfClicks, UUID schoolID) {
List<EdxActivationCodeEntity> edxActivationCodeEntityList = new ArrayList<>();
EdxRoleEntity savedRoleEntity = createRoleAndPermissionData(edxPermissionRepository, edxRoleRepository);
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package ca.bc.gov.educ.api.edx.schedulers;

import static org.assertj.core.api.Assertions.assertThat;

import java.time.LocalDateTime;
import java.util.List;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;

import ca.bc.gov.educ.api.edx.BaseEdxAPITest;
import ca.bc.gov.educ.api.edx.mappers.v1.EdxUserDistrictMapper;
import ca.bc.gov.educ.api.edx.mappers.v1.EdxUserMapper;
import ca.bc.gov.educ.api.edx.mappers.v1.EdxUserSchoolMapper;
import ca.bc.gov.educ.api.edx.model.v1.EdxUserDistrictEntity;
import ca.bc.gov.educ.api.edx.model.v1.EdxUserSchoolEntity;
import ca.bc.gov.educ.api.edx.repository.EdxUserDistrictRepository;
import ca.bc.gov.educ.api.edx.repository.EdxUserRepository;
import ca.bc.gov.educ.api.edx.repository.EdxUserSchoolRepository;
import ca.bc.gov.educ.api.edx.struct.v1.EdxUser;
import net.javacrumbs.shedlock.core.LockAssert;

class EdxUserSchedulerTest extends BaseEdxAPITest {
@Autowired
private EdxUserSchoolRepository userSchoolRepository;

@Autowired
private EdxUserDistrictRepository userDistrictRepository;

@Autowired
private EdxUserRepository userRepository;

@Autowired
private EdxUserScheduler scheduler;

private EdxUserSchoolMapper userSchoolMapper = EdxUserSchoolMapper.mapper;
private EdxUserDistrictMapper userDistrictMapper = EdxUserDistrictMapper.mapper;
private EdxUserMapper userMapper = EdxUserMapper.mapper;

@BeforeEach
public void setUp() {
LockAssert.TestHelper.makeAllAssertsPass(true);
}

@AfterEach
public void tearDown() {
this.userSchoolRepository.deleteAll();
this.userDistrictRepository.deleteAll();
this.userRepository.deleteAll();
}

@Test
void testPurgeExpiredUsers() {
LocalDateTime now = LocalDateTime.now().withNano(0);
EdxUser user = userMapper.toStructure(this.userRepository.save(userMapper.toModel(this.createEdxUser())));

List<EdxUserSchoolEntity> userSchools = List.of(
this.createEdxUserSchool(user, now.minusDays(1)),
this.createEdxUserSchool(user, now.plusDays(1))
).stream().map(userSchoolMapper::toModel).toList();

List<EdxUserDistrictEntity> userDistricts = List.of(
this.createEdxUserDistrict(user, now.minusDays(1)),
this.createEdxUserDistrict(user, now.plusDays(1))
).stream().map(userDistrictMapper::toModel).toList();

this.userSchoolRepository.saveAll(userSchools);
this.userDistrictRepository.saveAll(userDistricts);
scheduler.purgeExpiredEdxUsers();

List<EdxUserSchoolEntity> foundUserSchoolEntities = this.userSchoolRepository.findAll();
assertThat(foundUserSchoolEntities).hasSize(1);
assertThat(foundUserSchoolEntities.get(0).getExpiryDate()).isAfter(now);

List<EdxUserDistrictEntity> foundUserDistrictEntities = this.userDistrictRepository.findAll();
assertThat(foundUserDistrictEntities).hasSize(1);
assertThat(foundUserDistrictEntities.get(0).getExpiryDate()).isAfter(now);
}

}
2 changes: 2 additions & 0 deletions api/src/test/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ scheduled.jobs.extract.uncompleted.sagas.cron=-
scheduled.jobs.extract.uncompleted.sagas.cron.lockAtLeastFor=55s
scheduled.jobs.extract.uncompleted.sagas.cron.lockAtMostFor=58s

scheduled.jobs.purge.edx.users.cron=-

apis.endpoints.student.api=blah
institute.api.url=blah

Expand Down
1 change: 1 addition & 0 deletions tools/config/update-configmap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ fi
SCHEDULED_JOBS_EXTRACT_UNCOMPLETED_SAGAS_CRON="0 0/1 * * * *"
SCHEDULED_JOBS_EXTRACT_UNCOMPLETED_SAGAS_CRON_LOCK_AT_LEAST_FOR="55s"
SCHEDULED_JOBS_EXTRACT_UNCOMPLETED_SAGAS_CRON_LOCK_AT_MOST_FOR="57s"
SCHEDULED_JOBS_PURGE_EDX_USERS_CRON="0 30 0 * * *"
EDX_ACTIVATION_CODE_LENGTH="8"
EDX_ACTIVATION_CODE_VALID_CHARACTERS="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
echo
Expand Down
Loading