Skip to content
This repository was archived by the owner on May 5, 2021. It is now read-only.

Commit b237e87

Browse files
Merge pull request SORMAS-Foundation#2892 from hzi-braunschweig/feature-2638-2639-2640-climedo-demo
Feature 2638 2639 2640 climedo demo
2 parents e0752de + c187002 commit b237e87

11 files changed

Lines changed: 162 additions & 1 deletion

File tree

sormas-api/src/main/java/de/symeda/sormas/api/ConfigFacade.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ public interface ConfigFacade {
9696

9797
String getSymptomJournalSecret();
9898

99+
String getPatientDiaryUrl();
100+
99101
void validateExternalUrls();
100102

101103
Sormas2SormasConfig getSormas2SormasConfig();

sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,7 @@ public interface Captions {
387387
String Contact_caze_uuid = "Contact.caze.uuid";
388388
String Contact_cazeDisease = "Contact.cazeDisease";
389389
String Contact_cazeDistrict = "Contact.cazeDistrict";
390+
String Contact_climedoAccount = "Contact.climedoAccount";
390391
String Contact_community = "Contact.community";
391392
String Contact_communityUuid = "Contact.communityUuid";
392393
String Contact_contactCategory = "Contact.contactCategory";

sormas-api/src/main/java/de/symeda/sormas/api/person/PersonFacade.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ public interface PersonFacade {
3939

4040
PersonDto getPersonByUuid(String uuid);
4141

42+
PersonDto getPersonForJournal(String Uuid);
43+
4244
PersonDto savePerson(PersonDto dto);
4345

4446
void validate(PersonDto dto);

sormas-api/src/main/resources/captions.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,7 @@ Contact.caze.symptomsOnset=Symptoms onset
492492
Contact.caze.uuid=Case ID
493493
Contact.cazeDisease=Disease of source case
494494
Contact.cazeDistrict=District of source case
495+
Contact.climedoAccount=Climedo eDiary
495496
Contact.community=Responsible community
496497
Contact.contactClassification=Contact classification
497498
Contact.contactOfficer=Responsible contact officer

sormas-api/src/main/resources/captions_de-DE.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,7 @@ Contact.caze.symptomsOnset=Symptombeginn
492492
Contact.caze.uuid=Fall-ID
493493
Contact.cazeDisease=Krankheit des Indexfalls
494494
Contact.cazeDistrict=Landkreis des Indexfalls
495+
Contact.climedoAccount=Climedo Symptomtagebuch
495496
Contact.community=Zuständige Gemeinde
496497
Contact.contactClassification=Kontaktklassifikation
497498
Contact.contactOfficer=Verantwortliche*r (Gesundheitsamts-)Mitarbeiter*in

sormas-backend/src/main/java/de/symeda/sormas/backend/common/ConfigFacadeEjb.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ public class ConfigFacadeEjb implements ConfigFacade {
8787
public static final String INTERFACE_SYMPTOM_JOURNAL_CLIENT_ID = "interface.symptomjournal.clientid";
8888
public static final String INTERFACE_SYMPTOM_JOURNAL_SECRET = "interface.symptomjournal.secret";
8989

90+
public static final String INTERFACE_PATIENT_DIARY_URL = "interface.patientdiary.url";
91+
9092
public static final String DAYS_AFTER_CASE_GETS_ARCHIVED = "daysAfterCaseGetsArchived";
9193
private static final String DAYS_AFTER_EVENT_GETS_ARCHIVED = "daysAfterEventGetsArchived";
9294

@@ -367,6 +369,11 @@ public Sormas2SormasConfig getSormas2SormasConfig() {
367369
return config;
368370
}
369371

372+
@Override
373+
public String getPatientDiaryUrl() {
374+
return getProperty(INTERFACE_PATIENT_DIARY_URL, null);
375+
}
376+
370377
@Override
371378
public void validateExternalUrls() {
372379

sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import com.auth0.jwt.internal.org.apache.commons.lang3.StringUtils;
2121
import de.symeda.sormas.api.Disease;
22+
import de.symeda.sormas.api.FacadeProvider;
2223
import de.symeda.sormas.api.caze.CaseCriteria;
2324
import de.symeda.sormas.api.caze.CaseDataDto;
2425
import de.symeda.sormas.api.caze.CaseOutcome;
@@ -251,6 +252,28 @@ public PersonDto getPersonByUuid(String uuid) {
251252
.orElse(null);
252253
}
253254

255+
@Override
256+
public PersonDto getPersonForJournal(String Uuid) {
257+
PersonDto detailedPerson = getPersonByUuid(Uuid);
258+
//only specific attributes of the person shall be returned:
259+
if (detailedPerson != null) {
260+
PersonDto exportPerson = new PersonDto();
261+
exportPerson.setUuid(detailedPerson.getUuid());
262+
exportPerson.setEmailAddress(detailedPerson.getEmailAddress());
263+
exportPerson.setPhone(detailedPerson.getPhone());
264+
exportPerson.setPseudonymized(detailedPerson.isPseudonymized());
265+
exportPerson.setFirstName(detailedPerson.getFirstName());
266+
exportPerson.setLastName(detailedPerson.getLastName());
267+
exportPerson.setBirthdateYYYY(detailedPerson.getBirthdateYYYY());
268+
exportPerson.setBirthdateMM(detailedPerson.getBirthdateMM());
269+
exportPerson.setBirthdateDD(detailedPerson.getBirthdateDD());
270+
exportPerson.setSex(detailedPerson.getSex());
271+
return exportPerson;
272+
} else {
273+
return null;
274+
}
275+
}
276+
254277
@Override
255278
public PersonDto savePerson(PersonDto source) throws ValidationRuntimeException {
256279
Person person = personService.getByUuid(source.getUuid());

sormas-base/setup/sormas.properties

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,4 +139,8 @@ sms.auth.secret=
139139
#interface.symptomjournal.url=
140140
#interface.symptomjournal.authurl=
141141
#interface.symptomjournal.clientid=
142-
#interface.symptomjournal.secret=
142+
#interface.symptomjournal.secret=
143+
144+
# Website that is displayed in a new tab to show or create a climedo patient eDiary for a contact person; leave this commented
145+
# if you don't want to use this feature
146+
#interface.patientdiary.url=

sormas-rest/src/main/java/de/symeda/sormas/rest/ExternalVisitsResource.java

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,17 @@
33
import de.symeda.sormas.api.FacadeProvider;
44
import de.symeda.sormas.api.PushResult;
55
import de.symeda.sormas.api.person.PersonFollowUpEndDto;
6+
import de.symeda.sormas.api.person.PersonDto;
67
import de.symeda.sormas.api.person.PersonQuarantineEndDto;
78
import de.symeda.sormas.api.person.PersonSymptomJournalStatusDto;
89
import de.symeda.sormas.api.visit.ExternalVisitDto;
10+
import io.swagger.v3.oas.annotations.Operation;
11+
import io.swagger.v3.oas.annotations.Parameter;
12+
import io.swagger.v3.oas.annotations.enums.ParameterIn;
13+
import io.swagger.v3.oas.annotations.media.Content;
14+
import io.swagger.v3.oas.annotations.media.Schema;
15+
import io.swagger.v3.oas.annotations.parameters.RequestBody;
16+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
917

1018
import javax.annotation.security.RolesAllowed;
1119
import javax.ws.rs.Consumes;
@@ -14,6 +22,7 @@
1422
import javax.ws.rs.Path;
1523
import javax.ws.rs.PathParam;
1624
import javax.ws.rs.Produces;
25+
import javax.ws.rs.QueryParam;
1726
import javax.ws.rs.core.MediaType;
1827
import java.util.Date;
1928
import java.util.List;
@@ -26,14 +35,62 @@ public class ExternalVisitsResource extends EntityDtoResource {
2635

2736
public static final String EXTERNAL_VISITS_API_VERSION = "1.41.0";
2837

38+
@GET
39+
@Path("/person/{personUuid}")
40+
@Operation(summary = "Get person information", description = "Get some personal data for a specific person")
41+
@ApiResponse(
42+
description = "A selection of personal data, including first and last name, e-mail, phone number(s) and birth date if available"
43+
+ "for that person. Note that Null value fields may not be returned. If you get an unexpected result, it might help to verify"
44+
+ "if the personUuid is existing in your system via the isValid controller.",
45+
content = @Content(mediaType = "application/json",
46+
//@formatter:off
47+
schema = @Schema(example = "[" +
48+
" {" +
49+
" \"uuid\": \"UO2OCI-BPXSAO-7Q4RHO-RMXCKC4M\"," +
50+
" \"pseudonymized\": false," +
51+
" \"firstName\": \"Tim\"," +
52+
" \"lastName\": \"Tahler\"," +
53+
" \"sex\": \"MALE\"," +
54+
" \"birthdateDD\": 6," +
55+
" \"birthdateMM\": 4," +
56+
" \"birthdateYYYY\": 1974," +
57+
" \"phone\": \"0123456789\"," +
58+
" \"emailAddress\": \"[email protected]\"" +
59+
" }" +
60+
"]")))
61+
//@formatter:off
62+
public PersonDto getPersonByUuid(@PathParam("personUuid") String personUuid) {
63+
return FacadeProvider.getPersonFacade().getPersonForJournal(personUuid);
64+
};
65+
2966
@GET
3067
@Path("/person/{personUuid}/isValid")
68+
@Operation(summary = "Check person validity", description = "Check if a the Uuid given as parameter exists in SORMAS.",
69+
responses =
70+
@ApiResponse(description = "true a person with the given Uuid exists in SORMAS, false otherwise.", content = @Content(schema = @Schema(example = "true"))))
3171
public Boolean isValidPersonUuid(@PathParam("personUuid") String personUuid) {
3272
return FacadeProvider.getPersonFacade().isValidPersonUuid(personUuid);
3373
}
3474

75+
//@formatter:off
3576
@POST
3677
@Path("/person/{personUuid}/status")
78+
@Operation(summary = "Save symptom journal status",
79+
responses =
80+
@ApiResponse(description = "true if the status was set succesfully, false otherwise.",
81+
content = @Content(schema = @Schema(example = "true"))))
82+
@RequestBody(
83+
//@formatter:off
84+
description = "status may be one of the following:<br/>" +
85+
"UNREGISTERED: User has not yet sent any state<br/>" +
86+
"REGISTERED: After succesfull registration in SymptomJournal<br/>" +
87+
"ACCEPTED: User has accepted a confirmation<br/>" +
88+
"REJECTED: User has rejected (declined) a confirmation<br/>" +
89+
"DELETED: User was deleted",
90+
//@formatter:on
91+
content = @Content(schema = @Schema(example = "[\n {\n \"status\": \"REGISTERED\",\n"
92+
+ " \"statusDateTime\": \"2020-04-15T12:55:00.000+02:00\" // datetime format yyyy-MM-dd'T'HH:mm:ss.SSSZ\n }\n]")))
93+
//@formatter:on
3794
public boolean postSymptomJournalStatus(@PathParam("personUuid") String personUuid, PersonSymptomJournalStatusDto statusDto) {
3895
try {
3996
return FacadeProvider.getPersonFacade().setSymptomJournalStatus(personUuid, statusDto.getStatus());
@@ -44,13 +101,20 @@ public boolean postSymptomJournalStatus(@PathParam("personUuid") String personUu
44101

45102
@POST
46103
@Path("/")
104+
@Operation(summary = "Save visits",
105+
description = "Upload visits with all symptom and disease related data to SORMAS.",
106+
responses = @ApiResponse(description = "OK when visit was successfully saved, ERROR otherwise.",
107+
content = @Content(schema = @Schema(name = "processing", example = "OK"))))
47108
public List<PushResult> postExternalVisits(List<ExternalVisitDto> dtos) {
48109
List<PushResult> result = savePushedDto(dtos, FacadeProvider.getVisitFacade()::saveExternalVisit);
49110
return result;
50111
}
51112

52113
@GET
53114
@Path("/version")
115+
@Operation(summary = "Get API version")
116+
@ApiResponse(description = "The minimal version needed for compatibility with the external ReST API of SORMAS.",
117+
content = @Content(schema = @Schema(type = "string", example = "1.37.0")))
54118
public String getVersion() {
55119
return EXTERNAL_VISITS_API_VERSION;
56120
}
@@ -63,6 +127,24 @@ public List<PersonQuarantineEndDto> getLatestQuarantineEndDates(@PathParam("sinc
63127

64128
@GET
65129
@Path("/followUpEndDates/{since}")
130+
@Operation(summary = "Get follow up end dates",
131+
description = "Get latest follow up end date assigned to the specified person. "
132+
+ "Note: Only returns values for persons who have their symptom journal status set to ACCEPTED! "
133+
+ "Only returns values changed after {since}, which is interpreted as a UNIX timestamp.")
134+
//@formatter:off
135+
@ApiResponse(description = "List of personUuids and their latest follow up end dates as UNIX timestamps.",
136+
content = @Content(schema = @Schema(example = "[\n" +
137+
" {\n" +
138+
" \"personUuid\": \"Q56VFD-G3TXKT-R2DBIW-FTWIKAMI\",\n" +
139+
" \"latestFollowUpEndDate\": 1599602400000\n" +
140+
" },\n" +
141+
" {\n" +
142+
" \"personUuid\": \"TEYCIW-BHWHMH-MH2QIW-KBP72JMU\",\n" +
143+
" \"latestFollowUpEndDate\": 1593727200000\n" +
144+
" }\n" +
145+
"]")))
146+
//@formatter:on
147+
66148
public List<PersonFollowUpEndDto> getLatestFollowUpEndDates(@PathParam("since") long since) {
67149
return FacadeProvider.getPersonFacade().getLatestFollowUpEndDates(new Date(since), true);
68150
}

sormas-ui/src/main/java/de/symeda/sormas/ui/contact/AbstractContactView.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@
2525

2626
import de.symeda.sormas.api.Disease;
2727
import de.symeda.sormas.api.FacadeProvider;
28+
import de.symeda.sormas.api.contact.ContactCriteria;
2829
import de.symeda.sormas.api.contact.ContactDto;
30+
import de.symeda.sormas.api.contact.ContactIndexDto;
2931
import de.symeda.sormas.api.contact.ContactReferenceDto;
3032
import de.symeda.sormas.api.i18n.Captions;
3133
import de.symeda.sormas.api.i18n.I18nProperties;
3234
import de.symeda.sormas.api.person.PersonDto;
35+
import de.symeda.sormas.api.person.PersonReferenceDto;
3336
import de.symeda.sormas.api.user.UserRight;
3437
import de.symeda.sormas.api.utils.DataHelper;
3538
import de.symeda.sormas.ui.ControllerProvider;
@@ -40,6 +43,9 @@
4043
import de.symeda.sormas.ui.utils.AbstractDetailView;
4144
import de.symeda.sormas.ui.utils.CssStyles;
4245

46+
import java.util.Collections;
47+
import java.util.List;
48+
4349
@SuppressWarnings("serial")
4450
public abstract class AbstractContactView extends AbstractDetailView<ContactReferenceDto> {
4551

@@ -59,6 +65,18 @@ protected AbstractContactView(String viewName) {
5965
});
6066
getButtonsLayout().addComponent(btnCreatePIAAccount);
6167
}
68+
69+
if (FacadeProvider.getConfigFacade().getPatientDiaryUrl() != null
70+
&& UserProvider.getCurrent().hasUserRight(UserRight.MANAGE_EXTERNAL_SYMPTOM_JOURNAL)) {
71+
Button btnClimedoAccount = new Button(I18nProperties.getCaption(Captions.Contact_climedoAccount));
72+
CssStyles.style(btnClimedoAccount, ValoTheme.BUTTON_PRIMARY);
73+
btnClimedoAccount.addClickListener(e -> {
74+
ContactDto contact = FacadeProvider.getContactFacade().getContactByUuid(getReference().getUuid());
75+
PersonDto contactPerson = FacadeProvider.getPersonFacade().getPersonByUuid(contact.getPerson().getUuid());
76+
ControllerProvider.getContactController().openDiaryTab(contactPerson);
77+
});
78+
getButtonsLayout().addComponent(btnClimedoAccount);
79+
}
6280
}
6381

6482
@Override
@@ -98,6 +116,16 @@ protected ContactReferenceDto getReferenceByUuid(String uuid) {
98116
final ContactReferenceDto reference;
99117
if (FacadeProvider.getContactFacade().exists(uuid)) {
100118
reference = FacadeProvider.getContactFacade().getReferenceByUuid(uuid);
119+
} else if (FacadeProvider.getPersonFacade().isValidPersonUuid(uuid)) {
120+
PersonReferenceDto person = FacadeProvider.getPersonFacade().getReferenceByUuid(uuid);
121+
ContactCriteria criteria = new ContactCriteria();
122+
criteria.person(person);
123+
List<ContactIndexDto> personContacts = FacadeProvider.getContactFacade().getIndexList(criteria, null, null, Collections.emptyList());
124+
if (personContacts != null) {
125+
reference = FacadeProvider.getContactFacade().getReferenceByUuid(personContacts.get(0).getUuid());
126+
} else {
127+
reference = null;
128+
}
101129
} else {
102130
reference = null;
103131
}

0 commit comments

Comments
 (0)