Skip to content

Commit

Permalink
feat(server+ui): Schedule campaign: overload environment and dataset (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
nbrouand authored Nov 19, 2024
1 parent dd653ec commit 42bc2bc
Show file tree
Hide file tree
Showing 32 changed files with 1,051 additions and 627 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,6 @@ public TaskExecutor applicationTaskExecutor(ThreadPoolTaskExecutorBuilder builde
return builder.threadNamePrefix("app-task-exec").build();
}

@Bean
public ApplicationRunner scheduledMissedCampaignToExecute(CampaignScheduler campaignScheduler) {
return arg -> campaignScheduler.scheduledMissedCampaignIds();
}

/**
* @see ScheduleCampaign#executeScheduledCampaign()
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,8 @@

package com.chutneytesting.campaign.api;

import static com.chutneytesting.campaign.domain.Frequency.toFrequency;

import com.chutneytesting.campaign.api.dto.SchedulingCampaignDto;
import com.chutneytesting.campaign.domain.PeriodicScheduledCampaign;
import com.chutneytesting.campaign.domain.PeriodicScheduledCampaignRepository;
import com.chutneytesting.campaign.domain.ScheduledCampaignRepository;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
Expand All @@ -31,31 +28,31 @@
@CrossOrigin(origins = "*")
public class ScheduleCampaignController {

private final PeriodicScheduledCampaignRepository periodicScheduledCampaignRepository;
private final ScheduledCampaignRepository scheduledCampaignRepository;

public ScheduleCampaignController(PeriodicScheduledCampaignRepository periodicScheduledCampaignRepository) {
this.periodicScheduledCampaignRepository = periodicScheduledCampaignRepository;
public ScheduleCampaignController(ScheduledCampaignRepository scheduledCampaignRepository) {
this.scheduledCampaignRepository = scheduledCampaignRepository;
}

@PreAuthorize("hasAuthority('CAMPAIGN_READ')")
@GetMapping(path = "", produces = MediaType.APPLICATION_JSON_VALUE)
public List<SchedulingCampaignDto> getAll() {
return periodicScheduledCampaignRepository.getAll().stream()
.map(sc -> new SchedulingCampaignDto(sc.id, sc.campaignsId, sc.campaignsTitle, sc.nextExecutionDate, sc.frequency.label))
return scheduledCampaignRepository.getAll().stream()
.map(SchedulingCampaignDto::toDto)
.sorted(Comparator.comparing(SchedulingCampaignDto::getSchedulingDate))
.collect(Collectors.toList());
}

@PreAuthorize("hasAuthority('CAMPAIGN_WRITE')")
@PostMapping(path = "", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public void add(@RequestBody SchedulingCampaignDto dto) {
periodicScheduledCampaignRepository.add(new PeriodicScheduledCampaign(null, dto.getCampaignsId(), dto.getCampaignsTitle(), dto.getSchedulingDate(), toFrequency(dto.getFrequency())));
scheduledCampaignRepository.add(SchedulingCampaignDto.fromDto(dto));
}

@PreAuthorize("hasAuthority('CAMPAIGN_WRITE')")
@DeleteMapping(path = "/{schedulingCampaignId}", produces = MediaType.APPLICATION_JSON_VALUE)
public void delete(@PathVariable("schedulingCampaignId") Long schedulingCampaignId) {
periodicScheduledCampaignRepository.removeById(schedulingCampaignId);
scheduledCampaignRepository.removeById(schedulingCampaignId);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,45 +8,48 @@

package com.chutneytesting.campaign.api.dto;

import static com.chutneytesting.campaign.domain.Frequency.toFrequency;

import com.chutneytesting.campaign.domain.PeriodicScheduledCampaign;
import com.chutneytesting.campaign.domain.PeriodicScheduledCampaign.CampaignExecutionRequest;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@JsonIgnoreProperties(ignoreUnknown = true)
public class SchedulingCampaignDto {

private Long id;
private List<Long> campaignsId;
private List<String> campaignsTitle;
private LocalDateTime schedulingDate;
private String frequency;
private String environment;

private List<CampaignExecutionRequestDto> campaignExecutionRequest = new ArrayList<>();

@JsonCreator
public SchedulingCampaignDto() {
}

public SchedulingCampaignDto(Long id,
List<Long> campaignsId,
List<String> campaignsTitle,
LocalDateTime schedulingDate,
String frequency
String frequency,
String environment,
List<CampaignExecutionRequestDto> campaignExecutionRequest
) {
this.id = id;
this.campaignsId = campaignsId;
this.campaignsTitle = campaignsTitle;
this.schedulingDate = schedulingDate;
this.frequency = frequency;
this.environment = environment;
this.campaignExecutionRequest = campaignExecutionRequest;
}

public Long getId() {
return id;
}

public List<Long> getCampaignsId() {
return campaignsId;
public record CampaignExecutionRequestDto(Long campaignId, String campaignTitle, String datasetId) {
}

public List<String> getCampaignsTitle() {
return campaignsTitle;
public Long getId() {
return id;
}

public LocalDateTime getSchedulingDate() {
Expand All @@ -56,4 +59,31 @@ public LocalDateTime getSchedulingDate() {
public String getFrequency() {
return frequency;
}

public String getEnvironment() {
return environment;
}

public List<CampaignExecutionRequestDto> getCampaignExecutionRequest() {
return campaignExecutionRequest;
}

public static SchedulingCampaignDto toDto(PeriodicScheduledCampaign sc) {
return new SchedulingCampaignDto(sc.id,
sc.nextExecutionDate,
sc.frequency.label,
sc.environment,
sc.campaignExecutionRequests.stream().map(cer -> new CampaignExecutionRequestDto(cer.campaignId(), cer.campaignTitle(), cer.datasetId())).toList()
);
}

public static PeriodicScheduledCampaign fromDto(SchedulingCampaignDto dto) {
return new PeriodicScheduledCampaign(
dto.id,
dto.getSchedulingDate(),
toFrequency(dto.getFrequency()),
dto.getEnvironment(),
dto.campaignExecutionRequest.stream().map(cer -> new CampaignExecutionRequest(cer.campaignId(), cer.campaignTitle(), cer.datasetId())).toList()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,59 +14,58 @@
public class PeriodicScheduledCampaign {

public final Long id;
public final List<Long> campaignsId;
public final List<String> campaignsTitle;
public final LocalDateTime nextExecutionDate;
public final Frequency frequency;
public final String environment;
public final List<CampaignExecutionRequest> campaignExecutionRequests;

public PeriodicScheduledCampaign(Long id, List<Long> campaignsId, List<String> campaignsTitle, LocalDateTime nextExecutionDate, Frequency frequency) {
public PeriodicScheduledCampaign(Long id, LocalDateTime nextExecutionDate, Frequency frequency, String environment, List<CampaignExecutionRequest> campaignExecutionRequests) {
this.id = id;
this.campaignsId = campaignsId;
this.campaignsTitle = campaignsTitle;
this.nextExecutionDate = nextExecutionDate;
this.frequency = frequency;
this.environment = environment;
this.campaignExecutionRequests = campaignExecutionRequests;
}

public PeriodicScheduledCampaign(Long id, List<Long> campaignsId, List<String> campaignsTitle, LocalDateTime nextExecutionDate) {
this(id, campaignsId, campaignsTitle, nextExecutionDate, Frequency.EMPTY);
public PeriodicScheduledCampaign nextScheduledExecution() {
LocalDateTime scheduledDate = switch (this.frequency) {
case HOURLY -> this.nextExecutionDate.plusHours(1);
case DAILY -> this.nextExecutionDate.plusDays(1);
case WEEKLY -> this.nextExecutionDate.plusWeeks(1);
case MONTHLY -> this.nextExecutionDate.plusMonths(1);
default -> throw new IllegalStateException("Unexpected value: " + this.frequency);
};
return new PeriodicScheduledCampaign(id, scheduledDate, frequency, environment, campaignExecutionRequests);
}

public PeriodicScheduledCampaign(Long id, Long campaignId, String campaignTitle, LocalDateTime nextExecutionDate) {
this(id, List.of(campaignId), List.of(campaignTitle), nextExecutionDate, Frequency.EMPTY);
public record CampaignExecutionRequest(Long campaignId, String campaignTitle, String datasetId) {
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PeriodicScheduledCampaign that = (PeriodicScheduledCampaign) o;
return Objects.equals(id, that.id) && Objects.equals(campaignsId, that.campaignsId) && Objects.equals(campaignsTitle, that.campaignsTitle) && Objects.equals(nextExecutionDate, that.nextExecutionDate) && Objects.equals(frequency, that.frequency);
return Objects.equals(id, that.id) &&
Objects.equals(nextExecutionDate, that.nextExecutionDate) &&
Objects.equals(frequency, that.frequency) &&
Objects.equals(environment, that.environment) &&
Objects.equals(campaignExecutionRequests, that.campaignExecutionRequests);
}

@Override
public int hashCode() {
return Objects.hash(id, campaignsId, campaignsTitle, nextExecutionDate, frequency);
return Objects.hash(id, nextExecutionDate, frequency, environment, campaignExecutionRequests);
}

@Override
public String toString() {
return "SchedulingCampaign{" +
"id=" + id +
", campaignId=" + campaignsId +
", campaignTitle='" + campaignsTitle + '\'' +
", schedulingDate=" + nextExecutionDate +
", frequency='" + frequency + '\'' +
", environment='" + environment + '\'' +
", campaignExecutionRequests='" + campaignExecutionRequests + '\'' +
'}';
}

public PeriodicScheduledCampaign nextScheduledExecution() {
LocalDateTime scheduledDate = switch (this.frequency) {
case HOURLY -> this.nextExecutionDate.plusHours(1);
case DAILY -> this.nextExecutionDate.plusDays(1);
case WEEKLY -> this.nextExecutionDate.plusWeeks(1);
case MONTHLY -> this.nextExecutionDate.plusMonths(1);
default -> throw new IllegalStateException("Unexpected value: " + this.frequency);
};
return new PeriodicScheduledCampaign(id, campaignsId, campaignsTitle, scheduledDate, frequency);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
/**
* CRUD for SchedulingCampaign
*/
public interface PeriodicScheduledCampaignRepository {
public interface ScheduledCampaignRepository {

PeriodicScheduledCampaign add(PeriodicScheduledCampaign periodicScheduledCampaign);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import com.chutneytesting.campaign.domain.CampaignExecutionRepository;
import com.chutneytesting.campaign.domain.CampaignNotFoundException;
import com.chutneytesting.campaign.domain.CampaignRepository;
import com.chutneytesting.campaign.domain.PeriodicScheduledCampaignRepository;
import com.chutneytesting.campaign.domain.ScheduledCampaignRepository;
import com.chutneytesting.campaign.infra.jpa.CampaignEntity;
import com.chutneytesting.campaign.infra.jpa.CampaignScenarioEntity;
import com.chutneytesting.server.core.domain.scenario.campaign.Campaign;
Expand All @@ -33,15 +33,15 @@ public class DatabaseCampaignRepository implements CampaignRepository {
private final CampaignJpaRepository campaignJpaRepository;
private final CampaignScenarioJpaRepository campaignScenarioJpaRepository;
private final CampaignExecutionRepository campaignExecutionRepository;
private final PeriodicScheduledCampaignRepository periodicScheduledCampaignRepository;
private final ScheduledCampaignRepository scheduledCampaignRepository;

public DatabaseCampaignRepository(CampaignJpaRepository campaignJpaRepository,
CampaignScenarioJpaRepository campaignScenarioJpaRepository,
CampaignExecutionDBRepository campaignExecutionRepository, PeriodicScheduledCampaignRepository periodicScheduledCampaignRepository) {
CampaignExecutionDBRepository campaignExecutionRepository, ScheduledCampaignRepository scheduledCampaignRepository) {
this.campaignJpaRepository = campaignJpaRepository;
this.campaignScenarioJpaRepository = campaignScenarioJpaRepository;
this.campaignExecutionRepository = campaignExecutionRepository;
this.periodicScheduledCampaignRepository = periodicScheduledCampaignRepository;
this.scheduledCampaignRepository = scheduledCampaignRepository;
}

@Override
Expand Down Expand Up @@ -75,7 +75,7 @@ public boolean removeById(Long id) {
if (campaignJpaRepository.existsById(id)) {
campaignExecutionRepository.clearAllExecutionHistory(id);
campaignJpaRepository.deleteById(id);
periodicScheduledCampaignRepository.removeCampaignId(id);
scheduledCampaignRepository.removeCampaignId(id);
return true;
}
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,61 @@

package com.chutneytesting.campaign.infra;

import static java.util.Collections.emptyList;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import java.time.LocalDateTime;
import java.util.List;

@JsonPropertyOrder({ "id", "schedulingDate", "environment", "campaignsId", "campaignsTitle", "datasetsId" })
public class SchedulingCampaignDto {
public final String id;
public final List<Long> campaignsId;
public final List<String> campaignsTitle;
public final LocalDateTime schedulingDate;
public final String frequency;
public final String environment;

@JsonIgnore
public final List<CampaignExecutionRequestDto> campaignExecutionRequestDto;

/**
* for ObjectMapper only
**/
@JsonCreator
public SchedulingCampaignDto() {
id = null;
campaignsId = null;
schedulingDate = null;
campaignsTitle = null;
frequency = null;
environment = null;
campaignExecutionRequestDto = null;
}

@JsonIgnore
public SchedulingCampaignDto(String id,
List<Long> campaignsId,
List<String> campaignsTitle,
LocalDateTime schedulingDate,
String frequency) {
String frequency,
String environment,
List<CampaignExecutionRequestDto> campaignExecutionRequestDto) {
this.id = id;
this.campaignsId = campaignsId;
this.campaignsTitle = campaignsTitle;
this.schedulingDate = schedulingDate;
this.frequency = frequency;
this.campaignExecutionRequestDto = campaignExecutionRequestDto;
this.environment = environment;
}

public List<Long> getCampaignsId() {
return campaignExecutionRequestDto != null ? campaignExecutionRequestDto.stream().map(cer -> cer.campaignId).toList() : emptyList();
}

public List<String> getCampaignsTitle() {
return campaignExecutionRequestDto != null ? campaignExecutionRequestDto.stream().map(cer -> cer.campaignTitle).toList() : emptyList();
}

public List<String> getDatasetsId() {
return campaignExecutionRequestDto != null ? campaignExecutionRequestDto.stream().map(cer -> cer.datasetId).toList() : emptyList();
}

public record CampaignExecutionRequestDto(Long campaignId, String campaignTitle, String datasetId) {
}
}
Loading

0 comments on commit 42bc2bc

Please sign in to comment.