Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
17 changes: 8 additions & 9 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@

<java.version>17</java.version>
<spring-boot.version>3.5.5</spring-boot.version>
<testcontainers.version>1.21.3</testcontainers.version>

<testcontainers.version>2.0.2</testcontainers.version>
<docker.namespace>more-project</docker.namespace>

<start-class>io.redlink.more.studymanager.Application</start-class>
Expand Down Expand Up @@ -404,20 +403,20 @@
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>${testcontainers.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>

<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>${testcontainers.version}</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>

<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,14 @@ public LimeSurveyObservation(MoreObservationSDK sdk, C properties, LimeSurveyReq
public void activate(){
String surveyId = checkAndGetSurveyId();

//FIXME: This creates a LIME survey user for every participant, regardless if the Observation is relevant to the participant
Set<Integer> participantIds = sdk.participantIds(MorePlatformSDK.ParticipantFilter.ALL);
//FIXME: Check for the expected keys (token and limeUrl) and not just if any properties are present!
participantIds.removeIf(id -> sdk.getPropertiesForParticipant(id).isPresent());
limeSurveyRequestService.activateParticipants(participantIds, surveyId)
.forEach(data ->
sdk.setPropertiesForParticipant(
Integer.parseInt(data.firstname()),
Integer.parseInt(data.firstname()), //NOTE: both the firstname and lastname are set to the participantId
new ObservationProperties(
Map.of("token", data.token(),
"limeUrl", limeSurveyRequestService.getBaseUrl())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,13 @@ public class LimeSurveyObservationFactory<C extends LimeSurveyObservation<P>, P

public LimeSurveyObservationFactory() {}

public LimeSurveyObservationFactory(
//FIXME: Try to get rid of constructors only used by UnitTests to Mock the LimeSurveyRequestService
LimeSurveyObservationFactory(
ComponentFactoryProperties properties, LimeSurveyRequestService limeSurveyRequestService) {
this.componentProperties = properties;
this.limeSurveyRequestService = limeSurveyRequestService;
}

@Override
public LimeSurveyObservationFactory<C, P> init(ComponentFactoryProperties componentProperties){
this.componentProperties = componentProperties;
Expand Down
6 changes: 3 additions & 3 deletions studymanager-services/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -139,17 +139,17 @@
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<artifactId>testcontainers-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<artifactId>testcontainers-postgresql</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>elasticsearch</artifactId>
<artifactId>testcontainers-elasticsearch</artifactId>
<scope>test</scope>
</dependency>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ public static NotFoundException Study(long id) {
public static NotFoundException StudyGroup(long studyId, int studyGroupId) {
return new NotFoundException("StudyGroup", studyId + "/" + studyGroupId);
}
public static NotFoundException ObservationGroup(long studyId, int observationGroupId) {
return new NotFoundException("ObservationGroup", studyId + "/" + observationGroupId);
}

public static NotFoundException Participant(long studyId, int participantId) {
return new NotFoundException("Participant", studyId + "/" + participantId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public class Intervention {
private ScheduleEvent schedule;
private Instant created;
private Instant modified;
private Integer observationGroupId;

public Long getStudyId() {
return studyId;
Expand Down Expand Up @@ -67,6 +68,15 @@ public Intervention setStudyGroupId(Integer studyGroupId) {
return this;
}

public Integer getObservationGroupId() {
return observationGroupId;
}

public Intervention setObservationGroupId(Integer observationGroupId) {
this.observationGroupId = observationGroupId;
return this;
}

public ScheduleEvent getSchedule() {
return schedule;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class Observation {
private Instant modified;
private Boolean hidden;
private Boolean noSchedule = false;
private Integer observationGroupId;

public Long getStudyId() {
return studyId;
Expand Down Expand Up @@ -91,6 +92,15 @@ public Observation setStudyGroupId(Integer studyGroupId) {
return this;
}

public Integer getObservationGroupId() {
return observationGroupId;
}

public Observation setObservationGroupId(Integer observationGroupId) {
this.observationGroupId = observationGroupId;
return this;
}

public ObservationProperties getProperties() {
return properties;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright LBI-DHP and/or licensed to LBI-DHP under one or more
* contributor license agreements (LBI-DHP: Ludwig Boltzmann Institute
* for Digital Health and Prevention -- A research institute of the
* Ludwig Boltzmann Gesellschaft, Österreichische Vereinigung zur
* Förderung der wissenschaftlichen Forschung).
* Licensed under the Elastic License 2.0.
*/
package io.redlink.more.studymanager.model;

import io.redlink.more.studymanager.model.scheduler.Duration;

import java.time.Instant;

public class ObservationGroup {
private Long studyId;
private Integer observationGroupId;
private String title;
private String purpose;
private Instant created;
private Instant modified;

public Long getStudyId() {
return studyId;
}

public ObservationGroup setStudyId(Long studyId) {
this.studyId = studyId;
return this;
}

public Integer getObservationGroupId() {
return observationGroupId;
}

public ObservationGroup setObservationGroupId(Integer observationGroupId) {
this.observationGroupId = observationGroupId;
return this;
}

public String getTitle() {
return title;
}

public ObservationGroup setTitle(String title) {
this.title = title;
return this;
}

public String getPurpose() {
return purpose;
}

public ObservationGroup setPurpose(String purpose) {
this.purpose = purpose;
return this;
}

public Instant getCreated() {
return created;
}

public ObservationGroup setCreated(Instant created) {
this.created = created;
return this;
}

public Instant getModified() {
return modified;
}

public ObservationGroup setModified(Instant modified) {
this.modified = modified;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
*/
package io.redlink.more.studymanager.model;
import java.time.Instant;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

public class Participant {
private Long studyId;
Expand All @@ -19,6 +22,7 @@ public class Participant {
private Instant modified;
private Instant start;
private String registrationToken;
private Set<Integer> observationGroupIds = new HashSet<>();

public Long getStudyId() {
return this.studyId;
Expand Down Expand Up @@ -92,6 +96,27 @@ public Participant setStudyGroupId(Integer studyGroupId) {
return this;
}

public Participant setObservationGroupIds(Set<Integer> observationGroupIds) {
this.observationGroupIds = observationGroupIds == null ? new HashSet<>() : observationGroupIds;
return this;
}

public Set<Integer> getObservationGroupIds() {
return observationGroupIds;
}

public Participant addObservationGroupId(Integer observationGroupId) {
if(observationGroupIds != null) {
this.observationGroupIds.add(observationGroupId);
}
return this;
}

public Participant removeObservationGroupId(Integer observationGroupId) {
this.observationGroupIds.remove(observationGroupId);
return this;
}

public Instant getCreated() {
return created;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@

import java.util.List;
import java.util.Map;
import java.util.Set;

public class StudyImportExport {

private Study study;
private List<StudyGroup> studyGroups;
private List<ObservationGroup> observationGroups;
private List<Observation> observations;
private List<Intervention> interventions;
private List<ParticipantInfo> participants;
Expand All @@ -40,6 +42,15 @@ public StudyImportExport setStudyGroups(List<StudyGroup> studyGroups) {
return this;
}

public List<ObservationGroup> getObservationGroups() {
return observationGroups;
}

public StudyImportExport setObservationGroups(List<ObservationGroup> observationGroups) {
this.observationGroups = observationGroups;
return this;
}

public List<Observation> getObservations() {
return observations;
}
Expand Down Expand Up @@ -95,6 +106,7 @@ public StudyImportExport setIntegrations(List<IntegrationInfo> integrations) {
}

public record ParticipantInfo(
Integer groupId
Integer groupId,
Set<Integer> observationGroupIds
) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,22 @@
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.List;

import static io.redlink.more.studymanager.repository.RepositoryUtils.getValidNullableIntegerValue;

@Component
public class InterventionRepository {

private static final String INSERT_INTERVENTION = "INSERT INTO interventions(study_id,intervention_id,title,purpose,study_group_id,schedule) VALUES (:study_id,(SELECT COALESCE(MAX(intervention_id),0)+1 FROM interventions WHERE study_id = :study_id),:title,:purpose,:study_group_id,:schedule::jsonb) RETURNING *";
private static final String IMPORT_INTERVENTION = "INSERT INTO interventions(study_id,intervention_id,title,purpose,study_group_id,schedule) VALUES (:study_id,:intervention_id,:title,:purpose,:study_group_id,:schedule::jsonb) RETURNING *";
private static final String INSERT_INTERVENTION = "INSERT INTO interventions(study_id,intervention_id,title,purpose,study_group_id,schedule,observation_group_id) VALUES (:study_id,(SELECT COALESCE(MAX(intervention_id),0)+1 FROM interventions WHERE study_id = :study_id),:title,:purpose,:study_group_id,:schedule::jsonb,:observation_group_id) RETURNING *";
private static final String IMPORT_INTERVENTION = "INSERT INTO interventions(study_id,intervention_id,title,purpose,study_group_id,schedule,observation_group_id) VALUES (:study_id,:intervention_id,:title,:purpose,:study_group_id,:schedule::jsonb,:observation_group_id) RETURNING *";
private static final String GET_INTERVENTION_BY_IDS = "SELECT * FROM interventions WHERE study_id = ? AND intervention_id = ?";
private static final String LIST_INTERVENTIONS = "SELECT * FROM interventions WHERE study_id = ?";
private static final String LIST_INTERVENTIONS_FOR_GROUP = "SELECT * FROM interventions WHERE study_id = :study_id AND (study_group_id IS NULL OR study_group_id = :study_group_id)";
private static final String LIST_INTERVENTIONS_FOR_GROUP = "SELECT * FROM interventions WHERE study_id = :study_id AND (study_group_id IS NULL OR study_group_id = :study_group_id) AND (observation_group_id IS NULL OR observation_group_id = ANY(:observation_group_ids::INT[]))";
private static final String DELETE_INTERVENTION_BY_IDS = "DELETE FROM interventions WHERE study_id = ? AND intervention_id = ?";
private static final String DELETE_ALL = "DELETE FROM interventions";
private static final String UPDATE_INTERVENTION = "UPDATE interventions SET title=:title, study_group_id=:study_group_id, purpose=:purpose, schedule=:schedule::jsonb WHERE study_id=:study_id AND intervention_id=:intervention_id";
private static final String UPDATE_INTERVENTION = "UPDATE interventions SET title=:title, study_group_id=:study_group_id, purpose=:purpose, schedule=:schedule::jsonb, observation_group_id=:observation_group_id WHERE study_id=:study_id AND intervention_id=:intervention_id";
private static final String CREATE_ACTION = "INSERT INTO actions(study_id,intervention_id,action_id,type,properties) VALUES (:study_id,:intervention_id,(SELECT COALESCE(MAX(action_id),0)+1 FROM actions WHERE study_id = :study_id AND intervention_id=:intervention_id),:type,:properties::jsonb) RETURNING *";
private static final String IMPORT_ACTION = "INSERT INTO actions(study_id,intervention_id,action_id,type,properties) VALUES (:study_id,:intervention_id,:action_id,:type,:properties::jsonb) RETURNING *";
private static final String GET_ACTION_BY_IDS = "SELECT * FROM actions WHERE study_id=? AND intervention_id=? AND action_id=?";
Expand All @@ -60,7 +61,7 @@ public Intervention insert(Intervention intervention) {
try {
return namedTemplate.queryForObject(INSERT_INTERVENTION, interventionToParams(intervention), getInterventionRowMapper());
} catch (DataIntegrityViolationException e) {
throw new BadRequestException("Study group " + intervention.getStudyGroupId() + " does not exist on study " + intervention.getStudyId());
throw new BadRequestException("Unable to insert Invervention because it refers an not existing group (Study group " + intervention.getStudyGroupId() + " and/or Observation group " + intervention.getObservationGroupId() + " does not exist on study " + intervention.getStudyId());
}
}

Expand All @@ -76,7 +77,8 @@ public Intervention importIntervention(Long studyId, Intervention intervention)
"Error during import of intervention " +
intervention.getInterventionId() +
"for study " +
intervention.getStudyId()
intervention.getStudyId() +
"(" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")"
);
}
}
Expand All @@ -85,10 +87,14 @@ public List<Intervention> listInterventions(Long studyId) {
return template.query(LIST_INTERVENTIONS, getInterventionRowMapper(), studyId);
}

public List<Intervention> listInterventionsForGroup(Long studyId, Integer groupId) {
public List<Intervention> listInterventionsForGroup(Long studyId, Integer groupId){
return listInterventionsForGroup(studyId, groupId, List.of());
}
public List<Intervention> listInterventionsForGroup(Long studyId, Integer groupId, Collection<Integer> observationGroupIds) {
return namedTemplate.query(LIST_INTERVENTIONS_FOR_GROUP,
new MapSqlParameterSource("study_id", studyId)
.addValue("study_group_id", groupId),
.addValue("study_group_id", groupId)
.addValue("observation_group_ids", observationGroupIds == null ? new Integer[0] : observationGroupIds.toArray(new Integer[0])),
getInterventionRowMapper()
);
}
Expand Down Expand Up @@ -190,7 +196,8 @@ private static MapSqlParameterSource interventionToParams(Intervention intervent
.addValue("title", intervention.getTitle())
.addValue("purpose", intervention.getPurpose())
.addValue("study_group_id", intervention.getStudyGroupId())
.addValue("schedule", MapperUtils.writeValueAsString(intervention.getSchedule()));
.addValue("schedule", MapperUtils.writeValueAsString(intervention.getSchedule()))
.addValue("observation_group_id", intervention.getObservationGroupId());
}

private static MapSqlParameterSource triggerToParams(Long studyId, Integer interventionId, Trigger trigger) {
Expand Down Expand Up @@ -235,6 +242,7 @@ private static RowMapper<Intervention> getInterventionRowMapper() {
.setSchedule(MapperUtils.readValue(rs.getString("schedule"), Event.class))
.setStudyGroupId(getValidNullableIntegerValue(rs, "study_group_id"))
.setCreated(RepositoryUtils.readInstant(rs,"created"))
.setModified(RepositoryUtils.readInstant(rs,"modified"));
.setModified(RepositoryUtils.readInstant(rs,"modified"))
.setObservationGroupId(getValidNullableIntegerValue(rs, "observation_group_id"));
}
}
Loading
Loading