diff --git a/studymanager/src/main/java/io/redlink/more/studymanager/model/Intervention.java b/studymanager/src/main/java/io/redlink/more/studymanager/model/Intervention.java index 99f83777..44fcc59b 100644 --- a/studymanager/src/main/java/io/redlink/more/studymanager/model/Intervention.java +++ b/studymanager/src/main/java/io/redlink/more/studymanager/model/Intervention.java @@ -1,5 +1,8 @@ package io.redlink.more.studymanager.model; +import io.redlink.more.studymanager.model.scheduler.Event; +import io.redlink.more.studymanager.model.scheduler.ScheduleEvent; + import java.time.Instant; public class Intervention { @@ -8,7 +11,7 @@ public class Intervention { private String title; private String purpose; private Integer studyGroupId; - private Event schedule; + private ScheduleEvent schedule; private Instant created; private Instant modified; @@ -57,11 +60,11 @@ public Intervention setStudyGroupId(Integer studyGroupId) { return this; } - public Event getSchedule() { + public ScheduleEvent getSchedule() { return schedule; } - public Intervention setSchedule(Event schedule) { + public Intervention setSchedule(ScheduleEvent schedule) { this.schedule = schedule; return this; } diff --git a/studymanager/src/main/java/io/redlink/more/studymanager/model/Observation.java b/studymanager/src/main/java/io/redlink/more/studymanager/model/Observation.java index 70018d34..e81681b3 100644 --- a/studymanager/src/main/java/io/redlink/more/studymanager/model/Observation.java +++ b/studymanager/src/main/java/io/redlink/more/studymanager/model/Observation.java @@ -1,6 +1,7 @@ package io.redlink.more.studymanager.model; import io.redlink.more.studymanager.core.properties.ObservationProperties; +import io.redlink.more.studymanager.model.scheduler.ScheduleEvent; import java.time.Instant; @@ -13,7 +14,7 @@ public class Observation { private String type; private Integer studyGroupId; private ObservationProperties properties; - private Event schedule; + private ScheduleEvent schedule; private Instant created; private Instant modified; private Boolean hidden; @@ -91,11 +92,11 @@ public Observation setProperties(ObservationProperties properties) { return this; } - public Event getSchedule() { + public ScheduleEvent getSchedule() { return schedule; } - public Observation setSchedule(Event schedule) { + public Observation setSchedule(ScheduleEvent schedule) { this.schedule = schedule; return this; } diff --git a/studymanager/src/main/java/io/redlink/more/studymanager/model/scheduler/Duration.java b/studymanager/src/main/java/io/redlink/more/studymanager/model/scheduler/Duration.java new file mode 100644 index 00000000..1477ccb7 --- /dev/null +++ b/studymanager/src/main/java/io/redlink/more/studymanager/model/scheduler/Duration.java @@ -0,0 +1,118 @@ +package io.redlink.more.studymanager.model.scheduler; + +import com.fasterxml.jackson.annotation.JsonCreator; +import io.redlink.more.studymanager.api.v1.model.DurationDTO; + +public class Duration { + + private Integer value; + + /** + * unit of time to offset + */ + public enum Unit { + MINUTE("MINUTE"), + + HOUR("HOUR"), + + DAY("DAY"); + + private String value; + + Unit(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static Unit fromValue(String value) { + for (Unit b : Unit.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } + + public static Unit fromDurationDTOUnit(DurationDTO.UnitEnum unit) { + switch (unit) { + case MINUTE: + return MINUTE; + case HOUR: + return HOUR; + case DAY: + return DAY; + default: + throw new IllegalArgumentException("Unexpected value '" + unit + "'"); + } + } + + public static DurationDTO.UnitEnum toDurationDTOUnit(Unit unit) { + switch (unit) { + case MINUTE: + return DurationDTO.UnitEnum.MINUTE; + case HOUR: + return DurationDTO.UnitEnum.HOUR; + case DAY: + return DurationDTO.UnitEnum.DAY; + default: + throw new IllegalArgumentException("Unexpected value '" + unit + "'"); + } + } + } + + private Unit unit; + + public Duration() { + } + + public Integer getValue() { + return value; + } + + public Duration setValue(Integer value) { + this.value = value; + return this; + } + + public Unit getUnit() { + return unit; + } + + public Duration setUnit(Unit unit) { + this.unit = unit; + return this; + } + + public static DurationDTO toDurationDTO(Duration duration) { + if (duration != null) + return new DurationDTO() + .value(duration.getValue()) + .unit(Unit.toDurationDTOUnit(duration.unit)); + else return null; + } + + public static Duration fromDurationDTO(DurationDTO dto) { + if (dto != null) + return new Duration() + .setValue(dto.getValue()) + .setUnit(Unit.fromDurationDTOUnit(dto.getUnit())); + else return null; + } + + @Override + public String toString() { + return "Duration{" + + "offset=" + value + + ", unit=" + unit + + '}'; + } +} diff --git a/studymanager/src/main/java/io/redlink/more/studymanager/model/Event.java b/studymanager/src/main/java/io/redlink/more/studymanager/model/scheduler/Event.java similarity index 73% rename from studymanager/src/main/java/io/redlink/more/studymanager/model/Event.java rename to studymanager/src/main/java/io/redlink/more/studymanager/model/scheduler/Event.java index 6ca3a545..dab71fb0 100644 --- a/studymanager/src/main/java/io/redlink/more/studymanager/model/Event.java +++ b/studymanager/src/main/java/io/redlink/more/studymanager/model/scheduler/Event.java @@ -1,12 +1,19 @@ -package io.redlink.more.studymanager.model; +package io.redlink.more.studymanager.model.scheduler; import java.time.Instant; -public class Event { +public class Event implements ScheduleEvent { + public static final String TYPE = "Event"; + private String type; private Instant dateStart; private Instant dateEnd; private RecurrenceRule recurrenceRule; + @Override + public String getType() { + return TYPE; + } + public Instant getDateStart() { return dateStart; } @@ -33,4 +40,6 @@ public Event setRRule(RecurrenceRule recurrenceRule) { this.recurrenceRule = recurrenceRule; return this; } + + } diff --git a/studymanager/src/main/java/io/redlink/more/studymanager/model/RecurrenceRule.java b/studymanager/src/main/java/io/redlink/more/studymanager/model/scheduler/RecurrenceRule.java similarity index 97% rename from studymanager/src/main/java/io/redlink/more/studymanager/model/RecurrenceRule.java rename to studymanager/src/main/java/io/redlink/more/studymanager/model/scheduler/RecurrenceRule.java index b88d5a00..00e68eb3 100644 --- a/studymanager/src/main/java/io/redlink/more/studymanager/model/RecurrenceRule.java +++ b/studymanager/src/main/java/io/redlink/more/studymanager/model/scheduler/RecurrenceRule.java @@ -1,4 +1,4 @@ -package io.redlink.more.studymanager.model; +package io.redlink.more.studymanager.model.scheduler; import java.time.Instant; import java.util.List; diff --git a/studymanager/src/main/java/io/redlink/more/studymanager/model/scheduler/RelativeDate.java b/studymanager/src/main/java/io/redlink/more/studymanager/model/scheduler/RelativeDate.java new file mode 100644 index 00000000..f324e44c --- /dev/null +++ b/studymanager/src/main/java/io/redlink/more/studymanager/model/scheduler/RelativeDate.java @@ -0,0 +1,28 @@ +package io.redlink.more.studymanager.model.scheduler; + +public class RelativeDate { + + private Duration offset; + private String time; + + public RelativeDate() { + } + + public Duration getOffset() { + return offset; + } + + public RelativeDate setOffset(Duration offset) { + this.offset = offset; + return this; + } + + public String getTime() { + return time; + } + + public RelativeDate setTime(String time) { + this.time = time; + return this; + } +} diff --git a/studymanager/src/main/java/io/redlink/more/studymanager/model/scheduler/RelativeEvent.java b/studymanager/src/main/java/io/redlink/more/studymanager/model/scheduler/RelativeEvent.java new file mode 100644 index 00000000..5a7ef139 --- /dev/null +++ b/studymanager/src/main/java/io/redlink/more/studymanager/model/scheduler/RelativeEvent.java @@ -0,0 +1,57 @@ +package io.redlink.more.studymanager.model.scheduler; + +import io.redlink.more.studymanager.api.v1.model.RelativeDateDTO; +import io.redlink.more.studymanager.api.v1.model.RelativeRecurrenceRuleDTO; + +public class RelativeEvent implements ScheduleEvent { + + public static final String TYPE = "RelativeEvent"; + + private String type; + + private RelativeDate dtstart; + + private RelativeDate dtend; + + private RelativeRecurrenceRule rrrule; + + public RelativeEvent() { + } + + @Override + public String getType() { + return TYPE; + } + + public RelativeEvent setType(String type) { + this.type = type; + return this; + } + + public RelativeDate getDtstart() { + return dtstart; + } + + public RelativeEvent setDtstart(RelativeDate dtstart) { + this.dtstart = dtstart; + return this; + } + + public RelativeDate getDtend() { + return dtend; + } + + public RelativeEvent setDtend(RelativeDate dtend) { + this.dtend = dtend; + return this; + } + + public RelativeRecurrenceRule getRrrule() { + return rrrule; + } + + public RelativeEvent setRrrule(RelativeRecurrenceRule rrrule) { + this.rrrule = rrrule; + return this; + } +} diff --git a/studymanager/src/main/java/io/redlink/more/studymanager/model/scheduler/RelativeRecurrenceRule.java b/studymanager/src/main/java/io/redlink/more/studymanager/model/scheduler/RelativeRecurrenceRule.java new file mode 100644 index 00000000..abfaf462 --- /dev/null +++ b/studymanager/src/main/java/io/redlink/more/studymanager/model/scheduler/RelativeRecurrenceRule.java @@ -0,0 +1,29 @@ +package io.redlink.more.studymanager.model.scheduler; + +public class RelativeRecurrenceRule { + + private Duration frequency; + + private Duration endAfter; + + public RelativeRecurrenceRule() { + } + + public Duration getFrequency() { + return frequency; + } + + public RelativeRecurrenceRule setFrequency(Duration frequency) { + this.frequency = frequency; + return this; + } + + public Duration getEndAfter() { + return endAfter; + } + + public RelativeRecurrenceRule setEndAfter(Duration endAfter) { + this.endAfter = endAfter; + return this; + } +} diff --git a/studymanager/src/main/java/io/redlink/more/studymanager/model/scheduler/ScheduleEvent.java b/studymanager/src/main/java/io/redlink/more/studymanager/model/scheduler/ScheduleEvent.java new file mode 100644 index 00000000..079867d0 --- /dev/null +++ b/studymanager/src/main/java/io/redlink/more/studymanager/model/scheduler/ScheduleEvent.java @@ -0,0 +1,18 @@ +package io.redlink.more.studymanager.model.scheduler; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +@JsonIgnoreProperties( + value = "type", // ignore manually set type, it will be automatically generated by Jackson during serialization + allowSetters = true // allows the type to be set during deserialization +) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type", visible = true, defaultImpl = Event.class) +@JsonSubTypes({ + @JsonSubTypes.Type(value = Event.class, name = Event.TYPE), + @JsonSubTypes.Type(value = RelativeEvent.class, name = RelativeEvent.TYPE) +}) +public interface ScheduleEvent { + public String getType(); +} diff --git a/studymanager/src/main/java/io/redlink/more/studymanager/model/transformer/EventTransformer.java b/studymanager/src/main/java/io/redlink/more/studymanager/model/transformer/EventTransformer.java index 4ed3a42b..029bccc3 100644 --- a/studymanager/src/main/java/io/redlink/more/studymanager/model/transformer/EventTransformer.java +++ b/studymanager/src/main/java/io/redlink/more/studymanager/model/transformer/EventTransformer.java @@ -1,32 +1,62 @@ package io.redlink.more.studymanager.model.transformer; -import io.redlink.more.studymanager.api.v1.model.EventDTO; -import io.redlink.more.studymanager.api.v1.model.FrequencyDTO; -import io.redlink.more.studymanager.api.v1.model.RecurrenceRuleDTO; -import io.redlink.more.studymanager.api.v1.model.WeekdayDTO; -import io.redlink.more.studymanager.model.Event; -import io.redlink.more.studymanager.model.RecurrenceRule; +import io.redlink.more.studymanager.api.v1.model.*; +import io.redlink.more.studymanager.model.scheduler.*; public final class EventTransformer { private EventTransformer() { } - public static Event fromEventDTO_V1(EventDTO dto) { - if (dto != null) - return new Event() - .setDateStart(Transformers.toInstant(dto.getDtstart())) - .setDateEnd(Transformers.toInstant(dto.getDtend())) - .setRRule(fromRecurrenceRuleDTO(dto.getRrule())); + public static ScheduleEvent fromObservationScheduleDTO_V1(ObservationScheduleDTO genericDto) { + if (genericDto != null) { + if(genericDto.getType() == null || Event.TYPE.equals(genericDto.getType())) { + EventDTO dto = (EventDTO) genericDto; + return new Event() + .setDateStart(Transformers.toInstant(dto.getDtstart())) + .setDateEnd(Transformers.toInstant(dto.getDtend())) + .setRRule(fromRecurrenceRuleDTO(dto.getRrule())); + } else if(RelativeEvent.TYPE.equals(genericDto.getType())) { + RelativeEventDTO dto = (RelativeEventDTO) genericDto; + return new RelativeEvent() + .setDtstart(new RelativeDate() + .setOffset(fromDurationDTO(dto.getDtstart().getOffset())) + .setTime(dto.getDtstart().getTime())) + .setDtend(new RelativeDate() + .setOffset(fromDurationDTO(dto.getDtend().getOffset())) + .setTime(dto.getDtend().getTime())) + .setRrrule(fromRelativeRecurrenceRuleDTO(dto.getRrrule())); + + } else { + throw new IllegalArgumentException("Unknown Event Type: " + genericDto.getType()); + } + } else return null; } - public static EventDTO toEventDTO_V1(Event event) { + public static ObservationScheduleDTO toObservationScheduleDTO_V1(ScheduleEvent event) { if (event != null) - return new EventDTO() - .dtstart(Transformers.toOffsetDateTime(event.getDateStart())) - .dtend(Transformers.toOffsetDateTime(event.getDateEnd())) - .rrule(toRecurrenceRuleDTO(event.getRRule())); + if(event.getType() == null || Event.TYPE.equals(event.getType())) { + Event e = (Event) event; + return new EventDTO() + .type(Event.TYPE) + .dtstart(Transformers.toOffsetDateTime(e.getDateStart())) + .dtend(Transformers.toOffsetDateTime(e.getDateEnd())) + .rrule(toRecurrenceRuleDTO(e.getRRule())); + } else if(RelativeEvent.TYPE.equals(event.getType())) { + RelativeEvent e = (RelativeEvent) event; + return new RelativeEventDTO() + .type(RelativeEvent.TYPE) + .dtstart(new RelativeDateDTO() + .offset(toDurationDTO(e.getDtstart().getOffset())) + .time(e.getDtstart().getTime())) + .dtend(new RelativeDateDTO() + .offset(toDurationDTO(e.getDtend().getOffset())) + .time(e.getDtend().getTime())) + .rrrule(toRelativeRecurrenceRuleDTO(e.getRrrule())); + } else { + throw new IllegalArgumentException("Unknown Event Type: " + event.getType()); + } else return null; } @@ -57,4 +87,36 @@ private static RecurrenceRuleDTO toRecurrenceRuleDTO(RecurrenceRule recurrenceRu .bysetpos(recurrenceRule.getBySetPos()); else return null; } + + private static RelativeRecurrenceRuleDTO toRelativeRecurrenceRuleDTO(RelativeRecurrenceRule relativeRecurrenceRule) { + if (relativeRecurrenceRule != null) + return new RelativeRecurrenceRuleDTO() + .frequency(toDurationDTO(relativeRecurrenceRule.getFrequency())) + .endAfter(toDurationDTO(relativeRecurrenceRule.getEndAfter())); + else return null; + } + + private static RelativeRecurrenceRule fromRelativeRecurrenceRuleDTO(RelativeRecurrenceRuleDTO dto) { + if (dto != null) + return new RelativeRecurrenceRule() + .setFrequency(fromDurationDTO(dto.getFrequency())) + .setEndAfter(fromDurationDTO(dto.getEndAfter())); + else return null; + } + + private static Duration fromDurationDTO(DurationDTO dto) { + if (dto != null) + return new Duration() + .setValue(dto.getValue()) + .setUnit(dto.getUnit() != null ? Duration.Unit.fromDurationDTOUnit(dto.getUnit()) : null); + else return null; + } + + private static DurationDTO toDurationDTO(Duration duration) { + if (duration != null) + return new DurationDTO() + .value(duration.getValue()) + .unit(duration.getUnit() != null ? Duration.Unit.toDurationDTOUnit(duration.getUnit()) : null); + else return null; + } } diff --git a/studymanager/src/main/java/io/redlink/more/studymanager/model/transformer/InterventionTransformer.java b/studymanager/src/main/java/io/redlink/more/studymanager/model/transformer/InterventionTransformer.java index 95943f04..2764cf30 100644 --- a/studymanager/src/main/java/io/redlink/more/studymanager/model/transformer/InterventionTransformer.java +++ b/studymanager/src/main/java/io/redlink/more/studymanager/model/transformer/InterventionTransformer.java @@ -15,7 +15,7 @@ public static Intervention fromInterventionDTO_V1(InterventionDTO dto) { .setTitle(dto.getTitle()) .setPurpose(dto.getPurpose()) .setStudyGroupId(dto.getStudyGroupId()) - .setSchedule(EventTransformer.fromEventDTO_V1(dto.getSchedule())); + .setSchedule(EventTransformer.fromObservationScheduleDTO_V1(dto.getSchedule())); } public static InterventionDTO toInterventionDTO_V1(Intervention intervention) { @@ -25,7 +25,7 @@ public static InterventionDTO toInterventionDTO_V1(Intervention intervention) { .title(intervention.getTitle()) .purpose(intervention.getPurpose()) .studyGroupId(intervention.getStudyGroupId()) - .schedule(EventTransformer.toEventDTO_V1(intervention.getSchedule())) + .schedule(EventTransformer.toObservationScheduleDTO_V1(intervention.getSchedule())) .created(Transformers.toOffsetDateTime(intervention.getCreated())) .modified(Transformers.toOffsetDateTime(intervention.getModified())); } diff --git a/studymanager/src/main/java/io/redlink/more/studymanager/model/transformer/ObservationTransformer.java b/studymanager/src/main/java/io/redlink/more/studymanager/model/transformer/ObservationTransformer.java index fc21ab5c..5e6881fa 100644 --- a/studymanager/src/main/java/io/redlink/more/studymanager/model/transformer/ObservationTransformer.java +++ b/studymanager/src/main/java/io/redlink/more/studymanager/model/transformer/ObservationTransformer.java @@ -20,7 +20,7 @@ public static Observation fromObservationDTO_V1(ObservationDTO dto) { .setType(dto.getType()) .setStudyGroupId(dto.getStudyGroupId()) .setProperties(MapperUtils.MAPPER.convertValue(dto.getProperties(), ObservationProperties.class)) - .setSchedule(EventTransformer.fromEventDTO_V1(dto.getSchedule())) + .setSchedule(EventTransformer.fromObservationScheduleDTO_V1(dto.getSchedule())) .setHidden(dto.getHidden()) .setNoSchedule(dto.getNoSchedule()); } @@ -35,7 +35,7 @@ public static ObservationDTO toObservationDTO_V1(Observation observation) { .type(observation.getType()) .studyGroupId(observation.getStudyGroupId()) .properties(observation.getProperties()) - .schedule(EventTransformer.toEventDTO_V1(observation.getSchedule())) + .schedule(EventTransformer.toObservationScheduleDTO_V1(observation.getSchedule())) .created(Transformers.toOffsetDateTime(observation.getCreated())) .modified(Transformers.toOffsetDateTime(observation.getModified())) .hidden(observation.getHidden()) diff --git a/studymanager/src/main/java/io/redlink/more/studymanager/repository/InterventionRepository.java b/studymanager/src/main/java/io/redlink/more/studymanager/repository/InterventionRepository.java index 75894520..fecc9f3b 100644 --- a/studymanager/src/main/java/io/redlink/more/studymanager/repository/InterventionRepository.java +++ b/studymanager/src/main/java/io/redlink/more/studymanager/repository/InterventionRepository.java @@ -4,7 +4,7 @@ import io.redlink.more.studymanager.core.properties.TriggerProperties; import io.redlink.more.studymanager.exception.BadRequestException; import io.redlink.more.studymanager.model.Action; -import io.redlink.more.studymanager.model.Event; +import io.redlink.more.studymanager.model.scheduler.Event; import io.redlink.more.studymanager.model.Intervention; import io.redlink.more.studymanager.model.Trigger; import io.redlink.more.studymanager.utils.MapperUtils; diff --git a/studymanager/src/main/java/io/redlink/more/studymanager/repository/ObservationRepository.java b/studymanager/src/main/java/io/redlink/more/studymanager/repository/ObservationRepository.java index fbf59479..4326513a 100644 --- a/studymanager/src/main/java/io/redlink/more/studymanager/repository/ObservationRepository.java +++ b/studymanager/src/main/java/io/redlink/more/studymanager/repository/ObservationRepository.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import io.redlink.more.studymanager.core.properties.ObservationProperties; import io.redlink.more.studymanager.exception.BadRequestException; -import io.redlink.more.studymanager.model.Event; +import io.redlink.more.studymanager.model.scheduler.Event; import io.redlink.more.studymanager.model.Observation; import io.redlink.more.studymanager.utils.MapperUtils; import java.util.List; diff --git a/studymanager/src/main/resources/openapi/Event.yaml b/studymanager/src/main/resources/openapi/Event.yaml index ff98614c..a8a949a4 100644 --- a/studymanager/src/main/resources/openapi/Event.yaml +++ b/studymanager/src/main/resources/openapi/Event.yaml @@ -9,6 +9,9 @@ components: Event: type: object properties: + type: + type: string + default: Event dtstart: type: string format: date-time diff --git a/studymanager/src/main/resources/openapi/RelativeEvent.yaml b/studymanager/src/main/resources/openapi/RelativeEvent.yaml new file mode 100644 index 00000000..90898a22 --- /dev/null +++ b/studymanager/src/main/resources/openapi/RelativeEvent.yaml @@ -0,0 +1,63 @@ +openapi: "3.0.3" +info: + title: TimeRange Model for Relative Events + version: "1.0" + +components: + schemas: + Duration: + type: object + description: A duration of time + properties: + value: + type: integer + description: number of units + unit: + type: string + description: unit of time + enum: + - MINUTE + - HOUR + - DAY + RelativeDate: + type: object + description: A date relative to a specific base date (e.g study start) + properties: + offset: + $ref: '#/components/schemas/Duration' + time: + type: string + format: time + description: Follows ISO 8601 format for time + RelativeRecurrenceRule: + type: object + description: A recurrence rule relative to dtstart + properties: + frequency: + $ref: '#/components/schemas/Duration' + description: How often to repeat + endAfter: + $ref: '#/components/schemas/Duration' + description: How long to repeat + + RelativeEvent: + type: object + description: An event that occurs at a relative time + required: + - type + - dtstart + - dtend + properties: + type: + type: string + default: RelativeEvent + dtstart: + $ref: '#/components/schemas/RelativeDate' + description: When the event starts + dtend: + $ref: '#/components/schemas/RelativeDate' + description: When the event ends + rrrule: + $ref: '#/components/schemas/RelativeRecurrenceRule' + description: How to repeat the event + diff --git a/studymanager/src/main/resources/openapi/StudyManagerAPI.yaml b/studymanager/src/main/resources/openapi/StudyManagerAPI.yaml index e1f8414c..e9556076 100644 --- a/studymanager/src/main/resources/openapi/StudyManagerAPI.yaml +++ b/studymanager/src/main/resources/openapi/StudyManagerAPI.yaml @@ -1422,7 +1422,16 @@ components: type: object additionalProperties: true schedule: - $ref: './Event.yaml/#/components/schemas/Event' + oneOf: + - $ref: './Event.yaml/#/components/schemas/Event' + - $ref: './RelativeEvent.yaml/#/components/schemas/RelativeEvent' + discriminator: + propertyName: type + # mapping: + # event: + # $ref: './Event.yaml/#/components/schemas/Event' + # relativeEvent: + # $ref: './RelativeEvent.yaml/#/components/schemas/RelativeEvent' created: type: string format: date-time @@ -1514,7 +1523,11 @@ components: purpose: type: string schedule: - $ref: './Event.yaml/#/components/schemas/Event' + oneOf: + - $ref: './Event.yaml/#/components/schemas/Event' + - $ref: './RelativeEvent.yaml/#/components/schemas/RelativeEvent' + discriminator: + propertyName: type trigger: $ref: '#/components/schemas/Trigger' actions: diff --git a/studymanager/src/test/java/io/redlink/more/studymanager/controller/studymanager/ImportExportControllerTest.java b/studymanager/src/test/java/io/redlink/more/studymanager/controller/studymanager/ImportExportControllerTest.java index f7840ae3..31bddbc7 100644 --- a/studymanager/src/test/java/io/redlink/more/studymanager/controller/studymanager/ImportExportControllerTest.java +++ b/studymanager/src/test/java/io/redlink/more/studymanager/controller/studymanager/ImportExportControllerTest.java @@ -5,6 +5,8 @@ import io.redlink.more.studymanager.core.properties.ObservationProperties; import io.redlink.more.studymanager.core.properties.TriggerProperties; import io.redlink.more.studymanager.model.*; +import io.redlink.more.studymanager.model.scheduler.Event; +import io.redlink.more.studymanager.model.scheduler.RecurrenceRule; import io.redlink.more.studymanager.repository.DownloadTokenRepository; import io.redlink.more.studymanager.service.ImportExportService; import io.redlink.more.studymanager.service.OAuth2AuthenticationService; diff --git a/studymanager/src/test/java/io/redlink/more/studymanager/controller/studymanager/InterventionControllerTest.java b/studymanager/src/test/java/io/redlink/more/studymanager/controller/studymanager/InterventionControllerTest.java index 390dbbaa..8886178a 100644 --- a/studymanager/src/test/java/io/redlink/more/studymanager/controller/studymanager/InterventionControllerTest.java +++ b/studymanager/src/test/java/io/redlink/more/studymanager/controller/studymanager/InterventionControllerTest.java @@ -8,7 +8,7 @@ import io.redlink.more.studymanager.core.properties.TriggerProperties; import io.redlink.more.studymanager.model.Action; import io.redlink.more.studymanager.model.AuthenticatedUser; -import io.redlink.more.studymanager.model.Event; +import io.redlink.more.studymanager.model.scheduler.Event; import io.redlink.more.studymanager.model.Intervention; import io.redlink.more.studymanager.model.PlatformRole; import io.redlink.more.studymanager.model.Trigger; diff --git a/studymanager/src/test/java/io/redlink/more/studymanager/controller/studymanager/ObservationControllerTest.java b/studymanager/src/test/java/io/redlink/more/studymanager/controller/studymanager/ObservationControllerTest.java index 7f776cbe..18be3b38 100644 --- a/studymanager/src/test/java/io/redlink/more/studymanager/controller/studymanager/ObservationControllerTest.java +++ b/studymanager/src/test/java/io/redlink/more/studymanager/controller/studymanager/ObservationControllerTest.java @@ -3,7 +3,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.redlink.more.studymanager.api.v1.model.EventDTO; import io.redlink.more.studymanager.api.v1.model.ObservationDTO; +import io.redlink.more.studymanager.api.v1.model.ObservationScheduleDTO; import io.redlink.more.studymanager.model.*; +import io.redlink.more.studymanager.model.scheduler.Event; import io.redlink.more.studymanager.service.IntegrationService; import io.redlink.more.studymanager.service.OAuth2AuthenticationService; import io.redlink.more.studymanager.service.ObservationService; @@ -136,7 +138,7 @@ void testEmptySchedule() throws Exception { ObservationDTO observationRequest = new ObservationDTO() .studyId(1L) .title("a different title") - .schedule(MapperUtils.readValue(new HashMap(), EventDTO.class)) + .schedule(MapperUtils.readValue("{\"type\":\"Event\"}", ObservationScheduleDTO.class)) .observationId(1); mvc.perform(post("/api/v1/studies/1/observations") @@ -146,7 +148,7 @@ void testEmptySchedule() throws Exception { .andExpect(status().isCreated()) .andExpect(jsonPath("$.title").value("title")) .andExpect(jsonPath("$.studyId").value(observationRequest.getStudyId())) - .andExpect(jsonPath("$.schedule").value(MapperUtils.readValue(new HashMap(), EventDTO.class))) + .andExpect(jsonPath("$.schedule").value(MapperUtils.readValue("{\"type\":\"Event\"}", ObservationScheduleDTO.class))) .andExpect(jsonPath("$.modified").exists()) .andExpect(jsonPath("$.created").exists()); } diff --git a/studymanager/src/test/java/io/redlink/more/studymanager/repository/IntegrationRepositoryTest.java b/studymanager/src/test/java/io/redlink/more/studymanager/repository/IntegrationRepositoryTest.java index af716414..7027d205 100644 --- a/studymanager/src/test/java/io/redlink/more/studymanager/repository/IntegrationRepositoryTest.java +++ b/studymanager/src/test/java/io/redlink/more/studymanager/repository/IntegrationRepositoryTest.java @@ -2,6 +2,8 @@ import io.redlink.more.studymanager.core.properties.ObservationProperties; import io.redlink.more.studymanager.model.*; +import io.redlink.more.studymanager.model.scheduler.Event; +import io.redlink.more.studymanager.model.scheduler.RecurrenceRule; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/studymanager/src/test/java/io/redlink/more/studymanager/repository/InterventionRepositoryTest.java b/studymanager/src/test/java/io/redlink/more/studymanager/repository/InterventionRepositoryTest.java index 77406a68..37552fcd 100644 --- a/studymanager/src/test/java/io/redlink/more/studymanager/repository/InterventionRepositoryTest.java +++ b/studymanager/src/test/java/io/redlink/more/studymanager/repository/InterventionRepositoryTest.java @@ -3,6 +3,8 @@ import io.redlink.more.studymanager.core.properties.ActionProperties; import io.redlink.more.studymanager.model.*; import io.redlink.more.studymanager.core.properties.TriggerProperties; +import io.redlink.more.studymanager.model.scheduler.Event; +import io.redlink.more.studymanager.model.scheduler.RecurrenceRule; import io.redlink.more.studymanager.utils.MapperUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -64,7 +66,7 @@ void testInsertListUpdateDelete() { assertThat(interventionResponse.getInterventionId()).isNotNull(); assertThat(interventionResponse.getTitle()).isEqualTo(intervention.getTitle()); - assertThat(interventionResponse.getSchedule().getDateStart()).isEqualTo(startTime); + assertThat(((Event)interventionResponse.getSchedule()).getDateStart()).isEqualTo(startTime); assertThat(MapperUtils.writeValueAsString(interventionResponse.getSchedule())) .isEqualTo(MapperUtils.writeValueAsString(intervention.getSchedule())); diff --git a/studymanager/src/test/java/io/redlink/more/studymanager/repository/ObservationRepositoryTest.java b/studymanager/src/test/java/io/redlink/more/studymanager/repository/ObservationRepositoryTest.java index 82a2f8af..fb6e9061 100644 --- a/studymanager/src/test/java/io/redlink/more/studymanager/repository/ObservationRepositoryTest.java +++ b/studymanager/src/test/java/io/redlink/more/studymanager/repository/ObservationRepositoryTest.java @@ -2,6 +2,8 @@ import io.redlink.more.studymanager.core.properties.ObservationProperties; import io.redlink.more.studymanager.model.*; +import io.redlink.more.studymanager.model.scheduler.Event; +import io.redlink.more.studymanager.model.scheduler.RecurrenceRule; import io.redlink.more.studymanager.utils.MapperUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; diff --git a/studymanager/src/test/java/io/redlink/more/studymanager/service/ImportExportServiceTest.java b/studymanager/src/test/java/io/redlink/more/studymanager/service/ImportExportServiceTest.java index 5ec21784..2c8741f3 100644 --- a/studymanager/src/test/java/io/redlink/more/studymanager/service/ImportExportServiceTest.java +++ b/studymanager/src/test/java/io/redlink/more/studymanager/service/ImportExportServiceTest.java @@ -4,6 +4,7 @@ import io.redlink.more.studymanager.core.properties.ObservationProperties; import io.redlink.more.studymanager.core.properties.TriggerProperties; import io.redlink.more.studymanager.model.*; +import io.redlink.more.studymanager.model.scheduler.Event; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; diff --git a/studymanager/src/test/java/io/redlink/more/studymanager/transformer/ScheduleEventTransformerTest.java b/studymanager/src/test/java/io/redlink/more/studymanager/transformer/ScheduleEventTransformerTest.java new file mode 100644 index 00000000..c705673a --- /dev/null +++ b/studymanager/src/test/java/io/redlink/more/studymanager/transformer/ScheduleEventTransformerTest.java @@ -0,0 +1,107 @@ +package io.redlink.more.studymanager.transformer; + +import co.elastic.clients.elasticsearch.watcher.Day; +import io.redlink.more.studymanager.api.v1.model.EventDTO; +import io.redlink.more.studymanager.api.v1.model.ObservationScheduleDTO; +import io.redlink.more.studymanager.api.v1.model.RelativeEventDTO; +import io.redlink.more.studymanager.model.scheduler.*; +import io.redlink.more.studymanager.model.transformer.EventTransformer; +import io.redlink.more.studymanager.utils.MapperUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.time.temporal.TemporalUnit; + +public class ScheduleEventTransformerTest { + + @Test + public void testJsonToEventTransformer() { + String jsonEvent = "{\"rrule\": null, \"dateEnd\": 1683755999.000000000, \"dateStart\": 1683669600.000000000}"; + + String jsonRelativeEvent1 = """ +{ + "type":"RelativeEvent", + "dtstart":{ + "offset":{ + "value":1, + "unit":"DAY" + }, + "time":"12:00:00" + }, + "dtend":{ + "offset":{ + "value":2, + "unit":"DAY" + }, + "time":"12:00:00" + } +} + """; + + String jsonRelativeEvent2 = """ +{ + "type":"RelativeEvent", + "dtstart":{ + "offset":{ + "value":1, + "unit":"DAY" + }, + "time":"12:00:00" + }, + "dtend":{ + "offset":{ + "value":2, + "unit":"DAY" + }, + "time":"12:00:00" + }, + "rrrule":{ + "frequency":{ + "unit":"DAY", + "value":1 + }, + "endAfter":{ + "unit":"DAY", + "value":10 + } + } +} + """; + + ScheduleEvent event = MapperUtils.readValue(jsonEvent, ScheduleEvent.class); + Assertions.assertTrue(event instanceof Event); + + ScheduleEvent eventRelative1 = MapperUtils.readValue(jsonRelativeEvent1, ScheduleEvent.class); + Assertions.assertTrue(eventRelative1 instanceof RelativeEvent); + + ScheduleEvent eventRelative2 = MapperUtils.readValue(jsonRelativeEvent2, ScheduleEvent.class); + Assertions.assertTrue(eventRelative2 instanceof RelativeEvent); + } + + @Test + public void testDTOTransformer() { + Event event = new Event() + .setDateStart(Instant.now().plus(1, ChronoUnit.DAYS)) + .setDateEnd(Instant.now().plus(2, ChronoUnit.DAYS)); + + RelativeEvent relativeEvent = new RelativeEvent() + .setDtstart(new RelativeDate() + .setTime("12:00:00") + .setOffset(new Duration().setUnit(Duration.Unit.DAY).setValue(3))) + .setDtend(new RelativeDate() + .setTime("12:00:00") + .setOffset(new Duration().setUnit(Duration.Unit.DAY).setValue(4))) + .setRrrule(new RelativeRecurrenceRule() + .setFrequency(new Duration().setUnit(Duration.Unit.DAY).setValue(1)) + .setEndAfter(new Duration().setUnit(Duration.Unit.DAY).setValue(10))); + + ObservationScheduleDTO eventDTO = EventTransformer.toObservationScheduleDTO_V1(event); + ObservationScheduleDTO relativeEventDTO = EventTransformer.toObservationScheduleDTO_V1(relativeEvent); + + Assertions.assertTrue(eventDTO instanceof EventDTO); + Assertions.assertTrue(relativeEventDTO instanceof RelativeEventDTO); + + } +}