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

Commit 8e64da4

Browse files
author
barnabartha
committed
Merge branch 'development' into feature-3152-SymptomsReordering
2 parents bb95416 + d69ca03 commit 8e64da4

210 files changed

Lines changed: 2969 additions & 290 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ SORMAS officially supports and is tested on **Chromium-based browsers** (like Go
2727

2828
#### Is there a ReST API documentation?
2929
Yes! Please download the [latest release](https://github.com/hzi-braunschweig/SORMAS-Project/releases/latest) and copy the content of /deploy/openapi/sormas-rest.yaml to an editor that generates a visual API documentation (e.g. https://editor.swagger.io/).
30+
<br/>
31+
Runtime Swagger documentation of the External Visits Resource (used by external symptom journals such as CLIMEDO or PIA) is also available at ``<<host>>/sormas-rest/visits-external/openapi.json`` or ``<<host>>/sormas-rest/visits-external/openapi.yaml``
3032

3133
<p align="center"><img src="https://user-images.githubusercontent.com/23701005/74659600-ebb8fc00-5194-11ea-836b-a7ca9d682301.png"/></p>
3234

sormas-api/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@
6767
<artifactId>simmetrics-core</artifactId>
6868
</dependency>
6969

70+
<dependency>
71+
<groupId>org.jsoup</groupId>
72+
<artifactId>jsoup</artifactId>
73+
</dependency>
74+
7075
</dependencies>
7176

7277
</project>

sormas-api/src/main/java/de/symeda/sormas/api/caze/classification/ClassificationHtmlRenderer.java

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,11 @@
1717
*******************************************************************************/
1818
package de.symeda.sormas.api.caze.classification;
1919

20-
import static de.symeda.sormas.api.utils.HtmlHelper.escapeAndUnescapeBasicTags;
21-
import static de.symeda.sormas.api.utils.HtmlHelper.unescapeBasicTags;
22-
2320
import java.util.Date;
2421
import java.util.List;
2522

2623
import org.apache.commons.lang3.StringUtils;
27-
import org.apache.commons.text.StringEscapeUtils;
24+
import org.jsoup.safety.Whitelist;
2825

2926
import de.symeda.sormas.api.Disease;
3027
import de.symeda.sormas.api.FacadeProvider;
@@ -34,6 +31,7 @@
3431
import de.symeda.sormas.api.i18n.Strings;
3532
import de.symeda.sormas.api.utils.DataHelper;
3633
import de.symeda.sormas.api.utils.DateHelper;
34+
import de.symeda.sormas.api.utils.HtmlHelper;
3735
import de.symeda.sormas.api.utils.InfoProvider;
3836

3937
/**
@@ -176,7 +174,7 @@ public static String createHtmlForDownload(String sormasServerUrl, List<Disease>
176174
html.append("<h1 style=\"text-align: center; color: #005A9C;\">").append(I18nProperties.getString(Strings.classificationClassificationRules)).append("</h1>");
177175
html.append("<h4 style=\"text-align: center;\">")
178176
.append(I18nProperties.getString(Strings.classificationGeneratedFor))
179-
.append(" ").append(StringEscapeUtils.escapeHtml4(InfoProvider.get().getVersion()))
177+
.append(" ").append(HtmlHelper.cleanHtml(InfoProvider.get().getVersion()))
180178
.append(StringUtils.wrap(I18nProperties.getString(Strings.on), " "))
181179
.append(sormasServerUrl).append(StringUtils.wrap(I18nProperties.getString(Strings.at), " "))
182180
.append(DateHelper.formatLocalDateTime(new Date(), language)).append("</h4>");
@@ -241,7 +239,7 @@ private static String buildSubCriteriaDiv(
241239
for (ClassificationCriteriaDto subCriteria : ((ClassificationCollectiveCriteria) criteria).getSubCriteria()) {
242240
if (!(subCriteria instanceof ClassificationCollectiveCriteria) || subCriteria instanceof ClassificationCompactCriteria) {
243241
// For non-collective or compact collective criteria, add the description as a list item
244-
subCriteriaSb.append("- " + escapeAndUnescapeBasicTags(subCriteria.buildDescription() + "</br>"));
242+
subCriteriaSb.append("- " + HtmlHelper.cleanHtml(subCriteria.buildDescription(), Whitelist.basic()) + "</br>");
245243
} else if (subCriteria instanceof ClassificationCollectiveCriteria
246244
&& !(subCriteria instanceof ClassificationAllOfCriteriaDto)
247245
&& !(subCriteria.getClass() == ClassificationXOfCriteriaDto.class)) {
@@ -273,7 +271,7 @@ private static String createSurroundingDiv(ClassificationCriteriaType criteriaTy
273271
//@formatter:off
274272
return "<div class='classification-rules'>"
275273
+ "<div class='main-criteria main-criteria-"
276-
+ StringEscapeUtils.escapeHtml4(criteriaType.toString())
274+
+ HtmlHelper.cleanHtml(criteriaType.toString())
277275
+ "'>"
278276
+ content
279277
+ "</div></div>";
@@ -287,7 +285,7 @@ private static String createHeadlineDiv(String headline) {
287285

288286
//@formatter:off
289287
return "<div class='headline'>"
290-
+ StringEscapeUtils.escapeHtml4(headline)
288+
+ HtmlHelper.cleanHtml(headline, Whitelist.basic())
291289
+ "</div>";
292290
//@formatter:on
293291
}
@@ -296,13 +294,12 @@ private static String createHeadlineDiv(String headline) {
296294
* Creates a div containing an info text.
297295
*/
298296
private static String createInfoDiv() {
299-
return unescapeBasicTags(StringEscapeUtils.escapeHtml4(I18nProperties.getString(Strings.classificationInfoText)));
297+
return HtmlHelper.cleanI18nString(I18nProperties.getString(Strings.classificationInfoText));
300298
}
301299

302300
private static String createInfoDiv(int requirementsNumber) {
303-
return unescapeBasicTags(
304-
StringEscapeUtils.escapeHtml4(
305-
String.format(I18nProperties.getString(Strings.classificationInfoNumberText), DataHelper.parseNumberToString(requirementsNumber))));
301+
return HtmlHelper.cleanI18nString(
302+
String.format(I18nProperties.getString(Strings.classificationInfoNumberText), DataHelper.parseNumberToString(requirementsNumber)));
306303
}
307304

308305
/**
@@ -334,7 +331,7 @@ private static String createSubCriteriaSurroundingDiv(String content) {
334331
* Specific tags are allowed to be contained in i18n strings and are thus unescaped
335332
*/
336333
private static String createCriteriaItemDiv(String text) {
337-
return unescapeBasicTags(StringEscapeUtils.escapeHtml4(text) + "<br>");
334+
return (HtmlHelper.cleanHtml(text, Whitelist.basic()) + "<br>");
338335
}
339336

340337
private enum ClassificationCriteriaType {

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,16 +1077,16 @@ public interface Captions {
10771077
String MaternalHistory_swollenLymphsMonth = "MaternalHistory.swollenLymphsMonth";
10781078
String MaternalHistory_swollenLymphsOnset = "MaternalHistory.swollenLymphsOnset";
10791079
String menu = "menu";
1080-
String Messages_characters = "Messages.characters";
1081-
String Messages_email = "Messages.email";
1082-
String Messages_noPhoneNumberForCasePerson = "Messages.noPhoneNumberForCasePerson";
1083-
String Messages_noSmsSentForCase = "Messages.noSmsSentForCase";
1084-
String Messages_numberOfMessages = "Messages.numberOfMessages";
1085-
String Messages_numberOfMissingPhoneNumbers = "Messages.numberOfMissingPhoneNumbers";
1086-
String Messages_sendingSms = "Messages.sendingSms";
1087-
String Messages_sendSMS = "Messages.sendSMS";
1088-
String Messages_sentBy = "Messages.sentBy";
1089-
String Messages_sms = "Messages.sms";
1080+
String messagesCharacters = "messagesCharacters";
1081+
String messagesEmail = "messagesEmail";
1082+
String messagesNoPhoneNumberForCasePerson = "messagesNoPhoneNumberForCasePerson";
1083+
String messagesNoSmsSentForCase = "messagesNoSmsSentForCase";
1084+
String messagesNumberOfMessages = "messagesNumberOfMessages";
1085+
String messagesNumberOfMissingPhoneNumbers = "messagesNumberOfMissingPhoneNumbers";
1086+
String messagesSendingSms = "messagesSendingSms";
1087+
String messagesSendSMS = "messagesSendSMS";
1088+
String messagesSentBy = "messagesSentBy";
1089+
String messagesSms = "messagesSms";
10901090
String moreActions = "moreActions";
10911091
String name = "name";
10921092
String nationalHealthId = "nationalHealthId";

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,7 @@ public interface Strings {
629629
String messageDistrictsArchivingNotPossible = "messageDistrictsArchivingNotPossible";
630630
String messageDistrictsDearchived = "messageDistrictsDearchived";
631631
String messageDistrictsDearchivingNotPossible = "messageDistrictsDearchivingNotPossible";
632+
String messageEnterSms = "messageEnterSms";
632633
String messageEntryCreated = "messageEntryCreated";
633634
String messageEpiDataHint = "messageEpiDataHint";
634635
String messageEpidNumberWarning = "messageEpidNumberWarning";
@@ -724,8 +725,6 @@ public interface Strings {
724725
String messageRegionsArchived = "messageRegionsArchived";
725726
String messageRegionsArchivingNotPossible = "messageRegionsArchivingNotPossible";
726727
String messageRegionsDearchived = "messageRegionsDearchived";
727-
String Messages_enterSMS = "Messages.enterSMS";
728-
String Messages_smsSent = "Messages.smsSent";
729728
String messageSampleErrors = "messageSampleErrors";
730729
String messageSampleOpened = "messageSampleOpened";
731730
String messageSampleSaved = "messageSampleSaved";
@@ -771,6 +770,7 @@ public interface Strings {
771770
String notificationLabSampleShippedShort = "notificationLabSampleShippedShort";
772771
String notificationLabSampleShippedShortForContact = "notificationLabSampleShippedShortForContact";
773772
String notificationLabSampleShippedShortForEventParticipant = "notificationLabSampleShippedShortForEventParticipant";
773+
String notificationSmsSent = "notificationSmsSent";
774774
String notificationTaskDueGeneral = "notificationTaskDueGeneral";
775775
String notificationTaskDueSpecific = "notificationTaskDueSpecific";
776776
String notificationTaskStartGeneral = "notificationTaskStartGeneral";
Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,45 @@
1+
/*******************************************************************************
2+
* SORMAS® - Surveillance Outbreak Response Management & Analysis System
3+
* Copyright © 2016-2018 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI)
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*******************************************************************************/
118
package de.symeda.sormas.api.utils;
219

3-
import org.apache.commons.text.StringEscapeUtils;
20+
import org.jsoup.Jsoup;
21+
import org.jsoup.safety.Whitelist;
422

23+
// This class provides general XSS-Prevention methods using Jsoup.clean
524
public class HtmlHelper {
625

7-
// unescape specific tags (<b>,<i>,<br>,<li>,<ul>) escaped using StringEscapeUtils.escapeHtml4(String)
8-
public static String unescapeBasicTags(String escapedString) {
9-
String res = escapedString;
26+
public static final Whitelist EventActionWhitelist =
27+
Whitelist.relaxed().addTags("hr", "font").addAttributes("font", "size", "face", "color").addAttributes("div", "align");
1028

11-
// <b> Tags
12-
res = res.replaceAll("&lt;b&gt;", "<b>");
13-
res = res.replaceAll("&lt;/b&gt;", "</b>");
14-
// <i> Tags
15-
res = res.replaceAll("&lt;i&gt;", "<i>");
16-
res = res.replaceAll("&lt;/i&gt;", "</i>");
17-
// <ul> Tags
18-
res = res.replaceAll("&lt;ul&gt;", "<ul>");
19-
res = res.replaceAll("&lt;/ul&gt;", "</ul>");
20-
// <li> Tags
21-
res = res.replaceAll("&lt;li&gt;", "<li>");
22-
res = res.replaceAll("&lt;/li&gt;", "</li>");
23-
// <br> Tags
24-
res = res.replaceAll("&lt;br&gt;", "<br>");
25-
res = res.replaceAll("&lt;/br&gt;", "<br>");
26-
res = res.replaceAll("&lt;br/&gt;", "<br>");
29+
public static String cleanHtml(String string) {
30+
return (string == null) ? "" : Jsoup.clean(string, Whitelist.none());
31+
}
32+
33+
public static String cleanHtml(String string, Whitelist whitelist) {
34+
return (string == null) ? "" : Jsoup.clean(string, whitelist);
35+
}
2736

28-
return res;
37+
// this method should be used for i18n-strings and captions so that custom whitelist rules can be added when needed
38+
public static String cleanI18nString(String string) {
39+
return (string == null) ? "" : Jsoup.clean(string, Whitelist.basic());
2940
}
3041

31-
// escapes html4 and then unescapes specific tags
32-
public static String escapeAndUnescapeBasicTags(String text) {
33-
return unescapeBasicTags(StringEscapeUtils.escapeHtml4(text));
42+
public static String cleanHtmlRelaxed(String string) {
43+
return (string == null) ? "" : Jsoup.clean(string, Whitelist.relaxed());
3444
}
3545
}

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,16 +1151,16 @@ LoginSidebar.outbreakResponse=Outbreak Response
11511151
LoginSidebar.poweredBy=Powered By
11521152

11531153
# Messaging
1154-
Messages.sendSMS=Send SMS
1155-
Messages.sentBy=Sent by
1156-
Messages.noSmsSentForCase=No SMS sent to case person
1157-
Messages.noPhoneNumberForCasePerson=Case person has no phone number
1158-
Messages.sms = SMS
1159-
Messages.email = Email
1160-
Messages.sendingSms = Send new SMS
1161-
Messages.numberOfMissingPhoneNumbers = Number of selected cases without phone number: %s
1162-
Messages.characters = Characters: %d / 160
1163-
Messages.numberOfMessages = Nr. of messages: %d
1154+
messagesSendSMS=Send SMS
1155+
messagesSentBy=Sent by
1156+
messagesNoSmsSentForCase=No SMS sent to case person
1157+
messagesNoPhoneNumberForCasePerson=Case person has no phone number
1158+
messagesSms = SMS
1159+
messagesEmail = Email
1160+
messagesSendingSms = Send new SMS
1161+
messagesNumberOfMissingPhoneNumbers = Number of selected cases without phone number: %s
1162+
messagesCharacters = Characters: %d / 160
1163+
messagesNumberOfMessages = Nr. of messages: %d
11641164

11651165
# Main Menu
11661166
mainMenuAbout=About

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ actionSaveChanges=Änderungen speichern
123123
actionBackToNationOverview=Zurück zur Nationalübersicht
124124
actionSettings=Spracheinstellung
125125
actionNewForm=Neues Formular
126+
actionOverwrite=Überschreiben
126127

127128
# AdditionalTest
128129
additionalTestNewTest=Neues Testergebnis
@@ -209,6 +210,7 @@ campaignDashboardSubTabName=Sub-tab name
209210
campaignDashboardChartWidth=Breite in %
210211
campaignDashboardChartHeight=Höhe in %
211212
campaignDashboardOrder=Verfügung
213+
campaignSearch=Kampagne suchen
212214

213215
Campaign=Kampagne
214216
Campaign.name=Name
@@ -226,6 +228,7 @@ CampaignFormData.campaign = Kampagne
226228
CampaignFormData.campaignFormMeta = Formular
227229
CampaignFormData.formDate = Formulardatum
228230
CampaignFormData.area = Gebiet
231+
CampaignFormData.edit=Bearbeiten
229232

230233
# CaseData
231234
caseCasesList=Fall-Liste
@@ -379,6 +382,7 @@ CaseData.eventCount=Anzahl der Ereignisse
379382
CaseData.latestEventId=ID des neuesten Ereignisses
380383
CaseData.latestEventStatus=Aktuellster Ereignisstatus
381384
CaseData.latestEventTitle=Titel des aktuellsten Ereignisses
385+
CaseData.latestSampleDateTime=Latest collection date
382386
CaseData.caseIdIsm=Fall-ID ISM
383387
CaseData.covidTestReason=Grund für COVID-19-Test
384388
CaseData.covidTestReasonDetails=Anderer Grund
@@ -390,6 +394,11 @@ CaseData.quarantineReasonBeforeIsolationDetails=Anderer Grund
390394
CaseData.endOfIsolationReason=Grund des Ende der Isolation
391395
CaseData.endOfIsolationReasonDetails=Anderer Grund
392396
CaseData.sormasToSormasOriginInfo=Geteilt von
397+
CaseData.nosocomialOutbreak=Resulted from nosocomial outbreak
398+
CaseData.infectionSetting=Infection setting
399+
CaseData.prohibitionToWork=Prohibition to work
400+
CaseData.prohibitionToWorkFrom=Prohibition to work from
401+
CaseData.prohibitionToWorkUntil=Prohibition to work until
393402

394403
# CaseExport
395404
CaseExport.address=Adresse
@@ -564,6 +573,7 @@ Contact.disease=Krankheit des Indexfalls
564573
Contact.district=Zuständiger Bezirk
565574
Contact.epiData=Epidemiologische Daten
566575
Contact.externalID=Externe ID
576+
Contact.firstContactDate=Datum des ersten Kontakts
567577
Contact.firstName=Vorname der Kontaktperson
568578
Contact.followUpComment=Nachverfolgungs-Status-Kommentar
569579
Contact.followUpStatus=Nachverfolgungs-Status
@@ -573,6 +583,7 @@ Contact.lastContactDate=Datum des letzten Kontakts
573583
Contact.lastName=Nachname der Kontaktperson
574584
Contact.latestEventId=ID des neuesten Ereignisses
575585
Contact.latestEventTitle=Titel des neuesten Ereignisses
586+
Contact.multiDayContact=Mehrtägiger Kontakt
576587
Contact.numberOfVisits=Anzahl der Anrufe
577588
Contact.person=Kontaktperson
578589
Contact.quarantine=Quarantäne
@@ -620,6 +631,9 @@ Contact.quarantineOfficialOrderSent=Verfügung verschickt?
620631
Contact.quarantineOfficialOrderSentDate=Verfügung verschickt am
621632
Contact.endOfQuarantineReason=Grund des Ende der Quarantäne
622633
Contact.endOfQuarantineReasonDetails=Anderer Grund
634+
Contact.prohibitionToWork=Prohibition to work
635+
Contact.prohibitionToWorkFrom=Prohibition to work from
636+
Contact.prohibitionToWorkUntil=Prohibition to work until
623637

624638
# ContactExport
625639
ContactExport.address=Adresse
@@ -867,8 +881,11 @@ Event.informationSource=Informationsquelle
867881
Event.numberOfPendingTasks=Ausstehende Aufgaben
868882
Event.reportDateTime=Meldedatum
869883
Event.reportingUser=Meldender Nutzer
884+
Event.riskLevel=Risk level
870885
Event.srcType=Information von
871886
Event.srcEmail=E-Mail
887+
Event.srcInstitutionalPartnerType=Source institutional partner
888+
Event.srcInstitutionalPartnerTypeDetails=Source institutional partner details
872889
Event.srcFirstName=Vorname der Quelle
873890
Event.srcLastName=Nachname der Quelle
874891
Event.srcTelNo=Indexfall Telefonnummer
@@ -1233,6 +1250,7 @@ Person.districtName=Bezirk
12331250
Person.educationType=Bildung
12341251
Person.educationDetails=Details
12351252
Person.fathersName=Name des Vaters
1253+
Person.namesOfOtherGuardians=Names of other guardians
12361254
Person.gestationAgeAtBirth=Gestationsalter bei der Geburt (Wochen)
12371255
Person.healthcare.occupationDetails=Position
12381256
Person.lastDisease=Letzte Krankheit
@@ -1249,6 +1267,7 @@ Person.occupationFacilityType=Art der Einrichtung
12491267
Person.occupationRegion=Kanton der Einrichtung
12501268
Person.occupationType=Beschäftigungsart
12511269
Person.other.occupationDetails=Bitte geben Sie Ihren Beruf an
1270+
Person.armedForcesRelationType=Staff of armed forces
12521271
Person.phone=Telefonnummer
12531272
Person.phoneOwner=Besitzer des Telefons
12541273
Person.placeOfBirthRegion=Geburtskanton
@@ -1939,7 +1958,7 @@ sormasToSormasDialogTitle=Mit Gesundheitsamt teilen
19391958
sormasToSormasErrorDialogTitle=Fehler beim Teilen mit einem anderem Gesundheitsamt
19401959
sormasToSormasListTitle=Teilen
19411960
sormasToSormasShare=Teilen
1942-
sormasToSormasReturn=Return
1961+
sormasToSormasReturn=Zurück
19431962
sormasToSormasCaseNotShared=Dieser Fall ist nicht geteilt
19441963
sormasToSormasContactNotShared=Dieser Kontakt ist nicht geteilt
19451964
sormasToSormasSharedWith=Geteilt mit

0 commit comments

Comments
 (0)