Skip to content

Commit

Permalink
feat: Old cases and events are deleted after a configurable time (def…
Browse files Browse the repository at this point in the history
…ault is after 6 months) with all associated data.

* Integrates scheduled jobs which deletes the old cases and events.
* Sets the default property values in application.properties.
* Extends the repositories for the necessary methods.
* Fixes an error in IrisDateTimeProvider. The method is not allowed for `Instant`.
* fixes and improves unittests
* removes false JavaDoc @SInCE notes

Integrates JavaFaker library for a simpler and random creation of test
data.

Refs iris-connect/iris-backlog#244
PR #384
  • Loading branch information
jekutzsche authored Oct 6, 2021
1 parent aff7f17 commit 3da22e4
Show file tree
Hide file tree
Showing 14 changed files with 411 additions and 10 deletions.
6 changes: 6 additions & 0 deletions iris-client-bff/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,12 @@
<version>3.0.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.javafaker</groupId>
<artifactId>javafaker</artifactId>
<version>1.0.2</version>
<scope>test</scope>
</dependency>

<!-- Third party libs -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.util.Streamable;

/**
* @author Jens Kutzsche
Expand All @@ -27,9 +28,17 @@ public interface CaseDataRequestRepository extends JpaRepository<CaseDataRequest

Page<CaseDataRequest> findByStatus(Status status, Pageable pageable);

Page<CaseDataRequest> findByRefIdContainsOrNameContainsAllIgnoreCase(String search, String search1, Pageable pageable);
Page<CaseDataRequest> findByRefIdContainsOrNameContainsAllIgnoreCase(String search, String search1,
Pageable pageable);

@Query("select r from CaseDataRequest r where r.status = :status and ( upper(r.refId) like concat('%', upper(:search), '%') or upper(r.name) like concat('%', upper(:search), '%'))")
Page<CaseDataRequest> findByStatusAndSearchByRefIdOrName(Status status, String search, Pageable pageable);

/**
* Returns the {@link CaseDataRequest}s created before the given {@link Instant}.
*
* @param refDate must not be {@literal null}.
* @return
*/
Streamable<CaseDataRequest> findByMetadataCreatedIsBefore(Instant refDate);
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package iris.client_bff.cases;

import iris.client_bff.cases.model.CaseDataSubmission;

import iris.client_bff.cases.model.CaseDataSubmission.DataSubmissionIdentifier;

import javax.transaction.Transactional;

import org.springframework.data.repository.CrudRepository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.util.Streamable;

public interface CaseDataSubmissionRepository extends CrudRepository<CaseDataSubmission, DataSubmissionIdentifier> {
public interface CaseDataSubmissionRepository extends JpaRepository<CaseDataSubmission, DataSubmissionIdentifier> {

@Transactional
Streamable<CaseDataSubmission> findAllByRequest(CaseDataRequest request);

@Transactional
void deleteAllByRequestIn(Iterable<? extends CaseDataRequest> requests);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package iris.client_bff.cases;

import iris.client_bff.cases.CaseDataRequest.DataRequestIdentifier;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDate;
import java.time.Period;
import java.time.ZoneId;
import java.util.stream.Collectors;

import javax.transaction.Transactional;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

/**
* This class collects all old cases and deletes this.
*
* @author Jens Kutzsche
*/
@Component
@Slf4j
@RequiredArgsConstructor
class CaseDeleteJob {

private final @NonNull CaseDataRequestRepository caseRequests;
private final @NonNull CaseDataSubmissionRepository caseSubmissions;
private final @NonNull CaseDeletionProperties properties;

@Transactional
@Scheduled(cron = "${iris.client.case.delete-cron:-}")
void deleteCaseRequests() {

var refDate = LocalDate.now().minus(properties.getDeleteAfter()).atStartOfDay().atZone(ZoneId.systemDefault())
.toInstant();

var oldRequests = caseRequests.findByMetadataCreatedIsBefore(refDate).toList();

if (oldRequests.isEmpty()) {
return;
}

log.debug("{} case data request(s) are deleted with period {} after their creation!",
oldRequests,
properties.getDeleteAfter(),
oldRequests.get(0).getCreatedAt());

caseSubmissions.deleteAllByRequestIn(oldRequests);
caseRequests.deleteAll(oldRequests);

log.info("{} case data request(s) (IDs: {}) were deleted with period {} after their creation at {}!",
oldRequests.size(),
oldRequests.stream().map(CaseDataRequest::getId)
.map(DataRequestIdentifier::toString)
.collect(Collectors.joining(", ")),
properties.getDeleteAfter(),
oldRequests.get(0).getCreatedAt());
}

@ConstructorBinding
@RequiredArgsConstructor
@ConfigurationProperties("iris.client.case")
@Getter
public static class CaseDeletionProperties {

/**
* Defines the {@link Period} after that a case will be deleted starting from the creation date.
*/
private final Period deleteAfter;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import lombok.RequiredArgsConstructor;
import lombok.Setter;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAmount;
Expand Down Expand Up @@ -42,7 +42,7 @@ public void reset() {
*/
@Override
public Optional<TemporalAccessor> getNow() {
return Optional.of(Instant.now().plus(delta));
return Optional.of(LocalDateTime.now().plus(delta));
}

@ConstructorBinding
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.util.Streamable;

/**
* @author Jens Kutzsche
Expand All @@ -27,8 +28,17 @@ public interface EventDataRequestRepository extends JpaRepository<EventDataReque

Page<EventDataRequest> findByStatus(Status status, Pageable pageable);

Page<EventDataRequest> findByRefIdContainsOrNameContainsAllIgnoreCase(String search, String search1, Pageable pageable);
Page<EventDataRequest> findByRefIdContainsOrNameContainsAllIgnoreCase(String search, String search1,
Pageable pageable);

@Query("select r from EventDataRequest r where r.status = :status and ( upper(r.refId) like concat('%', upper(:search), '%') or upper(r.name) like concat('%', upper(:search), '%'))")
Page<EventDataRequest> findByStatusAndSearchByRefIdOrName(Status status, String search, Pageable pageable);

/**
* Returns the {@link EventDataRequest}s created before the given {@link Instant}.
*
* @param refDate must not be {@literal null}.
* @return
*/
Streamable<EventDataRequest> findByMetadataCreatedIsBefore(Instant refDate);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@

import javax.transaction.Transactional;

import org.springframework.data.repository.CrudRepository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.util.Streamable;

/**
* @author Jens Kutzsche
*/
public interface EventDataSubmissionRepository extends CrudRepository<EventDataSubmission, DataSubmissionIdentifier> {
public interface EventDataSubmissionRepository extends JpaRepository<EventDataSubmission, DataSubmissionIdentifier> {

@Transactional
Streamable<EventDataSubmission> findAllByRequest(EventDataRequest request);

@Transactional
void deleteAllByRequestIn(Iterable<? extends EventDataRequest> requests);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package iris.client_bff.events;

import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDate;
import java.time.Period;
import java.time.ZoneId;
import java.util.stream.Collectors;

import javax.transaction.Transactional;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

/**
* This class collects all old events and deletes this.
*
* @author Jens Kutzsche
*/
@Component
@Slf4j
@RequiredArgsConstructor
class EventDeleteJob {

private final @NonNull EventDataRequestRepository eventRequests;
private final @NonNull EventDataSubmissionRepository eventSubmissions;
private final @NonNull EventDeletionProperties properties;

@Transactional
@Scheduled(cron = "${iris.client.event.delete-cron:-}")
void deleteEventRequests() {

var refDate = LocalDate.now().minus(properties.getDeleteAfter()).atStartOfDay().atZone(ZoneId.systemDefault())
.toInstant();

var oldRequests = eventRequests.findByMetadataCreatedIsBefore(refDate).toList();

if (oldRequests.isEmpty()) {
return;
}

log.debug("{} event data request(s) are deleted with period {} after their creation!",
oldRequests,
properties.getDeleteAfter(),
oldRequests.get(0).getCreatedAt());

eventSubmissions.deleteAllByRequestIn(oldRequests);
eventRequests.deleteAll(oldRequests);

log.info("{} event data request(s) (IDs: {}) were deleted with period {} after their creation at {}!",
oldRequests.size(),
oldRequests.stream().map(EventDataRequest::getId)
.map(EventDataRequest.DataRequestIdentifier::toString)
.collect(Collectors.joining(", ")),
properties.getDeleteAfter(),
oldRequests.get(0).getCreatedAt());
}

@ConstructorBinding
@RequiredArgsConstructor
@ConfigurationProperties("iris.client.event")
@Getter
public static class EventDeletionProperties {

/**
* Defines the {@link Period} after that a event will be deleted starting from the creation date.
*/
private final Period deleteAfter;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package iris.client_bff.events.model;

import iris.client_bff.core.Id;
import iris.client_bff.events.EventDataRequest;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
Expand All @@ -13,6 +14,7 @@
import javax.persistence.Embeddable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.OneToOne;

@Entity
@Data
Expand Down Expand Up @@ -45,6 +47,9 @@ public class Location {

private String contactPhone;

@OneToOne(mappedBy = "location")
private EventDataRequest request;

@Embeddable
@EqualsAndHashCode
@Getter
Expand Down
4 changes: 4 additions & 0 deletions iris-client-bff/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ spring.application.name=IRIS Client Backend for Frontend

iris.client.mailing.active=false
iris.client.sendAbort.active=false
iris.client.case.delete-after=6m
iris.client.case.delete-cron=0 30 1 * * *
iris.client.event.delete-after=6m
iris.client.event.delete-cron=0 30 1 * * *

# Spring Mail
spring.mail.host=127.0.0.1
Expand Down
43 changes: 43 additions & 0 deletions iris-client-bff/src/test/java/iris/client_bff/FakerConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package iris.client_bff;

import lombok.extern.slf4j.Slf4j;

import java.util.Locale;
import java.util.Random;

import org.apache.commons.lang3.RandomUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.github.javafaker.Faker;

/**
* @author Jens Kutzsche
*/
@Configuration
@Slf4j
public class FakerConfig {

@Value("${iris.test.faker.seed:#{null}}")
Long preConfiguredSeed;

static Faker faker;

@Bean
public Faker getFaker() {

if (faker == null) {

var seed = preConfiguredSeed == null ? RandomUtils.nextLong() : preConfiguredSeed;

log.info(
"Faker is created with SEED = {}; The seed can be set with property iris.test.faker.seed or env IRIS_TEST_FAKER_SEED.",
seed);

faker = new Faker(Locale.GERMANY, new Random(seed));
}

return faker;
}
}
Loading

0 comments on commit 3da22e4

Please sign in to comment.