From 1161b36d22fa32204d013d81a119f017bf39efde Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Tue, 25 Jan 2022 14:34:51 +0200 Subject: [PATCH 001/253] #7246 - rename CoreAdo to DeletableAdo --- .../symeda/sormas/backend/campaign/Campaign.java | 4 ++-- .../java/de/symeda/sormas/backend/caze/Case.java | 4 ++-- .../symeda/sormas/backend/caze/CaseService.java | 6 +++--- .../backend/common/AbstractCoreAdoService.java | 2 +- .../common/{CoreAdo.java => DeletableAdo.java} | 2 +- .../symeda/sormas/backend/contact/Contact.java | 4 ++-- .../sormas/backend/contact/ContactService.java | 6 +++--- .../de/symeda/sormas/backend/event/Event.java | 4 ++-- .../sormas/backend/event/EventParticipant.java | 4 ++-- .../backend/event/EventParticipantFacadeEjb.java | 4 ++-- .../sormas/backend/event/EventService.java | 8 ++++---- .../immunization/entity/BaseImmunization.java | 4 ++-- .../sormas/backend/labmessage/LabMessage.java | 4 ++-- .../backend/labmessage/LabMessageService.java | 4 ++-- .../sormas/backend/labmessage/TestReport.java | 4 ++-- .../backend/labmessage/TestReportService.java | 16 ++-------------- .../backend/sample/AdditionalTestService.java | 4 ++-- .../sormas/backend/sample/PathogenTest.java | 4 ++-- .../backend/sample/PathogenTestService.java | 6 +++--- .../de/symeda/sormas/backend/sample/Sample.java | 4 ++-- .../sormas/backend/sample/SampleService.java | 4 ++-- .../sormas/backend/travelentry/TravelEntry.java | 4 ++-- 22 files changed, 47 insertions(+), 59 deletions(-) rename sormas-backend/src/main/java/de/symeda/sormas/backend/common/{CoreAdo.java => DeletableAdo.java} (92%) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/Campaign.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/Campaign.java index 8c94ef71bca..71fb55240db 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/Campaign.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/Campaign.java @@ -21,13 +21,13 @@ import de.symeda.auditlog.api.AuditedIgnore; import de.symeda.sormas.api.campaign.diagram.CampaignDashboardElement; import de.symeda.sormas.backend.campaign.form.CampaignFormMeta; -import de.symeda.sormas.backend.common.CoreAdo; +import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.user.User; import de.symeda.sormas.backend.util.ModelConstants; @Entity(name = "campaigns") @Audited -public class Campaign extends CoreAdo { +public class Campaign extends DeletableAdo { private static final long serialVersionUID = -2744033662114826543L; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/Case.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/Case.java index 5be3f2e4cee..d3881252fe5 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/Case.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/Case.java @@ -77,7 +77,7 @@ import de.symeda.sormas.backend.caze.maternalhistory.MaternalHistory; import de.symeda.sormas.backend.caze.porthealthinfo.PortHealthInfo; import de.symeda.sormas.backend.clinicalcourse.ClinicalCourse; -import de.symeda.sormas.backend.common.CoreAdo; +import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.disease.DiseaseVariantConverter; import de.symeda.sormas.backend.epidata.EpiData; @@ -103,7 +103,7 @@ @Entity(name = "cases") @Audited -public class Case extends CoreAdo implements SormasToSormasShareable, HasExternalData { +public class Case extends DeletableAdo implements SormasToSormasShareable, HasExternalData { private static final long serialVersionUID = -2697795184663562129L; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java index 281e3090ca5..495fded2a7c 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java @@ -109,7 +109,7 @@ import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.ChangeDateFilterBuilder; -import de.symeda.sormas.backend.common.CoreAdo; +import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.contact.ContactQueryContext; @@ -865,7 +865,7 @@ public Predicate createCriteriaFilter(CaseCrite } /** - * Creates a filter that excludes all cases that are either {@link Case#archived} or {@link CoreAdo#deleted}. + * Creates a filter that excludes all cases that are either {@link Case#archived} or {@link DeletableAdo#deleted}. */ public Predicate createActiveCasesFilter(CriteriaBuilder cb, Root root) { return cb.and(cb.isFalse(root.get(Case.ARCHIVED)), cb.isFalse(root.get(Case.DELETED))); @@ -877,7 +877,7 @@ public Predicate createActiveCasesFilter(CriteriaBuilder cb, Join join) /** * Creates a default filter that should be used as the basis of queries that do not use {@link CaseCriteria}. - * This essentially removes {@link CoreAdo#deleted} cases from the queries. + * This essentially removes {@link DeletableAdo#deleted} cases from the queries. */ public Predicate createDefaultFilter(CriteriaBuilder cb, From root) { return cb.isFalse(root.get(Case.DELETED)); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java index 2fe1333f8ad..a2a122047bf 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java @@ -7,7 +7,7 @@ import javax.persistence.criteria.JoinType; import javax.persistence.criteria.Predicate; -public abstract class AbstractCoreAdoService extends AdoServiceWithUserFilter { +public abstract class AbstractCoreAdoService extends AdoServiceWithUserFilter { public AbstractCoreAdoService(Class elementClass) { super(elementClass); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CoreAdo.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/DeletableAdo.java similarity index 92% rename from sormas-backend/src/main/java/de/symeda/sormas/backend/common/CoreAdo.java rename to sormas-backend/src/main/java/de/symeda/sormas/backend/common/DeletableAdo.java index 3af0f29358d..549ac6b42c6 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CoreAdo.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/DeletableAdo.java @@ -12,7 +12,7 @@ */ @MappedSuperclass @Audited -public abstract class CoreAdo extends AbstractDomainObject { +public abstract class DeletableAdo extends AbstractDomainObject { private static final long serialVersionUID = 6512756286608581221L; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/Contact.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/Contact.java index 561e8ff893b..382a5f3f4be 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/Contact.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/Contact.java @@ -62,7 +62,7 @@ import de.symeda.sormas.api.utils.YesNoUnknown; import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.clinicalcourse.HealthConditions; -import de.symeda.sormas.backend.common.CoreAdo; +import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.epidata.EpiData; import de.symeda.sormas.backend.infrastructure.community.Community; import de.symeda.sormas.backend.infrastructure.district.District; @@ -78,7 +78,7 @@ @Entity @Audited -public class Contact extends CoreAdo implements SormasToSormasShareable, HasExternalData { +public class Contact extends DeletableAdo implements SormasToSormasShareable, HasExternalData { private static final long serialVersionUID = -7764607075875188799L; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java index 3b62606d402..bf89b65baf8 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java @@ -85,7 +85,7 @@ import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.ChangeDateFilterBuilder; -import de.symeda.sormas.backend.common.CoreAdo; +import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.contact.transformers.ContactListEntryDtoResultTransformer; import de.symeda.sormas.backend.disease.DiseaseConfigurationFacadeEjb.DiseaseConfigurationFacadeEjbLocal; @@ -1338,7 +1338,7 @@ public void delete(Contact contact) { /** * Creates a filter that excludes all contacts that are either - * {@link CoreAdo#isDeleted()} or associated with cases that are + * {@link DeletableAdo#isDeleted()} or associated with cases that are * {@link Case#isArchived()}. */ public Predicate createActiveContactsFilter(CriteriaBuilder cb, Root root) { @@ -1357,7 +1357,7 @@ public Predicate createActiveContactsFilter(CriteriaBuilder cb, Join /** * Creates a default filter that should be used as the basis of queries that do * not use {@link ContactCriteria}. This essentially removes - * {@link CoreAdo#isDeleted()} contacts from the queries. + * {@link DeletableAdo#isDeleted()} contacts from the queries. */ public Predicate createDefaultFilter(CriteriaBuilder cb, From root) { return cb.isFalse(root.get(Contact.DELETED)); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/Event.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/Event.java index 52f1438ce49..80ac4363d91 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/Event.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/Event.java @@ -65,7 +65,7 @@ import de.symeda.sormas.api.exposure.WorkEnvironment; import de.symeda.sormas.api.externaldata.HasExternalData; import de.symeda.sormas.api.utils.YesNoUnknown; -import de.symeda.sormas.backend.common.CoreAdo; +import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.disease.DiseaseVariantConverter; import de.symeda.sormas.backend.location.Location; import de.symeda.sormas.backend.sormastosormas.entities.SormasToSormasShareable; @@ -77,7 +77,7 @@ @Entity(name = "events") @Audited -public class Event extends CoreAdo implements SormasToSormasShareable, HasExternalData { +public class Event extends DeletableAdo implements SormasToSormasShareable, HasExternalData { private static final long serialVersionUID = 4964495716032049582L; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipant.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipant.java index 985d79e0b70..e039cda87fb 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipant.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipant.java @@ -35,7 +35,7 @@ import de.symeda.auditlog.api.AuditedIgnore; import de.symeda.sormas.api.caze.VaccinationStatus; import de.symeda.sormas.backend.caze.Case; -import de.symeda.sormas.backend.common.CoreAdo; +import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.infrastructure.district.District; import de.symeda.sormas.backend.infrastructure.region.Region; import de.symeda.sormas.backend.person.Person; @@ -47,7 +47,7 @@ @Entity @Audited -public class EventParticipant extends CoreAdo implements SormasToSormasShareable { +public class EventParticipant extends DeletableAdo implements SormasToSormasShareable { private static final long serialVersionUID = -9006001699517297107L; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java index 55e2f589148..ef4bec6d1d7 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java @@ -90,7 +90,7 @@ import de.symeda.sormas.backend.caze.CaseFacadeEjb; import de.symeda.sormas.backend.caze.CaseService; import de.symeda.sormas.backend.common.AbstractDomainObject; -import de.symeda.sormas.backend.common.CoreAdo; +import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.common.messaging.MessageContents; import de.symeda.sormas.backend.common.messaging.MessageSubject; @@ -407,7 +407,7 @@ public List getIndexList( final Join samples = eventParticipant.join(EventParticipant.SAMPLES, JoinType.LEFT); samples.on( cb.and( - cb.isFalse(samples.get(CoreAdo.DELETED)), + cb.isFalse(samples.get(DeletableAdo.DELETED)), cb.equal(samples.get(Sample.ASSOCIATED_EVENT_PARTICIPANT), eventParticipant.get(AbstractDomainObject.ID)))); Expression inJurisdictionSelector = JurisdictionHelper.booleanSelector(cb, eventParticipantService.inJurisdiction(queryContext)); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java index 0409521a8b2..c57ae0d2228 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java @@ -64,7 +64,7 @@ import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.ChangeDateFilterBuilder; -import de.symeda.sormas.backend.common.CoreAdo; +import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.infrastructure.community.Community; @@ -788,14 +788,14 @@ private Predicate createEventDateFilter(CriteriaQuery cq, CriteriaBuilder cb, } /** - * Creates a filter that excludes all events that are either {@link Event#isArchived()} or {@link CoreAdo#isDeleted()}. + * Creates a filter that excludes all events that are either {@link Event#isArchived()} or {@link DeletableAdo#isDeleted()}. */ public Predicate createActiveEventsFilter(CriteriaBuilder cb, Root root) { return cb.and(cb.isFalse(root.get(Event.ARCHIVED)), cb.isFalse(root.get(Event.DELETED))); } /** - * Creates a filter that excludes all events that are either {@link Event#isArchived()} or {@link CoreAdo#isDeleted()}. + * Creates a filter that excludes all events that are either {@link Event#isArchived()} or {@link DeletableAdo#isDeleted()}. */ public Predicate createActiveEventsFilter(CriteriaBuilder cb, Path root) { return cb.and(cb.isFalse(root.get(Event.ARCHIVED)), cb.isFalse(root.get(Event.DELETED))); @@ -803,7 +803,7 @@ public Predicate createActiveEventsFilter(CriteriaBuilder cb, Path root) /** * Creates a default filter that should be used as the basis of queries that do not use {@link EventCriteria}. - * This essentially removes {@link CoreAdo#isDeleted()} events from the queries. + * This essentially removes {@link DeletableAdo#isDeleted()} events from the queries. */ public Predicate createDefaultFilter(CriteriaBuilder cb, Root root) { return cb.isFalse(root.get(Event.DELETED)); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/entity/BaseImmunization.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/entity/BaseImmunization.java index d85eaccc404..8174344d7d2 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/entity/BaseImmunization.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/entity/BaseImmunization.java @@ -27,7 +27,7 @@ import de.symeda.sormas.api.infrastructure.facility.FacilityType; import de.symeda.sormas.api.utils.YesNoUnknown; import de.symeda.sormas.backend.caze.Case; -import de.symeda.sormas.backend.common.CoreAdo; +import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.infrastructure.community.Community; import de.symeda.sormas.backend.infrastructure.country.Country; import de.symeda.sormas.backend.infrastructure.district.District; @@ -41,7 +41,7 @@ import de.symeda.sormas.backend.vaccination.Vaccination; @MappedSuperclass -public class BaseImmunization extends CoreAdo implements SormasToSormasShareable { +public class BaseImmunization extends DeletableAdo implements SormasToSormasShareable { private Disease disease; private String diseaseDetails; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/LabMessage.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/LabMessage.java index ca255b79f0f..95312dda3f0 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/LabMessage.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/LabMessage.java @@ -24,13 +24,13 @@ import de.symeda.sormas.api.sample.PathogenTestResultType; import de.symeda.sormas.api.sample.SampleMaterial; import de.symeda.sormas.api.sample.SpecimenCondition; -import de.symeda.sormas.backend.common.CoreAdo; +import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.sample.Sample; import de.symeda.sormas.backend.user.User; @Entity(name = "labmessage") @Audited -public class LabMessage extends CoreAdo { +public class LabMessage extends DeletableAdo { public static final String TABLE_NAME = "labmessage"; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/LabMessageService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/LabMessageService.java index bd94ec1ff84..ce83057c0b6 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/LabMessageService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/LabMessageService.java @@ -21,7 +21,7 @@ import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; -import de.symeda.sormas.backend.common.CoreAdo; +import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.event.EventParticipant; @@ -38,7 +38,7 @@ public LabMessageService() { /** * Creates a default filter that should be used as the basis of queries that do not use {@link LabMessageCriteria}. - * This essentially removes {@link CoreAdo#isDeleted()} lab messages from the queries. + * This essentially removes {@link DeletableAdo#isDeleted()} lab messages from the queries. */ public Predicate createDefaultFilter(CriteriaBuilder cb, Root root) { return cb.isFalse(root.get(LabMessage.DELETED)); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/TestReport.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/TestReport.java index 7a4935ae923..2955c6d94b6 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/TestReport.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/TestReport.java @@ -18,11 +18,11 @@ import de.symeda.auditlog.api.Audited; import de.symeda.sormas.api.sample.PathogenTestResultType; import de.symeda.sormas.api.sample.PathogenTestType; -import de.symeda.sormas.backend.common.CoreAdo; +import de.symeda.sormas.backend.common.DeletableAdo; @Entity(name = TestReport.TABLE_NAME) @Audited -public class TestReport extends CoreAdo { +public class TestReport extends DeletableAdo { private static final long serialVersionUID = -9164498173635523905L; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/TestReportService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/TestReportService.java index e37086d6515..a4991226bc3 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/TestReportService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/TestReportService.java @@ -1,25 +1,13 @@ package de.symeda.sormas.backend.labmessage; -import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.BaseAdoService; -import de.symeda.sormas.backend.common.CoreAdo; -import de.symeda.sormas.backend.sample.PathogenTest; -import de.symeda.sormas.backend.util.IterableHelper; -import de.symeda.sormas.backend.util.ModelConstants; -import org.apache.commons.collections.CollectionUtils; +import de.symeda.sormas.backend.common.DeletableAdo; import javax.ejb.LocalBean; import javax.ejb.Stateless; import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.Join; -import javax.persistence.criteria.JoinType; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; @Stateless @LocalBean @@ -31,7 +19,7 @@ public TestReportService() { /** * Creates a default filter that should be used as the basis of queries in this service.. - * This essentially removes {@link CoreAdo#deleted} test reports from the queries. + * This essentially removes {@link DeletableAdo#deleted} test reports from the queries. */ public Predicate createDefaultFilter(CriteriaBuilder cb, Root root) { return cb.isFalse(root.get(TestReport.DELETED)); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/AdditionalTestService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/AdditionalTestService.java index e04ead86118..fe9d0d4fd10 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/AdditionalTestService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/AdditionalTestService.java @@ -24,7 +24,7 @@ import de.symeda.sormas.api.utils.SortProperty; import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.common.AdoServiceWithUserFilter; -import de.symeda.sormas.backend.common.CoreAdo; +import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.event.EventParticipant; @@ -174,7 +174,7 @@ public List getAllBySample(Sample sample) { } /** - * Creates a filter that excludes all samples that are {@link CoreAdo#deleted} or associated with + * Creates a filter that excludes all samples that are {@link DeletableAdo#deleted} or associated with * cases that are {@link Case#archived}, contacts that are {@link Contact#deleted}. or event participants that are * {@link EventParticipant#deleted} */ diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTest.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTest.java index a7a5d894404..0c119ef52cc 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTest.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTest.java @@ -40,14 +40,14 @@ import de.symeda.sormas.api.sample.PathogenTestReferenceDto; import de.symeda.sormas.api.sample.PathogenTestResultType; import de.symeda.sormas.api.sample.PathogenTestType; -import de.symeda.sormas.backend.common.CoreAdo; +import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.disease.DiseaseVariantConverter; import de.symeda.sormas.backend.infrastructure.facility.Facility; import de.symeda.sormas.backend.user.User; @Entity @Audited -public class PathogenTest extends CoreAdo { +public class PathogenTest extends DeletableAdo { private static final long serialVersionUID = 2290351143518627813L; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestService.java index 721ffce690b..ffb28cc7bce 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestService.java @@ -47,7 +47,7 @@ import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; -import de.symeda.sormas.backend.common.CoreAdo; +import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.event.EventParticipant; @@ -324,7 +324,7 @@ public void delete(PathogenTest pathogenTest) { } /** - * Creates a filter that excludes all pathogen tests that are {@link CoreAdo#deleted} or associated with + * Creates a filter that excludes all pathogen tests that are {@link DeletableAdo#deleted} or associated with * cases that are {@link Case#archived}, contacts that are {@link Contact#deleted}. or event participants that are * {@link EventParticipant#deleted} */ @@ -336,7 +336,7 @@ public Predicate createActiveTestsFilter(CriteriaBuilder cb, Root /** * Creates a default filter that should be used as the basis of queries in this service.. - * This essentially removes {@link CoreAdo#deleted} pathogen tests from the queries. + * This essentially removes {@link DeletableAdo#deleted} pathogen tests from the queries. */ public Predicate createDefaultFilter(CriteriaBuilder cb, Root root) { return cb.isFalse(root.get(PathogenTest.DELETED)); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/Sample.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/Sample.java index e2d80373c66..eaadcb45572 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/Sample.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/Sample.java @@ -56,7 +56,7 @@ import de.symeda.sormas.api.sample.SamplingReason; import de.symeda.sormas.api.sample.SpecimenCondition; import de.symeda.sormas.backend.caze.Case; -import de.symeda.sormas.backend.common.CoreAdo; +import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.event.EventParticipant; import de.symeda.sormas.backend.infrastructure.facility.Facility; @@ -67,7 +67,7 @@ @Entity(name = "samples") @Audited -public class Sample extends CoreAdo implements SormasToSormasShareable { +public class Sample extends DeletableAdo implements SormasToSormasShareable { private static final long serialVersionUID = -7196712070188634978L; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleService.java index 79554f39ac7..45027c2f392 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleService.java @@ -80,7 +80,7 @@ import de.symeda.sormas.backend.caze.CaseService; import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; -import de.symeda.sormas.backend.common.CoreAdo; +import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.contact.ContactJoins; @@ -1047,7 +1047,7 @@ public Predicate createActiveSamplesFilter(CriteriaBuilder cb, From r /** * Creates a default filter that should be used as the basis of queries that do not use {@link SampleCriteria}. - * This essentially removes {@link CoreAdo#isDeleted()} samples from the queries. + * This essentially removes {@link DeletableAdo#isDeleted()} samples from the queries. */ public Predicate createDefaultFilter(CriteriaBuilder cb, Root root) { return cb.isFalse(root.get(Sample.DELETED)); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntry.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntry.java index 6edec8d025f..1db7d88f4a7 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntry.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntry.java @@ -22,7 +22,7 @@ import de.symeda.sormas.api.travelentry.DeaContentEntry; import de.symeda.sormas.api.utils.YesNoUnknown; import de.symeda.sormas.backend.caze.Case; -import de.symeda.sormas.backend.common.CoreAdo; +import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.disease.DiseaseVariantConverter; import de.symeda.sormas.backend.infrastructure.community.Community; import de.symeda.sormas.backend.infrastructure.district.District; @@ -34,7 +34,7 @@ @Entity(name = "travelentry") @Audited -public class TravelEntry extends CoreAdo { +public class TravelEntry extends DeletableAdo { private static final long serialVersionUID = 8415313365918535184L; From 872e5f6ec6fb4da95c515c15883e896354b8ded7 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Tue, 25 Jan 2022 16:11:04 +0200 Subject: [PATCH 002/253] #7246 - add new CoreAdo --- .../de/symeda/sormas/backend/caze/Case.java | 17 ++----- .../symeda/sormas/backend/common/CoreAdo.java | 45 +++++++++++++++++++ .../sormas/backend/common/DeletableAdo.java | 4 +- .../sormas/backend/contact/Contact.java | 4 +- .../de/symeda/sormas/backend/event/Event.java | 16 +------ .../backend/event/EventParticipant.java | 4 +- .../immunization/entity/BaseImmunization.java | 14 +----- .../immunization/entity/Immunization.java | 1 - .../backend/travelentry/TravelEntry.java | 15 +------ 9 files changed, 61 insertions(+), 59 deletions(-) create mode 100644 sormas-backend/src/main/java/de/symeda/sormas/backend/common/CoreAdo.java diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/Case.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/Case.java index d3881252fe5..852ae6c396f 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/Case.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/Case.java @@ -77,7 +77,7 @@ import de.symeda.sormas.backend.caze.maternalhistory.MaternalHistory; import de.symeda.sormas.backend.caze.porthealthinfo.PortHealthInfo; import de.symeda.sormas.backend.clinicalcourse.ClinicalCourse; -import de.symeda.sormas.backend.common.DeletableAdo; +import de.symeda.sormas.backend.common.CoreAdo; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.disease.DiseaseVariantConverter; import de.symeda.sormas.backend.epidata.EpiData; @@ -103,7 +103,7 @@ @Entity(name = "cases") @Audited -public class Case extends DeletableAdo implements SormasToSormasShareable, HasExternalData { +public class Case extends CoreAdo implements SormasToSormasShareable, HasExternalData { private static final long serialVersionUID = -2697795184663562129L; @@ -159,7 +159,7 @@ public class Case extends DeletableAdo implements SormasToSormasShareable, HasEx public static final String SEQUELAE = "sequelae"; public static final String SEQUELAE_DETAILS = "sequelaeDetails"; public static final String CASE_AGE = "caseAge"; - public static final String ARCHIVED = "archived"; + public static final String THERAPY = "therapy"; public static final String CLINICIAN_DETAILS = "clinicianDetails"; public static final String CASE_ORIGIN = "caseOrigin"; @@ -314,7 +314,7 @@ public class Case extends DeletableAdo implements SormasToSormasShareable, HasEx private Integer caseAge; - private boolean archived; + private String creationVersion; private Case duplicateOf; @@ -1069,15 +1069,6 @@ public void setCaseAge(Integer caseAge) { this.caseAge = caseAge; } - @Column - public boolean isArchived() { - return archived; - } - - public void setArchived(boolean archived) { - this.archived = archived; - } - @Column(length = 32) public String getCreationVersion() { return creationVersion; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CoreAdo.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CoreAdo.java new file mode 100644 index 00000000000..5cbc1ef2568 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CoreAdo.java @@ -0,0 +1,45 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.common; + +import javax.persistence.Column; +import javax.persistence.MappedSuperclass; + +import de.symeda.auditlog.api.Audited; + +/** + * An extension of the {@link AbstractDomainObject} that defines core data that is essential to the system. + * The integral definition of core data is that it is the working representation of a real-world event that is archived once the work is + * complete. + */ +@MappedSuperclass +@Audited +public class CoreAdo extends DeletableAdo { + + public static final String ARCHIVED = "archived"; + + private boolean archived; + + @Column + public boolean isArchived() { + return archived; + } + + public void setArchived(boolean archived) { + this.archived = archived; + } + +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/DeletableAdo.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/DeletableAdo.java index 549ac6b42c6..78a36a2696e 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/DeletableAdo.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/DeletableAdo.java @@ -6,8 +6,8 @@ import de.symeda.auditlog.api.Audited; /** - * An extension of the {@link AbstractDomainObject} that defines core data that is essential to the system. - * The integral definition of core data is that it may not be deleted from the system, e.g. because it is + * An extension of the {@link AbstractDomainObject} that defines data that is essential to the system. + * This data may not be deleted from the system, e.g. because it is * relevant for external systems that share data with or use data from SORMAS. */ @MappedSuperclass diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/Contact.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/Contact.java index 382a5f3f4be..561e8ff893b 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/Contact.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/Contact.java @@ -62,7 +62,7 @@ import de.symeda.sormas.api.utils.YesNoUnknown; import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.clinicalcourse.HealthConditions; -import de.symeda.sormas.backend.common.DeletableAdo; +import de.symeda.sormas.backend.common.CoreAdo; import de.symeda.sormas.backend.epidata.EpiData; import de.symeda.sormas.backend.infrastructure.community.Community; import de.symeda.sormas.backend.infrastructure.district.District; @@ -78,7 +78,7 @@ @Entity @Audited -public class Contact extends DeletableAdo implements SormasToSormasShareable, HasExternalData { +public class Contact extends CoreAdo implements SormasToSormasShareable, HasExternalData { private static final long serialVersionUID = -7764607075875188799L; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/Event.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/Event.java index 80ac4363d91..1b5e65058e3 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/Event.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/Event.java @@ -65,7 +65,7 @@ import de.symeda.sormas.api.exposure.WorkEnvironment; import de.symeda.sormas.api.externaldata.HasExternalData; import de.symeda.sormas.api.utils.YesNoUnknown; -import de.symeda.sormas.backend.common.DeletableAdo; +import de.symeda.sormas.backend.common.CoreAdo; import de.symeda.sormas.backend.disease.DiseaseVariantConverter; import de.symeda.sormas.backend.location.Location; import de.symeda.sormas.backend.sormastosormas.entities.SormasToSormasShareable; @@ -77,7 +77,7 @@ @Entity(name = "events") @Audited -public class Event extends DeletableAdo implements SormasToSormasShareable, HasExternalData { +public class Event extends CoreAdo implements SormasToSormasShareable, HasExternalData { private static final long serialVersionUID = 4964495716032049582L; @@ -133,7 +133,6 @@ public class Event extends DeletableAdo implements SormasToSormasShareable, HasE public static final String TASKS = "tasks"; public static final String REPORT_LAT = "reportLat"; public static final String REPORT_LON = "reportLon"; - public static final String ARCHIVED = "archived"; public static final String DISEASE_TRANSMISSION_MODE = "diseaseTransmissionMode"; public static final String TRANSREGIONAL_OUTBREAK = "transregionalOutbreak"; public static final String SUPERORDINATE_EVENT = "superordinateEvent"; @@ -201,8 +200,6 @@ public class Event extends DeletableAdo implements SormasToSormasShareable, HasE private List sormasToSormasShares = new ArrayList<>(0); private EventManagementStatus eventManagementStatus; - private boolean archived; - private InfectionPathCertainty infectionPathCertainty; private HumanTransmissionMode humanTransmissionMode; private ParenteralTransmissionMode parenteralTransmissionMode; @@ -676,15 +673,6 @@ public void setDiseaseTransmissionMode(DiseaseTransmissionMode diseaseTransmissi this.diseaseTransmissionMode = diseaseTransmissionMode; } - @Column - public boolean isArchived() { - return archived; - } - - public void setArchived(boolean archived) { - this.archived = archived; - } - @Override public String toString() { return EventReferenceDto.buildCaption(getDisease(), getDiseaseDetails(), getEventStatus(), getEventInvestigationStatus(), getStartDate()); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipant.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipant.java index e039cda87fb..985d79e0b70 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipant.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipant.java @@ -35,7 +35,7 @@ import de.symeda.auditlog.api.AuditedIgnore; import de.symeda.sormas.api.caze.VaccinationStatus; import de.symeda.sormas.backend.caze.Case; -import de.symeda.sormas.backend.common.DeletableAdo; +import de.symeda.sormas.backend.common.CoreAdo; import de.symeda.sormas.backend.infrastructure.district.District; import de.symeda.sormas.backend.infrastructure.region.Region; import de.symeda.sormas.backend.person.Person; @@ -47,7 +47,7 @@ @Entity @Audited -public class EventParticipant extends DeletableAdo implements SormasToSormasShareable { +public class EventParticipant extends CoreAdo implements SormasToSormasShareable { private static final long serialVersionUID = -9006001699517297107L; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/entity/BaseImmunization.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/entity/BaseImmunization.java index 8174344d7d2..f8c2d5e9a9f 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/entity/BaseImmunization.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/entity/BaseImmunization.java @@ -27,7 +27,7 @@ import de.symeda.sormas.api.infrastructure.facility.FacilityType; import de.symeda.sormas.api.utils.YesNoUnknown; import de.symeda.sormas.backend.caze.Case; -import de.symeda.sormas.backend.common.DeletableAdo; +import de.symeda.sormas.backend.common.CoreAdo; import de.symeda.sormas.backend.infrastructure.community.Community; import de.symeda.sormas.backend.infrastructure.country.Country; import de.symeda.sormas.backend.infrastructure.district.District; @@ -41,14 +41,13 @@ import de.symeda.sormas.backend.vaccination.Vaccination; @MappedSuperclass -public class BaseImmunization extends DeletableAdo implements SormasToSormasShareable { +public class BaseImmunization extends CoreAdo implements SormasToSormasShareable { private Disease disease; private String diseaseDetails; private Person person; private Date reportDate; private User reportingUser; - private boolean archived; private ImmunizationStatus immunizationStatus; private MeansOfImmunization meansOfImmunization; private String meansOfImmunizationDetails; @@ -146,15 +145,6 @@ public void setReportingUser(User reportingUser) { this.reportingUser = reportingUser; } - @Column - public boolean isArchived() { - return archived; - } - - public void setArchived(boolean archived) { - this.archived = archived; - } - @Enumerated(EnumType.STRING) public ImmunizationStatus getImmunizationStatus() { return immunizationStatus; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/entity/Immunization.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/entity/Immunization.java index 9f7589baaa7..8509af17f55 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/entity/Immunization.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/entity/Immunization.java @@ -32,7 +32,6 @@ public class Immunization extends BaseImmunization { public static final String PERSON_ID = "personId"; public static final String REPORT_DATE = "reportDate"; public static final String REPORTING_USER = "reportingUser"; - public static final String ARCHIVED = "archived"; public static final String IMMUNIZATION_STATUS = "immunizationStatus"; public static final String MEANS_OF_IMMUNIZATION = "meansOfImmunization"; public static final String IMMUNIZATION_MANAGEMENT_STATUS = "immunizationManagementStatus"; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntry.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntry.java index 1db7d88f4a7..7cd51a6bd82 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntry.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntry.java @@ -22,7 +22,7 @@ import de.symeda.sormas.api.travelentry.DeaContentEntry; import de.symeda.sormas.api.utils.YesNoUnknown; import de.symeda.sormas.backend.caze.Case; -import de.symeda.sormas.backend.common.DeletableAdo; +import de.symeda.sormas.backend.common.CoreAdo; import de.symeda.sormas.backend.disease.DiseaseVariantConverter; import de.symeda.sormas.backend.infrastructure.community.Community; import de.symeda.sormas.backend.infrastructure.district.District; @@ -34,7 +34,7 @@ @Entity(name = "travelentry") @Audited -public class TravelEntry extends DeletableAdo { +public class TravelEntry extends CoreAdo { private static final long serialVersionUID = 8415313365918535184L; @@ -44,7 +44,6 @@ public class TravelEntry extends DeletableAdo { public static final String PERSON_ID = "personId"; public static final String REPORT_DATE = "reportDate"; public static final String REPORTING_USER = "reportingUser"; - public static final String ARCHIVED = "archived"; public static final String DELETED = "deleted"; public static final String DISEASE = "disease"; public static final String DISEASE_VARIANT = "diseaseVariant"; @@ -66,7 +65,6 @@ public class TravelEntry extends DeletableAdo { private Person person; private Date reportDate; private User reportingUser; - private boolean archived; private boolean deleted; private Disease disease; private String diseaseDetails; @@ -146,15 +144,6 @@ public void setReportingUser(User reportingUser) { this.reportingUser = reportingUser; } - @Column - public boolean isArchived() { - return archived; - } - - public void setArchived(boolean archived) { - this.archived = archived; - } - @Override public boolean isDeleted() { return deleted; From cd0fdedc7e53891950085736754f5b2210747aa4 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Thu, 27 Jan 2022 12:57:00 +0200 Subject: [PATCH 003/253] #7246 - move immunization and travel entry facade methods to new core entities abstraction facade --- .../java/de/symeda/sormas/api/BaseFacade.java | 6 - .../de/symeda/sormas/api/CoreBaseFacade.java | 35 +++ .../api/immunization/ImmunizationFacade.java | 8 +- .../InfrastructureBaseFacade.java | 7 + .../api/travelentry/TravelEntryFacade.java | 5 +- .../resources/doc/SORMAS_Data_Dictionary.xlsx | Bin 243867 -> 243859 bytes .../resources/doc/SORMAS_User_Rights.xlsx | Bin 19076 -> 19067 bytes .../backend/campaign/CampaignService.java | 3 +- .../sormas/backend/caze/CaseService.java | 4 +- .../backend/common/AbstractBaseEjb.java | 23 -- .../common/AbstractCoreAdoService.java | 41 ++-- .../backend/common/AbstractCoreEjb.java | 114 +++++++++ .../common/AbstractDeletableAdoService.java | 31 +++ .../sormas/backend/contact/Contact.java | 5 + .../backend/contact/ContactService.java | 4 +- .../backend/event/EventParticipant.java | 6 + .../event/EventParticipantService.java | 4 +- .../sormas/backend/event/EventService.java | 4 +- .../DirectoryImmunizationService.java | 6 +- .../immunization/ImmunizationFacadeEjb.java | 224 +++++++----------- .../immunization/ImmunizationService.java | 5 +- .../AbstractInfrastructureEjb.java | 22 ++ .../backend/labmessage/LabMessageService.java | 4 +- .../backend/sample/PathogenTestService.java | 4 +- .../sormas/backend/sample/SampleService.java | 4 +- .../ReceivedImmunizationProcessor.java | 6 +- .../travelentry/TravelEntryFacadeEjb.java | 119 +++------- .../services/BaseTravelEntryService.java | 38 +++ .../services/TravelEntryService.java | 27 --- .../sormas/backend/AbstractBeanTest.java | 32 +-- .../travelentry/TravelEntryFacadeEjbTest.java | 4 +- 31 files changed, 443 insertions(+), 352 deletions(-) create mode 100644 sormas-api/src/main/java/de/symeda/sormas/api/CoreBaseFacade.java create mode 100644 sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java create mode 100644 sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractDeletableAdoService.java diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/BaseFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/BaseFacade.java index 57caa485b81..f121cdd71a0 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/BaseFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/BaseFacade.java @@ -13,12 +13,6 @@ public interface BaseFacade. + * + */ + +package de.symeda.sormas.api; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +import de.symeda.sormas.api.utils.criteria.BaseCriteria; + +public interface CoreBaseFacade + extends BaseFacade { + + void archive(String uuid); + + void dearchive(String uuid); + + boolean exists(String uuid); + + List getAllAfter(Date date, Integer batchSize, String lastSynchronizedUuid); +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/immunization/ImmunizationFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/immunization/ImmunizationFacade.java index 70fb11d95e4..6988576348c 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/immunization/ImmunizationFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/immunization/ImmunizationFacade.java @@ -20,12 +20,12 @@ import javax.ejb.Remote; -import de.symeda.sormas.api.BaseFacade; +import de.symeda.sormas.api.CoreBaseFacade; import de.symeda.sormas.api.common.Page; import de.symeda.sormas.api.utils.SortProperty; @Remote -public interface ImmunizationFacade extends BaseFacade { +public interface ImmunizationFacade extends CoreBaseFacade { void validate(ImmunizationDto immunizationDto); @@ -33,8 +33,6 @@ public interface ImmunizationFacade extends BaseFacade getDeletedUuidsSince(Date since); - boolean exists(String uuid); - void deleteImmunization(String uuid); List deleteImmunizations(List immunizationUuids); @@ -60,6 +58,4 @@ Page getIndexPage( boolean linkRecoveryImmunizationToSearchedCase(String specificCaseSearchValue, ImmunizationDto immunization); List getByPersonUuids(List uuids); - - List getAllAfter(Date date, Integer batchSize, String lastSynchronizedUuid); } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/InfrastructureBaseFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/InfrastructureBaseFacade.java index 9588eb09513..5def294ef77 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/InfrastructureBaseFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/InfrastructureBaseFacade.java @@ -11,8 +11,11 @@ import de.symeda.sormas.api.utils.criteria.BaseCriteria; public interface InfrastructureBaseFacade + extends BaseFacade { + DTO save(@Valid DTO dtoToSave, boolean allowMerge); + List getByExternalId(String externalId, boolean includeArchivedEntities); /** @@ -23,4 +26,8 @@ public interface InfrastructureBaseFacade { +public interface TravelEntryFacade extends CoreBaseFacade { void validate(TravelEntryDto travelEntryDto); @@ -21,8 +22,6 @@ public interface TravelEntryFacade extends BaseFacade getDeaContentOfLastTravelEntry(); diff --git a/sormas-api/src/main/resources/doc/SORMAS_Data_Dictionary.xlsx b/sormas-api/src/main/resources/doc/SORMAS_Data_Dictionary.xlsx index 134ef67d06ce23cff4003256d40e9ff9752bd889..b5d4c7d2573329476cfe30b0246d267182ef5fe1 100644 GIT binary patch delta 37601 zcmV(`K-0gQ@eY&m4h>LC0|XQR2nYxO3QRk(4I2Ri3QRk*D*>kj0}4z#lhp;x0}4z# zlcWYDe_cz%FcgOWO2~biGzB+8+abz8P#joMybH;(EjAw{(Qg0Vw9X3ZU6S`X4<~Q6 zJL(aAfDeN;H7;_B5g2LJV7eMVw)*3(710M$nD0xia z($%<+(Q!h8>_Ll=C&Hxg)p{*ry84bdA>Tv?e}qwbK{Q06L=E8Xg z2$Uo+f(8=slE&(^ySACEv+Yd3D|Hal6 zBSrqy+aY}$G?J(Q0VW>q!92}%MfS2Xb6$}>tju-x7kYMoq`zcU%?uz&RRigf)zczd z(wz}OQ&Th8LrvfM$AA93PpubGlu4fb>8o!(eEpRrvQ@rLvhAO~nn%O;|M1m6fB!%I zu`DZVmDgDXFu(oXf7ieJ%Br*E=UO=Gx9`6G?YCc9fGR8h^wqAa4*z(6U#@myAD18U zgUFy|lNbBAf`1m<`|?nTcwO#{@=B~K_<+l1Cq8gL4@9{t61FK2e?QkrA;{oU@oKG;Qp6>l zgZjC={N1msC4A;5(%@~g9EMQqStPWl`+1etW%44-Ae*Ept7*I^vx&s#>hiY(Y;T^$ z>E-W3L}FzO7B{OzVO2X}ZCV&B-^gDSw#y!NO3ni59cL}x zS)0OuZ4xJIk@e!-OAr?ICN@rK823yGe=GgXV;vXkB+kewM}#FFfvpLm6rah~b3dg( zAml-U4*h3J?%+DE#9%TT|IDvKQ!qILHw#HaE%ELC_G$#zE$lzLxYWt(-k zC0&8zf~~HcJX+vOwKn5?x>yIjTqC76>wo9XW1VCoww^%%cxTP> ze>BP8Sx=+kJInE(yutf#{_xJ4XKS$msP#Kba#-ex_VDiA8TH)CWnCn3+IPkj#El;W zk53u5-*x&V`GwcMOO15x!yY8mtzU*$xL#E`8SLSfW_dN)_ISMp8bHq4IA5`x@F)io zY3L(h1lfr@Snf@YMwEstVfZ;;t?Gkue>A_h6@SCya>8N8ZWul;_F_HEiNa&BRsS|5p-T- zV0duurt@T*Ix3P6$GVDFm0_J5(ofA_7J z_G^d&q2%=8z>%GN4b&h7o{UjMs6kc$V!gtcTak$Z`Cco|)<7E!y~^YMQ04nS=XC+Q z1Lvfw>7#KwjP+LqWR)zG_zcf6G}H6p>K5i;G@YXSlOUVl_G4Rtk;_8GM- z4D&31HgcA_-N;z3fW!F(*y~+Fe@}$D2`)&YE|K9ZKgumfLcQMuOLf`&6sI*MWYNeC z7DLq^C(k}uvjPu3ycgZ)4dD^_DhJ*X*&8UfBL5iuI2ai;Afj;TX#2{{Z{&koo_-BYHhV+SU`6HQe?=0 zwAgdS)vp_27>V4f5lr8{_2d)79lUi!GZQeJWnqO0c@8I3_?MuQc+F|jf`vUDEKHpM zzx+PF^U$7nV{+hH)*8Lfe`=Rd&AX%?EYTpJ zXpdd;Tb$CbaXHAL*fX&6=?_!?c}jlHK4tkUA?P1no31Y^%m^Kw_|s@aK&4uaa*y^$ zx@qx|z}aEwJDweRKAEpwmia1?tj#+hJ@u0C-}BI$x*-|op)Ns!piK0GP4?s=COhKT zlUe9RWUZZee<%|we*-!8G=gbR@T`Jake^51co4YLZ~-f{aO{9~!~+G-CyM0p5y(=} zgJk4S`Vb(kqx?`1xDGD3JvI_&2WiAgv!*7Ju`9j>3F`P?S8Fw5}LVzz{3g;7+N2C>{2_rw8c`#MluRJ6bm9qgpayjTq zr0;;SDE0|Rr)2v^KHE!ndXTERhj;JF z58l{aOy>cRs>em>22Y+t34XpzQUMZVQR0(aisB`qf85a2dmKdzXFPu(EmDVxBoeke z2FAPjds42D2m0B>-}Ww`Vsh>73i4R+7GGhN9oTjw9ci$@Rl!B_=h4`WOnBfd;Tq+2 zl?uX$C`|5P?$}odoI=+sM|!B7!Z~)maDMeO$08}~t6w^C2cC0vZWFOiR#)d0xS=<2 zr}RuIei6zc-mnENVz5d}2^x{(*Sa=SP-BoGxyxN?IyHUxUx z9(jHOR>SlRFR>dk{O|KFhliA5fkS8H`viL^-yrhqvp1Q@TflXBP4;_v{+XU|>TTwI ze+MB8$<+M{_`iKjxpVKyh3A0o)I3Y1UlHActBbje+<3Qh-&}`_*iy?ct%WE znAjb36WAG8o(Zn|6h<@-J;5!I)>zZne+?O)!P6dbud*h<2YA^l<~;_o8})P_z{&6F zef|`fkSNl*zcv%kew+dmh{P(8{4vm(CwGBE*fV#I4Lw`5&45)*R__46Kn^-a>$X&d z6!AgS&}3Xgxc+dOrq0LqOEil^SS1&T{}x`NWBWCl&7sa*T0rP!D;gzQ%B9;UXk}_VR%0ubKfiqktyuXs16$nt?Og>p=l#=BE;+-7ib7jW( z`Q$hL4gO6v}qsT|X`Gc@dx%F#f&KuEHNKnfw`oV?o9mY5AMgA{}UC@vQOf8 z$cdNS)O}uf)8TmTPX9t?8>ThGyD}RC94oW`7_eYU(+b$a^V-n7Qf36MTt}dQNL&}|$t&;@P%>48Wyyaqw^6wBHCBh~>qv$7e&;JT6@hGs#VX(7mSH$EfIDP=~ z=93r9$376EHNrRy-wv-eX0vNjU8 z2pIj08bU|j6T`}TVdRJY#Ir*>J>cn+vdYVRpTrD(4t) zK#H(l@2!E@9oL0cV4?NL`W+!6EzXCr@6$KAgY6+jb?05UOSbs95KQ6J{=r>5F#7K> zLlfWwqX9QOWrp`F0_eb*k9}_Gpi8l;)0|niu{#U=kg5p9f1$`r!o`d~PG%!pGQOU? zOw4HG(dyDzlp?3>7m^w|YdAefULfjylhs>ZeQB-xwjCA$- zT)8^_6nGJsrNe%!p8?kg^IRFu_1KM6WMH)CaPfw~YtsOYys|!u3J$t-x}-ecnr}dD=6uQ;4h@d=${fEib{tBZ z{JpWie?N~N0@wZl$fHf9g(h-LJEB^Zh>6$$EDBlKX>JLVecJSPbQuhgs3eIfwP&I?Sor^gRgt3{Qx zw~#7Wt19BP_$T<+Ax;XTu4V!+)zEgLIa+S$f4Q|L@KSB!RaHx)O_Hta5*@(q_wDae z0lx*Ngo@VwG>n3|!!bz14;DzufU90<$EODKvQAQTY+)WOkZ=4Tl4}ACWne#&#Tb3C zBnK!RI&m?8vn*n2`vg{N9E}tvbYCEvmLES@%HvbVJV;N59+g*Pu_EW^!^uXaQNh^; zf0mbi;F*a*PEFao4f;3_W{9@lQg3>r>@ThRbEBymbsNL-<{3zoWZWRammLo%5PoS6 zP^Zp8YYu1b_+Z&ZRlc(Xl2JHpnKTlpaSE|QyABsmp{z0X0N8gB2!hjh0&Qb0U>_`P zrHR+T$fHM;4jhq=pBprbk)63O#R?89e?z~3Wq?8CfZjAjlL;O2hY!F?X3_$yJ}1da zTve*Fg(uPvCZ})Ebdf&=e?~7g6%Ksb5$)B*6E9$uhc2+6(gqqjsHz0P-jPE^t~0`s z$f2ElutK#A|7dLrAyS<9JF8rw0uu!P)jK$Rs~wI>ef>Mz@}yQNoX_yS5dzv7e?>Xy zA&Q%ON^8l!YZJli%K=)4^{vd)sj&~iU96%^dBPk%bmKx z<45^bj9VGp(@Ydww3!?Z)VJ)}mRecaS1!)89n#6TK#OCkqLoPCaEez^$T%mM*DG8> zVFBfYA2>f&_a|I^HwZi+Zph>Lf5D?Y_5LD{6uJL%m@)bY7w8*;Hy|&zF z*C5CqnZ1G6_X$3IG4ki3JMzbb&xz1uHhIA<#_bjG;;l>THNl9dd@s=ae}O(gn+;`K zf(bowLyQ-o@gVcaVUFiRU9FfyIhrHQ1oqxW!#8lXmmM)Xz(1CUcqRVyl?+BJUc^`5 zk7^mZb*~<18Py8Jc`wkNwX&FXr4xcRY{Q*pgtlMPi{&S$`(e}vH-4QZsYJ^&MP51Uf2nX@iE;BHzk=?zELrEwhu{$=qD zVk{xKjSnGe4eza2kZ1{wZ8-`?>(($4%sNTdL0XZ}`-1TflYE1;Ybn1ZX54|N-CIz! z^P;)b-`Qh!B8_uAE+$BKNmc7;6N*6on)Ccxq%sz#{u@^d^2i?;9;&vSGi8>fK@W7;vmG4!53-nh^Pc9>((dB*9 z34-k#Bm`pP!8P^+J!NV;3xU=oqIhSiNF-`Un@Z?iHzdH#+aa}zHql|gYNQ7sNgboup63n@EIFcY8X{ds>4@OQC>|u zF@u~!Z+h_9El?k-YL^u2SzNG@5ycw4T4>X$Q;<_9piW1te_+~Az1h4lo!(q3j@gJR z6!<4dZ4qJDCXD}+yQl6?JW{3jp_F$z7&G4JV_+at#vNVxr;=Z#KPvY+aIXP(vS29Y z(QX=g0>lhm%X(=<8+O`^n8O|ftKMj~%b$y$oEYTpT}fs^XL2nqMN3S0(z)XLGQRohK`R0qc5d%hN1kZ1`NOmp;$FpY6jV>1K%e*q%e{i|{>zkLpI zHO@15fMH2jG%5+kiggY)UY#A?gW|Cd3l38H*Z)XKcREJ>DqC66EqU0^iF%kpg zc?r3dEi#Um5Qhqum68SaS1JARk=#;HF@$mJAZ#-;V4DGSlf|`l@EU?wo8B^k%6(rl zgKi|Bsf`M<{O_Cov@V(msZSr8GOIafq^gq`try+ce~<+20$XaziFSreKD}2k9XcFT zFEZ|NzCgNKaxm50^uGb^R-@0{%H%1J!?(l^vXrRU6 z{xtJLM*Y*G5TD^D*EH0p>yl5HiLO6B;VRmm9*A7LuDt15qm$^8PahC-IyFf;^#{0_9+|+0T06n{{VXq7U7f zO@Vhd>=guhbfcUjo!3|rdZoo6*PtV!^lRd??cC68ZLpn1Ur47gu4{0mg+=G!0`WYX zI3#QSMM7s-17X4kn`Xl(1S*~SGW943zF(4Uf9E9~3V-WK_NIGc#5(D!c;zuHvN?Sa z#bQHO^xJZ&en%Jv3ik@ zf2L!3j-l_m^zX%atHY-kIp1+p5|R~2=V(`xnIa4-l8>UC=7uPKNB39BAPfkEauaC+ zhx*2H&p~_9rmZ^n6im{GyQBVHw;g&%NHUDmO}6StvMF@DH-Z>4@tj5y>%N0=Hls@* zkV02niJyI%teeMO{2b-HXc1Ws;PdL_9L}bDNtJDY1@I#iUc{fFON} zE8=y3j@_{A2Uw|$VeDq=cd9k;%Fb)h>(Bu2SyfG(F^>yK`UBj2|8!0= zpe>yUlq?y8J<#03CFpZ(9HM0~bnd1D$hF3yP&V!i*GCVee9VnVaM#6)NK)zS;cwub zVr;{mYtjXWaaefun1L+7$?;R2f26$V-o2)S5fdxOpV>a%jFJ`S-LCw8GtMlp6uY6G zVJeTSDAwn=SaYn-wCS!#xPsn5BrdU-z)^I>V+a8DShV#8|q^^=WJwkgnRa zS9#m0khOqpP@?MDaqrD(Xp=sdgSkCf8NP2hV-bt z%{pPDDFGu*xp+vh76!xj8h$=wht~{@ikD{0m+a3ch94b@P3(MsD^|N;n)f>VVT6HE zOzNE5nynq*-uP!esS+rJRe?jSlbvQ8!tKniw(3NvEYT{GZNkdT<`yewn+|!BRsP21 z41BXro7o8gfuyFBL(xTVf1uXq2yV=e-sTA<4i@DuhU*{Y2BT$&&8Iwv>fYm3d_~`H z%U}V;Ahs2Tv89cJJ;NE)DKfU3BHvplcoaw24oS9AdBs9eRg7@&-P#Tk2n&Edf_&<= zAKMo04gS&C@8`3AhV49cH$A&2G(%Xcp8mi*Qw?2b66D%+`U;wYf9BM4B+|oFh&AO; zvBk<{lTt!AT?i+7YVwOUzBoVzmcV3^v(uSWt{|~!k_5euRI(?Sb39+woVJ8PzC0?% z1rOg^ce{P|eVjC26E$@;*qdj64LOOdopcU>!7c&x&-B znp9c*&*wNo>AUQrf8#qnXsQv8scgM6n=?#T$3}1Fj5*t#vjXC9lCLeHA$x`oFf8a6 zT!jMcJ861%<>3gKPiO$T`y~&6#fqIhn0pSIX$aI#l+2{i5Rbl3HK9~9V@p*e=t|9a zteP4&Im-L<1FumS-q8BKJ{YtO4Q|81x$JII%r)?P_gAGw|P-oWx`eh_WN#@JkVF{Qm;o2|K*&^d$d0le^UynWO@ zf@pBygmda;r|b71FsQ&Y8G2FQ(iO`($9^e$o@~UuL;!PbUm5Dh3vkLI#nRPycRbAq zFC9B8$)Fj{f7e%LX5dVeZMtA52V~ISveNleR=VRy@HAaQHf>ggTAxBnIr4ZLoH@=h&vwUB>Ir+i zqPqco2W3N$OzffQ+dsr0*+|K>n#I*F-_kk_z}cRRj#$p9>41g_w#WGZtU~=_4*Yg% zVqg%1f6kwLXBTJNUc1(YywkGFEoeE@a95ShnTFv!RZ>`fPO$u)c5aB6Q?Jp0mOh}S;^IG%J*TgJzM3=xecrZvDQYIhJO6mBT=^GsblEQBG0igl?iFW zRIRI6=3?MGtBh-WvL@X&awmQejO<6uUcZas7X zf8hI1eaw1ohoMYOMq2aAI*O|G)L<$R=Y6f=9J8L0_`|TqY-bf~jn{4DI|Ba!(@iq` zz%rKRBL-K~NG`lT9eTlpey?_{kd^8f&2ZCd#J8CGa1<)3H;rE_f0r93aSaka++i|Ge@)iNu>exnblz^4Zgylq9{L zBCs}*?Z^ONM}}V7Gg?bQdl*-kVO}Nxr3JI_6nhRP69`-`=pK(Oa23+t%sBvd=fP$2 z=uCmpxrR>Qx?BJ^=3Ld;eP!YXnUR11Wzs*QEHxV!8?*ibIvF^NKF_z~lcBU+e+p_$ zy%2sJ&nIt~8~k5+OzXW>3L!TGEpOD%8Bn{^2(v5$$z23q_`?DwPI5v4dZqrC>hmHg zKgqC}OE8^oBm_F;2Mc#H8~Yz!nmu5DNb{qR08!VK+a%H-!@%&Dj(I-R$^D zR-zSACI_JJ;dr>f3JKFk7t>3GfAsi?6a#_^eEipvr)F_rQk*$Po0^g6Vv7bWAL;Az zk$X_+O(%5Ooer1-eeObb5E++hX2$BtFNAwAppU}^x&-}K7?tS2 z)Bq$BsGGxZ2|x=QAGMD(s%GFin5>rx`(2^5#6%T4{u3X#yvo^nd{4IHe_+x!+NJS_ zVX{|E&AsN?i?QF#9e8#W0K?)+*Eio?MPjPVqk={{6)tW_ zx-Tasb$0ow*o7&6D^$71nZ#hQdxnGAe%QC)&<{Ix>;14PCNCNf2qUXq)U__gu%Ww zej$0bVsBYfvFrMZb*gu9tERGqvNJnhc$qEKaN{F)8sfrBW(u?M^`gRhpjnB^Fv&@w zk1T)ALp~Ay88UUUOFk2RQznUvX}dU>Q(Y^GGzxnL70iMI4J`uvaa>)P~FDydDRhc-Y79oy^fjM4?wFYiy56S0W-1!NJ4@C>e_IMw^SKeP0-7^k!a{zmI)-q{ew!y>giTi%S_%dUd zZ=~}1KVat7e_j#43Hwr3h*iJ9e~WDE-XPe9&meX$q!&MGJ{ItpW12#iq=l~_hBt-A zE$I?%2+L|!FJ7POrKz80hfMx;M$tH6l!th<7g5hyX%5=ZbYM>EtHNyZYc+^{Fn$<% zoc2+>^z`)|&c{P<%#fO4ovKp69M@&+g&MVusi*XAf8z{3AvVawAu0GsUNK365MHh0i5N;(o)xWq&hc zOL6x%;mp|*-W`-zK3tXQHheYK>Ms3Fn^*6$eR4~?^tUrXT#jIvEk$Guv&gedT{k|s z+iBYke<9wbh%3Hph^Zd=PUvmmW-m#RXPkxY`FgV@%p$N`3Ae%W7ieN30!2 z_RGc>kYNQLO?zZ6b~Z9Dm@2*2Qy5O=Rsr!ae>5b=Mky7OSrgS6R#=mH83{@|4BhD? zRkqFIvJ}~txlvr2%8<=X*_86-dNfigo7J+dkjM3GbXsgrxu^8|<*w4Nf1ESQ^T(P| zmpk(?@|pCuPF+?xli(IJvcoRg5ivd(ael#8ex42Ayh7Prg#fxrX@dOMp}Aq*zC0-pS5-dCz<=?f`K*7oS(5tY0>4*24L#-JoAh*>F2e5&2-{hG_xtO!`tJ7z zBxrkm@*>V30l9uYk@&>5ry;7Y+w8q`f1gj4eaXJUA!HM-hHwhme5;sjXuQz5>y2ZM zbE(f(BO6(i2U>~bf$@uW1E#LTE;-x}MZxIu$2OHcfnQ@JRlHN|O(LSz%$+X6nM&9+ zbe4vxo%X_~7N`XZW z7&7j-^bi8IUI}{Y2JS=_;@}IFiM=etVJek6^`4ly#zmIAP;KYX_LxlT34N^b3gI@( zd|oV9go_|+*%}^U=BYm_--G5Mf9~jIiA<-nIYjxWH#G!$p*Py$HUoqXm2K%HW(Gjl z0u4yq(OdU}J}1c+JO2W zZRk}|-r$-f+jIpw!ddNxVB*D7S0ENI)aH@%B#BB|I^fA%&;cL;m^ z!ceX;09dhtXiFW(Ea)lVS*#n6OQv*$j%8?0Qn!~SJ(AbfPTZFmr6!L-+<1TJGysPd zwayZSF$QUh+3m^VG_V)J)-=OAP(oa%84piRU*k`@yMi}qY)#19&lyWob5U_clIw;k zf-mHPD_hkQVg(MI>;XaJe^Mid)k&25Z>Fl?>V1*vK0~Z+J3A#>kPLZ#f1-m4Qy&GOfkY<(!Qc?8<8L|wC89lL&MNn5 zaFMu5mK%R(>Ehk*EM4#YGJ}OAkq2hvwe`JQ=X{xYaF}7G2$$Cu# zp1gC$s)Zw55tF#ADGA?B?CLClC;cQBRTh=?H!9MNEJzEc%hUm^WGhs-8*o12b5)2v ztK48#?fl?fpQI2->z-l|BWaY4ZdFFz7YXxD*Kn(L@J8>2EXl}M0qH$%dVaUG8g4zktdm5?BN}qiWLd-eULznV6a8tcUZUSf1t$TjOnthQ`D6V(bFM=4W(bK z0D#FhLCBNRrIg%Zxpp9=l7@S<9BlYCkJ8`h)miO8S}em?AVt(RBikfj!?yQRPCdVN zVtS&d`CXk_p8d7Xbk#^MG^o>R-J!Ke97RbL+-HFAFsVnT)Bnj(&ZB|UUf+T?!6kh# zZd?1jf8LT@SPu8&ubGhHoX8ozWiwz}7&aRoY9>2~oVAV=V*%R!BN6ZOLv>`tm=2Pi z8A@V;ODQQ0i$aQ72mKJ-?PAfOB4^{uyLG;FH|^;fBz@zI|~+BCMuU?e;)S^$n>|r{qhscaHgk3vVR+zhtcw~ zis|tIrE;#`@}LE=mJQ7P;8-3qZh0uIB$~Uts2WnETJG08inrcx?qoJebeUDTz93u7 z;Io!j>InoUrUr$AP?zfdt5v?)2>BM**}D7+-{u#tA5d3({l>|5SB0o$<9zcG0vL2y ze>X+K?;A*&e=@gH?0u~huDJZOY=$v*{erXDu6!f(eId!m88)1DKL>7ln>IiVU(55D-FCwh#TttrH| z-d{g@nkhoqFOu>2ZNBLX;elCm+Jcec_b)h>|Dz8fd=grDQ%;k!s}|7`fow_Gb&Kb-(6sl;uBx$R<=jN%(%SD_{(`oBd`3bpS79>6H54(6RvK%wg5%S??DY_A@EeQvV&6;ryznRav7|i~RB}^z= z#0~n+iVe^gNFC|GPW`5Mq$>mT1yT>*u!IQ>=8+}_=zW}`)s&DDfBxrvvYsCfq5v}O zB*m)U8%*qzWc|KIKvcEMsty49fo0qFb-79f#}7~ZoR(W@9&TBKeFz!zxK8u zJXaUXW#coxO|RP3@oYTuR>EVH&Qln>60*RKa(ukMt}yyoG0<$ruK169Dni-PGy0;YK(a zeWqZnv=8VIf2Rj@@){?MW_6|;t(0qRx`qd!_tdGl>07eR+O5Y+)3G6By7}FDm9?$T zeSuW6i&E^X_A||j8hP=)_E}~l8mWl zBq3yG5TU*6Ik+!(ojX$(U!QP!NK~O*PPH1GntK$im;mR9OcUvj4Op_Nr^UJ}b~25$ zw4JSBq+fm&(Yc*8Vy!sVlM|y?I9UM&&4;2+N=`ege{cQsQ7FATh)S$>Ni6QgYPCD= zbM6=-e`vrc+a|Hp$HfPuIxeiym+-_<$w7^JyI*N*?7Ii2WhWn(7b4mfIj!j!s%jM2 zbgzlk+m*DvPA6ukpPMc-1}Mj?-R*`_-GSh#VMdvI6s6e_ER-;<3EAuqR=(!&YxbCO z8nsY0T3fbNuH>(#!KItQC1|c|_@{kZe`n3sdA!1FUnv zGoCyA??C@$LcW^ug;!x+Qn_q(;P3_cm;YuFbL>f+*~5XW<%@IC_1{-{@Hb$7JKqxK zb-`p~xdxzqm4=%uixY|zQ=rS+b91ME=M{a!N&H ze`_h~b=A|-bUC@AE;$!86z7?o1?;cO1dX{M*gA0)W5QE%gB}_PYh?ndv#VI<*>yCl z99U9m1pyLQqaOji^PeSX{G849eeG3uF~$s6$=A|0OH#fu89$_Q~BR zD@-Z}FB^@wobDe!;!2k9#g-W$>}lJ}E0d!l7AMEO$CK+I zSn4-VYYbt3$TKnE>)8Y+D7f)h)RKogod{{@H(=|W3h5~DHf)9(Wj8{Ox&vAj1Hq4K z2t(648hXLR=R=A~Mb_6HXbKR_ct&-8LSro%c*V}hw;Aij{cW5*`a_m3`3_BIf3I+s zQov(A@X7G||JYZ<7_mVf5#HJ5xGwU;E??4DVPtN~QCW?4(TwKo@O#?g>~kWjqcl1) z(O$Aq85v0{ke{STsHgS7@Oym#hF_L);q>|Q-qu45;wr3GnZ&kq`F!Rq__Gt#y>!ov zC9L(z0gKO=_cH`K_QL9KT-k1we@1{LEAu_`c874afY6rmL##VbgAw8HAS=@_4(2mc z15DYF2g_|+?!BUbzb@J6PW1jom1ds{FiV?66f67B{~7c&1?m=5C*6^m%6NRJYS z-9l1_t0S^{hV+J`zD9W@*u~?1hA-e(&Nel~PiU7HMoN4jJvm8G0AJGwg+6)!23q02!R9E%-op79IC zfMHg7a(x#nutM=stND*EjfVKoe;k; zkNvaZchr#ahCTE%F&OqRf?QJ4D1VMqqN??pW?71p0Z6hz5hEe>e>XDV4v^49%CKz` zMpnC(VR^3%SaEhpkcoW4oXUJ6nc)0@Nba-{Ki7%$<$W=CM7ueFcy#=sYT>LF8`#^C z$wzmHH8Xb|N8Ko1?T%O>hItP1&qv^vLzMmH^rR{K55)P(mtgQVH*nV9rPV)KfB3ES zAIULcU4Wmp3-G5ce|^?cnQ9HQ3$9G;h^=5w!ujgUp>>}0R8*MQ==ct}t@@AyB||SB zhTQ*c0-3(RU;wk;)TLO%>B|eWV{zH$6^P0lWCZ)Sh{Zbll(%@ucg(yz{T!W{$_-@s z%VQHvqL4v20FG#z9#>+|i3dH6{n5l<5D)@W$$MsEY*UH`e-Wo4Dt&n!16n3auKCSh zaqHohW`9{MK_`kaxj6KJ{LQcC8Jgx(`j62U_*v0!zwTwyyAGvDeyIz_p|WKtrPe<* zfc=|MxHlLG#erepL-yCd`E;*N4vVRhxycHvcTJ84Yk81w;vc^Lw{dASMc3c-0Wvl& zDR-Kspqz$kf3`M!yD3ia@k$(_j$EYtSEFk;0JNdwd0p|*=L5{Q)CP|Om>~#VxlA;= z0iwe@YsE}usLqgYX)XCS@mUlc)25O<==>Xmqi^zZVs71L15z($7UL3GSlzQOF)j?gJ}=>~ zcK}Qg%(z7I$zdnY@}W-mD#sd#v@#zaV3~yk%Tq|pNn$}(RJ6r~1#gV9;$Ynr>kgo4 zvNY|hDUA#gj%bv05e{uo_yKDa6RnblY4YP)f1fz0^I9T(_%4fx@c8sL$&?+^zKdvC ze7gQ`snd5TW3a5z%p%77BMWKhe2hU-ezKYJKOh4qjfn#bS4iPi71;%7o#q4YqAVcP z6y0dD)oN!REj()>ZI$MwET)4FL~!FU`D%vsr1yvSY4SB|_!(p(~XcYKZqZdc8Hgu(=e*#Inte zFx?bJP1mG+SJ%UY_`IZ#;o<-mOgqX|fB!z{T1;M3OsS`wN?W(7t-RD%T&2xID@@<6 zGR&Hqo8LJrsN2)lBrP@8UF!6`QuHLgQoKm?6eLQrb)HlGp2ziC=yhh&1NLkrIf|s98|dfFJht?34`c*XyF@`2GhVX(gaU8Ptfsy` z$}zrL+DbTqTovNWHG_`c0O*3Xe__EfmKOv%TVc-~g->)-2lJ+%`0Pl0wH1e`2nou5X*U zSb954d6Kyrde;DcNYuNwIvw?E^X*_WkiSc$2GWOD$=^K3OgWF{=1DG8UO7Pb%0XUF z77jhUo2z~hQcJFe>9a#ksZ`~i1kr*sUBTuAu-nqQS}dP_AEzN+9XHCwsx^z zW69J7Hf%7gM~N0>y;lRN#hMiY{Uf-~8O10mV3L1S3|LL~(=}6Suq7sjMf%(#0uipN z>4#j5kD@4-YvkIn@{S_WxLb>r)D-?kiKj7^!`ReP!$s6l8dMdae`D;aP34USuq{85 zro{dI9N9Fc1}OZkm08a*_9F{~$%3r)bedpZK`LcWyQ)OCMkbE0EICneA0R7!_x0CS zETIMEBOc~~M|DLHa@PrUoO%;`Y*H8L_r<_8&H~?YLnaUWOx1*@&(VVy5gz=3Nx~HQ zb7w?;%xfAU5;}n$e^JVtu`vHNUC2(~!QK2YLh-#bt z|G^L3kw119&rDVMQ_BA(>?l4>_pgkH#w_r#nqNPzS%L0#q90Qj1+G1zA}x?kqGNxs z$uW3{r4~J@kn>&@K&;3t{P{SdTF+Ttr&wniHAqRi#$;4XePQ!JkWBZLA+ejIMBf7N+kw4>gld*e#G3Wh`Ck6F|9*B zOzE>;)k_rif6|=uLzMpcjCtPh`%YlcFylBjGBvD|cqtfn-GSlvUGl>GWYaoEx_Bnq zk?bHMZ`5j6Bua@siNm}nOmeXppC$67VO87@RBUSiBKSqKmx zv1TWFH5;hS`RtsT6f4U%S8M+9)3-uk|Y8tx7bgM6z5JTZ7)Df>E#iEmM_c*XGd?;H({Mzook z+rniRw(Gwxgij6@t%CX0ZQkr@mz(ZSB1hl zR*NWM#vMr77BUg>6to|9WW24M%I{1P_uQxO=^NKnNSB|Z*6nu1cUn?RJAY&L zH{D4e&cTW*yHS9T-%bS^mN@LBxHb?y(XqlTt#W#l^8Hyh^jRluH#%7r{ufT`3T6Y( z9rxK$^hZmHF85JG8-oo46M9{ymyRT#(mqvkC207oG$%!+XE%G_bTlKaosv5TR{7gu zZ`aHB4HjsxDt#!ph4!8x+i~{+{jvD)pzkj&+ZytYANeqNV)b6J*-zc{qw&l=!l8`( zi=UrpS}_V~x%`PlE9mRx2OhK)QdDx_u9{L`eMuE2UKaC%L5o@P*8KaLD+_}R>PP#P zl1w>z4;$6X~Se4#4dN~xvU#FI8Dpw3Lzcq)83wog&_;VkZk9NLSjXkcm zc|or==uvFct4HU(7O~VR52kZx5xTon8FG0E5XKCgR#*a*DjakpI$6G zx_nb#Bv7K6a@_Hb{INmvAxhy>fo*qQDbe#hDx*1eX0gVYUrx`MXWrM8FU7RrN&Te> znJPWITgS!(a}H5-2hpQf&I@_e=b!SP`hG5v{=kF%Y@RJh(M+yIS(~uxsQ%-AHc>+B zd+sD<(|1Yn*frAaZWb9|TCXh6kFeMW`RYe=$%VvV4}8vAl9ncCmc2=*Ka}|^lQJ~) zu)chFI$JxF2=I@QNmCAT}#Bu*HyT0U1X+{^G$kOutROOXh zSDFf*1*)2)bBJsVmvXkFi}d7;n!n1j`_mM#wNLJrp7r#YYyBMa+i^NjXRSyZJ`39QPAS%DL|Vo7)gFx>k7K=1nybZqac!03Bi>h)yx-Rj)(YHmsfwOc zrLblled#b2tN)`Sw&B&E>oa@Gn|MuISAVWn_F5jhYCabFQ=DyA(d1t~d ztTg+5PxX->KRHi2*Jjtyg#Wl2zw27Sr8f;%W~Q^gRc?OXB%gV;XVYd}zUed@?{C8b zW;%NT|F`1t_ICUH;`4PTL)%pCU+xx1ZH}#-F_=YWU320Z3?XN^rXl^lHMHWpqAlBc z-+XwCw&SPuxZ=L6sJZgW;Tt>A^dtSdQkDBK3S`em)^|L1@A>U-`>4Ic((8o0cekN< zVCQu{^XDh__xDrUf1Rf2>22AdpOxVirqFex2-3`W5fIF$$uWERsEX3^4DU6T+eTAy zclq>k1pFST3HpYuwXvf^m=yfnQ5W39f@X}U4>If2MSiC~da&yUFVj`K4MDV~qR+2s zgqe~p$6)r#`@zxqYX`rxU7H#~Or=200#2u1tRZtv?q6Ev<1nNL|CjHUW;K8Obp3r* z;Ya1Z!4ey9Z@83C@zZ7oJG6$0TaUa$TDpqpe-!aNV8W(gGeFP(^WeH&eTL^_3C%pe zC$laF`nxO~tT--l%!vyM@G3=qLF=*G8w}i??-2c%-DCLaY3+NKgll*GwZdp;8hSiw zDU&|9A~eR_Mvm{45Th@7==kH`2M`GcdFx9 z5$2uX+^S;R#rq5cHcHXj1Lp+8Q%&2tujUurm%S$=!PRrrcE;R>pSk7Pk}0LURqd6; z2rrjU%56tH&%Nq*IyU5gEApIeY&bI$TIl;jrUkPBvV2hk`*CVL5j(vD=tG}Hj{cyg zaFWiZw{>%x>b&c|YWFDHB+8S@L`iB`Wols0n*666_M0pVgi?2;Lzuceze>R9Jh@ZY}Gf;V`$!yHUXs5ifCIzswq+(SiUC(=2n+H_EYVcxg*<#tn}TTK4@Ll(fGu+R{q!i z6q<_zv?ow*7GEn(DKho-gT2fPpVk@2-9%&Q+&^8JV$cb$ejw2v!+Vy;75sNS4=bKR zJHhF(fsWH|M`fCP_NpDq5o3Hpd*blrw-G2|I^ojO>_yHw;_+7oW^B&MEUdV!dncwW zn=PIfr7m4?m%gU?UR2*B@|TC^soi{ioVq@bCx+s@?`nIVE4CZcj42igp{UszI-<2y zfOZr4d8?EGB_>3DVP_DxV6%>f#h*}%?7^h7S0kc29oBCm)m(m^}K3v zjjeO#T#uYVK*{xvHFM#Pk%=zm#Dx#_LF)`Z-t`=!%aHF=()teRSaS)?B^_Zy?(R9n z_Wa~aIi_>dq3<$}?!D#pYk$qbmcs+Krbc6yxT{B)y z?eL(QKg>GsA;GacH@5Gc^~R(j3w^fcuE@7bwbl#n`cjJDWjg5vzgeXB<}1_gyvQWk zI2aU9@#xmB{MS`!2&VV5_MbUuZ#b6Joln-vC=?Kmz|@BAYm;2HN$F`MJn>#oMylPeoG(sd}s3&yosoisk=Ql+UG z;i{v5dg^xvyl65gEJ#gfJaa~uDQt8ki?Yy3USH>|981?_*5ip^o%UP{O0K4PIh?WV z-(>Ku$++fwm&ti88~QQsnVy+9PQH%y%q#h!#qntKezsq+ADJ>(%XCvs!?|cx%1v*-0xKN?a>h`re{%ln&3@^t=jdr3?~f}|I>WnHJav!z8x54}1amq2Jp@UvH( zKa%*~ciqutZbd=QvQ)l2=9Z{6O)B(Ha#bmHt@G?U-IE{QQWu%rvXJ_$MnOEs;D>h6 zd-`z(H0sy|_lVvf`+K5p@L!v#pSgAt^g`Azqwr3w;CM%mHo3vUypjWJGP2Ch;;5?-x%S0%FE6dnr~)m z(E0Asm)oz5lpAuYKhI9JpKZkC<-F&!mAf({TV?HgPu4(aan92qvs*5}WT-cLS@Dn3 zlb(_(#Amc~Kdb&v)qIgM8on|4&f4RH76z|p?oD}%H|zh}H94$s9<$tQbSyY!u}Z{! ztV(j$?c)w?%NXU0>pu?l<|{^3Sw?CU+-W<{kR;)=al`3tq zb}(;O{xhw+am^;=R9C;;b9!FVdrq@@!K$VId+Mc)v0`++%AtVKeO5|LRu|2+-zm>p zqFz0AjrODYvd61kniHw2dNrAB+&#pIEP?J?{lm?VqiTrZCOswj^R>kQ-z+Q`3>E6}^E-ZtxI8j(n!wK{+K<#WS|j*8Co{CbxQ zWZCCKge0>Lcs!3_U<-JL8eVO9*6bY3vC`7*H(T&%9`oy`uu-wv#|_`b!+YPX-fo); zsfjVxbBb z_{W!%F7LZDdFg2Qzvu)#7(H)uQmM*;wR7Ioh5GH=M$z}Ec7-QzBX7M;ix0BMFB2U* z&|dB|9ePU>lYdKdjXP4~d{RJ|dknui^5-Q?Qm+-~tEFNYrjO8DxF48b=kZhSP+;Gm zc*)_BtFldDRQZ3#Ku7%GP^B|_@|1#a9l{K{?0OI zRw4BM#pJi*d)n@LiRaAYPAOBjU);@_ufrfdNniN15xZy63q88VI^zC|?+yR6e z`d?0+k@_HzGv5*%YZW3pycG6Q`Pj;e zxZAP&%RcAOD_5k^X}X`HSews0wp_P*B`t0C@~qg}PlaAcFRYlplTYA>`x^Vok^Ord z?-eV*s#-npAw0EM$Zj}m#Ex9!wR8e=;l-ycw+agwgG!z-78&z(e_ocBa1da6AGC2$ zwS3u4Px0C2P~)3LU4tOa0nNhS4oeHabxSu?YnJ0SIahtqkGRoHJKofrTgvktIv9sZ zV((Cte;;gRHtRMXyZBCgCWv9#htJZSk8Rb({)63syD0MBUs=sKUSH5j7Q@Yl@V3K8i z*`e&jcI_9EdW88WS7AGKJ;n?Zx-c{@c1K73q6#*}B(007cKLqI+kCMzUpXgZZXEp0 zzyIeqMZIC!LPM2sMpt(9!_m5!QSaxShQ-3;Wp|u?y)MhdmDq^2qQ5=6Xe+O!-i!%2 zX|OjiO8DFrsly|D)@G~abKkwiPZ<|jRi&wPU3-w+sG#u5a-_Dz++j>*$+hvgTXZYs z$={#m-#d2)1Rr!P7a+@#H{5fK&A!=wsCM}rKlK%B_o&pwxA*cApR60t<>(jxJg;CK z-cZ9>eU%A$no+a3@H7t{S~xN1om}B_owfptByGE8yI5<<5yyv`j~=&FM2dZpD^$Mf zjhYG=S`AdVURM&GYVT<0vj5B^KlgoG_d@R+rF>4^FfAdUv@wfD32x<&13fil({lT2 zc9J862k0_ioFCb7^VnyGTTWhgeTCnjuS-0}d{)u?h-_!aeqWi_2{DD}BPZjl!&yn$U-l(cPa@54zsY)!5*51io;oJiOQ}a4jqUAdCOG5$I(0=c zb?ma(fnR376wCD93_fsROGHOWTK1DAuFSKaFyyQ8w)ZpFk?zjpL>kF6IQs8X`*_)Vj}(O`lRp=}c*B|4sypy0%8Dyj3oWIyZaW{! z|K;lwj`tVSlT;E8?9y;nCQ9VhWsyDo%~RNpsL+T6W))pWDON#wsb+9 z^~-@qwPECkY;A2{mCx%#u19EHNcw+8kq zM|+YAgFERds{D8z>e|b8b9$Mg$Ni~SFQ^(}0zL{lUEcMrGXBv#%I9O>#|>3X7;4PW z-KKs`B^@#P6vOl8@JHR-Vsy$h3Srz7Qdb$oUtaGuv=Pmj-)VU?M$4Qfs(;e&>-2f* zldDb*oEI%oW+BYhFJ6T{+n8_Ee0V9n^56}b=S--OPPfh!^M|Q?)x7jGd-Txcw$_3D zi8=Q)m$fgR5O~wgs*Cb@uld5=+_%WH9mPE!KbCXGf$Pc@r&P9MOLb>v)8!^xg`og5 zG4B1va*`SKC(~&>^mV(;$YS3m`!h&Q_=zcTbD9NTKRR?iM=o;KqRp#ITY=5u@KaGr ztMJvE2u6{n3o~_dmND#;r*4q5qdPn)UL~H&xZ@?OAUDI2C)|7gu;Qgl&V4fzJ6`e* zhhg|AV|Ewbqgv13@l4Iyd;@yd#TtKvlXk=t`f!mhBr#GmgYEReDUD2Ixbbywg@?(N z<_dq3XJfgq(yDs0<&Hj(JSb_sT&qwJ;*)XY$!LE$#k+tgk@e?ga&iwsr!v2zTjmOV z4_(ch^1h=nm>Fm^*IeH>P$GU}+^lS*5p(;iUTcWckfrNr$K&%Kvbsv13b)^WjCmT? zF-BFStKT>&GbWc`rr-CqkTrp8zP+pT>E#H&a}C#Q*>bvebvHcqc8%Kcd%cE|^$6Ru zCRFEiwPKuI$WuF>0b$yfL3Y}r>daNG=H>cRkYQt= z=brDE-z=VMldvp!|48pFpJ!!-lcgq?QpjL8`WSb~x$?c-<@TZ4jKeA3Uc34aS2nao zaNpS+z>sUj7fA3LRl3giCiKb~)n6~_N82x`r4?1geI-A;diV8<=eG;L8yIJH?~srQ zj!F4r>cv2zgi=Ads3_Oa-S*w}tn}E4!hK$ke-DdSUE%UirA<7(yOmb2e_RnUks_+T z%9U1C#2{Mwq9k<6k5yV(Z=mtQOMAnE;vVNWg1X70-s#I;fj-yzAE} zS^;{#(v)u7Bc*4jR3IGAG`BG7Jg=O2RFeNbUHG1%bjCSpr^Kez#=gUXf^YlQi+v09 zY<@e6d3!mB4IH;F&=dOdGo6u1m90UhG*R7p(j)PAR$KDw$gPt*bM{!>y})+FT5h;x zB8~H~S>wutI7h{aRODm7z{Udu6GI9W(Wz*R=L79Y9StkPy@nR1M;@?5-Z?rsAt>`L zqol3n-uI*w29t*1h9{TH3#7rkxRiyRkqKDF+r}d#{B@e!Bt^BNeAky=X z_3q)-o!0vVBi@~GuFrihXyW+;SvLB!bcnwDWTZy;oZdNw3y%l-RNYcpzwI9mT6p%l zS`M9CImkW|_|Uhx?SQ>ZMYN*!3G~kW6`W#Lw5maS-1#R^?qeNcmGUG?&DMixtX=6cUNc8Y*3#=qQKO=BVB3S*?AwD)~dl#uE4MUc0t& z#WsBTL>k5;yILe9edPG`)RUT2Ki3vZ?fm)@j~jMh=pzp(@z2uC$k5--I{YV;Z1Qkm zXVY6dgjhR$lc8i-G1WU-zsz4+$yuRdC)I7Fei=$g*WU4|Pfp2sG@o0NiqOanOPap7 z+g=2HOLVG?S&i>j>rO}3cl)YezLdOATN=~gFZw8z-lRD`Pq&?NuZX%#foIcPPF)a< zKYjY$2#lZ9%09{+lIx{=mHRnHqgX{G_w;7js%omeX>GaiJ0Rj@jFRHS28G*I79q zv&!eDBP%=ZSKi-e{)V}zMM8;1@TESYS;VfA>!_$mOG4@8gP4vc`i)!Pd3tAA-6hUC z?_Kk%YT;XW$kbcb;nOK|N#NYvYLN`H-I|Ho@Brtb4;|Bk?W=yLXAhOy)t=@Ob`N*u znR=h>haPuN&1iAir*%r+cJB2;myP+bpPg}}it4vensZCj6tgjIil2w-eqFmQxv@+C zra8|HZPGq?{)1sDgR6#sf=GD5w z_%dSU635^VPt&XWA4du)?Y;4lVYXu=y5n@bN7RY8Xt%(WyP44!H?_^&=Aq2GKd~y7 z&)07pw%^bG%d+Fc?m@GRq{}Tzt-9*x1&$J zs2{sG2KMzFLl1^tnEhzTW2!fdYNNSma;$3BVAn`!gT4Lg1et1seT>@avvcc4`_2^% zeOE+%smmEci}^4NgtgV5~pSxEauyK zHO(&B@{w_`yk4?w4mI{rYphX+vAxLV%fa!h0hz(|NAIFpu7C5SmEo(*m07*@N%)Ya z?@+zOml+i0_{zk$8~cwoX*`^Wsqb2J{(ez$^@C`H*GKoaJo^Q;4~kXFau2%ENw3>y zt!eJ?7w9-6v?eF{<*rX*FI$s^PwT!F^OJ*pW#dL{t=ScK%)zhGSk>yIqVl5cp=@L{ zDSDWp-9OhxHHgkyIDO@8n!3XSw|@5uWFz}Yi>A4D3)|uGhcVe%!VNlXKM-cEMwY>~ z&N8f}-iv-I0(5p|h`po14!0F%1FqJ+ZydcfIH=EcT5PWS4PW*Il|Y(ya5XZ!!=-(C z^U6jf3t1D-4*UCh0gO+Z{}gR*Buoz;ZE5U0FS7Y7=g)UH^q<^OH<5f~;Zw!8fBFOx z%-9ap{4kGy>i&HrCvfJe2i0*K$v^Ln&W2ALt!kp4JP7j}y=c*fW=uN;e&LIdJ^iEK z>QW2FZzZS}ohqAu|E6^QrS+sMC*ZMBv|DrjIXUqEL7^WjuWlW>{)xWnDZe;+ce~{y zy$M-ydaZ~2!~4YT(T5f#&AprzrmbBVEuG|c8+JC%iSy*V#k|a7e&qZMqnRG|wQW{Y z&+}2YRA))oV)>>{&iMZI&Oe=1HU9J&D5TF@^;1C?44)gi%iR1rv`b9s?TDuD=cg~v z)mM#6*hQs%Jo3O^@pZpRl%4p6&XZj#LY5!gyria5WK(>23_kop+f#Y&*6l5RzSLWk z=y;Ub<#=SHK_sR3kd)bqRhwz>5k1o)Q-7|t`fvJ0HhJ>sAH zusicn)ALhbeq*IUKda@7TAU4u}$Evu28-Gw$lWXyK99?r)xq#wGT; zx>$!@Ys_-IdgvYh+2-d7avo)+Z}yq*eQm4ciV;1Aes|c<^W9C$4@M{Yt-F#OmZeS7 z%r4qjn|8F!og%+&|F~>l=Y9D^M?dEu{w$D|TJFh(IuXL_|wm)6l zW!6Hj-p4l7m?3n!hyUPNba&A%Huk}_YhzFMy?MsPwmy;}zItKP{~`#_w&u0 z!>MeOVXcpOnVj;V+O&_E#(eC`Qy?bR0xf#!Z=dKQV!S5qnB zKbkk+`duDxC{?kZAs_Bd%Xpyt?RG_t?$PvC-_+>tSQYCE-vT{nAwc7KrE?AsLj^LCTTQ}wLEe9*+x({`q9=;Lp!{a1uG)2qpF;lzV9IOP1K8j|JcZoO+)Aj*J{=W_e9gUjMhh# zqg~5#{lm623L{QWH!4_N^LI6)FDv{UFC8*rxO7-vO+csai6Lu0$ITfsrrYN?k(2xz z@s!e%Ntb8#9_o7_5|XRqa3RBs@?D+4wNqbsPa4iYsjTtgb2@*cCVy|psG0w#-q8Fq ze^1F@UD<>A_nf|@b%p(uoOMk~7yaWHs9~YzX1fo|{WQbz$GMCRE()&DTf%qI`uZL9 zcF$$!9-7K%q`kguxbFBsZb3Rn#co(=aZK%W0bk(_qxFT47Sdfz^#gX8<8eF~m8%+CMura|2Dh^5tGcyv_L};Z(RBUrmLcGOXv>HS z2;MTJ0uTN*Aa^$u1tueil>g>+;xaELJA{z>@i<=0&rs#9l@sBF)WHhW;tsa?D1u~} zJ?h$)Z$mT*%br*j{0ioH+?l^F5WNRr7>XxhkiGTS;K9V-)*|}yV3re)Y#FDMNhUp-F)q1;K%DVBkHnD7 zC!~y9iMhMA0%=|a+gmQ!LNI1U1QDDs_8y^GID@MMUcuOw+Ha|TE(`p-X{g@^B$ZS_ zQlPJuTTR7SRFm}nLCw*>ff%7$-7O=bj>K*4KFRQ$t-rbDhHNA$x6^|yH^}uGNMqz7 z$!rBYBH^EHHrZl1-D}qAHbQa1bf??^j6F{Y#|by?g3ky=!x^C+0b3+O zU4JK#2NTh~wHL_PAF!keLCLF3XLE@70mcWEtLA@g}9NupkP+$<4 zq5dhtJmY+&J_K)34u2%+^TFAzjbNtcwh9G3zX^7w|CwZTisng1hvo}OVEH1+RkLep ziv{Ddyj5JtCInEvTpLtX8=1KU5Bd- zTg4l231Ex%53CDYZkuow@mAdsf@BS=ghY^#VzW^QIDNb?6d#VFz*3SU;Qiq-tUU#( z3$~LI0rwPMm8B--gK{DOLC#Ku7rp_oiy{pIzS>|jnHE8^Q|vc7QWL6-1O%rU5Z)vN ztBeSE@^J)wSYsxV{P?hydk|ZN;e%SDP~_OXdl7Ia;Rr7lLIzksaN#dAA6A9!pVcCVcEiLz2dORKkr55et%| z+rqJ76v$fq0-T%!4f4}pX{;|T@*VYGN+^s4`FU$Gl@*!Dy|wtZ5Nzwb62W7M6(xZ6 zQbuA?c#oxgq$p&mj+}rk+@iGxGK}f(B6hbak`GP`A9~sh`4vtJA6jw`koz_wX`uv5 zWcwD0zZG(U#4Xi^kUfqAiYo>~Q)!FLCGqfgAWbmd5&4YrZw^q1J4u32O9=>%zk$E7~feeSd=D-(knoIqTM34#UM9`+Y-cv z)*>JLO#3QQ~ z=Anm@#83~nhEhjr!YX z0c_eq6nYozn-8j?V}x4RinKIFrPKdi#PXa&p-6`7m<_6g;_oWN>wx-{w>Z?QlWy<11)w-de&1<=sFrBgwBqd7&sK$jSx9 zfUlH`3)rN+55!B2V1lxUXcZ3a@`Y?!06Ga!JdgJ`i2zPK58?ns?}`$@qe*WfF#^yP zUlcPU0x~6{nMGzd_@Nd*fG$GG0L804bOpQ?0npNMz&r0s$YB$QuA?E_vjCNJLowhh zN!E9Kct6`A8bHOYMa>aghbw3+XLK8H92r|rnN1=>ULtlZ5AlqgE0HW9zeD!G4Wj@ z3p7py=K+Wif~Y(R`;hbmb{M1&Y-HNk^pmAX1rOFeWR^Y>cP=t8A z30X=X^c~;=QcByTQXxCwgddJ5Z?ONLcM>`CS)fPWgrf8U5OD&UBRVl$1vVBEyGqbI zV>VLE3m-ntqD1W?7UutUEW6oIK>*T3gUts)H6V@(H?*^D#_u34FVtSdEc6Y4_zXCF zKn4b-iSDH=kckf=gL42x)IryM2#WO@=B?b&SAW1~2|WTRz7H0%1$?+Z9ND(R2N1%S z5UQYVY|Rg+!UG)!C|=dc7YKww;Y7OvXD>lrM0*L?$kTO+=sFhB|87omqwSgikUh3d zwiPn*BjonYy!YpM;3Tu{6diyPffGK9Mn9m^+mN`_zyf{oBkcV*01*n%zH0<0t!uz3 z>tSN+!|kaEm@ehuE|l$)s0ZZ$0(_aKsh_=+0!~)j^2I>!i7M3BfvONBc%7hXfU{E} zN1`2%vlXCHVB<;I4}2Bi0HoWe>lX9{IN=+3e}$xP5F)z|+#It8k%HSQ zV*+^rCwyfxZUDI@2urjlaJCuri)i!u1G@oI_a~5kZRWZn0!UA7+anJY2%PYjrW3~3 z`yy~s-KHGdmss7$0=@Ak^xzYYULK+dAfzK60PMSv9?^Ek**Z`Ru<_Nnis{&kJJu@O zKj4_K*e9zJas*pj4vWjI$M>H^9d4$@UW406!qz zJ^`6yi7jK>Mx{4J&V>PJ@hyPLv6Q)VTKOY?~x4=oWComyW)c?HBGPnjbLj{pWo|(Hi__ zXf_1Jh)-%G1XSwC4;U2-C7@cN04@9pqwWC37wC!F>tfs#D&4Mhp!wVTeD zG~lNA&^9N}4Vdo-QH3T9s0{yxQME9Fwh0bZ-h|OWfa0}dy36TsuU6{YXmg>eFoHIj zmFsR?2XSvQ|4k5ygsQ{9n?R~?f(l1CP;o@TXbuWNzU>`{4bG!`2hCkDVPDEsA>d@VEssP>n2$ArkcU_VQ29*-qi2YyI}Wwm38T3H#cR{1 zWohEx=ZJ2jML_)#C_(&z`7y9ZtZ zpO9}adIHYlH8bo1J~W4up~|H_!wz(|51u;oHHwhTPMy9@+)byyEtyPKnD1ybp%7=H zfeMNZMq`L*E)KoO4x`{hcUW7})8sJm$BlnyiaI5RAnnR<@+R&&++K&vTrl0K7=pBO z3=rw#hS5wST7^U9c_GGFP&4pxJuIF3Rj2L%pgp~9NBIy#EJ3@=!1>fU;3T{4tkVm? ze2%dM?HjQ`rA81&%ZO+T4&~Ypqu`T%SldkeP9Lu1(%ZBjLOgKy5bAn(ZelLJQ_=)&j@7={Dhb_u!A2F@!IulwcP*zK68Z zVC6^!tZ%Jh)PRWE;81lN7)<~uexIU_s6gD|+P;OmP)jO7`&k;zC0sGIx9yYK4(8Lc z0|UmHMi?-$G$7@60bV+jMo7yYhxT8D(OiJy6QF&!Muj`L+h@lU>Q5siu)=2!;R>y{ zErDT2=v_J}-hp(2ids5Q(YOqw&O|g2hu(97(JFxAwYlY=_2OzOwymZ|p~-ZDc1FZ1 zxfO8Y+vfDi73NdQAZQz80F?-L7;Sd{e=poP47cn6c~QZ7=Cj@?gKByfF=AjlbZ<=xabQZvOv-L z0g6w+8pD}o1Gu*zq9-X?1pRBtu{&|M`}S+j;W|urDvKcEoCQR>Zop_J5v{_Z4goMa z2~fN=W!{~(eSlVYTWeb&hHQfN{geeIoRio#C(a<4&oP^zeIpyFT)PRQWkj?EhjN9$ z=vRQ^wa>j0Z4d;sxF6#FEom^slS9xRRrBV--LBi;rOt;z(z&3FzBvT#m>i&TG6F^) z648Df+8BvP!P7oi+5xlY08V;)HANt)T!OSzqf7_xZWG?t^28WeBm(f^`bv~gEoFEP4 z^i!C@BA<|sD?m{c&j`-oi6vZ!T!}un!=S!2bpOpk4(iWG$>4`XRPTfO^POa5Oo#rf z-U;#EMeWD$SN|@M9sdK%f=8R+3F=+KWtfRuVjzRGD?r(v-$gOvfBp-RuDbC5x35MH z@m7LbUMENHgwpd+Gax$_oj{jz1NC8t{EFhG?uK)-hpn+Mc3kW6X!l9b9 zumb>J;?t8l>aE0#(z7uPYEUf&sg{3v%Tkc zB^d&4Pr-QY`=?{7$}p=)5ej}vr&$EF_Nl`JK1C=Nd_8aBP(cmY7d(okfI5o^l`vwr zSNQ`tlPJN5`~Pqc9EVvL?h#l-?g17)GnnPfJ%ZvD9I9*y`xXOVe9A{uFKP9H0`KJh zZ_0H;FJwaaIlylb_R#K+rqx!+3s%qhsqS}J8hmp48`CHi@F0Gal-+* z3*T7$cwIG|I8_9;;x7JQ-4hUF3E}Lil>qL;?r^+U2|+Oqhnif06~W`+-S~}U>lj6$ zz)*`({kJ|pqhJEsQo^3?0vrORz$M_K_+M?K7?{IXgV{`2F)%gPg8X!x5F#C<@538byOYG5z0K zN4lZD`zU5qGYcUYJcow|t`QeE#tO&HR}+*FH9#qmo!|_f%fm-nr%G2O1H8OgfD!-q z7E0lO8TvSYa&!&hL)eIW36#(a3@Do~H-T#aaN!f42NKBZJh-sE5I2ULC0|XQR2nYxOgJ3kV4I2RigJ3kXD*>kj1A|~Rlhp;x1A|~R zlcWYDf89#NFc3yxrR2Vyq$?t!?IOy8ptxW~@h&7|TWo$vqTPLa)4EnrAs5MfXAYC8 zwg)|CALzqiO-)!qNrpyRHJGj@kL@nMAX$jQC^1@tH92A++oqC^OY3p(twSFN3|aD+ zz@@86AEV;{LH4LcC=y{(_-eftF+F_;PRKXWe<75Vo`c3Hl!yXmVeVEVIVqJ~mG0e- zi$F=h5jC0^fE5gW*oa<-e;bx$B@ba(scD*uX|r%?A_mWQw-3wk`C#V1OC(KoQgi81 zL{wQ4@OX4-CEv-@=IXlLk*1_&nNyaRv}KIbvvgi6_|-oPzwXvImuVqAX8Ze_nOn;h zBK%o%^9fK(2MFG+7E1*I006N8002-+0|XQR2nYxOgJ3k1QF9cN{Rb$2y1J{f1rCBv zRFVJ_0Npd{uoO6HBvAnZOg!Af^EB5H*~`lAc}4cHGS}H(=-K^|{*qNSGk_pf4Wvg_ zPm63xcSZzFP0e5rHGS(J|M~Mivz|p+rA7XyufF;4^;ee2SH(Kbw}1L-5s%;h!&m?O z{r~jGs;aG3(d0G2{PuT$U;pkatI5-!8{w$mzWe&O-+pBQs=WHsSG&4C{NwFywc3e& zQhg{6B8QeuQSOr({#kBst3xT0b+r?s-efA#$ztMvOn*58j)k*)uD zTYvw@Tl_)&7{4CG`ER47POL*&)M8b`2b?!M$$|TMB&t=JvQ43X__;|-K?e85i?vQG zkyLaJ>gVeG_n@ht;4?pw25*}eFoasqGNnD;&#SDd(q~}?*`#Gv`^lcnCKjLT^WP4z zy+xj6=f95;iIp>0+`Ja0Rquqg>0qp4BY#oY&U@GyL7yf36sO6>QM2T#L8~Nd>V(_J z$kcLs0=6b|C}6aI(%Ad^0GloIxKC+W@3@b?!v^-N^K|uz``tJEzL!(1xIt#J>F+Cc zoV9poZAt^SS(2_rK8SNKL0HtA#5kpKGB73ltqL~xO;WDYBqygF5mtBvwkC*5d?s7Z z{geTLkOv7m44)~vgX^RgqY;@-vwsp~1xLv%VwC-i$YwKtx~@4Kh>IOR!vD@2KZ>L@ z_Dl{y4?m|sYlXcfE6)6MymiU;!hJi%%@Jh#BE%w334uDr8;Xr6;Smx*-8qWS6O`tF z%S8zHAxl;w*vRV_iY-g>@z-upzS+3kP8bah36BHN?-lvt_IKm3Er4<0{wPkd-@|)c zzmnOt4aRYQDv?)d4R4LH>s2!tC#y6AU~b2+X|rmkksH8-!1#gP2ygj}k*Je2Bh;qD zC7-6hOZJCpO1n`xZoAzNA)Dv~FI6_*DIdr3#NC-R{VNQt!)) zY_o2*q$_Y-u+_Cw-@TQ;7Bw8t|w0=del~b0RZ)1HD!t2cOuDPo-5NZYXR?t z>E7dz62MHtx&bAeg(ShcS+8&R``cIeA6b@F(p0edBMz%`sm(Z_KGxA7*GQ>NbtvFQ zK4rqhZ=N9M&uMfJt8|khk2yF``QseVKg(QSZnfm)VK1*ep1-r)htWIhzDaYDSdSn8 zytC$iMV1!ttcS_?o#g}%-st@|e|Tpt^0n9i)cTzzIV|%;2YC1Xj0SGyQ&Xl%Hgv`m z#FZZek583!-*x;X`GuFhOO15t!|o*1wO@u;xLMT&8SL(wW_dN)_GG;V8bHq4v{>akOBt6@SCya>QZAZWul(_hLOR%9W@> zkr_v_uLFzfWV68;Nwn5Rb|4P{oYzB9);u#i*R590Hs^BeB%4Sw?olyWx3_fOBRsS| z5p-TtV0duurt@T*Ix3P6$GT2dwPBrG%F|4b&h5o{UjMs6kc$V!gnaTak+r`Cco@*FYN#y{gy!p)U4+ zE}9Z{2hK^|&`0BX80)VJ$f{T<@fn_DXr|}G)h*1yXgkHlCqXv9>&LdH`9N1MAL{y~ z*k{zTFwC?3*~nSyb|YiC0uJXFV6S(7DLoP9Cb%G}xT#jwWn|d*kCzVoTW8kpkU0QXGR<$ddY;8RW3mA*Fl`3%&9wpS89l_QG2<~|S ztmvz#e`ATycmdPgickw!A!&jG`)ZZI;1u}>YhL2PhxelYydgXyUlqVRB3p!iO37{r zy*eMP*a#vC^uB?SpHPvNWjJBLSy=nz6LiW@j(*tz*ZnDl+XMU9%|C_NRv!p?3yfkpQP zYX<*Z0q6K`VEIngM!>CpC13l0cUk>UHC)T@>A}x8>9*-_IQy;i6MNr;BGlUI#;}0y z0;I^10qL+8imP9@!Y~rKRV$djee205Mmu=xh-M~aILp$CQt}+msPHdAXUUq=q=ie{ zA1zIt0Kfb`zVq0gc~f%gWXDaiPcyOu_X|55dA7d{#><)K2mD91inUgM@3Y#aRP!#W z2TL@_C)!h&{FY?&Yg`U;EcOiS!vDb!9)0q2{wXhB2toho+H`$UVMgfaEb!wA0hMYw z%01d2>82&G1kR44!13(Z3&?!!sw!5gWNqF7>1mz_|GkJj-;KyPcTEKn1ZAS{Y_cbJ z3E2_Hp3NgKCTr~^`$Ls~QW?mx{TQY}!SfnsL4KZi(^2U9(Gpf@>DVFdhzAOuPZY_M zS0GE}0Fp^C8$y7zj`Blc=sLLI_S8t69i$N}&6=7>mJ=?#$X!MgZ%&%Z24r!Id#>H- z$PK3-jo~hex$ld{CQSMWaPRaI70=AdzbSG7Hckkc{fXkN^YpMnR!Si7w@9i*l$<_S+o0Wra_2CCcZ2lyXD9cRz`j&UA4{TBHsW zNhEA{0*rV2_q19e5A?H%za3ma#pK%k738ttExy1iJFx9WI?`f+tAdLZEaIsfoAAI{ z!Zj+IIunEuQJCD(!m%$9IEAiLjto#ag>&k9(c-SvKppGc!}MJ;eQ`@1w5n-3miFh)tNTzOA!2j(N%AI=;E<6WxrxtlC{fg)={Ur#Bq>6jJQT{fM2Vg z5YLDSOB1_;ZUQ?4%QM4u_hCfi&@QJh)37!k)VeY#7+0Z4Rtrx_Srr1#-{{ zTDPStq)ZN?fhOY`!u5yKDrnnrJ`h16o;oNw5bdZ4^v5KzZ3XyTaef-!^NFDozjj)4z~nJ zo)tDvBFiX_hWY3xp(V4Ag)+Z^CP;Hw!$jdibBl2Go>jr&ctL6!f{$y{kZJad>@5*cpaIDPY z&x5H)_ycKP-@l5C+jiMV8Ix##4s>k{cXjzN8B^}0>YOB)X6C0y;4POv%D-cHln9&j zh@!WTf-if}KEm|~9{H{x;bIgoe7_JVGTrk@vrlp>1R_i~p8pkC;z?+e!(iw2u1v^L zaDouz%?B@BkfGg z7`s%qvxwa#Od9CX#6>AA_Q>=VA%uGjBxxd0`eF{053j55!U`a1i-EQG={opD{@xcL zYa?-sfzi*YA#~zBFs!^6#X%IzJUgP(1D-yu>Y^(4X~NLwDDYrHAm2nYFOK14PuwXm z`-~ntD$?wI4DwF3PiwS)4^Kn}oIj)6j>C_0+c(ZAE?+@LHqHo`wJ-$1VL5UqA4j2q z9ZAX(qzLQf)*6Z3>$=nmEVTYuzavDX!+AFi0{SNRu-#>-?!1Y1=@uUsf+_OtAKc{~ zqyLU_Gy&c*8gRo?W_Z71fDWC-G~kvFx|FLXE0}egy7MrIsESa39Ll01T+H<2Y(B9i zh#7P)%DSnT zkuF}J3s)!bffs>UI_$RwIdFY2&z0d!&L^mSBYQYX4?EPj(Om?A1*Cq`0WJ^>M5W%3 z_G7ekeZ|{FK(T;-tEX0{wy*o!nxK(LB!^@Omm%jClz&ci`ICC|ugk!$FJ zcpYll|09TMF-Yx878m+brlpqsUqM!r3Mh%yx(TBPLM`BbH?nwkXdgfIo8@l_0I<^O zkvID0{cj1{6Ak!Z7VsY%Lj%1Tgs z)I9WNHie#-={}**kqeUGh=Gp;dXq9e;4H$ur5$2;PErP5saK`@L5lV<4H!aP_Y-vnVS*8~{K(7q>& zG5KIg4p2ID;$i@2Stiu>39QyMo+wP{zCbiBKYp;3$ES{Yke&55P+1(gLeK zC(SEdRjRUuCo%|U$8XSdkv|20MlUrL4t(4Z?bXE-FJP6&F0h}{1{yi2sszE_kwe9< zGr^I_p`CrOBDDl2Jv90PYI(A0qe5 z_1*CPqx>qytqksIF3K(1Ob!R?TlQ#6t*q=T7w6HA=ww`=#fenWN+fVN#fvCqoDlzsMs+?*9U2j6T98`i9^QD9UXDmqZ?? zN}sW(V$Eqr?n4g*I3W5|PYic^Tc#kwNz$&cz{wRzoZnfSw1VwnP~zdC56B%nAStRY zHKLyz5M*DOy@A*F0X}^>2^Nt%38sY4iP2*=ea0=u?G^Citt;y##fYb3FVOsdfj&T+ z4P{%x89i}hj2EEsAdA>xj^|xdub4wQSs={>_TEOrH*mG*9Wgt=KURliCI0l43`Q%T z#aG`?8X3BEs~%_>)e6LUFVLN}wwQIL6M{A6?#R@;_h9{&Q<-QXbFw&I0{DV)-n;yI!V?+T9MHEg7FTMe1o)WDZeCU+>xi< zTTry~;)T@T*;95Rt#dpsCP;T_-RNi&in(!43@)0kQGm8V8}CGPRvWKxu?5zJi%~K6 z3XOe$OLXTk?P0Ib%Y++$d3{qe$j#r-PET zbfl6&4ntRYYzFp^jTB)bqqwj!CMaqs-0jk!yCN4VxQrd_ie?>r#)g#|M%9z*@s(7R zSJO_-Aji;~0X%jGG=!?&rR92_lx$=~xkj%R+H~v`7Ssu-*U>6}nf7CEHZM%CHkOy*4A}XaK=#Fq-ZB=W-w?2Dy6|l3CE1TuMvP5fh$tuDHI; zZ@^t7eB7-0cS&7;ted8MO7hzh#M+D~ZZW*5)>IFN=z?Ur2&D5K_#z^UcmDhRJhHB7 z!$2+^AqQq_cUu*WMY)$> zKZm5A7CAh?u%s&*l>}oYx($&Ky{5OZUW>+Bm&uEjSgW)bTxGD}Qn!LZuCkW zw?oMc`jLF5HY&*Szi)=qx@aP#K7DM;tmd4Ms$OEWL3C4pLlU$zY?&!1+6glG^j^Sp z=y6bk$hgP(9GO5EQx=Csct<781=3UUoGe1Bp9_)ZQn{PDUQZZ*>&_Y87%|Yf!#b6^-qUFe1@Cc&`_VgOFm&H`u_NYtLS=qAae1#^0s?g6&cH8s?f1%z-w7m z^jK!drl13VW=5lsi8xfum|@oqo{GJsKN zK6Ga`1>VW97ZB*tjdG53USmnAb>!hpVm8Y=C z=JY`r-;zEnRz<;E8Fn}aZZoM|kFD*&<7;{I>+y9#^(;QjAK<{NRH3DW7pSj-uvUX0 zJ+gr#>VzU);J-mE07!4GtvC{GR5VO1mh%QUD?I_UDi#vB6(PNk+4MVCHIk1xSs(7i z>P3EkH66=S3`5stcrQ*{9X`Ft>5iL{kgPyDN4uKL6k$-2d=!;m7^3(c-CrexFdz`h zO{5JR8XC(z1sz12b?V$>Fv$?^p89v)br>8W%`r|l-KrzWrqJ=;2x7>@a~w&mhYrTc zjLv~T3SDuL_i$?hzDfTqj~v4*XoN!(GK^V&VeoH8{e~jL?=8GBDHw_$PnZ>!?_VC% z@tKl`9`p6_s+1lIlb+-(=^qQzLt}I*>feg7Q>}ql^h9PjIYB;{rQ?zJ6^m{>vn#P;!Kl&m=K_T~4happy> z*bVgzQ+ZrPu|6i{nqzhRw!0qT0(t|HILBg=!|;JIY_#O-44bNCglWPMW9cq8q_Jf{ z`fAfbx7M_1dKH0;vvOa7!2QQ`1yn#UNbN%UYapqvOgagesm}{vGc>NSnYyo-s|v( z2?j!10cN}v!{1rD)JcA9Spw==)ksuQ8IM5|1{_@t_(x;EpHKQ3w)5EC^z0tdjA5+?`UCS!HFUj6kZaTHD`*OTnq$w2$PT^` zYs#Nuii6qIXxaexdw0h3A2PH$3$g2bXp67(`s$(~@&@nY3*+7br& z)2m`!@bIm5x9ev=#7W~dQBzlgy?OSRkdt{|8VBt=^P-YWDSamQ;{8*C=|hhltb>Lg zSdl(blPZh<`4mSaeV1K-bbO}=O*O(Xm8}zvKb1Sg~^e^T0tf4T0K;ikTD|;?ei1A(U!vY^lo> zU8xz5Ra3*JKzV<0;57>4D_Y+-2ZOeu#cen^=iN<;*%r+LR*lww1M849Typ_rV4K1{HWFLoe!E`eIq{*gwghM;q}V5x`vA7l!)r44iUEiF7sI zy&h+TmyVs4WYCO%=IaYHGjJx#HeIrl12PzFIt2U&xL3gFk3=JsP(3cScUr8 z9Qf_j#K0hb2Aw|n&MwKfgLbVAd8cKUYtVA0;l3)HGY!Les->{}m}2=m?c5ME$sgg2 z{(Ws#Cc(ND)veCA0*C>{vXZOWmhZ!0d$!7#a~)U*Vy%rZE&cd$K%(r($In-amTJKb ztX7X}R-0$ywc0gfHE`{Ea;mqx#a-Zg4*9uxDsq*7rIkyYr4ufYZf#yBQ^&}i$DU(j zDihL#sajWw%*DWWRvFj$WKFtl;?9CFoY?o6y@rKT&Px-qFUoS4Y%zlko2$+B7x$Q; zJ#c=&+#jQmaTWw*4QxrYD^{PZ=rv!Lj2U^n2xV*_pImF)l=8IjiL@{y$n+zo;^BL% z+Jn81I&7DN0CfTMp}#7dKGo&sliktE{0m81!g@X@rO}^+0JU#8n4^PcZ9(m zrkiB=fu}^8j~HBSBf0Q_KlZ{I{a)=@AuH7}n&Gz9h;Qi!a1>_qIGB;0IK{1KSzcHs z)%p=!LK?xkp><)3H;vyYf0rvJaS0MW++i|*O8T;L47Zqm!T#K3BJunOH;TP`K6`qb zl4Q_R1lA_D9T@=Z$k0oBPHQP>591m$%*zCzv|tvVV$Z>30-?(V-Q$r3u0qT>3{;m1g4-W7c0lCj)2E=lObkGL)8o zOF@mP7ov~T#q14pga4~uvu1BqLdeZP%NzA`2Gp(}W0qwgxy#Uteptf9Nlqw0uhjoi zeO{*3CmA+#4yMzML_nv4aOuwG)8L~^vj^-CS@9~Qz^kjtRf4Na*w2se`EY{c1)CzE zpB+EVE3_iY$hlNAbN=TMlYrD_)Mhk%(C9ttm*2KO{A7Z$BT>oxTh1DYBvkXF&d^xj}ioClsC%Qz6OUuW55t*gf* z*QBM(Yi(|^{`LR(->plD*@L-%tJBbY^X=DPUqBWdupA^4mES#F-+XrwiK#M=3L5EE zxVR$ezMPcQ*%ilP7pC~FNaY@95`)3+84hOmVc&j3KkV3T@WXseUNl`k!hs{`br;#+ zM;%9Iy}93Pds|+Wqt)RR3MXnFNhF?nJCMnGLRzcTh9(fkG(?|Q7EC~CY zq#37Ok;B)8c?MXw)^rs8p?*cTUdIneaov$var}J@Tg;^r`96lVJaAsm5mlVH?`MoJ zGlu!bDxd!yW?mhC6!F`zFJ*;T4Ga9&$hPhkf^GB&V)s&d@uTKr36D9ZDP&1n^a5gd zTWH*pF42attWNdf4XIw*`e}B=kLjUz^Rh(~)F51f_upp8uj=BU0Z%_hH2gE#~e zM3Kj7AGJ%*P~Y)lI`*avsTnt!Dh14OUB+IhQQMe$O7Av*&fpVagG?NvvOtn|6r^gd zpQ{Ycrd|Wylx-KgLh}lny5S;3>jPmMhNoi~tY+tkO!hNVd^(rl$kkE!TyiAtHw;`3 zHgmQV_iz)=oGszqLwVuDRhe$XS7WX2D%f;+_0HR8*R)H2I}^nD2!`2GM8+_SBG1)z zXGk+-Ue>|oR&q-S=b&gH(SEo4wQ5!>u+*b;eM#G-Q^C0 z5%q;*(!rV5{a9#=o5y6ZwH?G&ZJtz>$hXXm;?h(`Y;MZ7lrPt#l}g#HmR*HBu4k*$VtdLxrQa`im45yGf>EB| zH;lU6SwwNbq_=gNsxFuWx0sO~cF~TB@xhRLwaD>r@MzQYcP7QEL76H|7IX=eiGr>{ zj72DaTo;Q4a7x!0>q`isa;Y=LTQD;%`4KbH(sRRRuZ{SuwR1Sh+$Wa|tZC-_j7>_5 z_V?wt-z~jyM6P-pcWmAK%YU`L{m$|>(LKrP*41nnC>P(Rr`z-qerG_~&FZ_~U!K)> zzc(O3+v|fDbN&d(_4A3uXRhr>sJia5_tJfTK34W6`wEAUO}HAtDP;4lVzQy>Qs=HW zjyWx)K3k1!WKr&DC6YVFFWL>6x)Qtea61+yqsyP#RQ3dZjgeIGPO&$Mh*opgUq*A4 zuxZSdH9d&jlH@{1o05-Er3)P9%8#*t6>r$QTX@rvs1a#lcGH`|W;E?`ZIgyB$+qzgo-HCScfYeM((*RKczO6hCu^Q=gAynO z7Cm6dxZ~182-JEd=&2jIGg*j(FH|P>vJ8i*RI2YiFmp}HJbk9x&av$=nbuSKSmPDK zZI=1GSgr^cLDsT0Ji^RV|Ehcs+K0G*reYJ(RJu$t61yKM+XNT`D=2&Kzs5oDTn*GLavbKE-$LoxB<)_SkY%!0cUY7JoURyhHTVa%%JO)YY{h`wU z96HoGOBBW!WEp0+CyUdKoJUM->Kk4oQ-n6wfA#cB6EKTi2#T7{} z8>R@phzqXlR8NQ%IB>ED1dU67jT~AJWkPZG<$N5)gacwT%^d?SE`-g?f+#FrN;t8+ z>#HGDMERA0AZ94ctbC>6Nb(-?ynygU6q1M%qjN%LTGlJ0tUHfwe&q)mTj9UMa1Nk? z=lMK)j&9@q(%~C}jn1#d6maaQuK}Q4O+G18$8hr*nYwJShEz*kcT+BZrXv8a3h8U} zO(|!SU)Y3N#t8jU!0~{if@A&0L5PNVMi(+JN;JcB%8=HLA~-Q0qqf3${)*1@EsGH( z)NznXQkSJMDMKxR`}CZtyZnw+Tr^2%zvTrh^w1r-zyQzCb&7L}e90}?B~k7TDTUBF z&|zR~5@;Y;w+I;X9QFr)VS{lf!=4~j{cR$aM8Lq4k{FG}$_P3*%# z0COs)1*wC;K90@Ob=AzDlGP_vTo93e%A-ZEI)IgIg$j2A&PRN% zOR;B_8_cSm9=yww6as18LjqzXjk3|L%BcG+VczK)ZuJh{=)I678Tl$8gU3zJ@4EfO zC_pcdxNs^}-a5s9SVX236{ctkeHw(4Gwsg&!_ z2D5I~Eg+%RC-|b*>(EuNL)aE2lLe()SuEuVD0b-ghSgSi9Ix^qoA>Ay-$HpO)FxEc z&0b_8XV5iIg{bb!BF*h`5AUciRwT^#P6D-p!4`qvVcn*GgA$8#rpr^4p{`_%o(?%| zDE(pu08F+CLY|a9rQ{CFr2`?AG~A=*V8gF@l>SDq&T0qJVimmrDWbL+*(UiKwtbj# z>iKmO(-S?;@8Z;o{I5-}t44C6LA_S%2CYTnRa8{LeFFFnlX~Pj{htiwd^M2T%UjST zxTFupb!%ULG+UAj%i(_fH4`$N6FI}TYz9mV!)BvH!(<1Mv(}MfEI`+PB9eV^s9zZ| zriWx_hLV`zQc6n0qL5LucLS3rcuU5roBjj7$7ye4C%Sen4IE^_!;KT^*s8jq}Y% z2w>2EVcir7zilC9{>j41u=k}-xZ?89svXAI^$X5oxALvf_k|=MXV`Mu!yLHjZQ1}e zfEhfBFdVMhCD6ag)#XKJ^E>rxkMxEMnP=nZk&6Apzx+26 z?Z3&I6eN*plW(1b^ZpwnK$n`N!EjL)jBLX$vNX-@o8k{*OL{@JVRp%{WcYs=;#A3c$J! zLb|=n0=Y8Tyi%P1wP8Z)t`^6gFuLwD>X6Z{O|Zc#Q9XV0bl4O2Y9~1IJCVOyH!G%p zL%Lcu2eK3s{%6ByzU5lM`soBnX)UfJ%v~3&Via$GP2fRf%z=M4{7#9(=^_2nJ!|Lj zC^@oke>=fs!olV)Eou7Qc5X-Z4eO|vif_RVL}&I_i~{Av+CR(iP!wyW!5aFOobYzl z0ln@aek1SqsW@cmrz$!WRG$4ow*7s7WwEW73mjY;8(=xJ=mY!=>|=3gs#@kBFO!Pr zpG~s%xr}|~MC>fX^n`cCno^J~vkF-~3todK2B1YzG7kmwn+6{VahR9I2D!#_kPyDw z(s0%q0Hu!fprOeT)R1Gwk&F9HgWtnZs+pqZrr&k9sn}90IrEza5AsS37wW=)Z$cT>H)iB09$@bL*mWZb0!It(V-*FHcMJOt>>ns;xkm$W1<BMvElP}k3I*V=xuEx8bDu}_eD;H*%AY?WCn0pgbXbcJAAyol1( zhFqGGphJ@(+>ph$xWq>2WN17m;i4P!i7%)GYu_2=Z3)b-s@&Y7x>>Jp_xsyd_#at! z*Uc69c`M;D$`%=rPnzl&byN-8q}fS{V*Hy>(@TU$il=AP=X#oRe1op4N4Sm8USr$RLWdi4R7JeXEKI?>jXf2bT>^l zZMhLnMxQGfD;olTIwaWvoxG+gqgkEnMl0i5+pf_8=sk5RZu?ejvv%w8vTSMynQni# zUSw^nQ(qvJ>>?wa6ntp;nr}stx#eq(UJztn9fTzeAU!0X8!j<-9|sRnCWmxwG){%s zdbBmM=j3=!+tdBUIp8eDcbz*?7hj%mbx2jATu!wb9-9Xgte61j6`3Z|9UHJ@(?E-L zQ|@FMX=yuK!AQUSDxz~eX~bG_tS2W%uW+&g3YvFilUAH|R{!4l=c7=1a}c#y?b1Zt ziq&fOx-YnYV~C(3qimZcQXiKbjOw_kL0`fnMg|4|t#Rlc9G9JZTv3X6R~EFU zW2CB4VAHK8R&Q6*4mzEfoqn#m%ow1YtajHMN_7WXI=k&l?Q(V z=C}7PQPGr4HkL~O>Q`yFxv)5q$S?)EyggTU`gdN@H>@O3x2IzDS{DbH3t`caF75}~ zM*?Gid9ch{hI(D~w6tB0uBcC(3mS^^OwI!K*QXSXxggj&Nu6NAQ*wjuS_o@p0%`J# zSQhzZG^+wwQfUPN64#&~0lnod1kyPco)eu-KQ%|DhDqcjklZ)wDnZ@Nj4H04f7j+^&zY^2ZG{CUhKt|86X;H+si9cpduD0 z$Gyk1%OF_lx5yd{VZSSKG2-jlghwd2@mSQ7hdZ7KY3Mg#>zxYeDDXCHh8ks8LQeVv zS~UZ~k7@`*(>fY@!Nli7hDk-%mmO$I5X^W+b#X*vJu&c#osn-d){FbwIC~6-ES>Xz z9h%Nw;4Gzp$9&*};rIWsuZA&VgFGU1_>6f!BcNl?tp3J-mF-q#1W5C$*fVc;1Xl|PZ6!a%y74p^5&jOc zG7aNkJ~uVMlnr^X+^*%;D@*w66C2%$-oL2Q9C9H>%koQtXB|nx&8Y1{=AQ`DVH~4k z5$zP&tHfbHR_l)kQ zhEubZsH}|v_81_PWM1o)$E@OiKon7ePL@4gn+$?Sx@0JorJOQ*x;qsWFDaFw%Rv_$ zOB`*U2};F)VODu^eOh4arnBZ0sDf%ckQ)s`c7tS&EYZNb^yDnIItzHZtH2 zkkCZRux%1XR=bs9c`poDd2&dQiG0AE%6uZ3@brL4?z9v?H>vdHeKvPQyE%Y(bo{Yu z;j9)L*xQN8M|X@hGj}~l-8fn8Ua>+9^BfePUx8bWQ1+M8lcwxH5a+8vg2CI|!dZWp z)&FGu;kVX*B*%nx0e;kfF2J9*^jXVfsx{0mxH7RLwt_hd=c_M=)_Kx1QDb7G*LT2e zHHQKy8G7+BrjdGm!@PK zDm#W!YW*Vv*uNQtdxL>c92oXJVt@UcPxs>Fu$U^Do2;;U)8=Tfo(}R&{KMD(HZF~( z==!TZK*q+U)lRd26qM6Y&DMr*H^m9wUx*{rk&Bf7YIW@ffG%{rXlg$Ce1!Ryy5MmD zGX$Y4mx)$4Ky-K~t(d6{)fw_FZ6x0&K8uoL+EkJUoqvOH^le^_LfH%?Fqv4^h-peA zobKRvD`Og@~!B3svV6OJV3QW$0x3)s;R;L$(v4@f^Q}# z^&q6_PSJ&bk_aTO6H~|%L}sr1o8Q)xAx%a8zO5c}ljfT;;nrr|bV#I(>&S2Fn`FEMmMrvXF+(#~7y7Cz~n%12S;hnmDj^;fw_f4TVhUr{5yU_1up`y{2*klWQZ;fA`3gJVU&+I zYH<2rM)ns&sZtH9q)RB2-=A{;hWLP^*IUC2 z+e=|gEZg1)(@kO2bZyFabv;aoPfPk3E)HOS!L*}X_3wkO#pJcclm^PFbak7$%1cAV zRk|#+!u0Jb!>p;f{hhOdx&v)((o$pHrC#3)MNg6o#f!v1L83HY7X{VtdHm0Ch1lN% z!|yLDNPd=7gfD;8@$-A8O?R8qRcm`C2RIRjGDXGNd`?nbN?8ofL5=(WEM|(4Fo>>y zhYqgwV4}PiL1oyIImKn#6`6$w)!GSToRDg}Z$A9a+Dkn)2a*-}7DHm<0{^SuigTdv zt#1GaPyE`Ys7@4bQ=TIans<0TtT zDDc+IYU=Cb0^_Ttt%MWERUy7YGwA4l4S+6K8x|a6d6D2p2^N*4SrT+JMy6uBb)!}q zvF@6ELV4&n(ERIVca`TjOkUJp!cj%8kIdFp>5$9h1?Sgb1<+MdeCi%8yf19Wb`=bd zWw#2rmJP)%Cn>Ay9OUJMp_jH=qUGH+A1^d%ZhQcvVTJm=2Wr?U0>$x4dV!1yxO=3lCowP&+F|#a zVH77J$VFAZZwawA0N869iiI41z)+ebl(upyvV(dLu|BFU)uRh7q~=;7s{WzPp5^#L zo8+k2);`utESb8%h7E@GsL+C}_i7}ySo2b#e+2hAlLRFNO!AM40juqPyk<%b_JoOH zkv?~bK!mFs`XOiIqbSPd8o4yAyrW1oZq{NYHHE)X;%S2AFgA_Ua1nKXlm=A==oouy zTX~}e?8=X18F7C#N8tFsIKTv?mD54zBjX{CUud1Ukps+JPaH+V)DSxRZVF69Nl>_ z;lb~iBusIza3Wmm*`$6hA~BP=-M+X z(gNuuI`%u89D}<=YSGggIqy{o#EQ%!SWIK8^_&+?hIOVFLj~=ZF7riivX+!(&j+Pq@lcy&d2O0)ksl>2AJ>7-PkC|H) zGq-9yrFF>18GY7&>*fiCy{zE;5T$=UW1ctsz7rTU%s7rsObzQac@m7f?#S@_E`4Tx zvS}S7T|5)*NOl;LH)^#ji#%P)Kx~7jzHBqO=L4Zmw>dl>uMRq8AS0U`X#7M6Wf))j zA&r3>;X=L?h*qd?cp!~u-YWS`Q3o2=(HLL~J5Yc>r0ZONn2?16D})Rq@I_N97d*36 zrstG*phk4zxzW79#CPVF89lTh{F8|>_oMYU8d`PBV{rxAQej5%vJYf`$yzOh4e5ihW$0q`F4)UMBTWHZ z+J`<8rU=~;g}~}DW&}^LCd%75O}KJ>EsV|>!vOVX!kQJ@sc?<+{&I0aStpBb(s1{1 z801?eD38j9Fj4Vfi_F)@v~AEuS1@ne*wnCQ5-g0E-^!w4q?C3IL#~zmQQ|SInCxIx z(oHOX<#VDW-97RPF5c*P&2p}N6fW+U9!PqW)5N95l8p?%i7pCDkU&0;RF&CfWKUya z-lJ-BbMj>wHf?cz(f`SYWl1|w-=UvM@K;jwY*c>X@ zQTU$!Y+FEL6O$6d+>dn0`mBKU=qIvVUw_k*x|Rkzqc5@6y2ZHrhAgIp8Fpo{Y1U}B z6g)J1MVY-Od{#%{1m^ugBuDHElGWIki$iL`>oP1cLL5rZv)$zVBUQ%Er*=E8&eWMa zC{{CN?NM|P{VQRmI)K6-b!Kv4bNI7*Nv7)h0Q_p_s%Cd&cT z{*)tAYiSrx52e?+J#i1puB$|Tqn6HI+5|&RMLKj9DzYA69 zrhArqoXC#9=O{|-b*Ag*udp{q=^n2G7g zrRthxHv-t4a_(!0e>bywcAMy-SIkw&sKhQSlu`NC^PH#&8~z*5@)18w+M~jC4*d$x zd-WhfD&gcAG0n8|754cn%PHECTB%WDr5z7#9#v}xF6Q;$_m+}QJK$v^KJI7p@2b($ zX}+7R@@;q8yPt^Oa2fn}u;y+*`g3LgIp!LF z$|YqLnFfy(+MT?w>3quirVULWm2}}hz*txjoB` z2-?WAlcRxak0b?L8kZGI`gs)s%O?%O&ub>`n=J5t(Zm<6&gXK@Zy%E|sUljmt4?4% z#$q^n46UP>J)33IgPsNkth4nQ=%jbzH%-W4YED`2R=&_ zE;Jc$Z#xi_6uWrPs!FZiQe(yM5 zaPjjqm6$xYDe)pkeuj6a4UQc`pP4@Y>$0oi08tVd@W2El+;G@jaAgSkZoHvY8mx;WL>I;^5(aq zW?NRw8Q&))6ZfHzw)@^>zwoKGu!*Nn%s}g7+!itH3-x^=zGorEnH@BE&B6QSMY+T zTHdXh<;5#$33ulT%k37c#w?ZwoxY%zeq1xvZfvJKr_h>W8NKjQuJnzKf)&%g#c%8k zD=UK@u9Ll;a$m3f>;6alWti@t+54(SIcBauI{EbbuJPU+6S;HEGR5m>g4MM8Gr4Pn zG$N>fqdzY7P9xcT?bu%i6EpZoNKG_{IIf;EPbIlCcUxPv3m?njA$L5Zu$4(^{eCF`GKwr!f(pk zPRm{3?$)vDRJGbitkp`QO=2K?W!j9~(^cioXHsb=#>Qw{+niq~B6*^Dg7SlT_wWxW zplw>CG*j=gdAE%Q)oC^+pIxFnbEk^Bqx@rTtas_hY}&WA_fHsbwAyWaisd_e$L)w$ z$m>R88-|GLQ?`%y-dJ$2Jer~-&V0u~tjq26SH6yQ;wiq!`I?1qq$6qXJcp{?<2)lf z;@%Sl%cUJMaVYa-OeA(Pb^0MoZg1akEo%82IzPBy-s6PTVN$9rA?ZBxm}2Z_%%_bP zzL*7~<5%xR>khy9bvT`@AZl!2p^Ze0YG{?j_<36pli*xBxqTjTP1<`^+iqk%{w1SLDtq}G5)&~tVp_j zJ=MLn(&}o_zrG}mtIyGyx29xKJ`|KehUgZCg&zB+DUltd!RG!o#l_ZAR>%2uR#u+? zv1YyLH*F8C{ULi|p&$7lFUmZa$fn?~?i8oGhwgK66KNVaxx~sXX3=xS$mmRlT%L>k zKll7D|AjBl^|L1|(wd)K;*J(vmF?HHOoj%ZTXNqC$RVo*HL}H8FZSK|0khmM3I`v6z=hpolY*wiD-k% zbkbH3TaLxjz!M%3vR4g7rqeHJ^;()@-s(QIXB_FyN(&W?ai@NpDMZXPaA!|1Mx>g@^W#DTf+NF1mlLU8JY(=RsN#%Q7tZ(_Uc6s2&MlcP zhUNlVb*vh4&6V_spj{?oRowqt;f?-$Ao~H6eSsN!gD&@msC^epC;Q$;o%yt3`Ih&I z-!Xr#Rkw;XkB;iux)c_c4f@fD+2{+Tc@6wHiC|vi6OFpwdM#8t>|RQB2A*N%Czl0I!8}&^((eMiFUMpWZU)ycgFr;OWx@u5A zQ~YbVSJ0^-&rKan!WpRm7nBC(hMze4<1SZbX+sn(a9`vvB>CHrr%f3@4bP% z%I93JN_mdRg0=o91%0r}lbPwLzz;p|uIas}tj3&REhqnA`ZqDy^F;EyCwKPI2N0c_ zM^VLRS%mIY=S3sLON%m&W@|LP9`rhLX;oaTXsE~Iw9jD&I`1yB8B;Ap>l1P~;w7!5 zUG7VjXL=VN(B_+;G1N})miE{G(3iP%?5|8~&+Kc|tGC%`iKHb@4de4HCu&c}+ZGiR zrBwB~^nJbH53MjXl{vIs`<#|>mPBOC+<2mPK)-)%l&mbUj%xDf!tK;{GdlCfv}#)F z;cc7(8S`s1ub#M*mA@RWP;QVszOS{|Nx!=`gd!}#mtRMs2 z`diok9P67x)PC3Ldhp=W)l7G()Elu9CCoC{`pyf6IG-_Q@fi{!>rr*I;?TSi8d_L) zRNXKp(*FImy7p}Ko?{I6wM*;9a;fM~Ul%-|`0;deYu(l3erRE4x8d7|;~Os^&l>6& zrkdo7ml)zH1UYb?49ckK)Y+j9IBWlm)=}B5y-`fv5|O$sQJdk z^@t89E&M4-law{Hm-?N-xSr8Qcm7CMeM_{(Xg!}P9jU8a=AM`1nbSOcw#MDZo0HFn zJXbmGxmR>z-M=Pk)LG(UO{6wwjg3^J>6q#FI zWGA^y#vSON_A=?MyFf23`N5Ncvr@b9>8Y$6M`-Sllx^f9nh%{u8^~IG=4FI5&7zXb z8-kUR4}N`hrs1Xc2>PZ?>rAA>9oFs*$+s72FUVJ_ztF^q$=A>1#>_*d8G1H?@#&=&lMRhw z2?@iY%iODNM-OKXvKn&4tDjo@$a-{2Cq|%O|E2Ro^BIFKYKe0?&r9Vh+R6Q@ECmj0 zcSneEcMI_#jc@aGvY#-O9=>_zg(lxK)Ov`=1^TggM_up@qRKJ7WF$Hdt-8^d@O4A) zY@6rR&l%%#)AN7*X{;~R$4=opa>BXXINN0Ve zqMhz-c-y}hPF^R{JLo|1POwEcFz3LHFy{@~i)ybe-b-(ATOQ|#U{=d7%=G_obo^cA zWfl$JnkKsXf_;s4(ryZlHQHm$1qtu-O)ebO{>gZ;@kj0 z5+bvLFYDZcyNoik6EKN?*sVUs&l6dHIxx#2+v!xRS)VE4Fen@4JhC=9Tx!)*>Z!kCvjHTH}=*X=X zLk34iN`|T{9`xqc80R0Kd=>8bGMe-vrDE;uIcw`qe1bFBg-|3 z|ClwyBI6C8vHsDZ%3%F~*7|oz^94iY;_;ru=&9duvskbtfw9pb#-8EY)C_f(w6w06?u(f#1#A7Pj7@w6R|yIYiD z^l-X9M>17YL$NtwAmnP*k$Uu-bYjW8*8=8cM#?vv?+feS{Db|T%0}Sdb*T$pm}{(3 zBbfQiy=R4J<`U%JlCMgdJ1ORSC)%G#d-3*X)j6bIkv7pVH}kT8*`HpEMu+74)M#1mFF) z$BIKwT>aX!R2X5Aq$anA)sD0Om!y~a?WdpCh_x*HT)Ake{qKAc6V0&7C_G^yXTtF( z<4kwIqWU{`C$pjb>I-{s9@H=`j(V9%eGL6P=7SIQgoEBv<)X2T66^A_hpB(q5Acnp z(k*nkznuOS(>ZQw>#iuHSkL5-sArOkpS(9DZlbb|7Q7zQzUFhP=WfAm!M!KTy=kngpBK|AxSe@_6TNT6 zOiuT)|I{HnI|{0@J5T0#JlT5~e#=#cqDJ+c&1zSVry}0AC2)=yO`VJv-X}|WG?XJ$ z+=EeU*!P8w+2O1?W|LD<%0>(k{p0Fu;}&G+R_yB7t%ivVgXv8NhC|waPuD9o*rtl9 z`bqX4Km~U?%_JE$EX2Kuz5Vj!8I@!-1Lw*o{@FWz`YH6CtCG(L`ZI{BrCI4e%-mXR zI{B05C;w}cXO~8q3qsHMi7?djQF%Fc<&V*Iw`&T$=;r$#!WT3;n6N~rZ0BXgu_wwi zlf3t2`_MT1VD+2(4%|NU5*aSBB^vYwi(P@eT#Z+igSEuo`Z|ytoFtbyc%_qMDIKj$ z#rvv2;C(vP3t4p=txA!B7sr|97V6F+esolSEbc%|-W3#T`76*YafgBapH;2o^Lqv- zQLCe$)s2ZhUY+Rkvpjuu^tR>rf=iihC?+DY>-kgKpvBfwbL$vXmG4jW={DE6BL#OC z97k+qSn7v4M>h%|&A-r6tGp;9;zgbAkB&HYmBGi9e^%-R+4SANksHD#?<|HDK1Y~+Y)7du#ri;%~pRK z{b^4ylSa^^#4a;lPii|KV&+A5gu&hBsGF4B+J^D+5%(hm=?bi4I$3DDiCUx9ThwZT zsOEy0XS$-r=K@(R*U}%FQ+|nO>STQO&T8F~?Zwr^5ZU;YZp8EBe@B!Pmb4Ce=sv2^ zl2gl!QO-Da%$z52-ukKHpW^Jdv>LAiJ9E(&IR)o)zBQ;S81vak>}OMDGstzxntj_? zlwD84x*~8TccYtgI!E{_>B?cfF8ASr4S98!qMAReCUb+ve2ybSha`W_*2n#r3{;bO z^1FQ{=hyJ;!oc;jjC3xxCj767UaX{^j#}gTC5F04v~qryHhym6xhd6K-N`UtXY$Lh zdeQg1XD9Yv=~vf#$nuTX_E*!&vj^Ja+)^DjGkxl$<^fXKQvC(@c)kkg)HpZHx>=>F zh>fD(BUrvj1iuw$Iz)3RZqNIh2gcp&26^T)$$TTqA2F9)khy$9A|Zj-PDsPy72gmy zKObY=rEJDb-UlM%$KAtQ!t|%dNTbdi?ZAY%p))y#C@n)ZnOg;QWYbSM^?fny`*^~K zslr|6YWb_EQ+G_#=JMwiX%p}IDLLI-R843iSu~oRenXj`klQ{ob&ovKu7pt@U zzV**O^KHnTzCKgIQ%0vKSam9#qs_FT|KW!^w&#lPz2}+toja_J0N=T}OlLcPo#mKS z%iFs5Xz`T^q7uID8X>`Z?<3Vs3Y_Q9r2Nt`wlEv=)jGYm5d1|r^Xjwyxlc*iIZdYq zuDIpe@huNzx#zl0Epw1`3pg))4W-eVxYPhWJMuW-oCcXiEj^29p%>W@t0KzIR(K4_WWYn7ni_rz)Z2>3*X0z2bEkU*UkZwH(ixHgS5c2Ckp}L`H8-x^4{f zkXZIl(W)KxxpQ%5ZDx7j!w9Bv)b&%EF+%1Av~`lb=nEeeXqk!wLTNH3PU{5S7qN+030@9xQC?VjdOZ&HA}%8=XGwKn z6nqc7^&VS{_N)2FSAWb9^QQhJd3mhIrf{QH;I_~Gb=NqB$i}m&%(PnGCkt~L3_G<1 z|D9JlwsGSgx>H^EV@BYcu5pE506Smj&6u2dwC8<#ek<7ZP#o!?j1U4`z6C>%BtdY*5KKtL|wFyp~N-n zHdm4N5=JrFiVi)om=MLP;~I}A<5WH8LM25_Q(jZuu0vCeCLw~|S&~ZMmr`oDXB=Bi zF04FvrDK7f+A*wm&Ev7-&7v~?^_HjQyr+mKN{&~njO~m1+;pgH?X;w`_*8Q4&>ynD z$~X3n9Lw@cf2ZVafZo?*8GiL8QpoV>{GbSjc-C{fBtPAvzb9k{_O##XV@0v0_(*tv zHP9WH-Jt4^M@P9H6^k-zm}CDzIgL=tLDcWH%> zzeKK@i>5F&9&73qW#Z90d+yg0!{_H7{0Mpx=KJlB#v!K<=<{}^>v?77`Mvs-MtOd^ zfj56dAwx)}ADp@)(H=@ixwg-Juh`i+sV>Pz3;Tk%3_=541D^kGL^s#miRk@g*{JfS z8L0xkF>xVzdG!nL>DQBwICFTY-*8fxmR~-2-YRMSrL)eN&pp;H-wd4Z9asuV=~AL} z!(?zUaEj8-w3+@vj|N0_94@51ndj5hPn~(BG;(9TNrk$>6E#M5#)+ux7*FYv+z9$D z)y;Ks?nc?snhs6P*uC9fg$q{FczT|^z1m9Myq`=G3Rmcjl$&X^t<-QDzU=&5et39A z$_|sDQGPp8z*urGN}*p0iF{AA9O$@bNO1o8ez)TiEi2X=XTg`$uJyhBeo;ETDB$~Z zV`HbsF2--%kBQy4Zs*6GLXDXVozFUQs+%vU;=)hUPqwq-&za5Q6ukIsgT7n8K3tl{ zCWmVLRM8gyq(NljW3+NSlQiSu@$k_p?Y|uS$=+Q36sl%ZX)6o{f4`#tj(s0&xkFr> zCS0&o_HP~iXNo%Y54u27$n1hYco51Rm_Dc+$KUQF9Qv5y_a1q%B(*R#-*tx9o^0`Q z5^I!{^UPCL=iF0%tADZ>ZnaBJR`|90v#CnS?=f#fS>xZ;pB&{gD5}HgH8MGor+;Gn z}v z`YfkOg6jeHXwHToNQz#}D)k4SkEEv=YDTQICH&2+>{jnlQRU0LQcd#9FSbm5-K;?> zkJ#MhtsWgK3^GG0 zytYUny4a)8$}{{-@nemOh5OYZ(yr5&%BqB9mcFYaPJc*CC%&>KFLR9h=Vcr4_d0X) zv(y_zA|W3JNxy+c`-)n>+)LNhS^T9)7bV#WLdgXT4QCF-*vUxip-t+^O>fjnKfb$% z;e}PDaq_zjC`jj*ht9_0gtL?pjgL{kS@(dMx>7*|`>XGhxAtF33yL|>qB3^7xrIYS zqD|}Bbg%himg0gl7B`6=%C+AT7!6cIOROrIk-oy{{X)fuusYLLc|%I9oWhb1&&iPK zizNR#BJ(-^tF3PHtB?^iyRJvNy@&O(Xj_y95cV%L-XPcFTd~2e$>CORTH{w z@QdPpR~iLF&qI$#w^kFhz4j4s0L$&ux3!CdY8-R3gC4~$1yyxy*WQ+gz7tN63K3ST2_43_I$E?l2Pf6>!B`T;6HXQF9 z46bMKl~@)O5%=qM{YA0x)D0b6ane!OaL!OQvGAAT0}ts5e{IG|gEO@Dy;pkC>*&7> zi~s&+C6CNBm{YHazGbF3_`*nPzO}3{OM()BQVHcfImH?}?T7IIY5p5qj z29N767bKWgv*#NE((by9Qm!g=oK3nP_++1Dd9&%^DbF@%mdk6#m7VjZ=xU8yr+6NI z6czc(=GYQ8wO^h%IgW0_nuy~gT0YD>$4Cyt=<~r{aF57wo{>Dcy=8|6T5nL-UAN%y zPi#D3a$qun&6BeybJoyFl-26nh_8gvYC606W!FBVqrzSqp7(k#EuKVCKA7;P=&srj z_;8~2-@B=w;tK*%+FX|}a6e~5yT+aVk{GerIds>IAR8>hK9r>kWH1=C}3-{cGXJMhE800PnPd z1;*GI{qG+F`vU?^FPN+!ULhiK%R}t^0RbZ-_@Bxl>k`~AF@Rqb;H=EE_1rQbWjhpc zrJ9|@7E%e>%WfOX4o9~QZ6~E|qtsb`+n~Ckf-@=&T(4}SFWvAi6@#3Rz5|M+QpQ6D z9tKEdf+rl5fHi)4$!(7q`zUN1)xIaT3@FPHuyEfb7{28nv^88Q5TLqkM1#*e;eKrb z$A8Or%YeQ+0hY92$t|REA>{bBp>tb#+b9piPa4ZY8?nt&SsuAP87RO7P|`#n*$%Xg z*`9r6#~lI|p*RAu+wt3CP~Q!}vXHQiR2n7{%(XI!VB}yj!CZY)6t|Qib~nH>k$P+k zsgzGAD0OxQ0ShW?JFxOBv@(hB8~09iQ>R*BeayDV$)^YbA@!h0E=M-VO<`b+74u|B3SmYYJ$YR*KFrf zX z+okeJ8$olhwQtV_^7jKQK^h^9ab5%a>3*IE) zsqOR(6gO z7-Ao`-JsF{Fst-2f|dU@PS7Q$69h)fS;_w5W9+V@A;DW}2 z0nNy&JB}C!Rl2RgC55e_b+|=gOL+rcaX5HB1O(sz4KD}mK>Qchg)QrUa9wd$buWTo z3?q(2z;nY5VvWebPKtmR7j`*Jwu3K@9O1J)DU28; zf*?(ZBODMUP$A%(1WfR4AA(@w7@hqHcoV>*b2Nm`kXQsD&^|zjVG8JWOmOc(!kjU7 z3<$W3aD0$bBp~Q#L=e;yBf-3bAb|xDKrn@4Y=q8`UKAk6WG5uW{NdP914}N176HKk zH-ca-p)1jVK#dpSP2e(qh|mS2&A+3FvjT)_kW&mG&=W$yw=-Li zf|_ze0e4Wu7;8)d;|uVR$HlYV-8Cb%#9n0jRmpL5d?hChhu*nC8!WL z=9~;c4{>7}WeNI)8_JFY1pIOY`Eg@H3U7~|)M z0hT4485V~Yl0azhxy^#(Ld8usyQjh&XlGp5EI7_YUfQe;)=WwU@h+D)=Y#XucV%-q zai+Z)e#J4sw1Bm-1JM2y5UXIhnJ3OU^Xd-spA`bWSVFkbTx-I;2yvu>%2U{GCXc-m zV(hOIt}f=49m0=bAv_#5`LNEASQ;Q;cS5)kxYRiB*epgjb`Y$%60|-Sq?8T_Qrr<9 z1O!r^n^V9gl;E|wRycFfoA7D?>16navq-0-H@%5tz*>T@*ERFbO%hC4t!w zAz$Iv4l)347`i+p2?2>}K5~X?O9C>fMB>&5n>sJXuL{|)mAVjQTY{p1oa?vi#f!0f zjHKMkK?urwhFslL=7n@i!H#KfLq2ER6cB>aN>LP;whu`BB^W2eIgT9NS{5Nl@Dp-u znMST*Q@dJfb+=&3lW zaZ3erPXgr)Z$(@RTJor=?ZI;jC{lRSgTd|g|71vSl zRj~g$iUom&<~D;Yp0kKCfFL#`5z$U&CP>r{&m56DUB(QYBz8I7fSfm-vc~JQuuMF= zoO+>0n@-)BU};X^q_WG2A6fxUxGFH)gB-)5qxN|F64suEyf*DjU?a6%6UQtO{a zAn8En_+RCO#<9Mo&~MzsK+q--3Umj8*PZZb+{B`Tx1c~TfR=2cO#nqWL!(akG_n(9gRtu>xl5rN;&8@0 z9VI0n#xC87T}}d!1#rR@BitG2MTRA0g)u;l&M5dA+=B(bg(n~)7?ND@7_|%5F)|@5 za`%$N_|TZL041SaN>h-d3w}vn914(Sg}82@=n*HNicNIfe&##}cA*YJD*(gg#Bu{j z5ywF?H}Iu01pvYV^0|R`$idoeP$RH$tMc+a)fyYnKe|g_G|3h3!}>{w1zQd2T|P08 z8gRn3jXpR^aMYEu zpA`=cin2{;;5yavO#&-ABZype$q92VA&}5r-gafa21M@c@exUYL+k$gpcK4}dYm0`v{|;$%L*z1zbFWVCk47(wEm z_<0-+?K3h5PU5?^RAX_%KrsUp>4|T_R8K%}4%L82Tq^Ieb}O{LX>)o3TL6;x!pj%> zlGF^F+Xt9-j(BeWdcOJ6u%c2V~BU9QEO4=BpzrOfVQ27D5HAv78@1&2l&qMaW#+Byz zZvzGnxWCq+vQ6|>2}3^*yiYE6CpdL8K;$>^`$VHwg_#%ncnj3B89H(kPkZSmpcR0; zHtj5|od`V!HcsXNE5nj7l%%eNC%DQzIj(Hffv5) zyoO>oQIENwd2l5ViqOkV)ZCVNkO%h7gANAZi=Yqy)W|<1uz%RC768T&E>Jq~#Wf$( z{TC7c|8g}9jR7azw&2^#7l3tA-nHzq6A3yK4AAjF{Hg>vVWzm@1*132xzr`13% zn@&^WjvH8~-LDWBp(@~n%WdQqNX2I^A!d#Nq7K3*%pL?vH3l6I!aJE`?EvT|uyMWg z$~QZO1HPJmfSLe`E9gDJbZhqiTPtM<6^y463I=9Nh6*M;F>3f;xm-svqdOz1Yi~$u6hTbsU{d2#N+bXTK1j z!MuS3i#Ne0Ea>|i2QB~*C#*1=^$>FkNsgN8eD;mp8WZMeLbhXOM;jT z>k99fbv9#>3&4v5^zY7+*^$G9$$$`-NO2gDA)|y*amxRb$O6{GnhN&d496El@>=9y zY&%HpN~9gq562f|#?^rvdsXM!l?VTRn6D7<;qqt*2P)5LU~~?TCPe^{^8jQX0cs~6 zftP-a;qb>cgzPTq0LUx?FMZ;M3)lZ&unBsYuNLs(qI^XYdlTIs3D7)77*&qM zYcoHne}~nU-=z)S=||$Vhu#U0nE@xUUDI}8f%!TBA5MD|t3tyDqm)s2lrsvTH`rlR zAE3C6Agm{rfL(j+E2W*Q`Wgy|!fV&8_f!f2r*pfU6u6+cXi&#Dn<{fyl_G8!WsSyb zi$?>Lffq*20E*KdBg(w^|2K9$6dR4#?qHRAk8L})UGwJShxw*AReobto(aIHa135s zIR>CSLNMwKP@ML`)cNz+n(uBkG?X2K*Pef6sfT?DDzc{gFeyy#lD@`O{)Nv-@$7$Fq1T6UqbD^_@qn1e0yW@Dy*?U zWsfwBYHy-uSk&$ajDmv)SbLnffD=1!?AwH$>)i`A#p1Qe-X0CWHignICvh2=k1-Cf zEgT0_l4N1@(kAMRMK_MaC^)l#wXY)lLk+Y8Xl;qFCO2tWd{U$7$ zdk#jyX%DP_s9~rLTUM)G`eYC%gx3#yKKL1XquqTM^tb>?B!hZ-L3ouY2&jx)gwcjg zv>%JAU&f)}pa_=EJ$(g%ZRcaVq`yGo$$07ZW7b~S7aF@ahPoLn5(fBi1x`-}BE{w~ z+Ovs{V^JDQ7zGDSu(o~3J7R3vcQ2_Yq@04+j#vxhzXF^@cJ<{OE0_Grbr7Ke>8Iia=_22?Ujl-By9CSa z;P^rik7I2}1+4lGFgk}vlhOdV7kfEmV+mI$rx%kR}hd z5q2+z19*U!0m{|^_;A{zSe0&X7^Td>qnsH4b@GK#eSqRFD^=%XI7|TT?%U%a6p(?} zo_pA$MGu@k&J{<`E0zlJ{C=jg3$ng z;;w~@Z;zaYxMD$zD?;Vjc&+p8+Emzk_wHLr{v9}eZw{W7H3z&+qJm^{Q0%yQn*bX{ zau)%y+(ocJS_SxBmxG1>B_bg63rKosC7zkzU1&_IRynoVp1bm&5 zED&cdiXP{C)*&*)at{#^EqJKRxWo5eB?8JRLD55Yx%j8F{<%O-yB1K?B6y*uTznRN zSom@s0+PU>=*2|69PI!5@cLq8<@*6ZehRd~&V=S5iF+tXTqe3K=d-7Uh=~4yYu?UG z_O;_?NCzd~!`G+y9*~q@LO=#fAd~O+@R|I^HBV_b$FKtR{I1oWbhEh0@3E94&umjE?@C=Dd0UO4OJ(q=b!ta9!5k)wn0Yu;`(T_#n8Nj~a zgqC2=Su!q>{lr8>eH=tYOgkD)$Pi{RF2u9g76KL(6PP8p5U=Uu%W4^RTQywe^4Zgp!oeh3r+hknDN zrZ%u5I1YvtXW2zr;Hn_BA^nFaDclluduPO3fO+K={8#3@3rtW42ynD7K=U9Gk+2v^ z5nha=2%u-9U|(>4Of3B0UDQ0T`nw%et`&3v?~V$-NQBA2IrBkWHrWfE0T@amB5K|L zW;2xpD}bYCVrZcVzyANQ;-BupEHcITlnjai%9sxa1Q+9<3$SE@zZ3)HUxUrOGY!E? zm|$R&U=~YYSOqsDYY7TI0G22L=+SztFAMhIngN&ckwJ$3IdH+ElKyYXs*hoU>P>y$xh8-@lj zDGG2fxwAumLIb7vPWg>h`85fLg5z)sNU028MBOqlMDiI<0Gy4};%)^GN@$j#z7lXN zV1p{k@ZEAT%hK%`EfLXo-~UP}&%yCb<@joemIKz)|6oCIY)%2$)!+pKutNbv5TX)X zcOHQN+>8rcdZb_d-}O1W7y4KUY7WlV;gT^`00Mt9nBa5;UeOGTwll!K$rbqZ5q{l& z&KY!`C0L`K)%nB-6MO;$xG6`6@xO({E5SQ~G!~cz9LZBa@{jO&pMC@cGFjoMn~(5O zVTG}za8v*X90ktmDR9>)-12}&JyTO40U3(_CJ>ZViC>+=V0y@M9&9)(_B5Xya;(IQ z-oy@7@?u2~LgkhC8?~_o_~{I6st9Umyb`}UH#_7%&jO`myOd}J;dsp|{9e9X1z6RD zVZo#-{KhH6q8cKwud@h>nC`!OnVq+^8=kDEI2;T<9{}&&4wF!66VRjk<5D+!4JH7eSU8Al3kl`?H5#zN+rhs( S`|=NXoq`f3F}4MJn&^MImYr1q diff --git a/sormas-api/src/main/resources/doc/SORMAS_User_Rights.xlsx b/sormas-api/src/main/resources/doc/SORMAS_User_Rights.xlsx index 25172e8bf9af96662a61a2f0fdfe5aacbe1095bf..4a80140f467afd23fe7eac7a2e1358c8e91d05e5 100644 GIT binary patch delta 3169 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 diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignService.java index 46af1c6b9ef..a3b01e5e3ca 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignService.java @@ -15,13 +15,14 @@ import de.symeda.sormas.api.campaign.CampaignCriteria; import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.backend.common.AbstractCoreAdoService; +import de.symeda.sormas.backend.common.AbstractDeletableAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.user.User; @Stateless @LocalBean -public class CampaignService extends AbstractCoreAdoService { +public class CampaignService extends AbstractDeletableAdoService { public CampaignService() { super(Campaign.class); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java index 495fded2a7c..3e0f43733b5 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java @@ -106,7 +106,7 @@ import de.symeda.sormas.backend.clinicalcourse.ClinicalCourse; import de.symeda.sormas.backend.clinicalcourse.ClinicalVisit; import de.symeda.sormas.backend.clinicalcourse.ClinicalVisitService; -import de.symeda.sormas.backend.common.AbstractCoreAdoService; +import de.symeda.sormas.backend.common.AbstractDeletableAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.ChangeDateFilterBuilder; import de.symeda.sormas.backend.common.DeletableAdo; @@ -158,7 +158,7 @@ @Stateless @LocalBean -public class CaseService extends AbstractCoreAdoService { +public class CaseService extends AbstractDeletableAdoService { private static final long SECONDS_30_DAYS = 30L * 24L * 60L * 60L; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractBaseEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractBaseEjb.java index ed8b8729010..8dfc49c4d1d 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractBaseEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractBaseEjb.java @@ -42,13 +42,6 @@ protected AbstractBaseEjb(Class adoClass, Class dtoClass, SRV service, this.userService = userService; } - @Override - public DTO save(DTO dtoToSave) { - return save(dtoToSave, false); - } - - // todo cannot be filled right now as we are missing ArchivableAbstractDomainObject - // with this abstract class e.g., ImmunizationFacadeEjb could be wired up to this as well public abstract void archive(String uuid); public abstract void dearchive(String uuid); @@ -84,22 +77,6 @@ public List getAllAfter(Date date) { // todo find a better name, it is not clear what it does protected abstract void selectDtoFields(CriteriaQuery cq, Root root); - protected DTO persistEntity(DTO dto, ADO entityToPersist, boolean checkChangeDate) { - entityToPersist = fillOrBuildEntity(dto, entityToPersist, checkChangeDate); - service.ensurePersisted(entityToPersist); - return toDto(entityToPersist); - } - - protected DTO mergeAndPersist(DTO dtoToSave, List duplicates, boolean checkChangeDate) { - ADO existingEntity = duplicates.get(0); - DTO existingDto = toDto(existingEntity); - DtoHelper.copyDtoValues(existingDto, dtoToSave, true); - return persistEntity(dtoToSave, existingEntity, checkChangeDate); - - } - - protected abstract List findDuplicates(DTO dto, boolean includeArchived); - protected abstract ADO fillOrBuildEntity(@NotNull DTO source, ADO target, boolean checkChangeDate); public abstract DTO toDto(ADO ado); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java index a2a122047bf..97b28b2d4c7 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java @@ -1,31 +1,28 @@ -package de.symeda.sormas.backend.common; +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ -import java.sql.Timestamp; +package de.symeda.sormas.backend.common; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.From; -import javax.persistence.criteria.JoinType; -import javax.persistence.criteria.Predicate; +import java.util.Date; +import java.util.List; -public abstract class AbstractCoreAdoService extends AdoServiceWithUserFilter { +public abstract class AbstractCoreAdoService extends AbstractDeletableAdoService { public AbstractCoreAdoService(Class elementClass) { super(elementClass); } - @Override - public void delete(ADO deleteme) { - - deleteme.setDeleted(true); - em.persist(deleteme); - em.flush(); - } - - protected Predicate changeDateFilter(CriteriaBuilder cb, Timestamp date, From path, String... joinFields) { - From parent = path; - for (int i = 0; i < joinFields.length; i++) { - parent = parent.join(joinFields[i], JoinType.LEFT); - } - return CriteriaBuilderHelper.greaterThanAndNotNull(cb, parent.get(AbstractDomainObject.CHANGE_DATE), date); - } + public abstract List getAllActiveAfter(Date date, Integer batchSize, String lastSynchronizedUuid); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java new file mode 100644 index 00000000000..a394e9c6625 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java @@ -0,0 +1,114 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.common; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +import de.symeda.sormas.api.EntityDto; +import de.symeda.sormas.api.ReferenceDto; +import de.symeda.sormas.api.utils.ValidationRuntimeException; +import de.symeda.sormas.api.utils.criteria.BaseCriteria; +import de.symeda.sormas.backend.user.UserService; +import de.symeda.sormas.backend.util.Pseudonymizer; + +public abstract class AbstractCoreEjb, CRITERIA extends BaseCriteria> + extends AbstractBaseEjb { + + public AbstractCoreEjb() { + } + + public AbstractCoreEjb(Class adoClass, Class dtoClass, SRV service, UserService userService) { + super(adoClass, dtoClass, service, userService); + } + + @Override + public DTO getByUuid(String uuid) { + Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithInaccessibleValuePlaceHolder(userService::hasRight); + return convertToDto(service.getByUuid(uuid), pseudonymizer); + } + + @Override + public List getByUuids(List uuids) { + Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithInaccessibleValuePlaceHolder(userService::hasRight); + return service.getByUuids(uuids).stream().map(c -> convertToDto(c, pseudonymizer)).collect(Collectors.toList()); + } + + @Override + public List getAllAfter(Date date) { + return getAllAfter(date, null, null); + } + + public List getAllAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { + Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithInaccessibleValuePlaceHolder(userService::hasRight); + return service.getAllActiveAfter(date, batchSize, lastSynchronizedUuid) + .stream() + .map(c -> convertToDto(c, pseudonymizer)) + .collect(Collectors.toList()); + } + + @Override + public DTO save(DTO dto) { + ADO existingAdo = dto.getUuid() != null ? service.getByUuid(dto.getUuid()) : null; + DTO existingDto = toDto(existingAdo); + + Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); + restorePseudonymizedDto(dto, existingDto, existingAdo, pseudonymizer); + + validate(dto); + + existingAdo = fillOrBuildEntity(dto, existingAdo, true); + service.ensurePersisted(existingAdo); + + return convertToDto(existingAdo, pseudonymizer); + } + + public boolean exists(String uuid) { + return service.exists(uuid); + } + + @Override + public void archive(String uuid) { + ADO ado = service.getByUuid(uuid); + if (ado != null) { + ado.setArchived(true); + service.ensurePersisted(ado); + } + } + + public void dearchive(String uuid) { + ADO ado = service.getByUuid(uuid); + if (ado != null) { + ado.setArchived(false); + service.ensurePersisted(ado); + } + } + + public DTO convertToDto(ADO source, Pseudonymizer pseudonymizer) { + + DTO dto = toDto(source); + pseudonymizeDto(source, dto, pseudonymizer); + return dto; + } + + protected abstract void pseudonymizeDto(ADO source, DTO dto, Pseudonymizer pseudonymizer); + + protected abstract void restorePseudonymizedDto(DTO dto, DTO existingDto, ADO immunization, Pseudonymizer pseudonymizer); + + public abstract void validate(DTO dto) throws ValidationRuntimeException; +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractDeletableAdoService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractDeletableAdoService.java new file mode 100644 index 00000000000..2cca34d98db --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractDeletableAdoService.java @@ -0,0 +1,31 @@ +package de.symeda.sormas.backend.common; + +import java.sql.Timestamp; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.From; +import javax.persistence.criteria.JoinType; +import javax.persistence.criteria.Predicate; + +public abstract class AbstractDeletableAdoService extends AdoServiceWithUserFilter { + + public AbstractDeletableAdoService(Class elementClass) { + super(elementClass); + } + + @Override + public void delete(ADO deleteme) { + + deleteme.setDeleted(true); + em.persist(deleteme); + em.flush(); + } + + protected Predicate changeDateFilter(CriteriaBuilder cb, Timestamp date, From path, String... joinFields) { + From parent = path; + for (int i = 0; i < joinFields.length; i++) { + parent = parent.join(joinFields[i], JoinType.LEFT); + } + return CriteriaBuilderHelper.greaterThanAndNotNull(cb, parent.get(AbstractDomainObject.CHANGE_DATE), date); + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/Contact.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/Contact.java index 561e8ff893b..69cfe6f77c7 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/Contact.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/Contact.java @@ -1087,4 +1087,9 @@ public String getQuarantineChangeComment() { public void setQuarantineChangeComment(String quarantineChangeComment) { this.quarantineChangeComment = quarantineChangeComment; } + + @Transient + public boolean isArchived() { + return false; + } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java index bf89b65baf8..9252467ba71 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java @@ -82,7 +82,7 @@ import de.symeda.sormas.backend.caze.CaseUserFilterCriteria; import de.symeda.sormas.backend.clinicalcourse.HealthConditions; import de.symeda.sormas.backend.clinicalcourse.HealthConditionsService; -import de.symeda.sormas.backend.common.AbstractCoreAdoService; +import de.symeda.sormas.backend.common.AbstractDeletableAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.ChangeDateFilterBuilder; import de.symeda.sormas.backend.common.DeletableAdo; @@ -120,7 +120,7 @@ @Stateless @LocalBean -public class ContactService extends AbstractCoreAdoService { +public class ContactService extends AbstractDeletableAdoService { @EJB private CaseService caseService; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipant.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipant.java index 985d79e0b70..e7a32baec29 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipant.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipant.java @@ -30,6 +30,7 @@ import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; +import javax.persistence.Transient; import de.symeda.auditlog.api.Audited; import de.symeda.auditlog.api.AuditedIgnore; @@ -187,4 +188,9 @@ public VaccinationStatus getVaccinationStatus() { public void setVaccinationStatus(VaccinationStatus vaccinationStatus) { this.vaccinationStatus = vaccinationStatus; } + + @Transient + public boolean isArchived() { + return false; + } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java index e7b7d0ba98f..e6fbd5f89d2 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java @@ -47,7 +47,7 @@ import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.backend.caze.Case; -import de.symeda.sormas.backend.common.AbstractCoreAdoService; +import de.symeda.sormas.backend.common.AbstractDeletableAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.contact.Contact; @@ -65,7 +65,7 @@ @Stateless @LocalBean -public class EventParticipantService extends AbstractCoreAdoService { +public class EventParticipantService extends AbstractDeletableAdoService { @EJB private EventService eventService; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java index c57ae0d2228..7a21e1ebf68 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java @@ -61,7 +61,7 @@ import de.symeda.sormas.backend.action.ActionService; import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.caze.CaseService; -import de.symeda.sormas.backend.common.AbstractCoreAdoService; +import de.symeda.sormas.backend.common.AbstractDeletableAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.ChangeDateFilterBuilder; import de.symeda.sormas.backend.common.DeletableAdo; @@ -94,7 +94,7 @@ @Stateless @LocalBean -public class EventService extends AbstractCoreAdoService { +public class EventService extends AbstractDeletableAdoService { @EJB private EventParticipantService eventParticipantService; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/DirectoryImmunizationService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/DirectoryImmunizationService.java index f35aacc4b7a..9d8fc801626 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/DirectoryImmunizationService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/DirectoryImmunizationService.java @@ -33,7 +33,7 @@ import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.api.utils.SortProperty; -import de.symeda.sormas.backend.common.AbstractCoreAdoService; +import de.symeda.sormas.backend.common.AbstractDeletableAdoService; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal; import de.symeda.sormas.backend.immunization.entity.DirectoryImmunization; @@ -56,14 +56,12 @@ @Stateless @LocalBean -public class DirectoryImmunizationService extends AbstractCoreAdoService { +public class DirectoryImmunizationService extends AbstractDeletableAdoService { @EJB private UserService userService; @EJB private FeatureConfigurationFacadeEjbLocal featureConfigurationFacade; - @EJB - private PersonService personService; public DirectoryImmunizationService() { super(DirectoryImmunization.class); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java index 0a32eec613f..cd4078d0daf 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java @@ -22,7 +22,6 @@ import java.util.Date; import java.util.List; import java.util.Objects; -import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -31,6 +30,9 @@ import javax.ejb.LocalBean; import javax.ejb.Stateless; import javax.enterprise.concurrent.ManagedScheduledExecutorService; +import javax.inject.Inject; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import javax.validation.Valid; import javax.validation.constraints.NotNull; @@ -73,8 +75,7 @@ import de.symeda.sormas.api.vaccination.VaccinationDto; import de.symeda.sormas.backend.caze.CaseFacadeEjb; import de.symeda.sormas.backend.caze.CaseService; -import de.symeda.sormas.backend.contact.ContactService; -import de.symeda.sormas.backend.event.EventParticipantService; +import de.symeda.sormas.backend.common.AbstractCoreEjb; import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb; import de.symeda.sormas.backend.immunization.entity.Immunization; import de.symeda.sormas.backend.infrastructure.community.CommunityFacadeEjb; @@ -107,7 +108,9 @@ import de.symeda.sormas.backend.vaccination.VaccinationFacadeEjb.VaccinationFacadeEjbLocal; @Stateless(name = "ImmunizationFacade") -public class ImmunizationFacadeEjb implements ImmunizationFacade { +public class ImmunizationFacadeEjb + extends AbstractCoreEjb + implements ImmunizationFacade { private final Logger logger = LoggerFactory.getLogger(ImmunizationFacadeEjb.class); @@ -118,8 +121,6 @@ public class ImmunizationFacadeEjb implements ImmunizationFacade { @EJB private PersonService personService; @EJB - private UserService userService; - @EJB private RegionService regionService; @EJB private DistrictService districtService; @@ -134,10 +135,6 @@ public class ImmunizationFacadeEjb implements ImmunizationFacade { @EJB private VaccinationFacadeEjbLocal vaccinationFacade; @EJB - private ContactService contactService; - @EJB - private EventParticipantService eventParticipantService; - @EJB private CaseFacadeEjb.CaseFacadeEjbLocal caseFacade; @EJB private SampleFacadeEjb.SampleFacadeEjbLocal sampleFacade; @@ -155,8 +152,14 @@ public class ImmunizationFacadeEjb implements ImmunizationFacade { private SormasToSormasContactFacadeEjb.SormasToSormasContactFacadeEjbLocal sormasToSormasContactFacade; @EJB private SormasToSormasEventFacadeEjb.SormasToSormasEventFacadeEjbLocal sormasToSormasEventFacadeEjbLocal; - @EJB - private FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal featureConfigurationFacade; + + public ImmunizationFacadeEjb() { + } + + @Inject + public ImmunizationFacadeEjb(ImmunizationService service, UserService userService) { + super(Immunization.class, ImmunizationDto.class, service, userService); + } public static ImmunizationReferenceDto toReferenceDto(Immunization entity) { if (entity == null) { @@ -172,53 +175,59 @@ public static ImmunizationReferenceDto toReferenceDto(ImmunizationDto dto) { return new ImmunizationReferenceDto(dto.getUuid(), dto.toString(), dto.getExternalId()); } - @Override - public ImmunizationDto getByUuid(String uuid) { - Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithInaccessibleValuePlaceHolder(userService::hasRight); - return convertToDto(immunizationService.getByUuid(uuid), pseudonymizer); - } - - @Override - public void archive(String uuid) { - Immunization immunization = immunizationService.getByUuid(uuid); - if (immunization != null) { - immunization.setArchived(true); - immunizationService.ensurePersisted(immunization); + public ImmunizationDto toDto(Immunization entity) { + if (entity == null) { + return null; } - } + ImmunizationDto dto = new ImmunizationDto(); + DtoHelper.fillDto(dto, entity); - @Override - public void dearchive(String uuid) { - Immunization immunization = immunizationService.getByUuid(uuid); - if (immunization != null) { - immunization.setArchived(false); - immunizationService.ensurePersisted(immunization); - } - } + dto.setDisease(entity.getDisease()); + dto.setDiseaseDetails(entity.getDiseaseDetails()); + dto.setPerson(PersonFacadeEjb.toReferenceDto(entity.getPerson())); + dto.setReportDate(entity.getReportDate()); + dto.setReportingUser(UserFacadeEjb.toReferenceDto(entity.getReportingUser())); + dto.setArchived(entity.isArchived()); + dto.setImmunizationStatus(entity.getImmunizationStatus()); + dto.setMeansOfImmunization(entity.getMeansOfImmunization()); + dto.setMeansOfImmunizationDetails(entity.getMeansOfImmunizationDetails()); + dto.setImmunizationManagementStatus(entity.getImmunizationManagementStatus()); + dto.setExternalId(entity.getExternalId()); + dto.setResponsibleRegion(RegionFacadeEjb.toReferenceDto(entity.getResponsibleRegion())); + dto.setResponsibleDistrict(DistrictFacadeEjb.toReferenceDto(entity.getResponsibleDistrict())); + dto.setResponsibleCommunity(CommunityFacadeEjb.toReferenceDto(entity.getResponsibleCommunity())); + dto.setCountry(CountryFacadeEjb.toReferenceDto(entity.getCountry())); + dto.setFacilityType(entity.getFacilityType()); + dto.setHealthFacility(FacilityFacadeEjb.toReferenceDto(entity.getHealthFacility())); + dto.setHealthFacilityDetails(entity.getHealthFacilityDetails()); + dto.setStartDate(entity.getStartDate()); + dto.setEndDate(entity.getEndDate()); + dto.setNumberOfDoses(entity.getNumberOfDoses()); + dto.setNumberOfDosesDetails(entity.getNumberOfDosesDetails()); + dto.setPreviousInfection(entity.getPreviousInfection()); + dto.setLastInfectionDate(entity.getLastInfectionDate()); + dto.setAdditionalDetails(entity.getAdditionalDetails()); + dto.setPositiveTestResultDate(entity.getPositiveTestResultDate()); + dto.setRecoveryDate(entity.getRecoveryDate()); + dto.setValidFrom(entity.getValidFrom()); + dto.setValidUntil(entity.getValidUntil()); + dto.setRelatedCase(CaseFacadeEjb.toReferenceDto(entity.getRelatedCase())); - @Override - public List getAllAfter(Date date) { - return getAllAfter(date, null, null); - } + List vaccinationDtos = new ArrayList<>(); + for (Vaccination vaccination : entity.getVaccinations()) { + VaccinationDto vaccinationDto = VaccinationFacadeEjbLocal.toDto(vaccination); + vaccinationDtos.add(vaccinationDto); + } + dto.setVaccinations(vaccinationDtos); - @Override - public List getAllAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { - Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithInaccessibleValuePlaceHolder(userService::hasRight); - return immunizationService.getAllActiveAfter(date, batchSize, lastSynchronizedUuid) - .stream() - .map(c -> convertToDto(c, pseudonymizer)) - .collect(Collectors.toList()); - } + dto.setSormasToSormasOriginInfo(SormasToSormasOriginInfoFacadeEjb.toDto(entity.getSormasToSormasOriginInfo())); + dto.setOwnershipHandedOver(entity.getSormasToSormasShares().stream().anyMatch(ShareInfoHelper::isOwnerShipHandedOver)); - @Override - public List getByUuids(List uuids) { - Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithInaccessibleValuePlaceHolder(userService::hasRight); - return immunizationService.getByUuids(uuids).stream().map(c -> convertToDto(c, pseudonymizer)).collect(Collectors.toList()); + return dto; } @Override - public List getAllUuids() { - return immunizationService.getAllUuids(); + protected void selectDtoFields(CriteriaQuery cq, Root root) { } @Override @@ -240,16 +249,6 @@ public List getDeletedUuidsSince(Date since) { return immunizationService.getDeletedUuidsSince(since); } - @Override - public boolean exists(String uuid) { - return immunizationService.exists(uuid); - } - - @Override - public ImmunizationReferenceDto getReferenceByUuid(String uuid) { - return Optional.of(uuid).map(u -> immunizationService.getByUuid(u)).map(ImmunizationFacadeEjb::toReferenceDto).orElse(null); - } - @Override public void deleteImmunization(String uuid) { if (!userService.hasRight(UserRight.IMMUNIZATION_DELETE)) { @@ -295,7 +294,7 @@ public List getSimilarImmunizations(ImmunizationSimilarityCrite } @Override - public ImmunizationDto save(ImmunizationDto dto, boolean allowMerge) { + public ImmunizationDto save(ImmunizationDto dto) { return save(dto, true, true); } @@ -313,7 +312,7 @@ public ImmunizationDto save(@Valid ImmunizationDto dto, boolean checkChangeDate, validate(dto); - Immunization immunization = fillOrBuildEntity(dto, existingImmunization, checkChangeDate, false); + Immunization immunization = fillOrBuildEntity(dto, existingImmunization, checkChangeDate); immunizationService.updateImmunizationStatusBasedOnVaccinations(immunization); @@ -343,21 +342,7 @@ public ImmunizationDto save(@Valid ImmunizationDto dto, boolean checkChangeDate, return convertToDto(immunization, pseudonymizer); } - @Override - public ImmunizationDto save(ImmunizationDto dto) { - return save(dto, false); - } - - public ImmunizationDto convertToDto(Immunization source, Pseudonymizer pseudonymizer) { - - ImmunizationDto dto = toDto(source); - - pseudonymizeDto(source, dto, pseudonymizer); - - return dto; - } - - private void pseudonymizeDto(Immunization source, ImmunizationDto dto, Pseudonymizer pseudonymizer) { + protected void pseudonymizeDto(Immunization source, ImmunizationDto dto, Pseudonymizer pseudonymizer) { if (dto != null) { boolean inJurisdiction = immunizationService.inJurisdictionOrOwned(source); pseudonymizer.pseudonymizeDto(ImmunizationDto.class, dto, inJurisdiction, c -> { @@ -368,7 +353,7 @@ private void pseudonymizeDto(Immunization source, ImmunizationDto dto, Pseudonym } } - private void restorePseudonymizedDto(ImmunizationDto dto, ImmunizationDto existingDto, Immunization immunization, Pseudonymizer pseudonymizer) { + protected void restorePseudonymizedDto(ImmunizationDto dto, ImmunizationDto existingDto, Immunization immunization, Pseudonymizer pseudonymizer) { if (existingDto != null) { final boolean inJurisdiction = immunizationService.inJurisdictionOrOwned(immunization); final User currentUser = userService.getCurrentUser(); @@ -446,65 +431,17 @@ public List deleteImmunizations(List immunizationUuids) { return deletedImmunizationUuids; } - public static ImmunizationDto toDto(Immunization entity) { - if (entity == null) { - return null; - } - ImmunizationDto dto = new ImmunizationDto(); - DtoHelper.fillDto(dto, entity); - - dto.setDisease(entity.getDisease()); - dto.setDiseaseDetails(entity.getDiseaseDetails()); - dto.setPerson(PersonFacadeEjb.toReferenceDto(entity.getPerson())); - dto.setReportDate(entity.getReportDate()); - dto.setReportingUser(UserFacadeEjb.toReferenceDto(entity.getReportingUser())); - dto.setArchived(entity.isArchived()); - dto.setImmunizationStatus(entity.getImmunizationStatus()); - dto.setMeansOfImmunization(entity.getMeansOfImmunization()); - dto.setMeansOfImmunizationDetails(entity.getMeansOfImmunizationDetails()); - dto.setImmunizationManagementStatus(entity.getImmunizationManagementStatus()); - dto.setExternalId(entity.getExternalId()); - dto.setResponsibleRegion(RegionFacadeEjb.toReferenceDto(entity.getResponsibleRegion())); - dto.setResponsibleDistrict(DistrictFacadeEjb.toReferenceDto(entity.getResponsibleDistrict())); - dto.setResponsibleCommunity(CommunityFacadeEjb.toReferenceDto(entity.getResponsibleCommunity())); - dto.setCountry(CountryFacadeEjb.toReferenceDto(entity.getCountry())); - dto.setFacilityType(entity.getFacilityType()); - dto.setHealthFacility(FacilityFacadeEjb.toReferenceDto(entity.getHealthFacility())); - dto.setHealthFacilityDetails(entity.getHealthFacilityDetails()); - dto.setStartDate(entity.getStartDate()); - dto.setEndDate(entity.getEndDate()); - dto.setNumberOfDoses(entity.getNumberOfDoses()); - dto.setNumberOfDosesDetails(entity.getNumberOfDosesDetails()); - dto.setPreviousInfection(entity.getPreviousInfection()); - dto.setLastInfectionDate(entity.getLastInfectionDate()); - dto.setAdditionalDetails(entity.getAdditionalDetails()); - dto.setPositiveTestResultDate(entity.getPositiveTestResultDate()); - dto.setRecoveryDate(entity.getRecoveryDate()); - dto.setValidFrom(entity.getValidFrom()); - dto.setValidUntil(entity.getValidUntil()); - dto.setRelatedCase(CaseFacadeEjb.toReferenceDto(entity.getRelatedCase())); - - List vaccinationDtos = new ArrayList<>(); - for (Vaccination vaccination : entity.getVaccinations()) { - VaccinationDto vaccinationDto = VaccinationFacadeEjbLocal.toDto(vaccination); - vaccinationDtos.add(vaccinationDto); - } - dto.setVaccinations(vaccinationDtos); - - dto.setSormasToSormasOriginInfo(SormasToSormasOriginInfoFacadeEjb.toDto(entity.getSormasToSormasOriginInfo())); - dto.setOwnershipHandedOver(entity.getSormasToSormasShares().stream().anyMatch(ShareInfoHelper::isOwnerShipHandedOver)); - - return dto; + @Override + public ImmunizationReferenceDto toRefDto(Immunization immunization) { + return toReferenceDto(immunization); } - private Immunization fillOrBuildEntity(@NotNull ImmunizationDto source, Immunization target, boolean checkChangeDate, boolean immunizationCopy) { + protected Immunization fillOrBuildEntity(@NotNull ImmunizationDto source, Immunization target, boolean checkChangeDate) { target = DtoHelper.fillOrBuildEntity(source, target, Immunization::new, checkChangeDate); target.setDisease(source.getDisease()); target.setDiseaseDetails(source.getDiseaseDetails()); - if (!immunizationCopy) { - target.setPerson(personService.getByReferenceDto(source.getPerson())); - } + target.setPerson(personService.getByReferenceDto(source.getPerson())); target.setReportDate(source.getReportDate()); target.setReportingUser(userService.getByReferenceDto(source.getReportingUser())); target.setArchived(source.isArchived()); @@ -534,12 +471,10 @@ private Immunization fillOrBuildEntity(@NotNull ImmunizationDto source, Immuniza target.setRelatedCase(caseService.getByReferenceDto(source.getRelatedCase())); List vaccinationEntities = new ArrayList<>(); - if (!immunizationCopy) { - for (VaccinationDto vaccinationDto : source.getVaccinations()) { - Vaccination vaccination = vaccinationFacade.fromDto(vaccinationDto, checkChangeDate); - vaccination.setImmunization(target); - vaccinationEntities.add(vaccination); - } + for (VaccinationDto vaccinationDto : source.getVaccinations()) { + Vaccination vaccination = vaccinationFacade.fromDto(vaccinationDto, checkChangeDate); + vaccination.setImmunization(target); + vaccinationEntities.add(vaccination); } target.getVaccinations().clear(); target.getVaccinations().addAll(vaccinationEntities); @@ -607,7 +542,7 @@ public boolean linkRecoveryImmunizationToSearchedCase(String specificCaseSearchV @Override public List getByPersonUuids(List uuids) { - return immunizationService.getByPersonUuids(uuids).stream().map(ImmunizationFacadeEjb::toDto).collect(Collectors.toList()); + return immunizationService.getByPersonUuids(uuids).stream().map(i -> toDto(i)).collect(Collectors.toList()); } public void syncSharesAsync(Immunization immunization) { @@ -660,9 +595,10 @@ public void syncSharesAsync(Immunization immunization) { public void copyImmunizationsToLeadPerson(ImmunizationDto immunizationDto, PersonDto leadPerson) { Immunization newImmunization = new Immunization(); newImmunization.setUuid(DataHelper.createUuid()); - newImmunization = fillOrBuildEntity(immunizationDto, newImmunization, false, true); + newImmunization = fillOrBuildEntity(immunizationDto, newImmunization, false); newImmunization.setPerson(personService.getByReferenceDto(leadPerson.toReference())); + newImmunization.setVaccinations(new ArrayList<>()); vaccinationFacade.copyExistingVaccinationsToNewImmunization(immunizationDto, newImmunization); immunizationService.ensurePersisted(newImmunization); @@ -672,5 +608,13 @@ public void copyImmunizationsToLeadPerson(ImmunizationDto immunizationDto, Perso @Stateless public static class ImmunizationFacadeEjbLocal extends ImmunizationFacadeEjb { + public ImmunizationFacadeEjbLocal() { + super(); + } + + @Inject + public ImmunizationFacadeEjbLocal(ImmunizationService service, UserService userService) { + super(service, userService); + } } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java index 6304fc0a2da..f26326e8210 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java @@ -37,6 +37,7 @@ import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; +import de.symeda.sormas.backend.common.AbstractCoreAdoService; import org.apache.commons.collections.CollectionUtils; import de.symeda.sormas.api.Disease; @@ -50,7 +51,7 @@ import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.backend.caze.Case; -import de.symeda.sormas.backend.common.AbstractCoreAdoService; +import de.symeda.sormas.backend.common.AbstractDeletableAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.ChangeDateFilterBuilder; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; @@ -83,8 +84,6 @@ public class ImmunizationService extends AbstractCoreAdoService { private SormasToSormasShareInfoService sormasToSormasShareInfoService; @EJB private FeatureConfigurationFacadeEjbLocal featureConfigurationFacade; - @EJB - private PersonService personService; public ImmunizationService() { super(Immunization.class); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/AbstractInfrastructureEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/AbstractInfrastructureEjb.java index 930ea7f7c81..65690b68f38 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/AbstractInfrastructureEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/AbstractInfrastructureEjb.java @@ -18,6 +18,7 @@ import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb; import de.symeda.sormas.backend.user.User; import de.symeda.sormas.backend.user.UserService; +import de.symeda.sormas.backend.util.DtoHelper; public abstract class AbstractInfrastructureEjb, CRITERIA extends BaseCriteria> extends AbstractBaseEjb @@ -42,6 +43,11 @@ protected AbstractInfrastructureEjb( this.duplicateErrorMessageProperty = duplicateErrorMessageProperty; } + @Override + public DTO save(DTO dtoToSave) { + return save(dtoToSave, false); + } + public DTO save(DTO dto, boolean allowMerge) { checkInfraDataLocked(); // default behaviour is to include archived data and check for the change date @@ -89,6 +95,19 @@ protected DTO doSave(DTO dtoToSave, boolean allowMerge, boolean includeArchived, return persistEntity(dtoToSave, existingEntity, checkChangeDate); } + protected DTO persistEntity(DTO dto, ADO entityToPersist, boolean checkChangeDate) { + entityToPersist = fillOrBuildEntity(dto, entityToPersist, checkChangeDate); + service.ensurePersisted(entityToPersist); + return toDto(entityToPersist); + } + + protected DTO mergeAndPersist(DTO dtoToSave, List duplicates, boolean checkChangeDate) { + ADO existingEntity = duplicates.get(0); + DTO existingDto = toDto(existingEntity); + DtoHelper.copyDtoValues(existingDto, dtoToSave, true); + return persistEntity(dtoToSave, existingEntity, checkChangeDate); + } + @Override public void archive(String uuid) { // todo this should be really in the parent but right now there the setter for archived is not available there @@ -121,5 +140,8 @@ public long count(CRITERIA criteria) { return service.count((cb, root) -> service.buildCriteriaFilter(criteria, cb, root)); } + + protected abstract List findDuplicates(DTO dto, boolean includeArchived); + // todo implement toDto() here } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/LabMessageService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/LabMessageService.java index ce83057c0b6..5b03210f2f7 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/LabMessageService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/LabMessageService.java @@ -19,7 +19,7 @@ import de.symeda.sormas.api.sample.SampleReferenceDto; import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.backend.caze.Case; -import de.symeda.sormas.backend.common.AbstractCoreAdoService; +import de.symeda.sormas.backend.common.AbstractDeletableAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; @@ -30,7 +30,7 @@ @Stateless @LocalBean -public class LabMessageService extends AbstractCoreAdoService { +public class LabMessageService extends AbstractDeletableAdoService { public LabMessageService() { super(LabMessage.class); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestService.java index ffb28cc7bce..7e242bb3ba6 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestService.java @@ -45,7 +45,7 @@ import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.api.utils.SortProperty; import de.symeda.sormas.backend.caze.Case; -import de.symeda.sormas.backend.common.AbstractCoreAdoService; +import de.symeda.sormas.backend.common.AbstractDeletableAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; @@ -56,7 +56,7 @@ @Stateless @LocalBean -public class PathogenTestService extends AbstractCoreAdoService { +public class PathogenTestService extends AbstractDeletableAdoService { @EJB private SampleService sampleService; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleService.java index 45027c2f392..3f88d62930b 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleService.java @@ -78,7 +78,7 @@ import de.symeda.sormas.backend.caze.CaseFacadeEjb; import de.symeda.sormas.backend.caze.CaseQueryContext; import de.symeda.sormas.backend.caze.CaseService; -import de.symeda.sormas.backend.common.AbstractCoreAdoService; +import de.symeda.sormas.backend.common.AbstractDeletableAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; @@ -106,7 +106,7 @@ @Stateless @LocalBean -public class SampleService extends AbstractCoreAdoService { +public class SampleService extends AbstractDeletableAdoService { @EJB private UserService userService; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/immunization/ReceivedImmunizationProcessor.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/immunization/ReceivedImmunizationProcessor.java index c9c3c23d081..148598d0efd 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/immunization/ReceivedImmunizationProcessor.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/immunization/ReceivedImmunizationProcessor.java @@ -43,19 +43,23 @@ public class ReceivedImmunizationProcessor public ReceivedImmunizationProcessor() { } + private ImmunizationFacadeEjb.ImmunizationFacadeEjbLocal immunizationFacadeEjb; + @Inject protected ReceivedImmunizationProcessor( + ImmunizationFacadeEjb.ImmunizationFacadeEjbLocal facadeEjb, ImmunizationService service, UserService userService, ConfigFacadeEjb.ConfigFacadeEjbLocal configFacade, SormasToSormasImmunizationDtoValidator validator) { super(service, userService, configFacade, validator); + this.immunizationFacadeEjb = facadeEjb; } @Override public void handleReceivedData(SormasToSormasImmunizationDto sharedData, Immunization existingData) { updateReportingUser(sharedData.getEntity(), existingData); - handleIgnoredProperties(sharedData.getEntity(), ImmunizationFacadeEjb.toDto(existingData)); + handleIgnoredProperties(sharedData.getEntity(), immunizationFacadeEjb.toDto(existingData)); ImmunizationDto im = sharedData.getEntity(); im.getVaccinations().forEach(vaccination -> { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java index 14adad24c9a..69d532cfa65 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java @@ -1,13 +1,13 @@ package de.symeda.sormas.backend.travelentry; -import java.util.Date; import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; import javax.ejb.EJB; import javax.ejb.LocalBean; import javax.ejb.Stateless; +import javax.inject.Inject; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import javax.validation.constraints.NotNull; import de.symeda.sormas.api.i18n.Captions; @@ -26,6 +26,7 @@ import de.symeda.sormas.api.utils.ValidationRuntimeException; import de.symeda.sormas.backend.caze.CaseFacadeEjb; import de.symeda.sormas.backend.caze.CaseService; +import de.symeda.sormas.backend.common.AbstractCoreEjb; import de.symeda.sormas.backend.infrastructure.community.CommunityFacadeEjb; import de.symeda.sormas.backend.infrastructure.community.CommunityService; import de.symeda.sormas.backend.infrastructure.district.DistrictFacadeEjb; @@ -44,7 +45,9 @@ import de.symeda.sormas.backend.util.Pseudonymizer; @Stateless(name = "TravelEntryFacade") -public class TravelEntryFacadeEjb implements TravelEntryFacade { +public class TravelEntryFacadeEjb + extends AbstractCoreEjb + implements TravelEntryFacade { @EJB TravelEntryService travelEntryService; @@ -53,8 +56,6 @@ public class TravelEntryFacadeEjb implements TravelEntryFacade { @EJB private PersonService personService; @EJB - private UserService userService; - @EJB private RegionService regionService; @EJB private DistrictService districtService; @@ -67,6 +68,14 @@ public class TravelEntryFacadeEjb implements TravelEntryFacade { @EJB private CaseFacadeEjb.CaseFacadeEjbLocal caseFacade; + public TravelEntryFacadeEjb() { + } + + @Inject + public TravelEntryFacadeEjb(TravelEntryService service, UserService userService) { + super(TravelEntry.class, TravelEntryDto.class, service, userService); + } + public static TravelEntryReferenceDto toReferenceDto(TravelEntry entity) { if (entity == null) { @@ -79,35 +88,6 @@ public static TravelEntryReferenceDto toReferenceDto(TravelEntry entity) { entity.getPerson().getLastName()); } - @Override - public TravelEntryDto getByUuid(String uuid) { - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); - return convertToDto(travelEntryService.getByUuid(uuid), pseudonymizer); - } - - @Override - public TravelEntryReferenceDto getReferenceByUuid(String uuid) { - return Optional.of(uuid).map(u -> travelEntryService.getByUuid(u)).map(TravelEntryFacadeEjb::toReferenceDto).orElse(null); - } - - @Override - public void archive(String uuid) { - TravelEntry travelEntry = travelEntryService.getByUuid(uuid); - if (travelEntry != null) { - travelEntry.setArchived(true); - travelEntryService.ensurePersisted(travelEntry); - } - } - - @Override - public void dearchive(String uuid) { - TravelEntry travelEntry = travelEntryService.getByUuid(uuid); - if (travelEntry != null) { - travelEntry.setArchived(false); - travelEntryService.ensurePersisted(travelEntry); - } - } - @Override public boolean isDeleted(String travelEntryUuid) { return travelEntryService.isDeleted(travelEntryUuid); @@ -146,20 +126,7 @@ public void deleteTravelEntry(String travelEntryUuid) { } @Override - public List getAllAfter(Date date) { - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); - return travelEntryService.getAllActiveAfter(date).stream().map(c -> convertToDto(c, pseudonymizer)).collect(Collectors.toList()); - } - - @Override - public List getByUuids(List uuids) { - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); - return travelEntryService.getByUuids(uuids).stream().map(c -> convertToDto(c, pseudonymizer)).collect(Collectors.toList()); - } - - @Override - public List getAllUuids() { - return travelEntryService.getAllUuids(); + protected void selectDtoFields(CriteriaQuery cq, Root root) { } @Override @@ -186,33 +153,7 @@ public long count(TravelEntryCriteria criteria, boolean ignoreUserFilter) { } @Override - public TravelEntryDto save(TravelEntryDto dto, boolean allowMerge) { - TravelEntry existingTravelEntry = dto.getUuid() != null ? travelEntryService.getByUuid(dto.getUuid()) : null; - TravelEntryDto existingDto = toDto(existingTravelEntry); - - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); - restorePseudonymizedDto(dto, existingDto, existingTravelEntry, pseudonymizer); - - validate(dto); - - existingTravelEntry = fillOrBuildEntity(dto, existingTravelEntry); - travelEntryService.ensurePersisted(existingTravelEntry); - - return convertToDto(existingTravelEntry, pseudonymizer); - } - - @Override - public TravelEntryDto save(TravelEntryDto dto) { - return save(dto, false); - } - - public TravelEntryDto convertToDto(TravelEntry source, Pseudonymizer pseudonymizer) { - TravelEntryDto dto = toDto(source); - pseudonimyzeDto(source, dto, pseudonymizer); - return dto; - } - - private void pseudonimyzeDto(TravelEntry source, TravelEntryDto dto, Pseudonymizer pseudonymizer) { + protected void pseudonymizeDto(TravelEntry source, TravelEntryDto dto, Pseudonymizer pseudonymizer) { if (dto != null) { boolean inJurisdiction = travelEntryService.inJurisdictionOrOwned(source); pseudonymizer.pseudonymizeDto(TravelEntryDto.class, dto, inJurisdiction, c -> { @@ -222,7 +163,8 @@ private void pseudonimyzeDto(TravelEntry source, TravelEntryDto dto, Pseudonymiz } } - private void restorePseudonymizedDto(TravelEntryDto dto, TravelEntryDto existingDto, TravelEntry travelEntry, Pseudonymizer pseudonymizer) { + @Override + protected void restorePseudonymizedDto(TravelEntryDto dto, TravelEntryDto existingDto, TravelEntry travelEntry, Pseudonymizer pseudonymizer) { if (existingDto != null) { final boolean inJurisdiction = travelEntryService.inJurisdictionOrOwned(travelEntry); final User currentUser = userService.getCurrentUser(); @@ -231,11 +173,6 @@ private void restorePseudonymizedDto(TravelEntryDto dto, TravelEntryDto existing } } - @Override - public boolean exists(String uuid) { - return travelEntryService.exists(uuid); - } - @Override public List getIndexList(TravelEntryCriteria criteria, Integer first, Integer max, List sortProperties) { List resultList = travelEntryService.getIndexList(criteria, first, max, sortProperties); @@ -338,8 +275,14 @@ public TravelEntryDto toDto(TravelEntry entity) { return dto; } - private TravelEntry fillOrBuildEntity(@NotNull TravelEntryDto source, TravelEntry target) { - target = DtoHelper.fillOrBuildEntity(source, target, TravelEntry::new, true); + @Override + public TravelEntryReferenceDto toRefDto(TravelEntry travelEntry) { + return null; + } + + @Override + protected TravelEntry fillOrBuildEntity(@NotNull TravelEntryDto source, TravelEntry target, boolean checkChangeDate) { + target = DtoHelper.fillOrBuildEntity(source, target, TravelEntry::new, checkChangeDate); target.setPerson(personService.getByReferenceDto(source.getPerson())); target.setReportDate(source.getReportDate()); @@ -388,5 +331,13 @@ private TravelEntry fillOrBuildEntity(@NotNull TravelEntryDto source, TravelEntr @LocalBean @Stateless public static class TravelEntryFacadeEjbLocal extends TravelEntryFacadeEjb { + + public TravelEntryFacadeEjbLocal() { + } + + @Inject + public TravelEntryFacadeEjbLocal(TravelEntryService service, UserService userService) { + super(service, userService); + } } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java index 2a3faf40026..90495c0db32 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java @@ -5,14 +5,20 @@ import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.From; import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; +import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.backend.common.AbstractCoreAdoService; +import de.symeda.sormas.backend.common.AbstractDeletableAdoService; import de.symeda.sormas.backend.travelentry.TravelEntry; import de.symeda.sormas.backend.travelentry.TravelEntryJurisdictionPredicateValidator; import de.symeda.sormas.backend.travelentry.TravelEntryQueryContext; import de.symeda.sormas.backend.user.User; import de.symeda.sormas.backend.user.UserService; +import java.util.Date; +import java.util.List; + public class BaseTravelEntryService extends AbstractCoreAdoService { @EJB @@ -42,4 +48,36 @@ public Predicate createDefaultFilter(CriteriaBuilder cb, From ro protected Predicate createUserFilter(TravelEntryQueryContext travelEntryQueryContext) { return inJurisdictionOrOwned(travelEntryQueryContext); } + + public List getAllActiveAfter(Date date) { + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(getElementClass()); + Root from = cq.from(getElementClass()); + + Predicate filter = createDefaultFilter(cb, from); + + if (getCurrentUser() != null) { + Predicate userFilter = createUserFilter(cb, cq, from); + if (userFilter != null) { + filter = cb.and(filter, userFilter); + } + } + + if (date != null) { + Predicate dateFilter = createChangeDateFilter(cb, from, DateHelper.toTimestampUpper(date)); + if (dateFilter != null) { + filter = cb.and(filter, dateFilter); + } + } + cq.where(filter); + cq.orderBy(cb.desc(from.get(TravelEntry.CHANGE_DATE))); + cq.distinct(true); + + return em.createQuery(cq).getResultList(); + } + + @Override + public List getAllActiveAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { + return getAllActiveAfter(date); + } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/TravelEntryService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/TravelEntryService.java index 457dcf19ddd..fffae90b9f0 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/TravelEntryService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/TravelEntryService.java @@ -174,33 +174,6 @@ public Predicate createActiveTravelEntriesFilter(CriteriaBuilder cb, From getAllActiveAfter(Date date) { - CriteriaBuilder cb = em.getCriteriaBuilder(); - CriteriaQuery cq = cb.createQuery(getElementClass()); - Root from = cq.from(getElementClass()); - - Predicate filter = createDefaultFilter(cb, from); - - if (getCurrentUser() != null) { - Predicate userFilter = createUserFilter(cb, cq, from); - if (userFilter != null) { - filter = cb.and(filter, userFilter); - } - } - - if (date != null) { - Predicate dateFilter = createChangeDateFilter(cb, from, DateHelper.toTimestampUpper(date)); - if (dateFilter != null) { - filter = cb.and(filter, dateFilter); - } - } - cq.where(filter); - cq.orderBy(cb.desc(from.get(TravelEntry.CHANGE_DATE))); - cq.distinct(true); - - return em.createQuery(cq).getResultList(); - } - public List getAllByResultingCase(Case caze) { CriteriaBuilder cb = em.getCriteriaBuilder(); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java index 1059533cd50..2bf89821404 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java @@ -23,21 +23,6 @@ import javax.persistence.EntityManager; import javax.persistence.Query; -import de.symeda.sormas.backend.common.DefaultEntitiesCreator; -import de.symeda.sormas.backend.labmessage.LabMessageService; -import de.symeda.sormas.backend.sormastosormas.entities.caze.ReceivedCaseProcessor; -import de.symeda.sormas.backend.sormastosormas.entities.caze.SormasToSormasCaseDtoValidator; -import de.symeda.sormas.backend.sormastosormas.entities.contact.ReceivedContactProcessor; -import de.symeda.sormas.backend.sormastosormas.entities.contact.SormasToSormasContactDtoValidator; -import de.symeda.sormas.backend.sormastosormas.entities.event.ReceivedEventProcessor; -import de.symeda.sormas.backend.sormastosormas.entities.event.SormasToSormasEventDtoValidator; -import de.symeda.sormas.backend.sormastosormas.entities.eventparticipant.SormasToSormasEventParticipantDtoValidator; -import de.symeda.sormas.backend.sormastosormas.entities.immunization.ReceivedImmunizationProcessor; -import de.symeda.sormas.backend.sormastosormas.entities.immunization.SormasToSormasImmunizationDtoValidator; -import de.symeda.sormas.backend.sormastosormas.entities.labmessage.SormasToSormasLabMessageDtoValidator; -import de.symeda.sormas.backend.sormastosormas.entities.labmessage.SormasToSormasLabMessageFacadeEjb; -import de.symeda.sormas.backend.sormastosormas.entities.sample.ReceivedSampleProcessor; -import de.symeda.sormas.backend.sormastosormas.entities.sample.SormasToSormasSampleDtoValidator; import org.junit.Before; import de.symeda.sormas.api.ConfigFacade; @@ -92,10 +77,10 @@ import de.symeda.sormas.api.sample.SampleFacade; import de.symeda.sormas.api.share.ExternalShareInfoFacade; import de.symeda.sormas.api.sormastosormas.SormasToSormasEncryptionFacade; -import de.symeda.sormas.api.sormastosormas.labmessage.SormasToSormasLabMessageFacade; import de.symeda.sormas.api.sormastosormas.caze.SormasToSormasCaseFacade; import de.symeda.sormas.api.sormastosormas.contact.SormasToSormasContactFacade; import de.symeda.sormas.api.sormastosormas.event.SormasToSormasEventFacade; +import de.symeda.sormas.api.sormastosormas.labmessage.SormasToSormasLabMessageFacade; import de.symeda.sormas.api.sormastosormas.sharerequest.SormasToSormasShareRequestFacade; import de.symeda.sormas.api.symptoms.SymptomsFacade; import de.symeda.sormas.api.systemevents.SystemEventFacade; @@ -127,6 +112,7 @@ import de.symeda.sormas.backend.clinicalcourse.ClinicalVisitFacadeEjb.ClinicalVisitFacadeEjbLocal; import de.symeda.sormas.backend.clinicalcourse.ClinicalVisitService; import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; +import de.symeda.sormas.backend.common.DefaultEntitiesCreator; import de.symeda.sormas.backend.contact.ContactFacadeEjb.ContactFacadeEjbLocal; import de.symeda.sormas.backend.contact.ContactService; import de.symeda.sormas.backend.customizableenum.CustomizableEnumFacadeEjb; @@ -174,6 +160,7 @@ import de.symeda.sormas.backend.infrastructure.subcontinent.SubcontinentFacadeEjb; import de.symeda.sormas.backend.infrastructure.subcontinent.SubcontinentService; import de.symeda.sormas.backend.labmessage.LabMessageFacadeEjb.LabMessageFacadeEjbLocal; +import de.symeda.sormas.backend.labmessage.LabMessageService; import de.symeda.sormas.backend.labmessage.TestReportFacadeEjb; import de.symeda.sormas.backend.labmessage.TestReportService; import de.symeda.sormas.backend.outbreak.OutbreakFacadeEjb.OutbreakFacadeEjbLocal; @@ -189,10 +176,22 @@ import de.symeda.sormas.backend.share.ExternalShareInfoService; import de.symeda.sormas.backend.sormastosormas.SormasToSormasFacadeEjb.SormasToSormasFacadeEjbLocal; import de.symeda.sormas.backend.sormastosormas.crypto.SormasToSormasEncryptionFacadeEjb; +import de.symeda.sormas.backend.sormastosormas.entities.caze.ReceivedCaseProcessor; +import de.symeda.sormas.backend.sormastosormas.entities.caze.SormasToSormasCaseDtoValidator; import de.symeda.sormas.backend.sormastosormas.entities.caze.SormasToSormasCaseFacadeEjb.SormasToSormasCaseFacadeEjbLocal; +import de.symeda.sormas.backend.sormastosormas.entities.contact.ReceivedContactProcessor; +import de.symeda.sormas.backend.sormastosormas.entities.contact.SormasToSormasContactDtoValidator; import de.symeda.sormas.backend.sormastosormas.entities.contact.SormasToSormasContactFacadeEjb.SormasToSormasContactFacadeEjbLocal; +import de.symeda.sormas.backend.sormastosormas.entities.event.ReceivedEventProcessor; +import de.symeda.sormas.backend.sormastosormas.entities.event.SormasToSormasEventDtoValidator; import de.symeda.sormas.backend.sormastosormas.entities.event.SormasToSormasEventFacadeEjb.SormasToSormasEventFacadeEjbLocal; +import de.symeda.sormas.backend.sormastosormas.entities.eventparticipant.SormasToSormasEventParticipantDtoValidator; +import de.symeda.sormas.backend.sormastosormas.entities.immunization.ReceivedImmunizationProcessor; +import de.symeda.sormas.backend.sormastosormas.entities.immunization.SormasToSormasImmunizationDtoValidator; +import de.symeda.sormas.backend.sormastosormas.entities.labmessage.SormasToSormasLabMessageDtoValidator; import de.symeda.sormas.backend.sormastosormas.entities.labmessage.SormasToSormasLabMessageFacadeEjb.SormasToSormasLabMessageFacadeEjbLocal; +import de.symeda.sormas.backend.sormastosormas.entities.sample.ReceivedSampleProcessor; +import de.symeda.sormas.backend.sormastosormas.entities.sample.SormasToSormasSampleDtoValidator; import de.symeda.sormas.backend.sormastosormas.share.ShareDataBuilderHelper; import de.symeda.sormas.backend.sormastosormas.share.shareinfo.ShareRequestInfoService; import de.symeda.sormas.backend.sormastosormas.share.shareinfo.SormasToSormasShareInfoFacadeEjb.SormasToSormasShareInfoFacadeEjbLocal; @@ -224,6 +223,7 @@ public abstract class AbstractBeanTest extends BaseBeanTest { protected final TestDataCreator creator = new TestDataCreator(this); + public static final String CONFIDENTIAL = "Confidential"; /** * Resets mocks to their initial state so that mock configurations are not diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjbTest.java index 5bfd89c5586..297fcdbf62f 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjbTest.java @@ -130,8 +130,8 @@ public void testCanSeeByResponsibleJurisdiction() { TravelEntryDto notInJurisdictionTravelEntry = getTravelEntryFacade().getByUuid(notSeenTravelEntry.getUuid()); assertEquals(notInJurisdictionTravelEntry.getUuid(), notSeenTravelEntry.getUuid()); - assertThat(notInJurisdictionTravelEntry.getPerson().getLastName(), is(isEmptyString())); - assertThat(notInJurisdictionTravelEntry.getPerson().getFirstName(), is(isEmptyString())); + assertThat(notInJurisdictionTravelEntry.getPerson().getLastName(), is(CONFIDENTIAL)); + assertThat(notInJurisdictionTravelEntry.getPerson().getFirstName(), is(CONFIDENTIAL)); assertEquals(notInJurisdictionTravelEntry.getDisease(), notSeenTravelEntry.getDisease()); } From 80ef21bdb5712f9c7e42995c57e38091bbf94bd6 Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Fri, 28 Jan 2022 14:22:58 +0100 Subject: [PATCH 004/253] Improvement Persons.feature after review --- .../e2etests/enums/CommunityValues.java | 10 + .../e2etests/enums/DistrictsValues.java | 10 + .../sormas/e2etests/enums/RegionsValues.java | 10 + .../persons/PersonDirectoryPage.java | 17 ++ .../persons/PersonDirectorySteps.java | 181 +++++++++++++++++- .../features/sanity/web/Persons.feature | 65 ++++++- 6 files changed, 285 insertions(+), 8 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CommunityValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CommunityValues.java index 170e61942d4..77d11478f9e 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CommunityValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CommunityValues.java @@ -18,6 +18,7 @@ package org.sormas.e2etests.enums; import lombok.Getter; +import lombok.SneakyThrows; @Getter public enum CommunityValues { @@ -30,4 +31,13 @@ public enum CommunityValues { this.name = name; this.uuid = uuid; } + + @SneakyThrows + public static String getValueFor(String option) { + CommunityValues[] communityValuesOptions = CommunityValues.values(); + for (CommunityValues value : communityValuesOptions) { + if (value.uuid.equalsIgnoreCase(option)) return value.name; + } + throw new Exception("Unable to find " + option + " value in Community Enum"); + } } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java index 4e319b51219..ae68e2bb24f 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java @@ -18,6 +18,7 @@ package org.sormas.e2etests.enums; import lombok.Getter; +import lombok.SneakyThrows; @Getter public enum DistrictsValues { @@ -30,4 +31,13 @@ public enum DistrictsValues { this.name = name; this.uuid = uuid; } + + @SneakyThrows + public static String getValueFor(String option) { + DistrictsValues[] districtValuesOptions = DistrictsValues.values(); + for (DistrictsValues value : districtValuesOptions) { + if (value.uuid.equalsIgnoreCase(option)) return value.name; + } + throw new Exception("Unable to find " + option + " value in District Enum"); + } } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RegionsValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RegionsValues.java index a70fcc5bf0b..51206d98035 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RegionsValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RegionsValues.java @@ -18,6 +18,7 @@ package org.sormas.e2etests.enums; import lombok.Getter; +import lombok.SneakyThrows; @Getter public enum RegionsValues { @@ -30,4 +31,13 @@ public enum RegionsValues { this.name = name; this.uuid = uuid; } + + @SneakyThrows + public static String getValueFor(String option) { + RegionsValues[] regionValuesOptions = RegionsValues.values(); + for (RegionsValues value : regionValuesOptions) { + if (value.uuid.equalsIgnoreCase(option)) return value.name; + } + throw new Exception("Unable to find " + option + " value in Region Enum"); + } } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/PersonDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/PersonDirectoryPage.java index 904e2f04ce8..a14fde0f816 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/PersonDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/PersonDirectoryPage.java @@ -25,7 +25,24 @@ public class PersonDirectoryPage { public static final By MULTIPLE_OPTIONS_SEARCH_INPUT = By.cssSelector("#nameAddressPhoneEmailLike"); public static final By APPLY_FILTERS_BUTTON = By.cssSelector("#actionApplyFilters"); + public static final By RESET_FILTERS_BUTTON = By.cssSelector("[id='actionResetFilters']"); public static final String PERSON_RESULTS_UUID_LOCATOR = "[title = '%s']"; public static final By SEARCH_PERSON_BY_FREE_TEXT = By.id("nameAddressPhoneEmailLike"); public static final By ALL_BUTTON = By.id("All"); + public static final By BIRTH_YEAR_COMBOBOX = + By.cssSelector("[id='birthdateYYYY'] [class='v-filterselect-button']"); + public static final By BIRTH_MONTH_COMBOBOX = + By.cssSelector("[id='birthdateMM'] [class='v-filterselect-button']"); + public static final By BIRTH_DAY_COMBOBOX = + By.cssSelector("[id='birthdateDD'] [class='v-filterselect-button']"); + public static final By PRESENT_CONDITION = + By.cssSelector("[id='presentCondition'] [class='v-filterselect-button']"); + public static final By REGIONS_COMBOBOX = + By.cssSelector("[id='region'] [class='v-filterselect-button']"); + public static final By DISTRICTS_COMBOBOX = + By.cssSelector("[id='district'] [class='v-filterselect-button']"); + public static final By COMMUNITY_PERSON_COMBOBOX = + By.cssSelector("[id='community'] [class='v-filterselect-button']"); + public static final By CASE_PERSON_ID_COLUMN_HEADERS = + By.cssSelector("v-grid-column-header-content v-grid-column-default-header-content"); } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java index ca338b33278..a23ccc7d312 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java @@ -18,19 +18,29 @@ package org.sormas.e2etests.steps.web.application.persons; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_GRID_RESULTS_ROWS; import static org.sormas.e2etests.pages.application.persons.EditPersonPage.UUID_INPUT; import static org.sormas.e2etests.pages.application.persons.EditPersonPage.getByPersonUuid; import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.*; import cucumber.api.java8.En; +import java.util.UUID; +import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.inject.Named; import org.openqa.selenium.By; +import org.sormas.e2etests.common.DataOperations; +import org.sormas.e2etests.enums.CommunityValues; +import org.sormas.e2etests.enums.DistrictsValues; +import org.sormas.e2etests.enums.PresentCondition; +import org.sormas.e2etests.enums.RegionsValues; +import org.sormas.e2etests.helpers.AssertHelpers; import org.sormas.e2etests.helpers.WebDriverHelpers; import org.sormas.e2etests.pojo.web.Person; import org.sormas.e2etests.state.ApiState; import org.sormas.e2etests.steps.web.application.contacts.EditContactPersonSteps; import org.sormas.e2etests.steps.web.application.events.EditEventSteps; +import org.testng.Assert; public class PersonDirectorySteps implements En { private final WebDriverHelpers webDriverHelpers; @@ -40,7 +50,9 @@ public class PersonDirectorySteps implements En { public PersonDirectorySteps( WebDriverHelpers webDriverHelpers, @Named("ENVIRONMENT_URL") String environmentUrl, - ApiState apiState) { + ApiState apiState, + DataOperations dataOperations, + AssertHelpers assertHelpers) { this.webDriverHelpers = webDriverHelpers; // TODO refactor all BDD methods naming to be more explicit regarding where data comes from @@ -64,6 +76,110 @@ public PersonDirectorySteps( webDriverHelpers.isElementVisibleWithTimeout(UUID_INPUT, 20); }); + Then( + "I choose random value for Year of birth filter in Persons for the last created person by API", + () -> { + String yearOfBirth = apiState.getLastCreatedPerson().getBirthdateYYYY().toString(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(BIRTH_YEAR_COMBOBOX, yearOfBirth); + }); + + Then( + "I choose random value for Month of birth filter in Persons for the last created person by API", + () -> { + String monthOfBirth = apiState.getLastCreatedPerson().getBirthdateMM().toString(); + webDriverHelpers.selectFromCombobox(BIRTH_MONTH_COMBOBOX, monthOfBirth); + }); + + Then( + "I choose random value for Day of birth filter in Persons for the last created person by API", + () -> { + String dayOfBirth = apiState.getLastCreatedPerson().getBirthdateDD().toString(); + webDriverHelpers.selectFromCombobox(BIRTH_DAY_COMBOBOX, dayOfBirth); + }); + + Then( + "I choose present condition field from specific range for the last created person by API", + () -> { + String presentCondition = apiState.getLastCreatedPerson().getPresentCondition(); + webDriverHelpers.selectFromCombobox( + PRESENT_CONDITION, PresentCondition.getValueFor(presentCondition)); + }); + + Then( + "I choose random value of Region in Persons for the last created person by API", + () -> { + String regionName = apiState.getLastCreatedPerson().getAddress().getRegion(); + webDriverHelpers.selectFromCombobox( + REGIONS_COMBOBOX, RegionsValues.getValueFor(regionName)); + }); + + Then( + "I choose random value of District in Persons for the last created person by API", + () -> { + String districtName = apiState.getLastCreatedPerson().getAddress().getDistrict(); + webDriverHelpers.selectFromCombobox( + DISTRICTS_COMBOBOX, DistrictsValues.getValueFor(districtName)); + }); + + Then( + "I choose random value of Community in Persons for the last created person by API", + () -> { + String communityName = apiState.getLastCreatedPerson().getAddress().getCommunity(); + webDriverHelpers.selectFromCombobox( + COMMUNITY_PERSON_COMBOBOX, CommunityValues.getValueFor(communityName)); + }); + + Then( + "I check that number of displayed Person results is {int}", + (Integer number) -> + assertHelpers.assertWithPoll20Second( + () -> + Assert.assertEquals( + webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), + number.intValue(), + "Number of displayed persons is not correct"))); + When( + "I click on the APPLY FILTERS button for Person", + () -> { + webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable( + APPLY_FILTERS_BUTTON, 30); + webDriverHelpers.clickOnWebElementBySelector(APPLY_FILTERS_BUTTON); + TimeUnit.SECONDS.sleep(10); + }); + + Then( + "I change Year of birth filter to {string} for Person", + (String yearOfBirth) -> + webDriverHelpers.selectFromCombobox(BIRTH_YEAR_COMBOBOX, yearOfBirth)); + + Then( + "I change Month of birth filter to {string} for Person", + (String monthOfBirth) -> + webDriverHelpers.selectFromCombobox(BIRTH_MONTH_COMBOBOX, monthOfBirth)); + + Then( + "I change Day of birth filter to {string} for Person", + (String dayOfBirth) -> webDriverHelpers.selectFromCombobox(BIRTH_DAY_COMBOBOX, dayOfBirth)); + + Then( + "I change present condition filter to {string} for Person", + (String presentCondition) -> + webDriverHelpers.selectFromCombobox(PRESENT_CONDITION, presentCondition)); + + Then( + "I change REGION filter to {string} for Person", + (String region) -> webDriverHelpers.selectFromCombobox(REGIONS_COMBOBOX, region)); + + Then( + "I change DISTRICT filter to {string} for Person", + (String district) -> webDriverHelpers.selectFromCombobox(DISTRICTS_COMBOBOX, district)); + + Then( + "I change Community filter to {string} for Person", + (String community) -> + webDriverHelpers.selectFromCombobox(COMMUNITY_PERSON_COMBOBOX, community)); + When( "I navigate to the last created Person page via URL", () -> { @@ -91,6 +207,15 @@ public PersonDirectorySteps( webDriverHelpers.clickOnWebElementBySelector(getByPersonUuid(personUuid)); }); + When( + "I click on the RESET FILTERS button for Person", + () -> { + webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable( + RESET_FILTERS_BUTTON, 30); + webDriverHelpers.clickOnWebElementBySelector(RESET_FILTERS_BUTTON); + TimeUnit.SECONDS.sleep(10); + }); + Then( "I search after last created person from API by {string}", (String searchCriteria) -> { @@ -111,7 +236,6 @@ public PersonDirectorySteps( webDriverHelpers.waitUntilElementIsVisibleAndClickable(APPLY_FILTERS_BUTTON); webDriverHelpers.clickOnWebElementBySelector(ALL_BUTTON); webDriverHelpers.waitForPageLoadingSpinnerToDisappear(150); - webDriverHelpers.fillInWebElement(MULTIPLE_OPTIONS_SEARCH_INPUT, searchText); webDriverHelpers.clickOnWebElementBySelector(APPLY_FILTERS_BUTTON); By uuidLocator = By.cssSelector(String.format(PERSON_RESULTS_UUID_LOCATOR, personUUID)); @@ -121,10 +245,53 @@ public PersonDirectorySteps( webDriverHelpers.isElementVisibleWithTimeout(UUID_INPUT, 20); }); - // TODO Michal, due to specific logic to filter only for this situation, create a method with a - // suggestive name, where you apply filters based on generated POJO data. - // We can't create multiple methods to reuse them in this case, but please keep in mind to - // create generic locators - // The above method will need to be finished by you (the switch to cover all search criteria) + Then( + "I search after last created person from API by factor {string}", + (String searchCriteria) -> { + String searchText = ""; + String personUUID = apiState.getLastCreatedPerson().getUuid(); + switch (searchCriteria) { + case "uuid": + searchText = dataOperations.getPartialUuidFromAssociatedLink((personUUID)); + break; + case "full name": + searchText = + apiState.getLastCreatedPerson().getLastName() + + " " + + apiState.getLastCreatedPerson().getFirstName(); + break; + case "phone number": + searchText = apiState.getLastCreatedPerson().getPhone(); + break; + case "email": + searchText = apiState.getLastCreatedPerson().getEmailAddress(); + break; + } + + webDriverHelpers.fillInWebElement(MULTIPLE_OPTIONS_SEARCH_INPUT, searchText); + }); + + Then( + "I change {string} information data field for Person", + (String searchCriteria) -> { + String searchText = ""; + String personUUID = + dataOperations.getPartialUuidFromAssociatedLink(UUID.randomUUID().toString()); + switch (searchCriteria) { + case "uuid": + searchText = personUUID; + break; + case "full name": + searchText = "Tom Jerry"; + break; + case "phone number": + searchText = "(06713) 6606268"; + break; + case "email": + searchText = "Tom.Jerry@person.com"; + break; + } + webDriverHelpers.fillInWebElement(MULTIPLE_OPTIONS_SEARCH_INPUT, searchText); + }); } } diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature index 25c8fadaf33..68016d2fbae 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature @@ -17,4 +17,67 @@ Feature: Edit Persons And While on Person edit page, I will edit all fields with new values And I edit all Person primary contact details and save Then I click on save button from Edit Person page - And I check that previous edited person is correctly displayed in Edit Person page \ No newline at end of file + And I check that previous edited person is correctly displayed in Edit Person page + + Scenario: Check Filters on Person page work as expected + Given API: I create a new person + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Then API: I create a new case + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + When I log in with National User + When I click on the Persons button from navbar + Then I choose random value for Year of birth filter in Persons for the last created person by API + And I choose random value for Month of birth filter in Persons for the last created person by API + And I choose random value for Day of birth filter in Persons for the last created person by API + Then I search after last created person from API by factor "uuid" + And I choose present condition field from specific range for the last created person by API + And I choose random value of Region in Persons for the last created person by API + And I choose random value of District in Persons for the last created person by API + And I choose random value of Community in Persons for the last created person by API + Then I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 1 + And I change Year of birth filter to "1955" for Person + Then I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 0 + Then I choose random value for Year of birth filter in Persons for the last created person by API + Then I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 1 + And I change Month of birth filter to "4" for Person + Then I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 0 + And I choose random value for Month of birth filter in Persons for the last created person by API + Then I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 1 + And I change Day of birth filter to "13" for Person + Then I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 0 + And I choose random value for Day of birth filter in Persons for the last created person by API + Then I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 1 + Then I change "uuid" information data field for Person + And I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 0 + And I search after last created person from API by factor "uuid" + And I change present condition filter to "Unknown" for Person + And I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 0 + And I choose present condition field from specific range for the last created person by API + Then I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 1 + And I change REGION filter to "Berlin" for Person + And I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 0 + And I choose random value of Region in Persons for the last created person by API + And I choose random value of District in Persons for the last created person by API + Then I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 1 + Then I change Community filter to "Community2" for Person + And I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 0 + And I choose random value of Community in Persons for the last created person by API + Then I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 1 + And I click on the APPLY FILTERS button for Person + And I click on the RESET FILTERS button for Person \ No newline at end of file From 0ac84784791fe93947447346a70b6eb7c45c612c Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Mon, 31 Jan 2022 16:15:33 +0200 Subject: [PATCH 005/253] #7246 - move event facade methods to new core entities abstraction facade --- .../java/de/symeda/sormas/api/BaseFacade.java | 3 +- .../symeda/sormas/api/event/EventFacade.java | 19 +- .../CaseClassificationFacadeEjb.java | 4 +- .../backend/common/AbstractCoreEjb.java | 7 +- .../sormas/backend/event/EventFacadeEjb.java | 210 +++++++++--------- .../event/EventParticipantFacadeEjb.java | 2 +- .../sormas/backend/event/EventService.java | 13 +- .../eventimport/EventImportFacadeEjb.java | 2 +- .../immunization/ImmunizationFacadeEjb.java | 50 ++--- .../immunization/ImmunizationService.java | 1 - .../backend/person/PersonFacadeEjb.java | 4 +- .../backend/sample/PathogenTestFacadeEjb.java | 4 +- .../backend/sample/SampleFacadeEjb.java | 4 +- .../event/ProcessedEventDataPersister.java | 2 +- .../event/ReceivedEventProcessor.java | 6 +- .../SormasToSormasShareInfoService.java | 4 +- .../travelentry/TravelEntryFacadeEjb.java | 32 ++- .../sormas/backend/TestDataCreator.java | 2 +- .../backend/caze/CaseFacadeEjbTest.java | 2 +- .../QuarantineOrderFacadeEjbTest.java | 2 +- .../EventFacadeEjbPseudonymizationTest.java | 4 +- .../backend/event/EventFacadeEjbTest.java | 12 +- .../ImmunizationFacadeEjbTest.java | 16 +- .../de/symeda/sormas/rest/EventResource.java | 6 +- .../sormas/ui/configuration/DevModeView.java | 2 +- .../sormas/ui/events/EventController.java | 22 +- .../ui/labmessage/LabMessageController.java | 2 +- .../de/symeda/sormas/ui/TestDataCreator.java | 4 +- .../ui/event/importer/EventImporterTest.java | 2 +- 29 files changed, 214 insertions(+), 229 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/BaseFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/BaseFacade.java index f121cdd71a0..d22b601fc0d 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/BaseFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/BaseFacade.java @@ -5,13 +5,14 @@ import java.util.List; import javax.validation.Valid; +import javax.validation.constraints.NotNull; import de.symeda.sormas.api.utils.SortProperty; import de.symeda.sormas.api.utils.criteria.BaseCriteria; public interface BaseFacade { - DTO save(@Valid DTO dto); + DTO save(@Valid @NotNull DTO dto); long count(CRITERIA criteria); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java index f9955906c1c..938455a7bde 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java @@ -27,6 +27,7 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; +import de.symeda.sormas.api.CoreBaseFacade; import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.common.Page; import de.symeda.sormas.api.externaldata.ExternalDataDto; @@ -37,34 +38,20 @@ import de.symeda.sormas.api.utils.ValidationRuntimeException; @Remote -public interface EventFacade { - - List getAllActiveEventsAfter(Date date); +public interface EventFacade extends CoreBaseFacade { Map getEventCountByDisease(EventCriteria eventCriteria); EventDto getEventByUuid(String uuid, boolean detailedReferences); - EventDto saveEvent(@Valid @NotNull EventDto dto); - - EventReferenceDto getReferenceByUuid(String uuid); - EventReferenceDto getReferenceByEventParticipant(String uuid); List getAllActiveUuids(); - List getAllActiveEventsAfter(Date date, Integer batchSize, String lastSynchronizedUuid); - - List getByUuids(List uuids); - void deleteEvent(String eventUuid) throws ExternalSurveillanceToolException; List deleteEvents(List eventUuids); - long count(EventCriteria eventCriteria); - - List getIndexList(EventCriteria eventCriteria, Integer first, Integer max, List sortProperties); - Page getIndexPage(@NotNull EventCriteria eventCriteria, Integer offset, Integer size, List sortProperties); List getExportList(EventCriteria eventCriteria, Collection selectedRows, Integer first, Integer max); @@ -83,8 +70,6 @@ public interface EventFacade { Boolean isEventEditAllowed(String eventUuid); - boolean exists(String uuid); - boolean doesExternalTokenExist(String externalToken, String eventUuid); String getUuidByCaseUuidOrPersonUuid(String value); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/classification/CaseClassificationFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/classification/CaseClassificationFacadeEjb.java index da6dd19fedc..32a1952f8a1 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/classification/CaseClassificationFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/classification/CaseClassificationFacadeEjb.java @@ -91,6 +91,8 @@ public class CaseClassificationFacadeEjb implements CaseClassificationFacade { @EJB private PersonFacadeEjbLocal personFacade; @EJB + private EventFacadeEjb.EventFacadeEjbLocal eventFacade; + @EJB private PathogenTestService pathogenTestService; @EJB private ConfigFacadeEjbLocal configFacade; @@ -114,7 +116,7 @@ public CaseClassification getClassification(CaseDataDto caze) { .stream() .map(PathogenTestFacadeEjb.PathogenTestFacadeEjbLocal::toDto) .collect(Collectors.toList()); - List caseEvents = eventService.getAllByCase(caze.getUuid()).stream().map(EventFacadeEjb::toDto).collect(Collectors.toList()); + List caseEvents = eventService.getAllByCase(caze.getUuid()).stream().map(eventFacade::toDto).collect(Collectors.toList()); Date lastVaccinationDate = null; if (caze.getDisease() == Disease.YELLOW_FEVER && caze.getVaccinationStatus() == VaccinationStatus.VACCINATED) { lastVaccinationDate = immunizationService.getLastVaccinationDateBefore(person.getUuid(), caze.getDisease(), CaseLogic.getStartDate(caze)); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java index a394e9c6625..51f509057ac 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java @@ -27,6 +27,9 @@ import de.symeda.sormas.backend.user.UserService; import de.symeda.sormas.backend.util.Pseudonymizer; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + public abstract class AbstractCoreEjb, CRITERIA extends BaseCriteria> extends AbstractBaseEjb { @@ -63,7 +66,7 @@ public List getAllAfter(Date date, Integer batchSize, String lastSynchroniz } @Override - public DTO save(DTO dto) { + public DTO save(@Valid @NotNull DTO dto) { ADO existingAdo = dto.getUuid() != null ? service.getByUuid(dto.getUuid()) : null; DTO existingDto = toDto(existingAdo); @@ -108,7 +111,7 @@ public DTO convertToDto(ADO source, Pseudonymizer pseudonymizer) { protected abstract void pseudonymizeDto(ADO source, DTO dto, Pseudonymizer pseudonymizer); - protected abstract void restorePseudonymizedDto(DTO dto, DTO existingDto, ADO immunization, Pseudonymizer pseudonymizer); + protected abstract void restorePseudonymizedDto(DTO dto, DTO existingDto, ADO entity, Pseudonymizer pseudonymizer); public abstract void validate(DTO dto) throws ValidationRuntimeException; } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java index ad39905cbc3..2b5ccd62c02 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java @@ -42,8 +42,7 @@ import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.enterprise.concurrent.ManagedScheduledExecutorService; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; +import javax.inject.Inject; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.CriteriaUpdate; @@ -92,6 +91,7 @@ import de.symeda.sormas.api.utils.SortProperty; import de.symeda.sormas.api.utils.ValidationRuntimeException; import de.symeda.sormas.backend.caze.Case; +import de.symeda.sormas.backend.common.AbstractCoreEjb; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.contact.Contact; @@ -125,17 +125,11 @@ import de.symeda.sormas.utils.EventJoins; @Stateless(name = "EventFacade") -public class EventFacadeEjb implements EventFacade { +public class EventFacadeEjb extends AbstractCoreEjb + implements EventFacade { private final Logger logger = LoggerFactory.getLogger(getClass()); - @PersistenceContext(unitName = ModelConstants.PERSISTENCE_UNIT_NAME) - private EntityManager em; - - @EJB - private UserService userService; - @EJB - private EventService eventService; @EJB private EventGroupService eventGroupService; @EJB @@ -161,41 +155,46 @@ public class EventFacadeEjb implements EventFacade { @Resource private ManagedScheduledExecutorService executorService; - @Override - public List getAllActiveUuids() { + public EventFacadeEjb() { + } - User user = userService.getCurrentUser(); - if (user == null) { - return Collections.emptyList(); + @Inject + public EventFacadeEjb(EventService service, UserService userService) { + super(Event.class, EventDto.class, service, userService); + } + + public static EventReferenceDto toReferenceDto(Event entity) { + + if (entity == null) { + return null; } - return eventService.getAllActiveUuids(); + return new EventReferenceDto(entity.getUuid(), entity.toString()); } - @Override - public List getAllActiveEventsAfter(Date date) { - return getAllActiveEventsAfter(date, null, null); + public static EventReferenceDto toDetailedReferenceDto(Event entity) { + + if (entity == null) { + return null; + } + + return new EventDetailedReferenceDto( + entity.getUuid(), + entity.toString(), + entity.getEventStatus(), + entity.getEventTitle(), + entity.getReportDateTime()); } @Override - public List getAllActiveEventsAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { + public List getAllActiveUuids() { User user = userService.getCurrentUser(); if (user == null) { return Collections.emptyList(); } - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); - return eventService.getAllActiveEventsAfter(date, batchSize, lastSynchronizedUuid) - .stream() - .map(e -> convertToDto(e, pseudonymizer)) - .collect(Collectors.toList()); - } - - @Override - public List getByUuids(List uuids) { - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); - return eventService.getByUuids(uuids).stream().map(e -> convertToDto(e, pseudonymizer)).collect(Collectors.toList()); + return service.getAllActiveUuids(); } @Override @@ -206,55 +205,65 @@ public List getDeletedUuidsSince(Date since) { return Collections.emptyList(); } - return eventService.getDeletedUuidsSince(since); + return service.getDeletedUuidsSince(since); } public Map getEventCountByDisease(EventCriteria eventCriteria) { - return eventService.getEventCountByDisease(eventCriteria); + return service.getEventCountByDisease(eventCriteria); } @Override public EventDto getEventByUuid(String uuid, boolean detailedReferences) { return (detailedReferences) - ? convertToDetailedReferenceDto(eventService.getByUuid(uuid), Pseudonymizer.getDefault(userService::hasRight)) - : convertToDto(eventService.getByUuid(uuid), Pseudonymizer.getDefault(userService::hasRight)); + ? convertToDetailedReferenceDto(service.getByUuid(uuid), Pseudonymizer.getDefault(userService::hasRight)) + : convertToDto(service.getByUuid(uuid), Pseudonymizer.getDefault(userService::hasRight)); } @Override public EventReferenceDto getReferenceByUuid(String uuid) { - return toReferenceDto(eventService.getByUuid(uuid)); + return toReferenceDto(service.getByUuid(uuid)); + } + + @Override + protected void selectDtoFields(CriteriaQuery cq, Root root) { + + } + + @Override + public EventReferenceDto toRefDto(Event event) { + return toReferenceDto(event); } @Override public EventReferenceDto getReferenceByEventParticipant(String uuid) { - return toReferenceDto(eventService.getEventReferenceByEventParticipant(uuid)); + return toReferenceDto(service.getEventReferenceByEventParticipant(uuid)); } @Override - public EventDto saveEvent(@Valid @NotNull EventDto dto) { - return saveEvent(dto, true, true); + public EventDto save(@Valid @NotNull EventDto dto) { + return save(dto, true, true); } - public EventDto saveEvent(@NotNull EventDto dto, boolean checkChangeDate, boolean internal) { + public EventDto save(@NotNull EventDto dto, boolean checkChangeDate, boolean internal) { Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); - Event existingEvent = dto.getUuid() != null ? eventService.getByUuid(dto.getUuid()) : null; + Event existingEvent = dto.getUuid() != null ? service.getByUuid(dto.getUuid()) : null; - if (internal && existingEvent != null && !eventService.isEventEditAllowed(existingEvent)) { + if (internal && existingEvent != null && !service.isEventEditAllowed(existingEvent)) { throw new AccessDeniedException(I18nProperties.getString(Strings.errorEventNotEditable)); } EventDto existingDto = toDto(existingEvent); - restorePseudonymizedDto(dto, existingEvent, existingDto, pseudonymizer); + restorePseudonymizedDto(dto, existingDto, existingEvent, pseudonymizer); if (dto.getReportDateTime() == null) { throw new ValidationRuntimeException(I18nProperties.getValidationError(Validations.validReportDateTime)); } - Event event = fromDto(dto, checkChangeDate); - eventService.ensurePersisted(event); + Event event = fillOrBuildEntity(dto, existingEvent, checkChangeDate); + service.ensurePersisted(event); onEventChange(toDto(event), internal); @@ -279,7 +288,7 @@ public void deleteEvent(String eventUuid) throws ExternalSurveillanceToolExcepti throw new UnsupportedOperationException("User " + userService.getCurrentUser().getUuid() + " is not allowed to delete events."); } - Event event = eventService.getByUuid(eventUuid); + Event event = service.getByUuid(eventUuid); deleteEvent(event); } @@ -290,7 +299,7 @@ private void deleteEvent(Event event) throws ExternalSurveillanceToolException { externalSurveillanceToolFacade.deleteEvents(Collections.singletonList(toDto(event))); } - eventService.delete(event); + service.delete(event); } public List deleteEvents(List eventUuids) { @@ -298,7 +307,7 @@ public List deleteEvents(List eventUuids) { throw new UnsupportedOperationException("User " + userService.getCurrentUser().getUuid() + " is not allowed to delete events."); } List deletedEventUuids = new ArrayList<>(); - List eventsToBeDeleted = eventService.getByUuids(eventUuids); + List eventsToBeDeleted = service.getByUuids(eventUuids); if (eventsToBeDeleted != null) { eventsToBeDeleted.forEach(eventToBeDeleted -> { if (!eventToBeDeleted.isDeleted()) { @@ -325,10 +334,10 @@ public long count(EventCriteria eventCriteria) { if (eventCriteria != null) { if (eventCriteria.getUserFilterIncluded()) { - filter = eventService.createUserFilter(cb, cq, event); + filter = service.createUserFilter(cb, cq, event); } - Predicate criteriaFilter = eventService.buildCriteriaFilter(eventCriteria, new EventQueryContext(cb, cq, event)); + Predicate criteriaFilter = service.buildCriteriaFilter(eventCriteria, new EventQueryContext(cb, cq, event)); filter = CriteriaBuilderHelper.and(cb, filter, criteriaFilter); } @@ -399,7 +408,7 @@ public List getIndexList(EventCriteria eventCriteria, Integer fir responsibleUser.get(User.UUID), responsibleUser.get(User.FIRST_NAME), responsibleUser.get(User.LAST_NAME), - JurisdictionHelper.booleanSelector(cb, eventService.inJurisdictionOrOwned(eventQueryContext)), + JurisdictionHelper.booleanSelector(cb, service.inJurisdictionOrOwned(eventQueryContext)), event.get(Event.CHANGE_DATE), event.get(Event.EVENT_IDENTIFICATION_SOURCE)); @@ -409,10 +418,10 @@ public List getIndexList(EventCriteria eventCriteria, Integer fir if (eventCriteria.getUserFilterIncluded()) { EventUserFilterCriteria eventUserFilterCriteria = new EventUserFilterCriteria(); eventUserFilterCriteria.includeUserCaseAndEventParticipantFilter(true); - filter = eventService.createUserFilter(cb, cq, event, eventUserFilterCriteria); + filter = service.createUserFilter(cb, cq, event, eventUserFilterCriteria); } - Predicate criteriaFilter = eventService.buildCriteriaFilter(eventCriteria, eventQueryContext); + Predicate criteriaFilter = service.buildCriteriaFilter(eventCriteria, eventQueryContext); filter = CriteriaBuilderHelper.and(cb, filter, criteriaFilter); } @@ -703,16 +712,16 @@ public List getExportList(EventCriteria eventCriteria, Collectio responsibleUser.get(User.UUID), responsibleUser.get(User.FIRST_NAME), responsibleUser.get(User.LAST_NAME), - JurisdictionHelper.booleanSelector(cb, eventService.inJurisdictionOrOwned(eventQueryContext)), + JurisdictionHelper.booleanSelector(cb, service.inJurisdictionOrOwned(eventQueryContext)), event.get(Event.EVENT_MANAGEMENT_STATUS), event.get(Event.EVENT_IDENTIFICATION_SOURCE)); cq.distinct(true); - Predicate filter = eventService.createUserFilter(cb, cq, event); + Predicate filter = service.createUserFilter(cb, cq, event); if (eventCriteria != null) { - Predicate criteriaFilter = eventService.buildCriteriaFilter(eventCriteria, eventQueryContext); + Predicate criteriaFilter = service.buildCriteriaFilter(eventCriteria, eventQueryContext); filter = CriteriaBuilderHelper.and(cb, filter, criteriaFilter); } @@ -872,9 +881,9 @@ public boolean isDeleted(String eventUuid) { @Override public void archiveOrDearchiveEvent(String eventUuid, boolean archive) { - Event event = eventService.getByUuid(eventUuid); + Event event = service.getByUuid(eventUuid); event.setArchived(archive); - eventService.ensurePersisted(event); + service.ensurePersisted(event); } @Override @@ -886,14 +895,14 @@ public List getArchivedUuidsSince(Date since) { return Collections.emptyList(); } - return eventService.getArchivedUuidsSince(since); + return service.getArchivedUuidsSince(since); } @Override public Set getAllSubordinateEventUuids(String eventUuid) { Set uuids = new HashSet<>(); - Event superordinateEvent = eventService.getByUuid(eventUuid); + Event superordinateEvent = service.getByUuid(eventUuid); addAllSubordinateEventsToSet(superordinateEvent, uuids); return uuids; @@ -909,7 +918,7 @@ private void addAllSubordinateEventsToSet(Event event, Set uuids) { public Set getAllSuperordinateEventUuids(String eventUuid) { Set uuids = new HashSet<>(); - Event event = eventService.getByUuid(eventUuid); + Event event = service.getByUuid(eventUuid); addSuperordinateEventToSet(event, uuids); return uuids; @@ -1001,7 +1010,7 @@ private void addSuperordinateEventToSet(Event event, Set uuids) { } } - public static EventDto toDto(Event source) { + public EventDto toDto(Event source) { if (source == null) { return null; @@ -1094,9 +1103,9 @@ public EventDto convertToDetailedReferenceDto(Event source, Pseudonymizer pseudo return eventDto; } - private void pseudonymizeDto(Event event, EventDto dto, Pseudonymizer pseudonymizer) { + protected void pseudonymizeDto(Event event, EventDto dto, Pseudonymizer pseudonymizer) { if (dto != null) { - boolean inJurisdiction = eventService.inJurisdictionOrOwned(event); + boolean inJurisdiction = service.inJurisdictionOrOwned(event); pseudonymizer.pseudonymizeDto(EventDto.class, dto, inJurisdiction, (e) -> { pseudonymizer.pseudonymizeUser(event.getReportingUser(), userService.getCurrentUser(), dto::setReportingUser); @@ -1104,39 +1113,17 @@ private void pseudonymizeDto(Event event, EventDto dto, Pseudonymizer pseudonymi } } - private void restorePseudonymizedDto(EventDto dto, Event existingEvent, EventDto existingDto, Pseudonymizer pseudonymizer) { + @Override + protected void restorePseudonymizedDto(EventDto dto, EventDto existingDto, Event event, Pseudonymizer pseudonymizer) { if (existingDto != null) { - boolean inJurisdiction = eventService.inJurisdictionOrOwned(existingEvent); + boolean inJurisdiction = service.inJurisdictionOrOwned(event); pseudonymizer.restorePseudonymizedValues(EventDto.class, dto, existingDto, inJurisdiction); - pseudonymizer.restoreUser(existingEvent.getReportingUser(), userService.getCurrentUser(), dto, dto::setReportingUser); - } - } - - public static EventReferenceDto toReferenceDto(Event entity) { - - if (entity == null) { - return null; - } - - return new EventReferenceDto(entity.getUuid(), entity.toString()); - } - - public static EventReferenceDto toDetailedReferenceDto(Event entity) { - - if (entity == null) { - return null; + pseudonymizer.restoreUser(event.getReportingUser(), userService.getCurrentUser(), dto, dto::setReportingUser); } - - return new EventDetailedReferenceDto( - entity.getUuid(), - entity.toString(), - entity.getEventStatus(), - entity.getEventTitle(), - entity.getReportDateTime()); } - public Event fromDto(@NotNull EventDto source, boolean checkChangeDate) { - Event target = DtoHelper.fillOrBuildEntity(source, eventService.getByUuid(source.getUuid()), Event::new, checkChangeDate); + public Event fillOrBuildEntity(@NotNull EventDto source, Event target, boolean checkChangeDate) { + target = DtoHelper.fillOrBuildEntity(source, target, Event::new, checkChangeDate); target.setEventStatus(source.getEventStatus()); target.setRiskLevel(source.getRiskLevel()); @@ -1180,7 +1167,7 @@ public Event fromDto(@NotNull EventDto source, boolean checkChangeDate) { target.setTypeOfPlaceText(source.getTypeOfPlaceText()); target.setTransregionalOutbreak(source.getTransregionalOutbreak()); target.setDiseaseTransmissionMode(source.getDiseaseTransmissionMode()); - target.setSuperordinateEvent(eventService.getByReferenceDto(source.getSuperordinateEvent())); + target.setSuperordinateEvent(service.getByReferenceDto(source.getSuperordinateEvent())); target.setEventManagementStatus(source.getEventManagementStatus()); target.setReportLat(source.getReportLat()); @@ -1230,7 +1217,7 @@ void archiveAllArchivableEvents(int daysAfterEventGetsArchived, @NotNull LocalDa Root from = cq.from(Event.class); Timestamp notChangedTimestamp = Timestamp.valueOf(notChangedSince.atStartOfDay()); - cq.where(cb.equal(from.get(Event.ARCHIVED), false), cb.not(eventService.createChangeDateFilter(cb, from, notChangedTimestamp))); + cq.where(cb.equal(from.get(Event.ARCHIVED), false), cb.not(service.createChangeDateFilter(cb, from, notChangedTimestamp))); cq.select(from.get(Event.UUID)); List uuids = em.createQuery(cq).getResultList(); @@ -1247,14 +1234,9 @@ void archiveAllArchivableEvents(int daysAfterEventGetsArchived, @NotNull LocalDa } } - @Override - public boolean exists(String uuid) { - return eventService.exists(uuid); - } - @Override public boolean doesExternalTokenExist(String externalToken, String eventUuid) { - return eventService.exists( + return service.exists( (cb, eventRoot, cq) -> CriteriaBuilderHelper.and( cb, cb.equal(eventRoot.get(Event.EXTERNAL_TOKEN), externalToken), @@ -1264,7 +1246,7 @@ public boolean doesExternalTokenExist(String externalToken, String eventUuid) { @Override public String getUuidByCaseUuidOrPersonUuid(String searchTerm) { - return eventService.getUuidByCaseUuidOrPersonUuid(searchTerm); + return service.getUuidByCaseUuidOrPersonUuid(searchTerm); } @Override @@ -1287,7 +1269,7 @@ public Set getAllRegionsRelatedToEventUuids(List uui @Override public void updateExternalData(@Valid List externalData) throws ExternalDataUpdateException { - eventService.updateExternalData(externalData); + service.updateExternalData(externalData); } @Override @@ -1306,8 +1288,8 @@ public List getSubordinateEventUuids(List uuids) { Predicate filters = CriteriaBuilderHelper.and( cb, - eventService.createUserFilter(cb, cq, from), - eventService.createActiveEventsFilter(cb, from), + service.createUserFilter(cb, cq, from), + service.createActiveEventsFilter(cb, from), eventJoins.getSuperordinateEvent().get(Event.UUID).in(batchedUuids)); cq.where(filters); @@ -1321,22 +1303,30 @@ public List getSubordinateEventUuids(List uuids) { @Override public boolean hasRegionAndDistrict(String eventUuid) { - return eventService.hasRegionAndDistrict(eventUuid); + return service.hasRegionAndDistrict(eventUuid); } @Override public boolean hasAnyEventParticipantWithoutJurisdiction(String eventUuid) { - return eventService.hasAnyEventParticipantWithoutJurisdiction(eventUuid); + return service.hasAnyEventParticipantWithoutJurisdiction(eventUuid); + } + + public Boolean isEventEditAllowed(String eventUuid) { + Event event = service.getByUuid(eventUuid); + return service.isEventEditAllowed(event); } @LocalBean @Stateless public static class EventFacadeEjbLocal extends EventFacadeEjb { - } + public EventFacadeEjbLocal() { + super(); + } - public Boolean isEventEditAllowed(String eventUuid) { - Event event = eventService.getByUuid(eventUuid); - return eventService.isEventEditAllowed(event); + @Inject + public EventFacadeEjbLocal(EventService service, UserService userService) { + super(service, userService); + } } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java index ef4bec6d1d7..ebe4e90f116 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java @@ -286,7 +286,7 @@ public EventParticipantDto saveEventParticipant(@Valid EventParticipantDto dto, notifyEventResponsibleUsersOfCommonEventParticipant(entity, event); } - onEventParticipantChanged(EventFacadeEjbLocal.toDto(entity.getEvent()), existingDto, entity, internal); + onEventParticipantChanged(eventFacade.toDto(entity.getEvent()), existingDto, entity, internal); return convertToDto(entity, pseudonymizer); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java index 7a21e1ebf68..05577c28260 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java @@ -61,11 +61,11 @@ import de.symeda.sormas.backend.action.ActionService; import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.caze.CaseService; -import de.symeda.sormas.backend.common.AbstractDeletableAdoService; +import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.ChangeDateFilterBuilder; -import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; +import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.infrastructure.community.Community; import de.symeda.sormas.backend.infrastructure.district.District; @@ -77,7 +77,6 @@ import de.symeda.sormas.backend.sample.Sample; import de.symeda.sormas.backend.sample.SampleJoins; import de.symeda.sormas.backend.sample.SampleJurisdictionPredicateValidator; -import de.symeda.sormas.backend.sample.SampleService; import de.symeda.sormas.backend.share.ExternalShareInfo; import de.symeda.sormas.backend.share.ExternalShareInfoService; import de.symeda.sormas.backend.sormastosormas.share.shareinfo.SormasToSormasShareInfoService; @@ -94,7 +93,7 @@ @Stateless @LocalBean -public class EventService extends AbstractDeletableAdoService { +public class EventService extends AbstractCoreAdoService { @EJB private EventParticipantService eventParticipantService; @@ -110,14 +109,13 @@ public class EventService extends AbstractDeletableAdoService { private SormasToSormasShareInfoService sormasToSormasShareInfoService; @EJB private ExternalShareInfoService externalShareInfoService; - @EJB - private SampleService sampleService; public EventService() { super(Event.class); } - public List getAllActiveEventsAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { + @Override + public List getAllActiveAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(getElementClass()); @@ -999,5 +997,4 @@ public boolean hasAnyEventParticipantWithoutJurisdiction(String eventUuid) { return em.createQuery(cq).getSingleResult() > 0; } - } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/eventimport/EventImportFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/eventimport/EventImportFacadeEjb.java index 99640cb5223..bdad64236df 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/eventimport/EventImportFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/eventimport/EventImportFacadeEjb.java @@ -141,7 +141,7 @@ public ImportLineResultDto saveImportedEntities(@Valid Even List eventGroupReferences = entities.getEventGroupReferences(); try { - event = eventFacade.saveEvent(event); + event = eventFacade.save(event); for (EventParticipantDto eventParticipant : eventParticipants) { PersonDto existingPerson = personFacade.getPersonByUuid(eventParticipant.getPerson().getUuid()); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java index cd4078d0daf..1d90123617e 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java @@ -114,8 +114,6 @@ public class ImmunizationFacadeEjb private final Logger logger = LoggerFactory.getLogger(ImmunizationFacadeEjb.class); - @EJB - private ImmunizationService immunizationService; @EJB private DirectoryImmunizationService directoryImmunizationService; @EJB @@ -237,7 +235,7 @@ public List getArchivedUuidsSince(Date since) { return Collections.emptyList(); } - return immunizationService.getArchivedUuidsSince(since); + return service.getArchivedUuidsSince(since); } @Override @@ -246,7 +244,7 @@ public List getDeletedUuidsSince(Date since) { if (userService.getCurrentUser() == null) { return Collections.emptyList(); } - return immunizationService.getDeletedUuidsSince(since); + return service.getDeletedUuidsSince(since); } @Override @@ -255,32 +253,32 @@ public void deleteImmunization(String uuid) { throw new UnsupportedOperationException("User " + userService.getCurrentUser().getUuid() + " is not allowed to delete immunizations"); } - Immunization immunization = immunizationService.getByUuid(uuid); - immunizationService.delete(immunization); + Immunization immunization = service.getByUuid(uuid); + service.delete(immunization); } @Override public boolean isArchived(String uuid) { - return immunizationService.isArchived(uuid); + return service.isArchived(uuid); } @Override public void archiveOrDearchiveImmunization(String uuid, boolean archive) { - Immunization immunization = immunizationService.getByUuid(uuid); + Immunization immunization = service.getByUuid(uuid); immunization.setArchived(archive); - immunizationService.ensurePersisted(immunization); + service.ensurePersisted(immunization); } @Override public boolean isImmunizationEditAllowed(String uuid) { - Immunization immunization = immunizationService.getByUuid(uuid); + Immunization immunization = service.getByUuid(uuid); - return immunizationService.isImmunizationEditAllowed(immunization); + return service.isImmunizationEditAllowed(immunization); } @Override public List getSimilarImmunizations(ImmunizationSimilarityCriteria criteria) { - return immunizationService.getSimilarImmunizations(criteria).stream().map(result -> { + return service.getSimilarImmunizations(criteria).stream().map(result -> { ImmunizationDto immunizationDto = new ImmunizationDto(); immunizationDto.setUuid((String) result[0]); immunizationDto.setMeansOfImmunization((MeansOfImmunization) result[1]); @@ -299,9 +297,9 @@ public ImmunizationDto save(ImmunizationDto dto) { } public ImmunizationDto save(@Valid ImmunizationDto dto, boolean checkChangeDate, boolean internal) { - Immunization existingImmunization = immunizationService.getByUuid(dto.getUuid()); + Immunization existingImmunization = service.getByUuid(dto.getUuid()); - if (internal && existingImmunization != null && !immunizationService.isImmunizationEditAllowed(existingImmunization)) { + if (internal && existingImmunization != null && !service.isImmunizationEditAllowed(existingImmunization)) { throw new AccessDeniedException(I18nProperties.getString(Strings.errorImmunizationNotEditable)); } @@ -314,7 +312,7 @@ public ImmunizationDto save(@Valid ImmunizationDto dto, boolean checkChangeDate, Immunization immunization = fillOrBuildEntity(dto, existingImmunization, checkChangeDate); - immunizationService.updateImmunizationStatusBasedOnVaccinations(immunization); + service.updateImmunizationStatusBasedOnVaccinations(immunization); immunization.getVaccinations().forEach(vaccination -> { VaccinationDto existingVaccination = null; @@ -333,7 +331,7 @@ public ImmunizationDto save(@Valid ImmunizationDto dto, boolean checkChangeDate, immunization.getDisease()); }); - immunizationService.ensurePersisted(immunization); + service.ensurePersisted(immunization); if (existingImmunization != null && internal && sormasToSormasFacade.isFeatureConfigured()) { syncSharesAsync(existingImmunization); @@ -344,7 +342,7 @@ public ImmunizationDto save(@Valid ImmunizationDto dto, boolean checkChangeDate, protected void pseudonymizeDto(Immunization source, ImmunizationDto dto, Pseudonymizer pseudonymizer) { if (dto != null) { - boolean inJurisdiction = immunizationService.inJurisdictionOrOwned(source); + boolean inJurisdiction = service.inJurisdictionOrOwned(source); pseudonymizer.pseudonymizeDto(ImmunizationDto.class, dto, inJurisdiction, c -> { User currentUser = userService.getCurrentUser(); pseudonymizer.pseudonymizeUser(source.getReportingUser(), currentUser, dto::setReportingUser); @@ -353,11 +351,11 @@ protected void pseudonymizeDto(Immunization source, ImmunizationDto dto, Pseudon } } - protected void restorePseudonymizedDto(ImmunizationDto dto, ImmunizationDto existingDto, Immunization immunization, Pseudonymizer pseudonymizer) { + protected void restorePseudonymizedDto(ImmunizationDto dto, ImmunizationDto existingDto, Immunization entity, Pseudonymizer pseudonymizer) { if (existingDto != null) { - final boolean inJurisdiction = immunizationService.inJurisdictionOrOwned(immunization); + final boolean inJurisdiction = service.inJurisdictionOrOwned(entity); final User currentUser = userService.getCurrentUser(); - pseudonymizer.restoreUser(immunization.getReportingUser(), currentUser, dto, dto::setReportingUser); + pseudonymizer.restoreUser(entity.getReportingUser(), currentUser, dto, dto::setReportingUser); pseudonymizer.restorePseudonymizedValues(ImmunizationDto.class, dto, existingDto, inJurisdiction); } } @@ -402,7 +400,7 @@ public List getIndexList(ImmunizationCriteria criteria, In @Override public List getEntriesList(ImmunizationListCriteria criteria, Integer first, Integer max) { Long personId = personService.getIdByUuid(criteria.getPerson().getUuid()); - return immunizationService.getEntriesList(personId, criteria.getDisease(), first, max); + return service.getEntriesList(personId, criteria.getDisease(), first, max); } @Override @@ -421,10 +419,10 @@ public List deleteImmunizations(List immunizationUuids) { throw new UnsupportedOperationException("User " + userService.getCurrentUser().getUuid() + " is not allowed to delete immunizations."); } List deletedImmunizationUuids = new ArrayList<>(); - List immunizationsToBeDeleted = immunizationService.getByUuids(immunizationUuids); + List immunizationsToBeDeleted = service.getByUuids(immunizationUuids); if (immunizationsToBeDeleted != null) { immunizationsToBeDeleted.forEach(immunizationToBeDeleted -> { - immunizationService.delete(immunizationToBeDeleted); + service.delete(immunizationToBeDeleted); deletedImmunizationUuids.add(immunizationToBeDeleted.getUuid()); }); } @@ -488,7 +486,7 @@ protected Immunization fillOrBuildEntity(@NotNull ImmunizationDto source, Immuni @Override public void updateImmunizationStatuses() { - immunizationService.updateImmunizationStatuses(); + service.updateImmunizationStatuses(); } @Override @@ -542,7 +540,7 @@ public boolean linkRecoveryImmunizationToSearchedCase(String specificCaseSearchV @Override public List getByPersonUuids(List uuids) { - return immunizationService.getByPersonUuids(uuids).stream().map(i -> toDto(i)).collect(Collectors.toList()); + return service.getByPersonUuids(uuids).stream().map(i -> toDto(i)).collect(Collectors.toList()); } public void syncSharesAsync(Immunization immunization) { @@ -601,7 +599,7 @@ public void copyImmunizationsToLeadPerson(ImmunizationDto immunizationDto, Perso newImmunization.setVaccinations(new ArrayList<>()); vaccinationFacade.copyExistingVaccinationsToNewImmunization(immunizationDto, newImmunization); - immunizationService.ensurePersisted(newImmunization); + service.ensurePersisted(newImmunization); } @LocalBean diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java index f26326e8210..daa81301fe7 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java @@ -51,7 +51,6 @@ import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.backend.caze.Case; -import de.symeda.sormas.backend.common.AbstractDeletableAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.ChangeDateFilterBuilder; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java index 2e9ff956320..523e49b0b89 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java @@ -207,6 +207,8 @@ public class PersonFacadeEjb implements PersonFacade { @EJB private EventParticipantFacadeEjbLocal eventParticipantFacade; @EJB + private EventFacadeEjbLocal eventFacade; + @EJB private DistrictFacadeEjbLocal districtFacade; @EJB private CommunityFacadeEjbLocal communityFacade; @@ -1093,7 +1095,7 @@ public void onPersonChanged(PersonDto existingPerson, Person newPerson, boolean for (EventParticipant personEventParticipant : personEventParticipants) { eventParticipantFacade.onEventParticipantChanged( - EventFacadeEjbLocal.toDto(personEventParticipant.getEvent()), + eventFacade.toDto(personEventParticipant.getEvent()), EventParticipantFacadeEjbLocal.toDto(personEventParticipant), personEventParticipant, syncShares); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java index cee10b9bf71..7f161dbe11f 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java @@ -95,6 +95,8 @@ public class PathogenTestFacadeEjb implements PathogenTestFacade { @EJB private EventParticipantFacadeEjbLocal eventParticipantFacade; @EJB + private EventFacadeEjbLocal eventFacade; + @EJB private PathogenTestService pathogenTestService; @EJB private SampleService sampleService; @@ -265,7 +267,7 @@ private void handleAssotiatedObjectChanges(PathogenTest pathogenTest, boolean sy EventParticipant associatedEventParticipant = pathogenTest.getSample().getAssociatedEventParticipant(); if (associatedEventParticipant != null) { eventParticipantFacade.onEventParticipantChanged( - EventFacadeEjbLocal.toDto(associatedEventParticipant.getEvent()), + eventFacade.toDto(associatedEventParticipant.getEvent()), EventParticipantFacadeEjbLocal.toDto(associatedEventParticipant), associatedEventParticipant, syncShares); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java index c94d3c3f31d..e3ffe5d2ca8 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java @@ -162,6 +162,8 @@ public class SampleFacadeEjb implements SampleFacade { @EJB private EventParticipantFacadeEjbLocal eventParticipantFacade; @EJB + private EventFacadeEjbLocal eventFacade; + @EJB private MessagingService messagingService; @EJB private UserRoleConfigFacadeEjbLocal userRoleConfigFacade; @@ -989,7 +991,7 @@ private void handleAssotiatedObjectChanges(Sample newSample, boolean syncShares) EventParticipant associatedEventParticipant = newSample.getAssociatedEventParticipant(); if (associatedEventParticipant != null) { eventParticipantFacade.onEventParticipantChanged( - EventFacadeEjbLocal.toDto(associatedEventParticipant.getEvent()), + eventFacade.toDto(associatedEventParticipant.getEvent()), EventParticipantFacadeEjbLocal.toDto(associatedEventParticipant), associatedEventParticipant, syncShares); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/event/ProcessedEventDataPersister.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/event/ProcessedEventDataPersister.java index 6d4876a3abd..92902019522 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/event/ProcessedEventDataPersister.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/event/ProcessedEventDataPersister.java @@ -51,7 +51,7 @@ protected SormasToSormasShareInfoService getShareInfoService() { public void persistSharedData(SormasToSormasEventDto processedData, Event existingEvent) throws SormasToSormasValidationException { EventDto event = processedData.getEntity(); - handleValidationError(() -> eventFacade.saveEvent(event, false, false), Captions.CaseData, buildCaseValidationGroupName(event)); + handleValidationError(() -> eventFacade.save(event, false, false), Captions.CaseData, buildCaseValidationGroupName(event)); } @Override diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/event/ReceivedEventProcessor.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/event/ReceivedEventProcessor.java index be0bcbf62d1..ecb9e9bcd8c 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/event/ReceivedEventProcessor.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/event/ReceivedEventProcessor.java @@ -15,6 +15,7 @@ package de.symeda.sormas.backend.sormastosormas.entities.event; +import javax.ejb.EJB; import javax.ejb.LocalBean; import javax.ejb.Stateless; import javax.inject.Inject; @@ -38,6 +39,9 @@ public class ReceivedEventProcessor extends ReceivedDataProcessor { + @EJB + private EventFacadeEjb.EventFacadeEjbLocal eventFacade; + public ReceivedEventProcessor() { } @@ -52,7 +56,7 @@ protected ReceivedEventProcessor( @Override public void handleReceivedData(SormasToSormasEventDto sharedData, Event existingData) { - handleIgnoredProperties(sharedData.getEntity(), EventFacadeEjb.toDto(existingData)); + handleIgnoredProperties(sharedData.getEntity(), eventFacade.toDto(existingData)); EventDto event = sharedData.getEntity(); updateReportingUser(event, existingData); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/share/shareinfo/SormasToSormasShareInfoService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/share/shareinfo/SormasToSormasShareInfoService.java index 3bb3c79595e..9792732e760 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/share/shareinfo/SormasToSormasShareInfoService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/share/shareinfo/SormasToSormasShareInfoService.java @@ -54,6 +54,8 @@ public class SormasToSormasShareInfoService extends AdoServiceWithUserFilter 0) { - externalSurveillanceToolGatewayFacade.deleteEvents(events.stream().map(EventFacadeEjb::toDto).collect(Collectors.toList())); + externalSurveillanceToolGatewayFacade.deleteEvents(events.stream().map(eventFacade::toDto).collect(Collectors.toList())); } } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java index 69d532cfa65..eed356e3f14 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java @@ -49,8 +49,6 @@ public class TravelEntryFacadeEjb extends AbstractCoreEjb implements TravelEntryFacade { - @EJB - TravelEntryService travelEntryService; @EJB TravelEntryListService travelEntryListService; @EJB @@ -90,25 +88,25 @@ public static TravelEntryReferenceDto toReferenceDto(TravelEntry entity) { @Override public boolean isDeleted(String travelEntryUuid) { - return travelEntryService.isDeleted(travelEntryUuid); + return service.isDeleted(travelEntryUuid); } @Override public boolean isArchived(String travelEntryUuid) { - return travelEntryService.isArchived(travelEntryUuid); + return service.isArchived(travelEntryUuid); } @Override public void archiveOrDearchiveTravelEntry(String travelEntryUuid, boolean archive) { - TravelEntry travelEntry = travelEntryService.getByUuid(travelEntryUuid); + TravelEntry travelEntry = service.getByUuid(travelEntryUuid); travelEntry.setArchived(archive); - travelEntryService.ensurePersisted(travelEntry); + service.ensurePersisted(travelEntry); } @Override public Boolean isTravelEntryEditAllowed(String travelEntryUuid) { - TravelEntry travelEntry = travelEntryService.getByUuid(travelEntryUuid); - return travelEntryService.isTravelEntryEditAllowed(travelEntry); + TravelEntry travelEntry = service.getByUuid(travelEntryUuid); + return service.isTravelEntryEditAllowed(travelEntry); } @Override @@ -117,8 +115,8 @@ public void deleteTravelEntry(String travelEntryUuid) { throw new UnsupportedOperationException("User " + userService.getCurrentUser().getUuid() + " is not allowed to delete travel entries"); } - TravelEntry travelEntry = travelEntryService.getByUuid(travelEntryUuid); - travelEntryService.delete(travelEntry); + TravelEntry travelEntry = service.getByUuid(travelEntryUuid); + service.delete(travelEntry); if (travelEntry.getResultingCase() != null) { caseFacade.onCaseChanged(CaseFacadeEjb.toDto(travelEntry.getResultingCase()), travelEntry.getResultingCase()); @@ -131,7 +129,7 @@ protected void selectDtoFields(CriteriaQuery cq, Root getDeaContentOfLastTravelEntry() { - final TravelEntry lastTravelEntry = travelEntryService.getLastTravelEntry(); + final TravelEntry lastTravelEntry = service.getLastTravelEntry(); if (lastTravelEntry != null) { Pseudonymizer aDefault = Pseudonymizer.getDefault(userService::hasRight); @@ -149,13 +147,13 @@ public long count(TravelEntryCriteria criteria) { @Override public long count(TravelEntryCriteria criteria, boolean ignoreUserFilter) { - return travelEntryService.count(criteria, ignoreUserFilter); + return service.count(criteria, ignoreUserFilter); } @Override protected void pseudonymizeDto(TravelEntry source, TravelEntryDto dto, Pseudonymizer pseudonymizer) { if (dto != null) { - boolean inJurisdiction = travelEntryService.inJurisdictionOrOwned(source); + boolean inJurisdiction = service.inJurisdictionOrOwned(source); pseudonymizer.pseudonymizeDto(TravelEntryDto.class, dto, inJurisdiction, c -> { User currentUser = userService.getCurrentUser(); pseudonymizer.pseudonymizeUser(source.getReportingUser(), currentUser, dto::setReportingUser); @@ -164,18 +162,18 @@ protected void pseudonymizeDto(TravelEntry source, TravelEntryDto dto, Pseudonym } @Override - protected void restorePseudonymizedDto(TravelEntryDto dto, TravelEntryDto existingDto, TravelEntry travelEntry, Pseudonymizer pseudonymizer) { + protected void restorePseudonymizedDto(TravelEntryDto dto, TravelEntryDto existingDto, TravelEntry entity, Pseudonymizer pseudonymizer) { if (existingDto != null) { - final boolean inJurisdiction = travelEntryService.inJurisdictionOrOwned(travelEntry); + final boolean inJurisdiction = service.inJurisdictionOrOwned(entity); final User currentUser = userService.getCurrentUser(); - pseudonymizer.restoreUser(travelEntry.getReportingUser(), currentUser, dto, dto::setReportingUser); + pseudonymizer.restoreUser(entity.getReportingUser(), currentUser, dto, dto::setReportingUser); pseudonymizer.restorePseudonymizedValues(TravelEntryDto.class, dto, existingDto, inJurisdiction); } } @Override public List getIndexList(TravelEntryCriteria criteria, Integer first, Integer max, List sortProperties) { - List resultList = travelEntryService.getIndexList(criteria, first, max, sortProperties); + List resultList = service.getIndexList(criteria, first, max, sortProperties); Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight, I18nProperties.getCaption(Captions.inaccessibleValue)); pseudonymizer.pseudonymizeDtoCollection(TravelEntryIndexDto.class, resultList, TravelEntryIndexDto::isInJurisdiction, null); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java index 1c7cf017360..3b43583a178 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java @@ -925,7 +925,7 @@ public EventDto createEvent( customSettings.accept(event); } - event = beanTest.getEventFacade().saveEvent(event); + event = beanTest.getEventFacade().save(event); return event; } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java index 0c3bc530b71..edfe7f80d16 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java @@ -1357,7 +1357,7 @@ public void testMergeCase() throws IOException { getVisitFacade().saveVisit(otherVisit); EventDto event = creator.createEvent(otherUserReference); event.setDisease(otherCase.getDisease()); - getEventFacade().saveEvent(event); + getEventFacade().save(event); EventParticipantDto otherCaseEventParticipant = creator.createEventParticipant(event.toReference(), otherPerson, otherUserReference); otherCaseEventParticipant.setResultingCase(otherCaseReference); getEventParticipantFacade().saveEventParticipant(otherCaseEventParticipant); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjbTest.java index f661d0cba5c..12e643f7989 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjbTest.java @@ -129,7 +129,7 @@ public void setup() throws URISyntaxException { EventDto eventDto = creator.createEvent(userDto.toReference()); eventDto.setEventTitle("An event"); - getEventFacade().saveEvent(eventDto); + getEventFacade().save(eventDto); eventParticipantDto = creator.createEventParticipant(eventDto.toReference(), personDto, "participated", userDto.toReference()); sampleDto = SampleDto.build(userDto.toReference(), caseDataDto.toReference()); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbPseudonymizationTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbPseudonymizationTest.java index 8d8fb8cc510..9b6b930d430 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbPseudonymizationTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbPseudonymizationTest.java @@ -85,7 +85,7 @@ public void testUpdatePseudonymizedEvent() { event.setConnectionNumber("updated"); event.setResponsibleUser(null); - getEventFacade().saveEvent(event); + getEventFacade().save(event); Event savedEvent = getEventService().getByUuid(event.getUuid()); @@ -99,7 +99,7 @@ public void testUpdateWithPseudonymizedDto() { event.setPseudonymized(true); event.setResponsibleUser(null); - getEventFacade().saveEvent(event); + getEventFacade().save(event); Event savedEvent = getEventService().getByUuid(event.getUuid()); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbTest.java index 528e34bd2f0..58fced979a3 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbTest.java @@ -138,7 +138,7 @@ public void testEventUpdate() { event.setEventDesc(testDescription); event.setStartDate(startDate); - final EventDto updatedEvent = getEventFacade().saveEvent(event); + final EventDto updatedEvent = getEventFacade().save(event); Assert.assertEquals(testDescription, updatedEvent.getEventDesc()); Assert.assertEquals(startDate, updatedEvent.getStartDate()); } @@ -252,7 +252,7 @@ public void testArchiveOrDearchiveEvent() { Date testStartDate = new Date(); // getAllActiveEvents/getAllActiveEventParticipants and getAllUuids should return length 1 - assertEquals(1, getEventFacade().getAllActiveEventsAfter(null).size()); + assertEquals(1, getEventFacade().getAllAfter(null).size()); assertEquals(1, getEventFacade().getAllActiveUuids().size()); assertEquals(1, getEventParticipantFacade().getAllActiveEventParticipantsAfter(null).size()); assertEquals(1, getEventParticipantFacade().getAllActiveUuids().size()); @@ -260,7 +260,7 @@ public void testArchiveOrDearchiveEvent() { getEventFacade().archiveOrDearchiveEvent(event.getUuid(), true); // getAllActiveEvents/getAllActiveEventParticipants and getAllUuids should return length 0 - assertEquals(0, getEventFacade().getAllActiveEventsAfter(null).size()); + assertEquals(0, getEventFacade().getAllAfter(null).size()); assertEquals(0, getEventFacade().getAllActiveUuids().size()); assertEquals(0, getEventParticipantFacade().getAllActiveEventParticipantsAfter(null).size()); assertEquals(0, getEventParticipantFacade().getAllActiveUuids().size()); @@ -271,7 +271,7 @@ public void testArchiveOrDearchiveEvent() { getEventFacade().archiveOrDearchiveEvent(event.getUuid(), false); // getAllActiveEvents/getAllActiveEventParticipants and getAllUuids should return length 1 - assertEquals(1, getEventFacade().getAllActiveEventsAfter(null).size()); + assertEquals(1, getEventFacade().getAllAfter(null).size()); assertEquals(1, getEventFacade().getAllActiveUuids().size()); assertEquals(1, getEventParticipantFacade().getAllActiveEventParticipantsAfter(null).size()); assertEquals(1, getEventParticipantFacade().getAllActiveUuids().size()); @@ -347,7 +347,7 @@ public void testCreateWithoutUuid() { event.setEventTitle("Test event"); event.setEventLocation(new LocationDto()); - EventDto savedEvent = getEventFacade().saveEvent(event); + EventDto savedEvent = getEventFacade().save(event); MatcherAssert.assertThat(savedEvent.getUuid(), not(isEmptyOrNullString())); MatcherAssert.assertThat(savedEvent.getEventLocation().getUuid(), not(isEmptyOrNullString())); @@ -396,7 +396,7 @@ public void testEventCriteriaChangedSinceLastShareWithReportingTool() { getExternalShareInfoService().ensurePersisted(shareInfo); sharedEvent.setEventDesc("Dummy description"); - getEventFacade().saveEvent(sharedEvent); + getEventFacade().save(sharedEvent); creator.createEvent(user.toReference()); creator.createEvent(user.toReference()); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjbTest.java index 1083c41b329..9a0bcbea04c 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjbTest.java @@ -538,14 +538,14 @@ public void testUpdateImmunizationStatusBasedOnVaccinationsCompleted() { final PersonDto person = creator.createPerson("John", "Doe"); - final ImmunizationDto immunization = creator.createImmunizationDto( - Disease.DENGUE, - person.toReference(), - nationalUser.toReference(), - ImmunizationStatus.PENDING, - MeansOfImmunization.VACCINATION, - ImmunizationManagementStatus.SCHEDULED, - rdcf1); + ImmunizationDto immunization = getImmunizationFacade().save(creator.createImmunizationDto( + Disease.DENGUE, + person.toReference(), + nationalUser.toReference(), + ImmunizationStatus.PENDING, + MeansOfImmunization.VACCINATION, + ImmunizationManagementStatus.SCHEDULED, + rdcf1)); immunization.setNumberOfDoses(2); immunization.setStartDate(DateHelper.subtractDays(new Date(), 1)); diff --git a/sormas-rest/src/main/java/de/symeda/sormas/rest/EventResource.java b/sormas-rest/src/main/java/de/symeda/sormas/rest/EventResource.java index 2a73e639353..22918939960 100644 --- a/sormas-rest/src/main/java/de/symeda/sormas/rest/EventResource.java +++ b/sormas-rest/src/main/java/de/symeda/sormas/rest/EventResource.java @@ -54,13 +54,13 @@ public class EventResource extends EntityDtoResource { @GET @Path("/all/{since}") public List getAllEvents(@PathParam("since") long since) { - return FacadeProvider.getEventFacade().getAllActiveEventsAfter(new Date(since)); + return FacadeProvider.getEventFacade().getAllAfter(new Date(since)); } @GET @Path("/all/{since}/{size}/{lastSynchronizedUuid}") public List getAllEvents(@PathParam("since") long since, @PathParam("size") int size, @PathParam("lastSynchronizedUuid") String lastSynchronizedUuid) { - return FacadeProvider.getEventFacade().getAllActiveEventsAfter(new Date(since), size, lastSynchronizedUuid); + return FacadeProvider.getEventFacade().getAllAfter(new Date(since), size, lastSynchronizedUuid); } /** @@ -87,7 +87,7 @@ public List getByUuids(List uuids) { @POST @Path("/push") public List postEvents(@Valid List dtos) { - return savePushedDto(dtos, FacadeProvider.getEventFacade()::saveEvent); + return savePushedDto(dtos, FacadeProvider.getEventFacade()::save); } @GET diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/DevModeView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/DevModeView.java index b29851c87ac..c3e9600b648 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/DevModeView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/DevModeView.java @@ -1320,7 +1320,7 @@ private void generateEvents() { // status event.setEventStatus(EventStatus.EVENT); - FacadeProvider.getEventFacade().saveEvent(event); + FacadeProvider.getEventFacade().save(event); // EventParticipants int numParticipants = randomInt(config.getMinParticipantsPerEvent(), config.getMaxParticipantsPerEvent()); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventController.java index b03852b957a..3be4ed642f0 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventController.java @@ -419,7 +419,7 @@ public void selectOrCreateSubordinateEvent(EventReferenceDto superordinateEventR if (selectedIndexEvent != null) { EventDto selectedEvent = FacadeProvider.getEventFacade().getEventByUuid(selectedIndexEvent.getUuid(), false); selectedEvent.setSuperordinateEvent(superordinateEventRef); - FacadeProvider.getEventFacade().saveEvent(selectedEvent); + FacadeProvider.getEventFacade().save(selectedEvent); navigateToData(superordinateEventRef.getUuid()); Notification.show(I18nProperties.getString(Strings.messageEventLinkedAsSubordinate), Type.TRAY_NOTIFICATION); @@ -447,7 +447,7 @@ public void selectOrCreateSuperordinateEvent(EventReferenceDto subordinateEventR EventIndexDto selectedEvent = selectionField.getValue(); if (selectedEvent != null) { subordinateEvent.setSuperordinateEvent(selectedEvent.toReference()); - FacadeProvider.getEventFacade().saveEvent(subordinateEvent); + FacadeProvider.getEventFacade().save(subordinateEvent); navigateToData(subordinateEventRef.getUuid()); Notification.show(I18nProperties.getString(Strings.messageEventLinkedAsSuperordinate), Type.TRAY_NOTIFICATION); @@ -473,7 +473,7 @@ public void removeLinkCaseEventParticipant(EventDto event, CaseDataDto caseDataD public void removeSuperordinateEvent(EventDto subordinateEvent, boolean reloadPage, String notificationMessage) { subordinateEvent.setSuperordinateEvent(null); - FacadeProvider.getEventFacade().saveEvent(subordinateEvent); + FacadeProvider.getEventFacade().save(subordinateEvent); if (reloadPage) { navigateToData(subordinateEvent.getUuid()); @@ -590,7 +590,7 @@ public CommitDiscardWrapperComponent getEventCreateComponent(Case editView.addCommitListener(() -> { if (!eventCreateForm.getFieldGroup().isModified()) { EventDto dto = eventCreateForm.getValue(); - FacadeProvider.getEventFacade().saveEvent(dto); + FacadeProvider.getEventFacade().save(dto); Notification.show(I18nProperties.getString(Strings.messageEventCreated), Type.WARNING_MESSAGE); if (caseRef != null) { @@ -624,7 +624,7 @@ public CommitDiscardWrapperComponent getEventCreateComponentForCa editView.addCommitListener(() -> { if (!eventCreateForm.getFieldGroup().isModified()) { EventDto dto = eventCreateForm.getValue(); - FacadeProvider.getEventFacade().saveEvent(dto); + FacadeProvider.getEventFacade().save(dto); Notification.show(I18nProperties.getString(Strings.messageEventCreated), Type.WARNING_MESSAGE); linkCasesToEvent(new EventReferenceDto(dto.getUuid()), finalCaseDataDtos); @@ -651,7 +651,7 @@ public CommitDiscardWrapperComponent getEventCreateComponentForCo editView.addCommitListener(() -> { if (!eventCreateForm.getFieldGroup().isModified()) { EventDto dto = eventCreateForm.getValue(); - FacadeProvider.getEventFacade().saveEvent(dto); + FacadeProvider.getEventFacade().save(dto); Notification.show(I18nProperties.getString(Strings.messageEventCreated), Type.WARNING_MESSAGE); linkContactsToEvent(new EventReferenceDto(dto.getUuid()), finalContactDtos); @@ -675,7 +675,7 @@ public CommitDiscardWrapperComponent getEventCreateComponent(Cont editView.addCommitListener(() -> { if (!eventCreateForm.getFieldGroup().isModified()) { EventDto dto = eventCreateForm.getValue(); - FacadeProvider.getEventFacade().saveEvent(dto); + FacadeProvider.getEventFacade().save(dto); Notification.show(I18nProperties.getString(Strings.messageEventCreated), Type.TRAY_NOTIFICATION); EventReferenceDto createdEvent = new EventReferenceDto(dto.getUuid()); @@ -708,13 +708,13 @@ public CommitDiscardWrapperComponent getEventCreateComponent( newEvent.setSuperordinateEvent(superOrSubordinateEvent.toReference()); } - FacadeProvider.getEventFacade().saveEvent(newEvent); + FacadeProvider.getEventFacade().save(newEvent); EventReferenceDto newEventRef = new EventReferenceDto(newEvent.getUuid()); if (createSuperordinateEvent) { superOrSubordinateEvent.setSuperordinateEvent(newEventRef); - FacadeProvider.getEventFacade().saveEvent(superOrSubordinateEvent); + FacadeProvider.getEventFacade().save(superOrSubordinateEvent); } navigateToData(superOrSubordinateEvent.getUuid()); @@ -803,7 +803,7 @@ public CommitDiscardWrapperComponent getEventDataEditComponent(fi } private void saveEvent(Consumer saveCallback, EventDto eventDto) { - eventDto = FacadeProvider.getEventFacade().saveEvent(eventDto); + eventDto = FacadeProvider.getEventFacade().save(eventDto); Notification.show(I18nProperties.getString(Strings.messageEventSaved), Type.WARNING_MESSAGE); SormasUI.refreshView(); @@ -852,7 +852,7 @@ public void onCommit() { eventDto.setEventManagementStatus(updatedTempEvent.getEventManagementStatus()); } - FacadeProvider.getEventFacade().saveEvent(eventDto); + FacadeProvider.getEventFacade().save(eventDto); } popupWindow.close(); navigateToIndex(); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/labmessage/LabMessageController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/labmessage/LabMessageController.java index 8660520e8c3..bcfe5d1bace 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/labmessage/LabMessageController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/labmessage/LabMessageController.java @@ -466,7 +466,7 @@ private void createEvent(LabMessageDto labMessageDto, PersonDto person) { editView.addCommitListener(() -> { if (!eventCreateForm.getFieldGroup().isModified()) { EventDto dto = eventCreateForm.getValue(); - FacadeProvider.getEventFacade().saveEvent(dto); + FacadeProvider.getEventFacade().save(dto); Notification.show(I18nProperties.getString(Strings.messageEventCreated), Notification.Type.WARNING_MESSAGE); createEventParticipant(dto, labMessageDto, person); diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/TestDataCreator.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/TestDataCreator.java index a45a57086d9..eee80d3a038 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/TestDataCreator.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/TestDataCreator.java @@ -454,7 +454,7 @@ public EventDto createEvent( customSettings.accept(event); } - event = FacadeProvider.getEventFacade().saveEvent(event); + event = FacadeProvider.getEventFacade().save(event); return event; } @@ -487,7 +487,7 @@ public EventDto createEvent( event.setResponsibleUser(responsibleUser); event.setDisease(disease); - event = FacadeProvider.getEventFacade().saveEvent(event); + event = FacadeProvider.getEventFacade().save(event); return event; } diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/event/importer/EventImporterTest.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/event/importer/EventImporterTest.java index 3262b12f6d4..2f79db3fd5c 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/event/importer/EventImporterTest.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/event/importer/EventImporterTest.java @@ -60,7 +60,7 @@ public void testImportAllEvents() throws IOException, InvalidColumnException, In assertEquals(4, getEventFacade().count(null)); assertEquals(3, getPersonFacade().count(null)); - List events = getEventFacade().getAllActiveEventsAfter(null); + List events = getEventFacade().getAllAfter(null); Optional optionalEventWith2Participants = events.stream().filter(event -> "Event title with 2 participants".equals(event.getEventTitle())).findFirst(); assertTrue(optionalEventWith2Participants.isPresent()); From b0b47167d387a089285b190e0667bbf27c172225 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Tue, 1 Feb 2022 15:02:49 +0200 Subject: [PATCH 006/253] #7246 - fix event tests --- .../symeda/sormas/api/event/EventFacade.java | 2 -- .../sormas/backend/event/EventFacadeEjb.java | 33 ++++++++----------- .../immunization/ImmunizationService.java | 1 - .../sormas/backend/AbstractBeanTest.java | 3 +- .../backend/event/EventFacadeEjbTest.java | 6 ++-- .../backend/person/PersonFacadeEjbTest.java | 4 +-- .../backend/task/TaskFacadeEjbTest.java | 4 +-- 7 files changed, 21 insertions(+), 32 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java index 938455a7bde..85768a22f19 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java @@ -60,8 +60,6 @@ public interface EventFacade extends CoreBaseFacade getArchivedUuidsSince(Date since); List getDeletedUuidsSince(Date since); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java index 2b5ccd62c02..33ef85fc023 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java @@ -43,6 +43,8 @@ import javax.ejb.TransactionAttributeType; import javax.enterprise.concurrent.ManagedScheduledExecutorService; import javax.inject.Inject; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.CriteriaUpdate; @@ -225,16 +227,6 @@ public EventReferenceDto getReferenceByUuid(String uuid) { return toReferenceDto(service.getByUuid(uuid)); } - @Override - protected void selectDtoFields(CriteriaQuery cq, Root root) { - - } - - @Override - public EventReferenceDto toRefDto(Event event) { - return toReferenceDto(event); - } - @Override public EventReferenceDto getReferenceByEventParticipant(String uuid) { return toReferenceDto(service.getEventReferenceByEventParticipant(uuid)); @@ -247,7 +239,6 @@ public EventDto save(@Valid @NotNull EventDto dto) { public EventDto save(@NotNull EventDto dto, boolean checkChangeDate, boolean internal) { - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); Event existingEvent = dto.getUuid() != null ? service.getByUuid(dto.getUuid()) : null; if (internal && existingEvent != null && !service.isEventEditAllowed(existingEvent)) { @@ -256,6 +247,7 @@ public EventDto save(@NotNull EventDto dto, boolean checkChangeDate, boolean int EventDto existingDto = toDto(existingEvent); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); restorePseudonymizedDto(dto, existingDto, existingEvent, pseudonymizer); if (dto.getReportDateTime() == null) { @@ -638,6 +630,11 @@ public List getIndexList(EventCriteria eventCriteria, Integer fir return indexList; } + @Override + protected void selectDtoFields(CriteriaQuery cq, Root root) { + + } + @Override public Page getIndexPage(EventCriteria eventCriteria, Integer offset, Integer size, List sortProperties) { List eventIndexList = getIndexList(eventCriteria, offset, size, sortProperties); @@ -878,14 +875,6 @@ public boolean isDeleted(String eventUuid) { return count > 0; } - @Override - public void archiveOrDearchiveEvent(String eventUuid, boolean archive) { - - Event event = service.getByUuid(eventUuid); - event.setArchived(archive); - service.ensurePersisted(event); - } - @Override public List getArchivedUuidsSince(Date since) { @@ -1087,6 +1076,11 @@ public EventDto toDto(Event source) { return target; } + @Override + public EventReferenceDto toRefDto(Event event) { + return null; + } + public EventDto convertToDto(Event source, Pseudonymizer pseudonymizer) { EventDto eventDto = toDto(source); @@ -1113,7 +1107,6 @@ protected void pseudonymizeDto(Event event, EventDto dto, Pseudonymizer pseudony } } - @Override protected void restorePseudonymizedDto(EventDto dto, EventDto existingDto, Event event, Pseudonymizer pseudonymizer) { if (existingDto != null) { boolean inJurisdiction = service.inJurisdictionOrOwned(event); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java index daa81301fe7..3e7f2d3d197 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java @@ -62,7 +62,6 @@ import de.symeda.sormas.backend.person.Person; import de.symeda.sormas.backend.person.PersonJoins; import de.symeda.sormas.backend.person.PersonJurisdictionPredicateValidator; -import de.symeda.sormas.backend.person.PersonService; import de.symeda.sormas.backend.sormastosormas.share.shareinfo.SormasToSormasShareInfoService; import de.symeda.sormas.backend.user.User; import de.symeda.sormas.backend.user.UserService; diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java index 2bf89821404..714650cf0a1 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java @@ -48,7 +48,6 @@ import de.symeda.sormas.api.docgeneneration.QuarantineOrderFacade; import de.symeda.sormas.api.document.DocumentFacade; import de.symeda.sormas.api.epidata.EpiDataFacade; -import de.symeda.sormas.api.event.EventFacade; import de.symeda.sormas.api.event.EventParticipantFacade; import de.symeda.sormas.api.externalsurveillancetool.ExternalSurveillanceToolFacade; import de.symeda.sormas.api.feature.FeatureConfigurationFacade; @@ -326,7 +325,7 @@ public DashboardFacade getDashboardFacade() { return getBean(DashboardFacadeEjb.DashboardFacadeEjbLocal.class); } - public EventFacade getEventFacade() { + public EventFacadeEjbLocal getEventFacade() { return getBean(EventFacadeEjbLocal.class); } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbTest.java index 58fced979a3..83f3b259ee8 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbTest.java @@ -257,7 +257,7 @@ public void testArchiveOrDearchiveEvent() { assertEquals(1, getEventParticipantFacade().getAllActiveEventParticipantsAfter(null).size()); assertEquals(1, getEventParticipantFacade().getAllActiveUuids().size()); - getEventFacade().archiveOrDearchiveEvent(event.getUuid(), true); + getEventFacade().archive(event.getUuid()); // getAllActiveEvents/getAllActiveEventParticipants and getAllUuids should return length 0 assertEquals(0, getEventFacade().getAllAfter(null).size()); @@ -268,7 +268,7 @@ public void testArchiveOrDearchiveEvent() { // getArchivedUuidsSince should return length 1 assertEquals(1, getEventFacade().getArchivedUuidsSince(testStartDate).size()); - getEventFacade().archiveOrDearchiveEvent(event.getUuid(), false); + getEventFacade().dearchive(event.getUuid()); // getAllActiveEvents/getAllActiveEventParticipants and getAllUuids should return length 1 assertEquals(1, getEventFacade().getAllAfter(null).size()); @@ -304,7 +304,7 @@ public void testArchiveAllArchivableEvents() { Disease.ANTHRAX, rdcf.district); EventFacadeEjbLocal cut = getBean(EventFacadeEjbLocal.class); - cut.archiveOrDearchiveEvent(event1.getUuid(), true); + cut.archive(event1.getUuid()); // One other event EventDto event2 = creator.createEvent( diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java index 379e8fd3fb7..32fe8460cb4 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java @@ -314,7 +314,7 @@ public void testGetMatchingNameDtos() { creator.createEventParticipant(inactiveEvent.toReference(), person7, user.toReference()); getCaseFacade().archiveOrDearchiveCase(inactiveCase.getUuid(), true); - getEventFacade().archiveOrDearchiveEvent(inactiveEvent.getUuid(), true); + getEventFacade().archive(inactiveEvent.getUuid()); // Only persons that have active case, contact or event participant associations should be retrieved List relevantNameUuids = getPersonFacade().getSimilarPersonDtos(user.toReference(), new PersonSimilarityCriteria()) @@ -328,7 +328,7 @@ public void testGetMatchingNameDtos() { creator.createCase(user.toReference(), person4.toReference(), rdcf); getCaseFacade().archiveOrDearchiveCase(inactiveCase.getUuid(), false); - getEventFacade().archiveOrDearchiveEvent(inactiveEvent.getUuid(), false); + getEventFacade().archive(inactiveEvent.getUuid()); PersonSimilarityCriteria criteria = new PersonSimilarityCriteria().sex(Sex.MALE).birthdateYYYY(1980).birthdateMM(1).birthdateDD(1); List matchingUuids = getPersonFacade().getSimilarPersonDtos(user.toReference(), criteria) diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/task/TaskFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/task/TaskFacadeEjbTest.java index 34853bcdf6f..401a0aedfdf 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/task/TaskFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/task/TaskFacadeEjbTest.java @@ -174,14 +174,14 @@ public void testArchivedTaskNotGettingTransfered() { assertEquals(6, getTaskFacade().getAllActiveUuids().size()); getCaseFacade().archiveOrDearchiveCase(caze.getUuid(), true); - getEventFacade().archiveOrDearchiveEvent(event.getUuid(), true); + getEventFacade().archive(event.getUuid()); // getAllActiveTasks and getAllUuids should return length 1 assertEquals(1, getTaskFacade().getAllActiveTasksAfter(null).size()); assertEquals(1, getTaskFacade().getAllActiveUuids().size()); getCaseFacade().archiveOrDearchiveCase(caze.getUuid(), false); - getEventFacade().archiveOrDearchiveEvent(event.getUuid(), false); + getEventFacade().dearchive(event.getUuid()); // getAllActiveTasks and getAllUuids should return length 5 + 1 (contact investigation) assertEquals(6, getTaskFacade().getAllActiveTasksAfter(null).size()); From 1017797b2b848b4de4e21eeb81f9d79b088b5098 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Tue, 1 Feb 2022 15:49:29 +0200 Subject: [PATCH 007/253] #7246 - move event participant facade methods to new core entities abstraction facade --- .../api/event/EventParticipantFacade.java | 19 +- .../event/EventParticipantFacadeEjb.java | 180 +++++++++--------- .../event/EventParticipantService.java | 11 +- .../backend/person/PersonFacadeEjb.java | 3 +- .../backend/sample/PathogenTestFacadeEjb.java | 2 +- .../backend/sample/SampleFacadeEjb.java | 2 +- .../sormas/backend/AbstractBeanTest.java | 2 +- 7 files changed, 105 insertions(+), 114 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventParticipantFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventParticipantFacade.java index c738d3ad06e..a907858f9a2 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventParticipantFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventParticipantFacade.java @@ -25,13 +25,14 @@ import javax.ejb.Remote; import javax.validation.Valid; +import de.symeda.sormas.api.CoreBaseFacade; import de.symeda.sormas.api.Language; import de.symeda.sormas.api.common.Page; import de.symeda.sormas.api.importexport.ExportConfigurationDto; import de.symeda.sormas.api.utils.SortProperty; @Remote -public interface EventParticipantFacade { +public interface EventParticipantFacade extends CoreBaseFacade { List getAllEventParticipantsByEventAfter(Date date, String eventUuid); @@ -45,16 +46,8 @@ public interface EventParticipantFacade { List getAllActiveUuids(); - List getByUuids(List uuids); - void deleteEventParticipant(EventParticipantReferenceDto eventParticipantRef); - List getIndexList( - EventParticipantCriteria eventParticipantCriteria, - Integer first, - Integer max, - List sortProperties); - Page getIndexPage( EventParticipantCriteria eventParticipantCriteria, Integer offset, @@ -63,18 +56,10 @@ Page getIndexPage( List getListEntries(EventParticipantCriteria eventParticipantCriteria, Integer first, Integer max); - EventParticipantDto getByUuid(String uuid); - void validate(EventParticipantDto eventParticipant); - long count(EventParticipantCriteria eventParticipantCriteria); - Map getContactCountPerEventParticipant(List eventParticipantUuids, EventParticipantCriteria eventParticipantCriteria); - boolean exists(String uuid); - - EventParticipantReferenceDto getReferenceByUuid(String uuid); - EventParticipantReferenceDto getReferenceByEventAndPerson(String eventUuid, String personUuid); List getAllActiveEventParticipantsAfter(Date date, Integer batchSize, String lastSynchronizedUuid); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java index ebe4e90f116..889d8682031 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java @@ -32,8 +32,7 @@ import javax.ejb.EJB; import javax.ejb.LocalBean; import javax.ejb.Stateless; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; +import javax.inject.Inject; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Expression; @@ -89,9 +88,10 @@ import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.caze.CaseFacadeEjb; import de.symeda.sormas.backend.caze.CaseService; +import de.symeda.sormas.backend.common.AbstractCoreEjb; import de.symeda.sormas.backend.common.AbstractDomainObject; -import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; +import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.common.messaging.MessageContents; import de.symeda.sormas.backend.common.messaging.MessageSubject; import de.symeda.sormas.backend.common.messaging.MessagingService; @@ -131,26 +131,24 @@ import de.symeda.sormas.utils.EventParticipantJoins; @Stateless(name = "EventParticipantFacade") -public class EventParticipantFacadeEjb implements EventParticipantFacade { +public class EventParticipantFacadeEjb + extends + AbstractCoreEjb + implements EventParticipantFacade { private final Logger logger = LoggerFactory.getLogger(getClass()); - @PersistenceContext(unitName = ModelConstants.PERSISTENCE_UNIT_NAME) - private EntityManager em; - @EJB private EventService eventService; @EJB private EventFacadeEjbLocal eventFacade; @EJB - private EventParticipantService eventParticipantService; + private EventParticipantService service; @EJB private PersonService personService; @EJB private CaseService caseService; @EJB - private UserService userService; - @EJB private ContactService contactService; @EJB private RegionService regionService; @@ -163,6 +161,25 @@ public class EventParticipantFacadeEjb implements EventParticipantFacade { @EJB private VaccinationFacadeEjb.VaccinationFacadeEjbLocal vaccinationFacade; + public EventParticipantFacadeEjb() { + } + + @Inject + public EventParticipantFacadeEjb(EventParticipantService service, UserService userService) { + super(EventParticipant.class, EventParticipantDto.class, service, userService); + } + + public static EventParticipantReferenceDto toReferenceDto(EventParticipant entity) { + + if (entity == null) { + return null; + } + + Person person = entity.getPerson(); + + return new EventParticipantReferenceDto(entity.getUuid(), person.getFirstName(), person.getFirstName()); + } + @Override public List getAllEventParticipantsByEventAfter(Date date, String eventUuid) { @@ -178,7 +195,7 @@ public List getAllEventParticipantsByEventAfter(Date date, } Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); - return eventParticipantService.getAllByEventAfter(date, event).stream().map(e -> convertToDto(e, pseudonymizer)).collect(Collectors.toList()); + return service.getAllByEventAfter(date, event).stream().map(e -> convertToDto(e, pseudonymizer)).collect(Collectors.toList()); } @Override @@ -189,7 +206,7 @@ public List getAllActiveUuids() { return Collections.emptyList(); } - return eventParticipantService.getAllActiveUuids(user); + return service.getAllActiveUuids(user); } @Override @@ -206,7 +223,7 @@ public List getAllActiveEventParticipantsAfter(Date date, I } Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); - return eventParticipantService.getAllActiveEventParticipantsAfter(date, user, batchSize, lastSynchronizedUuid) + return service.getAllActiveAfter(date, user, batchSize, lastSynchronizedUuid) .stream() .map(c -> convertToDto(c, pseudonymizer)) .collect(Collectors.toList()); @@ -220,19 +237,24 @@ public List getDeletedUuidsSince(Date since) { return Collections.emptyList(); } - List deletedEventParticipants = eventParticipantService.getDeletedUuidsSince(since, user); + List deletedEventParticipants = service.getDeletedUuidsSince(since, user); return deletedEventParticipants; } @Override public List getByUuids(List uuids) { Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); - return eventParticipantService.getByUuids(uuids).stream().map(c -> convertToDto(c, pseudonymizer)).collect(Collectors.toList()); + return service.getByUuids(uuids).stream().map(c -> convertToDto(c, pseudonymizer)).collect(Collectors.toList()); + } + + @Override + protected void selectDtoFields(CriteriaQuery cq, Root root) { + } @Override public EventParticipantDto getEventParticipantByUuid(String uuid) { - return convertToDto(eventParticipantService.getByUuid(uuid), Pseudonymizer.getDefault(userService::hasRight)); + return convertToDto(service.getByUuid(uuid), Pseudonymizer.getDefault(userService::hasRight)); } @Override @@ -252,9 +274,9 @@ public EventParticipantDto saveEventParticipant(@Valid EventParticipantDto dto) } public EventParticipantDto saveEventParticipant(@Valid EventParticipantDto dto, boolean checkChangeDate, boolean internal) { - EventParticipant existingParticipant = dto.getUuid() != null ? eventParticipantService.getByUuid(dto.getUuid()) : null; + EventParticipant existingParticipant = dto.getUuid() != null ? service.getByUuid(dto.getUuid()) : null; - if (internal && existingParticipant != null && !eventParticipantService.isEventParticipantEditAllowed(existingParticipant)) { + if (internal && existingParticipant != null && !service.isEventParticipantEditAllowed(existingParticipant)) { throw new AccessDeniedException(I18nProperties.getString(Strings.errorEventParticipantNotEditable)); } @@ -277,8 +299,8 @@ public EventParticipantDto saveEventParticipant(@Valid EventParticipantDto dto, validate(dto); - EventParticipant entity = fromDto(dto, checkChangeDate); - eventParticipantService.ensurePersisted(entity); + EventParticipant entity = fillOrBuildEntity(dto, existingParticipant, checkChangeDate); + service.ensurePersisted(entity); if (existingParticipant == null) { // The Event Participant is newly created, let's check if the related person is related to other events @@ -373,14 +395,14 @@ public void deleteEventParticipant(EventParticipantReferenceDto eventParticipant throw new UnsupportedOperationException("Your user is not allowed to delete event participants"); } - EventParticipant eventParticipant = eventParticipantService.getByReferenceDto(eventParticipantRef); - eventParticipantService.delete(eventParticipant); + EventParticipant eventParticipant = service.getByReferenceDto(eventParticipantRef); + service.delete(eventParticipant); } @Override public EventParticipantDto getByUuid(String uuid) { return convertToDto( - eventParticipantService.getByUuid(uuid), + service.getByUuid(uuid), Pseudonymizer.getDefault(userService::hasRight, I18nProperties.getCaption(Captions.inaccessibleValue))); } @@ -410,9 +432,8 @@ public List getIndexList( cb.isFalse(samples.get(DeletableAdo.DELETED)), cb.equal(samples.get(Sample.ASSOCIATED_EVENT_PARTICIPANT), eventParticipant.get(AbstractDomainObject.ID)))); - Expression inJurisdictionSelector = JurisdictionHelper.booleanSelector(cb, eventParticipantService.inJurisdiction(queryContext)); - Expression inJurisdictionOrOwnedSelector = - JurisdictionHelper.booleanSelector(cb, eventParticipantService.inJurisdictionOrOwned(queryContext)); + Expression inJurisdictionSelector = JurisdictionHelper.booleanSelector(cb, service.inJurisdiction(queryContext)); + Expression inJurisdictionOrOwnedSelector = JurisdictionHelper.booleanSelector(cb, service.inJurisdictionOrOwned(queryContext)); cq.multiselect( eventParticipant.get(EventParticipant.UUID), person.get(Person.UUID), @@ -450,7 +471,7 @@ public List getIndexList( inJurisdictionSelector, inJurisdictionOrOwnedSelector); - Predicate filter = eventParticipantService.buildCriteriaFilter(eventParticipantCriteria, queryContext); + Predicate filter = service.buildCriteriaFilter(eventParticipantCriteria, queryContext); if (eventParticipantCriteria.getPathogenTestResult() != null) { filter = CriteriaBuilderHelper @@ -528,10 +549,10 @@ public List getListEntries(EventParticipantCriteri event.get(Event.EVENT_STATUS), event.get(Event.DISEASE), event.get(Event.EVENT_TITLE), - JurisdictionHelper.booleanSelector(cb, eventParticipantService.inJurisdictionOrOwned(queryContext))); + JurisdictionHelper.booleanSelector(cb, service.inJurisdictionOrOwned(queryContext))); - Predicate filter = CriteriaBuilderHelper - .and(cb, eventParticipantService.buildCriteriaFilter(eventParticipantCriteria, queryContext), cb.isFalse(event.get(Event.DELETED))); + Predicate filter = + CriteriaBuilderHelper.and(cb, service.buildCriteriaFilter(eventParticipantCriteria, queryContext), cb.isFalse(event.get(Event.DELETED))); cq.where(filter); cq.orderBy(cb.desc(eventParticipant.get(EventParticipant.CREATION_DATE))); @@ -579,7 +600,7 @@ public List getExportList( eventParticipant.get(EventParticipant.UUID), person.get(Person.NATIONAL_HEALTH_ID), person.get(Location.ID), - JurisdictionHelper.booleanSelector(cb, eventParticipantService.inJurisdictionOrOwned(eventParticipantQueryContext)), + JurisdictionHelper.booleanSelector(cb, service.inJurisdictionOrOwned(eventParticipantQueryContext)), event.get(Event.UUID), @@ -635,7 +656,7 @@ public List getExportList( citizenship.get(Country.DEFAULT_NAME), eventParticipant.get(EventParticipant.VACCINATION_STATUS)); - Predicate filter = eventParticipantService.buildCriteriaFilter(eventParticipantCriteria, eventParticipantQueryContext); + Predicate filter = service.buildCriteriaFilter(eventParticipantCriteria, eventParticipantQueryContext); filter = CriteriaBuilderHelper.andInValues(selectedRows, filter, cb, eventParticipant.get(EventParticipant.UUID)); cq.where(filter); @@ -774,7 +795,7 @@ public long count(EventParticipantCriteria eventParticipantCriteria) { CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(Long.class); Root root = cq.from(EventParticipant.class); - Predicate filter = eventParticipantService.buildCriteriaFilter(eventParticipantCriteria, new EventParticipantQueryContext(cb, cq, root)); + Predicate filter = service.buildCriteriaFilter(eventParticipantCriteria, new EventParticipantQueryContext(cb, cq, root)); cq.where(filter); cq.select(cb.count(root)); return em.createQuery(cq).getSingleResult(); @@ -823,29 +844,18 @@ public Map getContactCountPerEventParticipant( return contactCountMap; } - @Override - public boolean exists(String uuid) { - return eventParticipantService.exists(uuid); - } - - @Override - public EventParticipantReferenceDto getReferenceByUuid(String uuid) { - EventParticipant eventParticipant = eventParticipantService.getByUuid(uuid); - return new EventParticipantReferenceDto(eventParticipant.getUuid()); - } - @Override public EventParticipantReferenceDto getReferenceByEventAndPerson(String eventUuid, String personUuid) { - return Optional.ofNullable(eventParticipantService.getByEventAndPerson(eventUuid, personUuid)) + return Optional.ofNullable(service.getByEventAndPerson(eventUuid, personUuid)) .map(eventParticipant -> new EventParticipantReferenceDto(eventParticipant.getUuid())) .orElse(null); } @Override public boolean isEventParticipantEditAllowed(String uuid) { - EventParticipant eventParticipant = eventParticipantService.getByUuid(uuid); + EventParticipant eventParticipant = service.getByUuid(uuid); - return eventParticipantService.isEventParticipantEditAllowed(eventParticipant); + return service.isEventParticipantEditAllowed(eventParticipant); } @Override @@ -855,15 +865,14 @@ public EventParticipantDto getFirst(EventParticipantCriteria criteria) { return null; } - return eventParticipantService.getFirst(criteria) + return service.getFirst(criteria) .map(e -> convertToDto(e, Pseudonymizer.getDefault(userService::hasRight, I18nProperties.getCaption(Captions.inaccessibleValue)))) .orElse(null); } - public EventParticipant fromDto(@NotNull EventParticipantDto source, boolean checkChangeDate) { + public EventParticipant fillOrBuildEntity(@NotNull EventParticipantDto source, EventParticipant target, boolean checkChangeDate) { - EventParticipant target = - DtoHelper.fillOrBuildEntity(source, eventParticipantService.getByUuid(source.getUuid()), EventParticipant::new, checkChangeDate); + target = DtoHelper.fillOrBuildEntity(source, target, EventParticipant::new, checkChangeDate); target.setReportingUser(userService.getByReferenceDto(source.getReportingUser())); target.setEvent(eventService.getByReferenceDto(source.getEvent())); @@ -882,52 +891,31 @@ public EventParticipant fromDto(@NotNull EventParticipantDto source, boolean che return target; } - public EventParticipantDto convertToDto(EventParticipant source, Pseudonymizer pseudonymizer) { - EventParticipantDto dto = toDto(source); - pseudonymizeDto(source, dto, pseudonymizer); - - return dto; - } - - private void pseudonymizeDto(EventParticipant source, EventParticipantDto dto, Pseudonymizer pseudonymizer) { + protected void pseudonymizeDto(EventParticipant source, EventParticipantDto dto, Pseudonymizer pseudonymizer) { if (source != null) { validate(dto); - boolean inJurisdiction = eventParticipantService.inJurisdictionOrOwned(source); + boolean inJurisdiction = service.inJurisdictionOrOwned(source); pseudonymizer.pseudonymizeDto(EventParticipantDto.class, dto, inJurisdiction, null); dto.getPerson().getAddresses().forEach(l -> pseudonymizer.pseudonymizeDto(LocationDto.class, l, inJurisdiction, null)); } } - private void restorePseudonymizedDto( + protected void restorePseudonymizedDto( EventParticipantDto dto, EventParticipantDto originalDto, EventParticipant originalEventParticipant, Pseudonymizer pseudonymizer) { if (originalDto != null) { - pseudonymizer.restorePseudonymizedValues( - EventParticipantDto.class, - dto, - originalDto, - eventParticipantService.inJurisdictionOrOwned(originalEventParticipant)); - } - } - - public static EventParticipantReferenceDto toReferenceDto(EventParticipant entity) { - - if (entity == null) { - return null; + pseudonymizer + .restorePseudonymizedValues(EventParticipantDto.class, dto, originalDto, service.inJurisdictionOrOwned(originalEventParticipant)); } - - Person person = entity.getPerson(); - - return new EventParticipantReferenceDto(entity.getUuid(), person.getFirstName(), person.getFirstName()); } - public static EventParticipantDto toDto(EventParticipant source) { + public EventParticipantDto toDto(EventParticipant source) { if (source == null) { return null; @@ -950,10 +938,9 @@ public static EventParticipantDto toDto(EventParticipant source) { return target; } - @LocalBean - @Stateless - public static class EventParticipantFacadeEjbLocal extends EventParticipantFacadeEjb { - + @Override + public EventParticipantReferenceDto toRefDto(EventParticipant eventParticipant) { + return toReferenceDto(eventParticipant); } @Override @@ -970,13 +957,13 @@ public List getAllActiveEventParticipantsByEvent(String eve return Collections.emptyList(); } - return eventParticipantService.getAllActiveByEvent(event).stream().map(e -> toDto(e)).collect(Collectors.toList()); + return service.getAllActiveByEvent(event).stream().map(e -> toDto(e)).collect(Collectors.toList()); } @Override public List getByEventUuids(List eventUuids) { Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); - return eventParticipantService.getByEventUuids(eventUuids).stream().map(e -> convertToDto(e, pseudonymizer)).collect(Collectors.toList()); + return service.getByEventUuids(eventUuids).stream().map(e -> convertToDto(e, pseudonymizer)).collect(Collectors.toList()); } @Override @@ -990,8 +977,8 @@ public List getMatchingEventParticipants(EventPartic Join personJoin = eventParticipantRoot.join(EventParticipant.PERSON, JoinType.LEFT); Join eventJoin = eventParticipantRoot.join(EventParticipant.EVENT, JoinType.LEFT); - Expression jurisdictionSelector = JurisdictionHelper - .booleanSelector(cb, eventParticipantService.inJurisdictionOrOwned(new EventParticipantQueryContext(cb, cq, eventParticipantRoot))); + Expression jurisdictionSelector = + JurisdictionHelper.booleanSelector(cb, service.inJurisdictionOrOwned(new EventParticipantQueryContext(cb, cq, eventParticipantRoot))); cq.multiselect( eventParticipantRoot.get(EventParticipant.UUID), personJoin.get(Person.FIRST_NAME), @@ -1013,8 +1000,8 @@ public List getMatchingEventParticipants(EventPartic eventJoin.get(Event.START_DATE), jurisdictionSelector); - final Predicate defaultFilter = eventParticipantService.createDefaultFilter(cb, eventParticipantRoot); - final Predicate userFilter = eventParticipantService.createUserFilter(cb, cq, eventParticipantRoot); + final Predicate defaultFilter = service.createDefaultFilter(cb, eventParticipantRoot); + final Predicate userFilter = service.createUserFilter(cb, cq, eventParticipantRoot); final PersonReferenceDto person = criteria.getPerson(); final Predicate samePersonFilter = person != null ? cb.equal(personJoin.get(Person.UUID), person.getUuid()) : null; @@ -1048,7 +1035,7 @@ public List getMatchingEventParticipants(EventPartic @Override public List getByPersonUuids(List personUuids) { - return eventParticipantService.getByPersonUuids(personUuids).stream().map(EventParticipantFacadeEjb::toDto).collect(Collectors.toList()); + return service.getByPersonUuids(personUuids).stream().map(ep -> toDto(ep)).collect(Collectors.toList()); } @Override @@ -1062,6 +1049,19 @@ public List getByEventAndPersons(String eventUuid, List resultList = em.createQuery(cq).getResultList(); - return resultList.stream().map(EventParticipantFacadeEjb::toDto).collect(Collectors.toList()); + return resultList.stream().map(ep -> toDto(ep)).collect(Collectors.toList()); + } + + @LocalBean + @Stateless + public static class EventParticipantFacadeEjbLocal extends EventParticipantFacadeEjb { + + public EventParticipantFacadeEjbLocal() { + } + + @Inject + public EventParticipantFacadeEjbLocal(EventParticipantService service, UserService userService) { + super(service, userService); + } } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java index e6fbd5f89d2..d6ffac938ad 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java @@ -39,6 +39,7 @@ import javax.persistence.criteria.Root; import javax.persistence.criteria.Subquery; +import de.symeda.sormas.backend.common.AbstractCoreAdoService; import org.apache.commons.collections.CollectionUtils; import de.symeda.sormas.api.Disease; @@ -65,7 +66,7 @@ @Stateless @LocalBean -public class EventParticipantService extends AbstractDeletableAdoService { +public class EventParticipantService extends AbstractCoreAdoService { @EJB private EventService eventService; @@ -78,7 +79,13 @@ public EventParticipantService() { super(EventParticipant.class); } - public List getAllActiveEventParticipantsAfter(Date date, User user, Integer batchSize, String lastSynchronizedUuid) { + + @Override + public List getAllActiveAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { + return getAllActiveAfter(date, null, batchSize, lastSynchronizedUuid); + } + + public List getAllActiveAfter(Date date, User user, Integer batchSize, String lastSynchronizedUuid) { CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(getElementClass()); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java index 523e49b0b89..a79359d598f 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java @@ -103,7 +103,6 @@ import de.symeda.sormas.api.person.PersonReferenceDto; import de.symeda.sormas.api.person.PersonSimilarityCriteria; import de.symeda.sormas.api.person.PresentCondition; -import de.symeda.sormas.api.person.Sex; import de.symeda.sormas.api.person.SimilarPersonDto; import de.symeda.sormas.api.person.SymptomJournalStatus; import de.symeda.sormas.api.user.UserReferenceDto; @@ -1096,7 +1095,7 @@ public void onPersonChanged(PersonDto existingPerson, Person newPerson, boolean eventParticipantFacade.onEventParticipantChanged( eventFacade.toDto(personEventParticipant.getEvent()), - EventParticipantFacadeEjbLocal.toDto(personEventParticipant), + eventParticipantFacade.toDto(personEventParticipant), personEventParticipant, syncShares); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java index 7f161dbe11f..059c5479148 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java @@ -268,7 +268,7 @@ private void handleAssotiatedObjectChanges(PathogenTest pathogenTest, boolean sy if (associatedEventParticipant != null) { eventParticipantFacade.onEventParticipantChanged( eventFacade.toDto(associatedEventParticipant.getEvent()), - EventParticipantFacadeEjbLocal.toDto(associatedEventParticipant), + eventParticipantFacade.toDto(associatedEventParticipant), associatedEventParticipant, syncShares); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java index e3ffe5d2ca8..3648dd2e912 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java @@ -992,7 +992,7 @@ private void handleAssotiatedObjectChanges(Sample newSample, boolean syncShares) if (associatedEventParticipant != null) { eventParticipantFacade.onEventParticipantChanged( eventFacade.toDto(associatedEventParticipant.getEvent()), - EventParticipantFacadeEjbLocal.toDto(associatedEventParticipant), + eventParticipantFacade.toDto(associatedEventParticipant), associatedEventParticipant, syncShares); } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java index 714650cf0a1..22bb95367b5 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java @@ -333,7 +333,7 @@ public EventService getEventService() { return getBean(EventService.class); } - public EventParticipantFacade getEventParticipantFacade() { + public EventParticipantFacadeEjbLocal getEventParticipantFacade() { return getBean(EventParticipantFacadeEjbLocal.class); } From ff7238fda26d7fbbef0306ace750e63ce719b31d Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Wed, 2 Feb 2022 11:31:35 +0200 Subject: [PATCH 008/253] #7246 - move campaign facade methods to new core entities abstraction facade --- .../sormas/api/campaign/CampaignFacade.java | 21 +--- .../resources/doc/SORMAS_Data_Dictionary.xlsx | Bin 243859 -> 243858 bytes .../resources/doc/SORMAS_User_Rights.xlsx | Bin 19067 -> 19067 bytes .../sormas/backend/campaign/Campaign.java | 14 +-- .../backend/campaign/CampaignFacadeEjb.java | 90 ++++++++++-------- .../backend/campaign/CampaignService.java | 28 +----- .../common/AbstractCoreAdoService.java | 5 - .../backend/common/AbstractCoreEjb.java | 2 +- .../common/AdoServiceWithUserFilter.java | 7 +- .../CustomizableEnumFacadeEjb.java | 2 +- .../DiseaseConfigurationFacadeEjb.java | 2 +- .../event/EventParticipantFacadeEjb.java | 2 +- .../event/EventParticipantService.java | 8 +- .../sormas/backend/event/EventService.java | 2 +- .../FeatureConfigurationFacadeEjb.java | 4 +- .../immunization/ImmunizationService.java | 2 +- .../backend/person/PersonFacadeEjb.java | 7 +- .../sormas/backend/person/PersonService.java | 8 +- .../report/AggregateReportFacadeEjb.java | 7 +- .../backend/report/WeeklyReportFacadeEjb.java | 7 +- .../services/BaseTravelEntryService.java | 2 +- .../sormas/backend/user/UserFacadeEjb.java | 2 +- .../backend/user/UserRoleConfigFacadeEjb.java | 2 +- .../main/resources/META-INF/persistence.xml | 2 + .../sormas/backend/AbstractBeanTest.java | 4 +- .../sormas/backend/TestDataCreator.java | 2 +- .../campaign/CampaignFacadeEjbTest.java | 6 +- .../test/resources/META-INF/persistence.xml | 2 + .../test/resources/META-INF/persistence.xml | 2 + 29 files changed, 93 insertions(+), 149 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/campaign/CampaignFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/campaign/CampaignFacade.java index 9a60ca9438b..50f3d3b566f 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/campaign/CampaignFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/campaign/CampaignFacade.java @@ -6,40 +6,23 @@ import javax.ejb.Remote; import javax.validation.Valid; +import de.symeda.sormas.api.CoreBaseFacade; import de.symeda.sormas.api.campaign.diagram.CampaignDashboardElement; import de.symeda.sormas.api.utils.SortProperty; @Remote -public interface CampaignFacade { - - List getIndexList(CampaignCriteria campaignCriteria, Integer first, Integer max, List sortProperties); +public interface CampaignFacade extends CoreBaseFacade { List getAllActiveCampaignsAsReference(); CampaignReferenceDto getLastStartedCampaign(); - long count(CampaignCriteria campaignCriteria); - - CampaignDto saveCampaign(@Valid CampaignDto dto); - - CampaignDto getByUuid(String uuid); - List getCampaignDashboardElements(String campaignUuid); boolean isArchived(String uuid); void deleteCampaign(String uuid); - void archiveOrDearchiveCampaign(String campaignUuid, boolean archive); - - CampaignReferenceDto getReferenceByUuid(String uuid); - - boolean exists(String uuid); - - List getAllAfter(Date campaignChangeDate); - - List getByUuids(List uuids); - List getAllActiveUuids(); void validate(CampaignReferenceDto campaignReferenceDto); diff --git a/sormas-api/src/main/resources/doc/SORMAS_Data_Dictionary.xlsx b/sormas-api/src/main/resources/doc/SORMAS_Data_Dictionary.xlsx index b5d4c7d2573329476cfe30b0246d267182ef5fe1..8f1ec7fc4436d3b183fdb191d7389844518cadff 100644 GIT binary patch delta 13021 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 diff --git a/sormas-api/src/main/resources/doc/SORMAS_User_Rights.xlsx b/sormas-api/src/main/resources/doc/SORMAS_User_Rights.xlsx index 4a80140f467afd23fe7eac7a2e1358c8e91d05e5..042bff1c191c487e72d0a74579754cc0e004beb7 100644 GIT binary patch delta 483 zcmex8h4J?kM&1B#W)=|!4h{~61`nr=ywZ%!Kzg$_V;z_=c@5JUkig_>W|jK8UPlZB z+~QTA?3=qqTWjH4rBh7{c0B0nE?1Pio%GpR=3CpiNo)4rKn+1wpF?MK-Kv7Lc52++EuYpn zsew7m#L!`)_=m%8U#$MzHc;oTY3icq8s+_ub$I>zRLJ-tWxf($+Nus zl@=*^9(a6l>C_ta^Q&LazT0M|s(rf0H~qMth4te#6)PWv|5y35EBb!S($*4>ZT#DX zw@=Yl`my=hGvNSlc8*)?%o$i285lMKF-rJt-p}I01r9(yekCR_!&p!i5~R^WiV#M< zu!u1@OzVYJCMS5YZr<;v3kmG^?q*;K4G%joo#|oC0Sx>QkbRTac$k9)pLy6r6nR>J W>10nUFulOj6->YIbOzIUUcLaTc)tk% delta 483 zcmex8h4J?kM&1B#W)=|!4h{|mZXfH7ywZ%!Kzg$_V;z_=c@5JUkig_>W|jI_@52Tn zZU4Pa)Xp|xRbTj4AXPzwZ;i&i)+aZ_X7f+V*j}F>mCpJ+cG7oCe)asVwl4&0oA{ee zP4$Yp1SK-BChU^3-@5ya&|-nsz@#l~Sv4&U+kI7Kr(ZjKFPhzsPaxpai~~zo7s@Yw z+`@9RSxnKt#q;6puTe)zzRDIl?d#^N=UDuuDWk)wQ{#lrnLAlW)R#_LeW~_Gp`eCm z0t>GiThJ5MpQ*|fvj1cwCQY?zNnE-t^VIU9hnL(~D|ha%j+u6z&G>&TQ{Jk{v%LA0 znw&fjJifTpt8UWsPrsJkeb^Rw%qS`)=kg_9eaZBv*{=W2oImt_^VhSXT1(is)bE(P z^XpC}rF2vC_yBKq4*9B(ZdOJHhK)ds5`LTav-og<1CWnji3!Xw7F2} dashboardElements; private Set campaignFormMetas = new HashSet<>(); @@ -98,15 +97,6 @@ public void setCreatingUser(User creatingUser) { this.creatingUser = creatingUser; } - @Column - public boolean isArchived() { - return archived; - } - - public void setArchived(boolean archived) { - this.archived = archived; - } - @Override public String toString() { return name; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java index a0927c95aff..cd0bc56bce7 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java @@ -13,6 +13,7 @@ import javax.ejb.EJB; import javax.ejb.LocalBean; import javax.ejb.Stateless; +import javax.inject.Inject; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.TypedQuery; @@ -25,6 +26,8 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; +import de.symeda.sormas.backend.common.AbstractCoreEjb; +import de.symeda.sormas.backend.util.Pseudonymizer; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -55,22 +58,23 @@ import de.symeda.sormas.backend.util.QueryHelper; @Stateless(name = "CampaignFacade") -public class CampaignFacadeEjb implements CampaignFacade { +public class CampaignFacadeEjb extends AbstractCoreEjb implements CampaignFacade { - @PersistenceContext(unitName = ModelConstants.PERSISTENCE_UNIT_NAME) - private EntityManager em; - - @EJB - private CampaignService campaignService; @EJB private CampaignFormMetaService campaignFormMetaService; @EJB - private UserService userService; - @EJB private UserRoleConfigFacadeEjbLocal userRoleConfigFacade; @EJB private CampaignDiagramDefinitionFacadeEjb.CampaignDiagramDefinitionFacadeEjbLocal campaignDiagramDefinitionFacade; + public CampaignFacadeEjb() { + } + + @Inject + public CampaignFacadeEjb( CampaignService service, UserService userService) { + super(Campaign.class, CampaignDto.class, service, userService); + } + @Override public List getIndexList(CampaignCriteria campaignCriteria, Integer first, Integer max, List sortProperties) { @@ -80,10 +84,10 @@ public List getIndexList(CampaignCriteria campaignCriteria, In cq.multiselect(campaign.get(Campaign.UUID), campaign.get(Campaign.NAME), campaign.get(Campaign.START_DATE), campaign.get(Campaign.END_DATE)); - Predicate filter = campaignService.createUserFilter(cb, cq, campaign); + Predicate filter = service.createUserFilter(cb, cq, campaign); if (campaignCriteria != null) { - Predicate criteriaFilter = campaignService.buildCriteriaFilter(campaignCriteria, cb, campaign); + Predicate criteriaFilter = service.buildCriteriaFilter(campaignCriteria, cb, campaign); filter = CriteriaBuilderHelper.and(cb, filter, criteriaFilter); } @@ -115,7 +119,7 @@ public List getIndexList(CampaignCriteria campaignCriteria, In @Override public List getAllActiveCampaignsAsReference() { - return campaignService.getAll() + return service.getAll() .stream() .filter(c -> !c.isDeleted() && !c.isArchived()) .map(CampaignFacadeEjb::toReferenceDto) @@ -129,7 +133,7 @@ public CampaignReferenceDto getLastStartedCampaign() { final CriteriaQuery query = cb.createQuery(Campaign.class); final Root from = query.from(Campaign.class); query.select(from); - query.where(cb.and(campaignService.createActiveCampaignsFilter(cb, from), cb.lessThanOrEqualTo(from.get(Campaign.START_DATE), new Date()))); + query.where(cb.and(service.createActiveCampaignsFilter(cb, from), cb.lessThanOrEqualTo(from.get(Campaign.START_DATE), new Date()))); query.orderBy(cb.desc(from.get(Campaign.START_DATE))); final TypedQuery q = em.createQuery(query); @@ -145,10 +149,10 @@ public long count(CampaignCriteria campaignCriteria) { CriteriaQuery cq = cb.createQuery(Long.class); Root campaign = cq.from(Campaign.class); - Predicate filter = campaignService.createUserFilter(cb, cq, campaign); + Predicate filter = service.createUserFilter(cb, cq, campaign); if (campaignCriteria != null) { - Predicate criteriaFilter = campaignService.buildCriteriaFilter(campaignCriteria, cb, campaign); + Predicate criteriaFilter = service.buildCriteriaFilter(campaignCriteria, cb, campaign); filter = CriteriaBuilderHelper.and(cb, filter, criteriaFilter); } @@ -158,17 +162,16 @@ public long count(CampaignCriteria campaignCriteria) { } @Override - public CampaignDto saveCampaign(@Valid CampaignDto dto) { - - Campaign campaign = fromDto(dto, true); - campaignService.ensurePersisted(campaign); + public CampaignDto save(@Valid CampaignDto dto) { + validate(dto); + Campaign campaign = fillOrBuildEntity(dto, service.getByUuid(dto.getUuid()), true); + service.ensurePersisted(campaign); return toDto(campaign); } - public Campaign fromDto(@NotNull CampaignDto source, boolean checkChangeDate) { - validate(source); + public Campaign fillOrBuildEntity(@NotNull CampaignDto source, Campaign target, boolean checkChangeDate) { - Campaign target = DtoHelper.fillOrBuildEntity(source, campaignService.getByUuid(source.getUuid()), Campaign::new, checkChangeDate); + target = DtoHelper.fillOrBuildEntity(source, target, Campaign::new, checkChangeDate); target.setCreatingUser(userService.getByReferenceDto(source.getCreatingUser())); target.setDescription(source.getDescription()); @@ -190,7 +193,7 @@ public void validate(CampaignReferenceDto campaignReferenceDto) { validate(getByUuid(campaignReferenceDto.getUuid())); } - protected void validate(CampaignDto campaignDto) { + public void validate(CampaignDto campaignDto) { final List campaignDashboardElements = campaignDto.getCampaignDashboardElements(); if (campaignDashboardElements != null) { @@ -288,22 +291,27 @@ public CampaignDto toDto(Campaign source) { return target; } + @Override + public CampaignReferenceDto toRefDto(Campaign campaign) { + return toReferenceDto(campaign); + } + @Override public CampaignDto getByUuid(String uuid) { - return toDto(campaignService.getByUuid(uuid)); + return toDto(service.getByUuid(uuid)); } @Override public List getCampaignDashboardElements(String campaignUuid) { final List result = new ArrayList<>(); if (campaignUuid != null) { - final Campaign campaign = campaignService.getByUuid(campaignUuid); + final Campaign campaign = service.getByUuid(campaignUuid); final List dashboardElements = campaign.getDashboardElements(); if (dashboardElements != null) { result.addAll(dashboardElements); } } else { - campaignService.getAllActive().forEach(campaign -> { + service.getAllActive().forEach(campaign -> { final List dashboardElements = campaign.getDashboardElements(); if (dashboardElements != null) { result.addAll(dashboardElements); @@ -357,38 +365,35 @@ public void deleteCampaign(String campaignUuid) { + I18nProperties.getString(Strings.entityCampaigns).toLowerCase() + "."); } - campaignService.delete(campaignService.getByUuid(campaignUuid)); + service.delete(service.getByUuid(campaignUuid)); } @Override - public void archiveOrDearchiveCampaign(String campaignUuid, boolean archive) { + protected void pseudonymizeDto(Campaign source, CampaignDto dto, Pseudonymizer pseudonymizer) { - Campaign campaign = campaignService.getByUuid(campaignUuid); - campaign.setArchived(archive); - campaignService.ensurePersisted(campaign); } @Override - public CampaignReferenceDto getReferenceByUuid(String uuid) { - return toReferenceDto(campaignService.getByUuid(uuid)); - } + protected void restorePseudonymizedDto(CampaignDto dto, CampaignDto existingDto, Campaign entity, Pseudonymizer pseudonymizer) { - @Override - public boolean exists(String uuid) { - return campaignService.exists(uuid); } @Override public List getAllAfter(Date date) { - return campaignService.getAllAfter(date, userService.getCurrentUser()) + return service.getAllAfter(date) .stream() .map(campaignFormMeta -> toDto(campaignFormMeta)) .collect(Collectors.toList()); } + @Override + protected void selectDtoFields(CriteriaQuery cq, Root root) { + + } + @Override public List getByUuids(List uuids) { - return campaignService.getByUuids(uuids).stream().map(c -> toDto(c)).collect(Collectors.toList()); + return service.getByUuids(uuids).stream().map(c -> toDto(c)).collect(Collectors.toList()); } @Override @@ -397,7 +402,7 @@ public List getAllActiveUuids() { return Collections.emptyList(); } - return campaignService.getAllActiveUuids(); + return service.getAllActiveUuids(); } public static CampaignReferenceDto toReferenceDto(Campaign entity) { @@ -411,5 +416,12 @@ public static CampaignReferenceDto toReferenceDto(Campaign entity) { @LocalBean @Stateless public static class CampaignFacadeEjbLocal extends CampaignFacadeEjb { + public CampaignFacadeEjbLocal() { + } + + @Inject + public CampaignFacadeEjbLocal(CampaignService service, UserService userService) { + super(service, userService); + } } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignService.java index a3b01e5e3ca..e9f85bf5cd5 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignService.java @@ -1,6 +1,5 @@ package de.symeda.sormas.backend.campaign; -import java.util.Date; import java.util.List; import javax.ejb.LocalBean; @@ -15,14 +14,12 @@ import de.symeda.sormas.api.campaign.CampaignCriteria; import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.backend.common.AbstractCoreAdoService; -import de.symeda.sormas.backend.common.AbstractDeletableAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; -import de.symeda.sormas.backend.user.User; @Stateless @LocalBean -public class CampaignService extends AbstractDeletableAdoService { +public class CampaignService extends AbstractCoreAdoService { public CampaignService() { super(Campaign.class); @@ -93,29 +90,6 @@ public List getAllActiveUuids() { return em.createQuery(cq).getResultList(); } - public List getAllAfter(Date since, User user) { - - CriteriaBuilder cb = em.getCriteriaBuilder(); - CriteriaQuery cq = cb.createQuery(getElementClass()); - Root root = cq.from(getElementClass()); - - Predicate filter = createUserFilter(cb, cq, root); - if (since != null) { - Predicate dateFilter = createChangeDateFilter(cb, root, since); - if (filter != null) { - filter = cb.and(filter, dateFilter); - } else { - filter = dateFilter; - } - } - if (filter != null) { - cq.where(filter); - } - cq.orderBy(cb.desc(root.get(AbstractDomainObject.CHANGE_DATE))); - - return em.createQuery(cq).getResultList(); - } - public List getAllActive() { CriteriaBuilder cb = em.getCriteriaBuilder(); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java index 97b28b2d4c7..6096413e77c 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java @@ -15,14 +15,9 @@ package de.symeda.sormas.backend.common; -import java.util.Date; -import java.util.List; - public abstract class AbstractCoreAdoService extends AbstractDeletableAdoService { public AbstractCoreAdoService(Class elementClass) { super(elementClass); } - - public abstract List getAllActiveAfter(Date date, Integer batchSize, String lastSynchronizedUuid); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java index 51f509057ac..f3ea1287f68 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java @@ -59,7 +59,7 @@ public List getAllAfter(Date date) { public List getAllAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithInaccessibleValuePlaceHolder(userService::hasRight); - return service.getAllActiveAfter(date, batchSize, lastSynchronizedUuid) + return service.getAllAfter(date, batchSize, lastSynchronizedUuid) .stream() .map(c -> convertToDto(c, pseudonymizer)) .collect(Collectors.toList()); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AdoServiceWithUserFilter.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AdoServiceWithUserFilter.java index 8bbda9260fe..dfaa0d346c8 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AdoServiceWithUserFilter.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AdoServiceWithUserFilter.java @@ -1,5 +1,6 @@ package de.symeda.sormas.backend.common; +import java.util.Collections; import java.util.Date; import java.util.List; @@ -28,11 +29,11 @@ public AdoServiceWithUserFilter(Class elementClass) { @SuppressWarnings("rawtypes") public abstract Predicate createUserFilter(CriteriaBuilder cb, CriteriaQuery cq, From from); - public List getAllAfter(Date since, User user) { - return getAllAfter(since, user, null, null); + public List getAllAfter(Date since) { + return getAllAfter(since, null, null); } - public List getAllAfter(Date since, User user, Integer batchSize, String lastSynchronizedUuid) { + public List getAllAfter(Date since, Integer batchSize, String lastSynchronizedUuid) { CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(getElementClass()); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumFacadeEjb.java index b3710a4ee10..9a53c83bb94 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumFacadeEjb.java @@ -83,7 +83,7 @@ public class CustomizableEnumFacadeEjb implements CustomizableEnumFacade { @Lock(LockType.READ) @Override public List getAllAfter(Date date) { - return service.getAllAfter(date, null).stream().map(this::toDto).collect(Collectors.toList()); + return service.getAllAfter(date).stream().map(this::toDto).collect(Collectors.toList()); } @Lock(LockType.READ) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfigurationFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfigurationFacadeEjb.java index 2c3ff8aa95a..c7b6e93665f 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfigurationFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfigurationFacadeEjb.java @@ -54,7 +54,7 @@ public class DiseaseConfigurationFacadeEjb implements DiseaseConfigurationFacade @Override public List getAllAfter(Date date) { - return service.getAllAfter(date, null).stream().map(d -> toDto(d)).collect(Collectors.toList()); + return service.getAllAfter(date).stream().map(d -> toDto(d)).collect(Collectors.toList()); } @Override diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java index 889d8682031..ed1507b7c97 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java @@ -223,7 +223,7 @@ public List getAllActiveEventParticipantsAfter(Date date, I } Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); - return service.getAllActiveAfter(date, user, batchSize, lastSynchronizedUuid) + return service.getAllAfter(date, user, batchSize, lastSynchronizedUuid) .stream() .map(c -> convertToDto(c, pseudonymizer)) .collect(Collectors.toList()); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java index d6ffac938ad..d3c7eb8f24a 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java @@ -48,7 +48,6 @@ import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.backend.caze.Case; -import de.symeda.sormas.backend.common.AbstractDeletableAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.contact.Contact; @@ -80,12 +79,11 @@ public EventParticipantService() { } - @Override - public List getAllActiveAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { - return getAllActiveAfter(date, null, batchSize, lastSynchronizedUuid); + public List getAllAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { + return getAllAfter(date, null, batchSize, lastSynchronizedUuid); } - public List getAllActiveAfter(Date date, User user, Integer batchSize, String lastSynchronizedUuid) { + public List getAllAfter(Date date, User user, Integer batchSize, String lastSynchronizedUuid) { CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(getElementClass()); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java index 05577c28260..064fc8370c0 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java @@ -115,7 +115,7 @@ public EventService() { } @Override - public List getAllActiveAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { + public List getAllAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(getElementClass()); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/feature/FeatureConfigurationFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/feature/FeatureConfigurationFacadeEjb.java index 7749488f55c..76f1d4c8736 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/feature/FeatureConfigurationFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/feature/FeatureConfigurationFacadeEjb.java @@ -101,9 +101,7 @@ public class FeatureConfigurationFacadeEjb implements FeatureConfigurationFacade @Override public List getAllAfter(Date date) { - - User user = userService.getCurrentUser(); - return service.getAllAfter(date, user).stream().map(FeatureConfigurationFacadeEjb::toDto).collect(Collectors.toList()); + return service.getAllAfter(date).stream().map(FeatureConfigurationFacadeEjb::toDto).collect(Collectors.toList()); } @Override diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java index 3e7f2d3d197..ac504d2587f 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java @@ -160,7 +160,7 @@ private Predicate createChangeDateFilter(CriteriaBuilder cb, From getAllActiveAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { + public List getAllAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(getElementClass()); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java index a79359d598f..f276ecd0857 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java @@ -258,11 +258,8 @@ public List getPersonsAfter(Date date) { @Override public List getPersonsAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { - final User user = userService.getCurrentUser(); - if (user == null) { - return Collections.emptyList(); - } - return toPseudonymizedDtos(personService.getAllAfter(date, user, batchSize, lastSynchronizedUuid)); + + return toPseudonymizedDtos(personService.getAllAfter(date, batchSize, lastSynchronizedUuid)); } @Override diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonService.java index f5837711c52..0cd4f16a4df 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonService.java @@ -361,13 +361,15 @@ public Predicate buildCriteriaFilter(PersonCriteria personCriteria, PersonQueryC } @Override - public List getAllAfter(Date date, User user) { - return getAllAfter(date, user, null, null); + public List getAllAfter(Date date) { + return getAllAfter(date, null, null); } @Override // todo refactor this to use the create user filter form persons - public List getAllAfter(Date date, User user, Integer batchSize, String lastSynchronizedUuid) { + public List getAllAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { + + User user = getCurrentUser(); CriteriaBuilder cb = em.getCriteriaBuilder(); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/report/AggregateReportFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/report/AggregateReportFacadeEjb.java index 0f3b1b7cc3c..2a5ad9c07be 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/report/AggregateReportFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/report/AggregateReportFacadeEjb.java @@ -70,12 +70,7 @@ public class AggregateReportFacadeEjb implements AggregateReportFacade { @Override public List getAllAggregateReportsAfter(Date date) { - User user = userService.getCurrentUser(); - if (user == null) { - return Collections.emptyList(); - } - - return service.getAllAfter(date, user).stream().map(r -> toDto(r)).collect(Collectors.toList()); + return service.getAllAfter(date).stream().map(r -> toDto(r)).collect(Collectors.toList()); } @Override diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/report/WeeklyReportFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/report/WeeklyReportFacadeEjb.java index 47a5f6e69a7..e745d6bd53c 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/report/WeeklyReportFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/report/WeeklyReportFacadeEjb.java @@ -110,12 +110,7 @@ public List getAllWeeklyReportsAfter(Date date) { @Override public List getAllWeeklyReportsAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { - User user = userService.getCurrentUser(); - if (user == null) { - return Collections.emptyList(); - } - - return weeklyReportService.getAllAfter(date, user, batchSize, lastSynchronizedUuid) + return weeklyReportService.getAllAfter(date, batchSize, lastSynchronizedUuid) .stream() .map(WeeklyReportFacadeEjb::toDto) .collect(Collectors.toList()); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java index 90495c0db32..7fd96a466b1 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java @@ -77,7 +77,7 @@ public List getAllActiveAfter(Date date) { } @Override - public List getAllActiveAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { + public List getAllAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { return getAllActiveAfter(date); } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserFacadeEjb.java index e290717c878..97419d78b09 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserFacadeEjb.java @@ -499,7 +499,7 @@ public Page getIndexPage(UserCriteria userCriteria, int offset, int siz @Override public List getAllAfter(Date date) { - return userService.getAllAfter(date, null).stream().map(c -> toDto(c)).collect(Collectors.toList()); + return userService.getAllAfter(date).stream().map(c -> toDto(c)).collect(Collectors.toList()); } @Override diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserRoleConfigFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserRoleConfigFacadeEjb.java index 4d208e012fe..adb5762400c 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserRoleConfigFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserRoleConfigFacadeEjb.java @@ -52,7 +52,7 @@ public class UserRoleConfigFacadeEjb implements UserRoleConfigFacade { @Override public List getAllAfter(Date since) { - return userRoleConfigService.getAllAfter(since, null).stream().map(c -> toDto(c)).collect(Collectors.toList()); + return userRoleConfigService.getAllAfter(since).stream().map(c -> toDto(c)).collect(Collectors.toList()); } @Override diff --git a/sormas-backend/src/main/resources/META-INF/persistence.xml b/sormas-backend/src/main/resources/META-INF/persistence.xml index 07a195394c2..4e6d17b098e 100644 --- a/sormas-backend/src/main/resources/META-INF/persistence.xml +++ b/sormas-backend/src/main/resources/META-INF/persistence.xml @@ -11,6 +11,8 @@ de.symeda.sormas.backend.action.Action de.symeda.sormas.backend.caze.Case de.symeda.sormas.backend.common.AbstractDomainObject + de.symeda.sormas.backend.common.DeletableAdo + de.symeda.sormas.backend.common.CoreAdo de.symeda.sormas.backend.contact.Contact de.symeda.sormas.backend.epidata.EpiData de.symeda.sormas.backend.event.Event diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java index 22bb95367b5..046ac1af5cd 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java @@ -30,7 +30,6 @@ import de.symeda.sormas.api.Language; import de.symeda.sormas.api.action.ActionFacade; import de.symeda.sormas.api.bagexport.BAGExportFacade; -import de.symeda.sormas.api.campaign.CampaignFacade; import de.symeda.sormas.api.campaign.data.CampaignFormDataFacade; import de.symeda.sormas.api.campaign.diagram.CampaignDiagramDefinitionFacade; import de.symeda.sormas.api.campaign.form.CampaignFormMetaFacade; @@ -48,7 +47,6 @@ import de.symeda.sormas.api.docgeneneration.QuarantineOrderFacade; import de.symeda.sormas.api.document.DocumentFacade; import de.symeda.sormas.api.epidata.EpiDataFacade; -import de.symeda.sormas.api.event.EventParticipantFacade; import de.symeda.sormas.api.externalsurveillancetool.ExternalSurveillanceToolFacade; import de.symeda.sormas.api.feature.FeatureConfigurationFacade; import de.symeda.sormas.api.geo.GeoShapeProvider; @@ -653,7 +651,7 @@ public CampaignFormDataFacade getCampaignFormDataFacade() { return getBean(CampaignFormDataFacadeEjbLocal.class); } - public CampaignFacade getCampaignFacade() { + public CampaignFacadeEjbLocal getCampaignFacade() { return getBean(CampaignFacadeEjbLocal.class); } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java index 3b43583a178..ea51163ebfb 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java @@ -1327,7 +1327,7 @@ public CampaignDto createCampaign(UserDto user) { campaign.setName("CampaignName"); campaign.setDescription("Campaign description"); - campaign = beanTest.getCampaignFacade().saveCampaign(campaign); + campaign = beanTest.getCampaignFacade().save(campaign); return campaign; } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjbTest.java index f64eb1ccf52..99bf052437a 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjbTest.java @@ -26,13 +26,13 @@ public void testGetLastStartedCampaign() { final UserDto user = creator.createUser(rdcf, UserRole.SURVEILLANCE_SUPERVISOR); final CampaignDto campaign1 = creator.createCampaign(user); campaign1.setStartDate(new Date(System.currentTimeMillis() - 7 * ONE_DAY_IN_MILLIS)); // last week - getCampaignFacade().saveCampaign(campaign1); + getCampaignFacade().save(campaign1); final CampaignDto campaign2 = creator.createCampaign(user); campaign2.setStartDate(new Date(System.currentTimeMillis() - ONE_DAY_IN_MILLIS)); // yesterday - getCampaignFacade().saveCampaign(campaign2); + getCampaignFacade().save(campaign2); final CampaignDto campaign3 = creator.createCampaign(user); campaign3.setStartDate(new Date(System.currentTimeMillis() + ONE_DAY_IN_MILLIS)); // tomorrow - getCampaignFacade().saveCampaign(campaign3); + getCampaignFacade().save(campaign3); CampaignReferenceDto lastStartedCampaign = getCampaignFacade().getLastStartedCampaign(); Assert.assertEquals(campaign2.getUuid(), lastStartedCampaign.getUuid()); diff --git a/sormas-backend/src/test/resources/META-INF/persistence.xml b/sormas-backend/src/test/resources/META-INF/persistence.xml index bd389fa404c..71746659a76 100644 --- a/sormas-backend/src/test/resources/META-INF/persistence.xml +++ b/sormas-backend/src/test/resources/META-INF/persistence.xml @@ -10,6 +10,8 @@ de.symeda.sormas.backend.action.Action de.symeda.sormas.backend.caze.Case de.symeda.sormas.backend.common.AbstractDomainObject + de.symeda.sormas.backend.common.DeletableAdo + de.symeda.sormas.backend.common.CoreAdo de.symeda.sormas.backend.contact.Contact de.symeda.sormas.backend.epidata.EpiData de.symeda.sormas.backend.event.Event diff --git a/sormas-ui/src/test/resources/META-INF/persistence.xml b/sormas-ui/src/test/resources/META-INF/persistence.xml index 65befb67eb8..d818c9e8241 100644 --- a/sormas-ui/src/test/resources/META-INF/persistence.xml +++ b/sormas-ui/src/test/resources/META-INF/persistence.xml @@ -10,6 +10,8 @@ de.symeda.sormas.backend.action.Action de.symeda.sormas.backend.caze.Case de.symeda.sormas.backend.common.AbstractDomainObject + de.symeda.sormas.backend.common.DeletableAdo + de.symeda.sormas.backend.common.CoreAdo de.symeda.sormas.backend.contact.Contact de.symeda.sormas.backend.epidata.EpiData de.symeda.sormas.backend.event.Event From 1a4df8428e6ea16b5792d88277f6db3726da58c0 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Wed, 2 Feb 2022 14:33:08 +0200 Subject: [PATCH 009/253] #7246 - move contact facade methods to new core facade --- .../sormas/api/contact/ContactFacade.java | 25 +- .../sormas/backend/caze/CaseFacadeEjb.java | 4 +- .../backend/contact/ContactFacadeEjb.java | 217 ++++++++---------- .../backend/contact/ContactService.java | 7 +- .../DocumentTemplateEntitiesBuilder.java | 2 +- .../DocumentTemplateFacadeEjb.java | 2 +- .../backend/person/PersonFacadeEjb.java | 2 +- .../backend/sample/PathogenTestFacadeEjb.java | 2 +- .../backend/sample/SampleFacadeEjb.java | 2 +- .../ProcessedContactDataPersister.java | 4 +- .../contact/ReceivedContactProcessor.java | 8 +- .../sormas/backend/AbstractBeanTest.java | 2 +- .../sormas/backend/TestDataCreator.java | 2 +- .../backend/caze/CaseFacadeEjbTest.java | 4 +- .../ContactFacadeEjbPseudonymizationTest.java | 24 +- .../backend/contact/ContactFacadeEjbTest.java | 60 ++--- .../backend/contact/ContactServiceTest.java | 38 +-- .../QuarantineOrderFacadeEjbTest.java | 2 +- .../PersonFacadeEjbPseudonymizationTest.java | 6 +- .../backend/person/PersonFacadeEjbTest.java | 28 +-- .../person/PersonFacadeEjbUserFilterTest.java | 4 +- .../SormasToSormasCaseFacadeEjbTest.java | 8 +- .../SormasToSormasContactFacadeEjbTest.java | 8 +- .../vaccination/VaccinationFacadeEjbTest.java | 14 +- .../symeda/sormas/rest/ContactResource.java | 2 +- .../symeda/sormas/ui/caze/CaseController.java | 12 +- .../sormas/ui/configuration/DevModeView.java | 4 +- .../ui/contact/AbstractContactView.java | 2 +- .../sormas/ui/contact/ContactController.java | 32 +-- .../sormas/ui/contact/ContactDataView.java | 10 +- .../sormas/ui/contact/ContactPersonView.java | 2 +- .../sormas/ui/contact/ContactVisitsView.java | 4 +- .../ui/contact/importer/ContactImporter.java | 4 +- .../events/eventLink/EventListComponent.java | 2 +- .../ui/labmessage/LabMessageController.java | 2 +- .../sormas/ui/samples/AbstractSampleForm.java | 2 +- .../ui/samples/PathogenTestController.java | 2 +- .../sormas/ui/samples/SampleController.java | 4 +- .../sormas/ui/samples/SampleDataView.java | 2 +- .../sormas/ui/visit/VisitController.java | 6 +- .../de/symeda/sormas/ui/TestDataCreator.java | 4 +- .../ui/importexport/ImportExportTest.java | 2 +- 42 files changed, 265 insertions(+), 308 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java index 4ecceb411b7..42b3fdba865 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java @@ -25,6 +25,7 @@ import javax.ejb.Remote; import javax.validation.Valid; +import de.symeda.sormas.api.CoreBaseFacade; import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.Language; import de.symeda.sormas.api.common.Page; @@ -39,28 +40,14 @@ import de.symeda.sormas.api.visit.VisitSummaryExportDto; @Remote -public interface ContactFacade { +public interface ContactFacade extends CoreBaseFacade { - List getAllActiveContactsAfter(Date date); - - ContactDto getContactByUuid(String uuid); - - Boolean isValidContactUuid(String uuid); - - ContactDto saveContact(@Valid ContactDto dto); - - ContactDto saveContact(@Valid ContactDto dto, boolean handleChanges, boolean handleCaseChanges); - - ContactReferenceDto getReferenceByUuid(String uuid); + ContactDto save(@Valid ContactDto dto, boolean handleChanges, boolean handleCaseChanges); List getAllActiveUuids(); void generateContactFollowUpTasks(); - List getAllActiveContactsAfter(Date date, Integer batchSize, String lastSynchronizedUuid); - - List getByUuids(List uuids); - Long countContactsForMap(RegionReferenceDto regionRef, DistrictReferenceDto districtRef, Disease disease, Date from, Date to); List getContactsForMap(RegionReferenceDto regionRef, DistrictReferenceDto districtRef, Disease disease, Date from, Date to); @@ -71,8 +58,6 @@ public interface ContactFacade { FollowUpPeriodDto calculateFollowUpUntilDate(ContactDto contactDto, boolean ignoreOverwrite); - List getIndexList(ContactCriteria contactCriteria, Integer first, Integer max, List sortProperties); - List getEntriesList(String personUuid, Integer first, Integer max); Page getIndexPage(ContactCriteria contactCriteria, Integer offset, Integer size, List sortProperties); @@ -115,8 +100,6 @@ List getContactsForDashboard( int getFollowUpUntilCount(ContactCriteria contactCriteria); - long count(ContactCriteria contactCriteria); - List getDeletedUuidsSince(Date since); boolean isDeleted(String contactUuid); @@ -144,8 +127,6 @@ List getContactFollowUpList( boolean isContactEditAllowed(String contactUuid); - boolean exists(String uuid); - boolean doesExternalTokenExist(String externalToken, String contactUuid); List getByPersonUuids(List personUuids); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java index 29a84287c79..05876da8a12 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java @@ -3241,8 +3241,8 @@ private void mergeCase(CaseDataDto leadCaseData, CaseDataDto otherCaseData, bool ContactDto newContact = ContactDto.build(leadCase.toReference(), leadCase.getDisease(), leadCase.getDiseaseDetails(), leadCase.getDiseaseVariant()); newContact.setPerson(new PersonReferenceDto(contact.getPerson().getUuid())); - DtoHelper.copyDtoValues(newContact, ContactFacadeEjb.toDto(contact), cloning); - contactFacade.saveContact(newContact, false, false); + DtoHelper.copyDtoValues(newContact, contactFacade.toDto(contact), cloning); + contactFacade.save(newContact, false, false); } else { // simply move existing entities to the merge target contact.setCaze(leadCase); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java index f06aeb74982..b897b591984 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java @@ -48,8 +48,7 @@ import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.enterprise.concurrent.ManagedScheduledExecutorService; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; +import javax.inject.Inject; import javax.persistence.Query; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; @@ -139,6 +138,7 @@ import de.symeda.sormas.backend.caze.CaseFacadeEjb.CaseFacadeEjbLocal; import de.symeda.sormas.backend.caze.CaseService; import de.symeda.sormas.backend.clinicalcourse.ClinicalCourseFacadeEjb; +import de.symeda.sormas.backend.common.AbstractCoreEjb; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; @@ -202,28 +202,22 @@ import de.symeda.sormas.backend.visit.VisitService; @Stateless(name = "ContactFacade") -public class ContactFacadeEjb implements ContactFacade { +public class ContactFacadeEjb extends AbstractCoreEjb + implements ContactFacade { private static final long SECONDS_30_DAYS = TimeUnit.DAYS.toSeconds(30L); private final Logger logger = LoggerFactory.getLogger(getClass()); - @PersistenceContext(unitName = ModelConstants.PERSISTENCE_UNIT_NAME) - private EntityManager em; - @EJB private ConfigFacadeEjbLocal configFacade; @EJB - private ContactService contactService; - @EJB private ContactListCriteriaBuilder listCriteriaBuilder; @EJB private CaseService caseService; @EJB private PersonService personService; @EJB - private UserService userService; - @EJB private VisitService visitService; @EJB private VisitFacadeEjbLocal visitFacade; @@ -268,25 +262,21 @@ public class ContactFacadeEjb implements ContactFacade { @Resource private ManagedScheduledExecutorService executorService; - @Override - public List getAllActiveUuids() { - - User user = userService.getCurrentUser(); - - if (user == null) { - return Collections.emptyList(); - } + public ContactFacadeEjb() { + } - return contactService.getAllActiveUuids(user); + @Inject + public ContactFacadeEjb(ContactService service, UserService userService) { + super(Contact.class, ContactDto.class, service, userService); } @Override - public List getAllActiveContactsAfter(Date date) { - return getAllActiveContactsAfter(date, null, null); + protected void selectDtoFields(CriteriaQuery cq, Root root) { + } @Override - public List getAllActiveContactsAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { + public List getAllActiveUuids() { User user = userService.getCurrentUser(); @@ -294,17 +284,7 @@ public List getAllActiveContactsAfter(Date date, Integer batchSize, return Collections.emptyList(); } - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); - return contactService.getAllActiveContactsAfter(date, batchSize, lastSynchronizedUuid) - .stream() - .map(c -> convertToDto(c, pseudonymizer)) - .collect(Collectors.toList()); - } - - @Override - public List getByUuids(List uuids) { - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); - return contactService.getByUuids(uuids).stream().map(c -> convertToDto(c, pseudonymizer)).collect(Collectors.toList()); + return service.getAllActiveUuids(user); } @Override @@ -316,48 +296,33 @@ public List getDeletedUuidsSince(Date since) { return Collections.emptyList(); } - return contactService.getDeletedUuidsSince(user, since); - } - - @Override - public ContactDto getContactByUuid(String uuid) { - return convertToDto(contactService.getByUuid(uuid), Pseudonymizer.getDefault(userService::hasRight)); + return service.getDeletedUuidsSince(user, since); } private ContactDto getContactWithoutPseudonyimizationByUuid(String uuid) { - return toDto(contactService.getByUuid(uuid)); - } - - @Override - public Boolean isValidContactUuid(String uuid) { - return contactService.exists(uuid); - } - - @Override - public ContactReferenceDto getReferenceByUuid(String uuid) { - return convertToReferenceDto(contactService.getByUuid(uuid)); + return toDto(service.getByUuid(uuid)); } @Override - public ContactDto saveContact(@Valid ContactDto dto) { - return saveContact(dto, true, true); + public ContactDto save(@Valid ContactDto dto) { + return save(dto, true, true); } @Override - public ContactDto saveContact(@Valid ContactDto dto, boolean handleChanges, boolean handleCaseChanges) { - return saveContact(dto, handleChanges, handleCaseChanges, true, true); + public ContactDto save(@Valid ContactDto dto, boolean handleChanges, boolean handleCaseChanges) { + return save(dto, handleChanges, handleCaseChanges, true, true); } - public ContactDto saveContact(ContactDto dto, boolean handleChanges, boolean handleCaseChanges, boolean checkChangeDate, boolean internal) { - final Contact existingContact = dto.getUuid() != null ? contactService.getByUuid(dto.getUuid()) : null; + public ContactDto save(ContactDto dto, boolean handleChanges, boolean handleCaseChanges, boolean checkChangeDate, boolean internal) { + final Contact existingContact = dto.getUuid() != null ? service.getByUuid(dto.getUuid()) : null; - if (internal && existingContact != null && !contactService.isContactEditAllowed(existingContact)) { + if (internal && existingContact != null && !service.isContactEditAllowed(existingContact)) { throw new AccessDeniedException(I18nProperties.getString(Strings.errorContactNotEditable)); } final ContactDto existingContactDto = toDto(existingContact); - restorePseudonymizedDto(dto, existingContact, existingContactDto); + restorePseudonymizedDto(dto, existingContactDto, existingContact, Pseudonymizer.getDefault(userService::hasRight)); validate(dto); @@ -370,7 +335,7 @@ public ContactDto saveContact(ContactDto dto, boolean handleChanges, boolean han // throw new UnsupportedOperationException("Contact creation is not allowed for diseases that don't have contact follow-up."); // } - Contact entity = fromDto(dto, checkChangeDate); + Contact entity = fillOrBuildEntity(dto, existingContact, checkChangeDate); doSave(entity, true); if (existingContact == null && featureConfigurationFacade.isTaskGenerationFeatureEnabled(TaskType.CONTACT_INVESTIGATION)) { @@ -390,18 +355,18 @@ public ContactDto saveContact(ContactDto dto, boolean handleChanges, boolean han if (entity.getFollowUpComment() != null) { sb.append(entity.getFollowUpComment()).append(" "); } - contactService.cancelFollowUp( + service.cancelFollowUp( entity, sb.append( I18nProperties .getString(convertedToCase ? Strings.messageSystemFollowUpCanceled : Strings.messageSystemFollowUpCanceledByDropping)) .toString()); } else { - contactService.updateFollowUpDetails( + service.updateFollowUpDetails( entity, existingContactDto != null && entity.getFollowUpStatus() != existingContactDto.getFollowUpStatus()); } - contactService.udpateContactStatus(entity); + service.udpateContactStatus(entity); if (handleCaseChanges && entity.getCaze() != null) { caseFacade.onCaseChanged(CaseFacadeEjbLocal.toDto(entity.getCaze()), entity.getCaze(), internal); @@ -489,7 +454,7 @@ public Long countContactsForMap(RegionReferenceDto regionRef, DistrictReferenceD Region region = regionService.getByReferenceDto(regionRef); District district = districtService.getByReferenceDto(districtRef); - return contactService.countContactsForMap(region, district, disease, from, to); + return service.countContactsForMap(region, district, disease, from, to); } @Override @@ -503,7 +468,7 @@ public List getContactsForMap( Region region = regionService.getByReferenceDto(regionRef); District district = districtService.getByReferenceDto(districtRef); - return contactService.getContactsForMap(region, district, disease, from, to); + return service.getContactsForMap(region, district, disease, from, to); } @Override @@ -520,13 +485,13 @@ public void deleteContact(String contactUuid) { throw new UnsupportedOperationException("User " + userService.getCurrentUser().getUuid() + " is not allowed to delete contacts."); } - Contact contact = contactService.getByUuid(contactUuid); + Contact contact = service.getByUuid(contactUuid); deleteContact(contact); } private void deleteContact(Contact contact) { externalJournalService.handleExternalJournalPersonUpdateAsync(contact.getPerson().toReference()); - contactService.delete(contact); + service.delete(contact); if (contact.getCaze() != null) { caseFacade.onCaseChanged(CaseFacadeEjbLocal.toDto(contact.getCaze()), contact.getCaze()); } @@ -537,7 +502,7 @@ public List deleteContacts(List contactUuids) { throw new UnsupportedOperationException("User " + userService.getCurrentUser().getUuid() + " is not allowed to delete contacts."); } List deletedContactUuids = new ArrayList<>(); - List contactsToBeDeleted = contactService.getByUuids(contactUuids); + List contactsToBeDeleted = service.getByUuids(contactUuids); if (contactsToBeDeleted != null) { contactsToBeDeleted.forEach(contactToBeDeleted -> { if (!contactToBeDeleted.isDeleted()) { @@ -1146,7 +1111,7 @@ public List getContactFollowUpList( } private Expression jurisdictionSelector(ContactQueryContext qc) { - return JurisdictionHelper.booleanSelector(qc.getCriteriaBuilder(), contactService.inJurisdictionOrOwned(qc)); + return JurisdictionHelper.booleanSelector(qc.getCriteriaBuilder(), service.inJurisdictionOrOwned(qc)); } @Override @@ -1180,7 +1145,7 @@ public List getIndexList(ContactCriteria contactCriteria, Integ public List getEntriesList(String personUuid, Integer first, Integer max) { Long personId = personFacade.getPersonIdByUuid(personUuid); - List entries = contactService.getEntriesList(personId, first, max); + List entries = service.getEntriesList(personId, first, max); Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight, I18nProperties.getCaption(Captions.inaccessibleValue)); pseudonymizer.pseudonymizeDtoCollection(ContactListEntryDto.class, entries, ContactListEntryDto::isInJurisdiction, null); @@ -1293,9 +1258,9 @@ public int getNonSourceCaseCountForDashboard(List caseUuids) { } - public Contact fromDto(@NotNull ContactDto source, boolean checkChangeDate) { + public Contact fillOrBuildEntity(@NotNull ContactDto source, Contact target, boolean checkChangeDate) { - Contact target = DtoHelper.fillOrBuildEntity(source, contactService.getByUuid(source.getUuid()), Contact::new, checkChangeDate); + target = DtoHelper.fillOrBuildEntity(source, target, Contact::new, checkChangeDate); target.setCaze(caseService.getByReferenceDto(source.getCaze())); target.setPerson(personService.getByReferenceDto(source.getPerson())); @@ -1427,53 +1392,45 @@ public List getContactsForDashboard( District district = districtService.getByReferenceDto(districtRef); User user = userService.getCurrentUser(); - return contactService.getContactsForDashboard(region, district, disease, from, to, user); + return service.getContactsForDashboard(region, district, disease, from, to, user); } @Override public List getByPersonUuids(List personUuids) { - return contactService.getByPersonUuids(personUuids).stream().map(ContactFacadeEjb::toDto).collect(Collectors.toList()); + return service.getByPersonUuids(personUuids).stream().map(c -> toDto(c)).collect(Collectors.toList()); } @Override public Map getNewContactCountPerStatus(ContactCriteria contactCriteria) { User user = userService.getCurrentUser(); - return contactService.getNewContactCountPerStatus(contactCriteria, user); + return service.getNewContactCountPerStatus(contactCriteria, user); } @Override public Map getNewContactCountPerClassification(ContactCriteria contactCriteria) { User user = userService.getCurrentUser(); - return contactService.getNewContactCountPerClassification(contactCriteria, user); + return service.getNewContactCountPerClassification(contactCriteria, user); } @Override public Map getNewContactCountPerFollowUpStatus(ContactCriteria contactCriteria) { User user = userService.getCurrentUser(); - return contactService.getNewContactCountPerFollowUpStatus(contactCriteria, user); + return service.getNewContactCountPerFollowUpStatus(contactCriteria, user); } @Override public int getFollowUpUntilCount(ContactCriteria contactCriteria) { User user = userService.getCurrentUser(); - return contactService.getFollowUpUntilCount(contactCriteria, user); + return service.getFollowUpUntilCount(contactCriteria, user); } - public ContactDto convertToDto(Contact source, Pseudonymizer pseudonymizer) { - - ContactDto dto = toDto(source); - pseudonymizeDto(source, dto, pseudonymizer); - - return dto; - } - - private void pseudonymizeDto(Contact source, ContactDto dto, Pseudonymizer pseudonymizer) { + public void pseudonymizeDto(Contact source, ContactDto dto, Pseudonymizer pseudonymizer) { if (dto != null) { - final ContactJurisdictionFlagsDto contactJurisdictionFlagsDto = contactService.inJurisdictionOrOwned(source); + final ContactJurisdictionFlagsDto contactJurisdictionFlagsDto = service.inJurisdictionOrOwned(source); boolean isInJurisdiction = contactJurisdictionFlagsDto.getInJurisdiction(); User currentUser = userService.getCurrentUser(); @@ -1496,14 +1453,13 @@ private void pseudonymizeDto(Contact source, ContactDto dto, Pseudonymizer pseud } } - private void restorePseudonymizedDto(ContactDto dto, Contact existingContact, ContactDto existingContactDto) { + @Override + protected void restorePseudonymizedDto(ContactDto dto, ContactDto existingContactDto, Contact existingContact, Pseudonymizer pseudonymizer) { if (existingContactDto != null) { - final ContactJurisdictionFlagsDto contactJurisdictionFlagsDto = contactService.inJurisdictionOrOwned(existingContact); + final ContactJurisdictionFlagsDto contactJurisdictionFlagsDto = service.inJurisdictionOrOwned(existingContact); boolean isInJurisdiction = contactJurisdictionFlagsDto.getInJurisdiction(); User currentUser = userService.getCurrentUser(); - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); - String followUpComment = null; if (dto.isPseudonymized() || !pseudonymizer.isAccessible(ContactDto.class, ContactDto.FOLLOW_UP_COMMENT, isInJurisdiction)) { /** @@ -1530,7 +1486,7 @@ private ContactReferenceDto convertToReferenceDto(Contact source) { ContactReferenceDto dto = toReferenceDto(source); if (source != null && dto != null) { - final ContactJurisdictionFlagsDto contactJurisdictionFlagsDto = contactService.inJurisdictionOrOwned(source); + final ContactJurisdictionFlagsDto contactJurisdictionFlagsDto = service.inJurisdictionOrOwned(source); boolean isInJurisdiction = contactJurisdictionFlagsDto.getInJurisdiction(); Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); @@ -1559,7 +1515,7 @@ public static ContactReferenceDto toReferenceDto(Contact source) { return source.toReference(); } - public static ContactDto toDto(Contact source) { + public ContactDto toDto(Contact source) { if (source == null) { return null; @@ -1666,6 +1622,11 @@ public static ContactDto toDto(Contact source) { return target; } + @Override + public ContactReferenceDto toRefDto(Contact contact) { + return convertToReferenceDto(contact); + } + @RolesAllowed(UserRole._SYSTEM) @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public void generateContactFollowUpTasks() { @@ -1673,7 +1634,7 @@ public void generateContactFollowUpTasks() { // get all contacts that are followed up LocalDateTime fromDateTime = LocalDate.now().atStartOfDay(); LocalDateTime toDateTime = fromDateTime.plusDays(1); - List contacts = contactService.getFollowUpBetween(DateHelper8.toDate(fromDateTime), DateHelper8.toDate(toDateTime)); + List contacts = service.getFollowUpBetween(DateHelper8.toDate(fromDateTime), DateHelper8.toDate(toDateTime)); for (Contact contact : contacts) { // Only generate tasks for contacts that are under follow-up @@ -1782,11 +1743,11 @@ public List getMatchingContacts(ContactSimilarityCriteria cri contactRoot.get(Contact.CONTACT_STATUS), contactRoot.get(Contact.FOLLOW_UP_STATUS))); - selections.addAll(contactService.getJurisdictionSelections(contactQueryContext)); + selections.addAll(service.getJurisdictionSelections(contactQueryContext)); cq.multiselect(selections); - final Predicate defaultFilter = contactService.createDefaultFilter(cb, contactRoot); - final Predicate userFilter = contactService.createUserFilter(cb, cq, contactRoot); + final Predicate defaultFilter = service.createDefaultFilter(cb, contactRoot); + final Predicate userFilter = service.createUserFilter(cb, cq, contactRoot); final PersonReferenceDto person = criteria.getPerson(); final Predicate samePersonFilter = person != null ? cb.equal(joins.getPerson().get(Person.UUID), person.getUuid()) : null; @@ -1808,14 +1769,14 @@ public List getMatchingContacts(ContactSimilarityCriteria cri final Date lastContactDate = criteria.getLastContactDate(); final Predicate recentContactsFilter = CriteriaBuilderHelper.and( cb, - contactService.recentDateFilter(cb, reportDate, contactRoot.get(Contact.REPORT_DATE_TIME), 30), - contactService.recentDateFilter(cb, lastContactDate, contactRoot.get(Contact.LAST_CONTACT_DATE), 30)); + service.recentDateFilter(cb, reportDate, contactRoot.get(Contact.REPORT_DATE_TIME), 30), + service.recentDateFilter(cb, lastContactDate, contactRoot.get(Contact.LAST_CONTACT_DATE), 30)); final Date relevantDate = criteria.getRelevantDate(); final Predicate relevantDateFilter = CriteriaBuilderHelper.or( cb, - contactService.recentDateFilter(cb, relevantDate, contactRoot.get(Contact.REPORT_DATE_TIME), 30), - contactService.recentDateFilter(cb, relevantDate, contactRoot.get(Contact.LAST_CONTACT_DATE), 30)); + service.recentDateFilter(cb, relevantDate, contactRoot.get(Contact.REPORT_DATE_TIME), 30), + service.recentDateFilter(cb, relevantDate, contactRoot.get(Contact.LAST_CONTACT_DATE), 30)); cq.where( CriteriaBuilderHelper.and( @@ -1849,12 +1810,12 @@ public List getMatchingContacts(ContactSimilarityCriteria cri @Override public boolean exists(String uuid) { - return this.contactService.exists(uuid); + return this.service.exists(uuid); } @Override public boolean doesExternalTokenExist(String externalToken, String contactUuid) { - return contactService.exists( + return service.exists( (cb, contactRoot, cq) -> CriteriaBuilderHelper.and( cb, cb.equal(contactRoot.get(Contact.EXTERNAL_TOKEN), externalToken), @@ -1862,17 +1823,11 @@ public boolean doesExternalTokenExist(String externalToken, String contactUuid) cb.notEqual(contactRoot.get(Contact.DELETED), Boolean.TRUE))); } - @LocalBean - @Stateless - public static class ContactFacadeEjbLocal extends ContactFacadeEjb { - - } - @Override public boolean isContactEditAllowed(String contactUuid) { - Contact contact = contactService.getByUuid(contactUuid); + Contact contact = service.getByUuid(contactUuid); - return contactService.isContactEditAllowed(contact); + return service.isContactEditAllowed(contact); } @Override @@ -1883,7 +1838,7 @@ public void mergeContact(String leadUuid, String otherUuid) { // 1 Merge Dtos // 1.1 Contact copyDtoValues(leadContactDto, otherContactDto); - saveContact(leadContactDto); + save(leadContactDto); // 1.2 Person - Only merge when the persons have different UUIDs if (!DataHelper.equal(leadContactDto.getPerson().getUuid(), otherContactDto.getPerson().getUuid())) { @@ -1893,8 +1848,8 @@ public void mergeContact(String leadUuid, String otherUuid) { } // 2 Change ContactReference - Contact leadContact = contactService.getByUuid(leadContactDto.getUuid()); - Contact otherContact = contactService.getByUuid(otherContactDto.getUuid()); + Contact leadContact = service.getByUuid(leadContactDto.getUuid()); + Contact otherContact = service.getByUuid(otherContactDto.getUuid()); // 2.1 Tasks List tasks = taskService.findBy(new TaskCriteria().contact(otherContactDto.toReference()), true); @@ -1941,10 +1896,10 @@ private void copyDtoValues(ContactDto leadContactDto, ContactDto otherContactDto @Override public void deleteContactAsDuplicate(String uuid, String duplicateOfUuid) { - Contact contact = contactService.getByUuid(uuid); - Contact duplicateOfContact = contactService.getByUuid(duplicateOfUuid); + Contact contact = service.getByUuid(uuid); + Contact duplicateOfContact = service.getByUuid(duplicateOfUuid); contact.setDuplicateOf(duplicateOfContact); - contactService.ensurePersisted(contact); + service.ensurePersisted(contact); deleteContact(uuid); } @@ -1978,8 +1933,8 @@ public List getContactsForDuplicateMerging(ContactCriter // * same birth date (when fully defined) Predicate sourceCaseFilter = cb.equal(sourceCase, sourceCase2); - Predicate userFilter = contactService.createUserFilter(cb, cq, root); - Predicate criteriaFilter = criteria != null ? contactService.buildCriteriaFilter(criteria, contactQueryContext) : null; + Predicate userFilter = service.createUserFilter(cb, cq, root); + Predicate criteriaFilter = criteria != null ? service.buildCriteriaFilter(criteria, contactQueryContext) : null; Expression nameSimilarityExpr = cb.concat(person.get(Person.FIRST_NAME), " "); nameSimilarityExpr = cb.concat(nameSimilarityExpr, person.get(Person.LAST_NAME)); Expression nameSimilarityExpr2 = cb.concat(person2.get(Person.FIRST_NAME), " "); @@ -2019,7 +1974,7 @@ public List getContactsForDuplicateMerging(ContactCriter cb.lessThanOrEqualTo(root2.get(Contact.CREATION_DATE), DateHelper.getStartOfDay(criteria.getCreationDateFrom())), cb.greaterThanOrEqualTo(root2.get(Contact.CREATION_DATE), DateHelper.getEndOfDay(criteria.getCreationDateTo())))); - Predicate filter = cb.and(contactService.createDefaultFilter(cb, root), contactService.createDefaultFilter(cb, root2), sourceCaseFilter); + Predicate filter = cb.and(service.createDefaultFilter(cb, root), service.createDefaultFilter(cb, root2), sourceCaseFilter); if (userFilter != null) { filter = cb.and(filter, userFilter); } @@ -2094,7 +2049,7 @@ private void selectMergeIndexDtoFields(CriteriaBuilder cb, CriteriaQuery externalData) throws ExternalDataUpdateException { - contactService.updateExternalData(externalData); + service.updateExternalData(externalData); } private float calculateCompleteness(Contact contact) { @@ -2156,4 +2111,18 @@ private float calculateCompleteness(Contact contact) { return completeness; } + + @LocalBean + @Stateless + public static class ContactFacadeEjbLocal extends ContactFacadeEjb { + + public ContactFacadeEjbLocal() { + } + + @Inject + public ContactFacadeEjbLocal(ContactService service, UserService userService) { + super(service, userService); + } + } + } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java index 9252467ba71..6770c5881e5 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java @@ -45,6 +45,7 @@ import javax.transaction.Transactional; import javax.validation.constraints.NotNull; +import de.symeda.sormas.backend.common.AbstractCoreAdoService; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -120,7 +121,7 @@ @Stateless @LocalBean -public class ContactService extends AbstractDeletableAdoService { +public class ContactService extends AbstractCoreAdoService { @EJB private CaseService caseService; @@ -133,8 +134,6 @@ public class ContactService extends AbstractDeletableAdoService { @EJB private EpiDataService epiDataService; @EJB - private HealthConditionsService healthConditionsService; - @EJB private SormasToSormasShareInfoService sormasToSormasShareInfoService; @EJB private ExposureService exposureService; @@ -173,7 +172,7 @@ public List findBy(ContactCriteria contactCriteria, User user) { return em.createQuery(cq).getResultList(); } - public List getAllActiveContactsAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { + public List getAllAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(getElementClass()); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateEntitiesBuilder.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateEntitiesBuilder.java index ddef7efd2cf..da172738c73 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateEntitiesBuilder.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateEntitiesBuilder.java @@ -105,7 +105,7 @@ public DocumentTemplateEntities getQuarantineOrderEntities( return buildEntities(RootEntityType.ROOT_CASE, caseDataDto, caseDataDto.getPerson(), sample, pathogenTest); case QUARANTINE_ORDER_CONTACT: - ContactDto contactDto = contactFacade.getContactByUuid(rootEntityUuid); + ContactDto contactDto = contactFacade.getByUuid(rootEntityUuid); return buildEntities(ROOT_CONTACT, contactDto, contactDto.getPerson(), sample, pathogenTest); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java index 4c594e688dd..8b4f163acf3 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java @@ -394,7 +394,7 @@ private EntityDtoAccessHelper.IReferenceDtoResolver getReferenceDtoResolver() { } else if (CaseReferenceDto.class.isAssignableFrom(referenceDtoClass)) { return caseFacade.getCaseDataByUuid(uuid); } else if (ContactReferenceDto.class.isAssignableFrom(referenceDtoClass)) { - return contactFacade.getContactByUuid(uuid); + return contactFacade.getByUuid(uuid); } else if (UserReferenceDto.class.isAssignableFrom(referenceDtoClass)) { return userFacade.getByUuid(uuid); } else if (RegionReferenceDto.class.isAssignableFrom(referenceDtoClass)) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java index f276ecd0857..b0e19672bc8 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java @@ -1081,7 +1081,7 @@ public void onPersonChanged(PersonDto existingPerson, Person newPerson, boolean // Call onContactChanged once for every contact // Attention: this may lead to infinite recursion when not properly implemented for (Contact personContact : personContacts) { - contactFacade.onContactChanged(ContactFacadeEjbLocal.toDto(personContact), syncShares); + contactFacade.onContactChanged(contactFacade.toDto(personContact), syncShares); } List personEventParticipants = diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java index 059c5479148..bfe305a05db 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java @@ -260,7 +260,7 @@ private void handleAssotiatedObjectChanges(PathogenTest pathogenTest, boolean sy // update contact if necessary Contact associatedContact = pathogenTest.getSample().getAssociatedContact(); if (associatedContact != null) { - contactFacade.onContactChanged(ContactFacadeEjbLocal.toDto(associatedContact), syncShares); + contactFacade.onContactChanged(contactFacade.toDto(associatedContact), syncShares); } // update event participant if necessary diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java index 3648dd2e912..5a7e31ded62 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java @@ -985,7 +985,7 @@ private void handleAssotiatedObjectChanges(Sample newSample, boolean syncShares) } if (newSample.getAssociatedContact() != null) { - contactFacade.onContactChanged(ContactFacadeEjbLocal.toDto(newSample.getAssociatedContact()), syncShares); + contactFacade.onContactChanged(contactFacade.toDto(newSample.getAssociatedContact()), syncShares); } EventParticipant associatedEventParticipant = newSample.getAssociatedEventParticipant(); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/contact/ProcessedContactDataPersister.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/contact/ProcessedContactDataPersister.java index c6d5bd44f70..78f0b8209ab 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/contact/ProcessedContactDataPersister.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/contact/ProcessedContactDataPersister.java @@ -71,13 +71,13 @@ private void persistProcessedData(SormasToSormasContactDto processedData, boolea Captions.Person, contactValidationGroupName); handleValidationError( - () -> contactFacade.saveContact(processedData.getEntity(), true, true, false, false), + () -> contactFacade.save(processedData.getEntity(), true, true, false, false), Captions.Contact, contactValidationGroupName); } else { //save contact first during update handleValidationError( - () -> contactFacade.saveContact(processedData.getEntity(), true, true, false, false), + () -> contactFacade.save(processedData.getEntity(), true, true, false, false), Captions.Contact, contactValidationGroupName); handleValidationError( diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/contact/ReceivedContactProcessor.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/contact/ReceivedContactProcessor.java index 0aca32b9f83..52223e62e61 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/contact/ReceivedContactProcessor.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/contact/ReceivedContactProcessor.java @@ -17,6 +17,7 @@ import java.util.Optional; +import javax.ejb.EJB; import javax.ejb.LocalBean; import javax.ejb.Stateless; import javax.inject.Inject; @@ -32,6 +33,7 @@ import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.contact.ContactFacadeEjb; import de.symeda.sormas.backend.contact.ContactService; +import de.symeda.sormas.backend.event.EventFacadeEjb; import de.symeda.sormas.backend.person.PersonFacadeEjb; import de.symeda.sormas.backend.sormastosormas.data.received.ReceivedDataProcessor; import de.symeda.sormas.backend.user.UserService; @@ -42,6 +44,10 @@ public class ReceivedContactProcessor extends ReceivedDataProcessor { + @EJB + private ContactFacadeEjb.ContactFacadeEjbLocal contactFacade; + + public ReceivedContactProcessor() { } @@ -56,7 +62,7 @@ protected ReceivedContactProcessor( @Override public void handleReceivedData(SormasToSormasContactDto sharedData, Contact existingData) { - handleIgnoredProperties(sharedData.getEntity(), ContactFacadeEjb.toDto(existingData)); + handleIgnoredProperties(sharedData.getEntity(), contactFacade.toDto(existingData)); handleIgnoredProperties( sharedData.getPerson(), Optional.ofNullable(existingData).map(c -> PersonFacadeEjb.toDto(c.getPerson())).orElse(null)); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java index 046ac1af5cd..0f83cf43ae3 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java @@ -311,7 +311,7 @@ public CaseClassificationFacadeEjb getCaseClassificationLogic() { return getBean(CaseClassificationFacadeEjb.class); } - public ContactFacade getContactFacade() { + public ContactFacadeEjbLocal getContactFacade() { return getBean(ContactFacadeEjbLocal.class); } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java index ea51163ebfb..349c29cb524 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java @@ -740,7 +740,7 @@ public ContactDto createContact( customConfig.accept(contact); } - contact = beanTest.getContactFacade().saveContact(contact); + contact = beanTest.getContactFacade().save(contact); return contact; } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java index edfe7f80d16..4f0d92e7854 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java @@ -340,7 +340,7 @@ public void testDiseaseChangeUpdatesContacts() { // Follow-up status and duration should be set to no follow-up and null // respectively because // Measles does not require a follow-up - contact = getContactFacade().getContactByUuid(contact.getUuid()); + contact = getContactFacade().getByUuid(contact.getUuid()); assertEquals(FollowUpStatus.NO_FOLLOW_UP, contact.getFollowUpStatus()); assertNull(contact.getFollowUpUntil()); } @@ -888,7 +888,7 @@ public void testCaseDeletion() throws ExternalSurveillanceToolException { // Database should contain the created case, contact, task and sample assertNotNull(getCaseFacade().getCaseDataByUuid(caze.getUuid())); - assertNotNull(getContactFacade().getContactByUuid(contact.getUuid())); + assertNotNull(getContactFacade().getByUuid(contact.getUuid())); assertNotNull(getSampleFacade().getSampleByUuid(sample.getUuid())); assertNotNull(getSampleTestFacade().getByUuid(pathogenTest.getUuid())); assertNotNull(getAdditionalTestFacade().getByUuid(additionalTest.getUuid())); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbPseudonymizationTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbPseudonymizationTest.java index 66b9f8c56ae..f8009ff9917 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbPseudonymizationTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbPseudonymizationTest.java @@ -18,6 +18,7 @@ package de.symeda.sormas.backend.contact; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.isEmptyString; import static org.hamcrest.Matchers.not; @@ -31,6 +32,7 @@ import java.util.Date; import java.util.List; +import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.runners.MockitoJUnitRunner; @@ -88,7 +90,7 @@ public void testGetContactInJurisdiction() { CaseDataDto caze = createCase(user2, rdcf2); ContactDto contact = createContact(user2, caze, rdcf2); - assertNotPseudonymized(getContactFacade().getContactByUuid(contact.getUuid()), true); + assertNotPseudonymized(getContactFacade().getByUuid(contact.getUuid()), true); } @Test @@ -106,7 +108,7 @@ public void testGetContactOutsideJurisdiction() { new Date(), Disease.CORONAVIRUS, rdcf2); - assertPseudonymized(getContactFacade().getContactByUuid(contact.getUuid())); + assertPseudonymized(getContactFacade().getByUuid(contact.getUuid())); } @Test @@ -133,7 +135,7 @@ public void testPseudonymizeGetAllAfter() { Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.YEAR, 2019); - List contacts = getContactFacade().getAllActiveContactsAfter(calendar.getTime()); + List contacts = getContactFacade().getAllAfter(calendar.getTime()); assertNotPseudonymized(contacts.stream().filter(c -> c.getUuid().equals(contact1.getUuid())).findFirst().get(), true); assertPseudonymized(contacts.stream().filter(c -> c.getUuid().equals(contact2.getUuid())).findFirst().get()); @@ -296,7 +298,7 @@ public void testUpdatePseudonymizedContact() { contact.setReportLon(null); contact.setReportLatLonAccuracy(20F); - getContactFacade().saveContact(contact); + getContactFacade().save(contact); Contact updatedContact = getContactService().getByUuid(contact.getUuid()); @@ -323,7 +325,7 @@ public void testUpdateContactInJurisdictionWithPseudonymizedDto() { contact.setReportLon(null); contact.setReportLatLonAccuracy(20F); - getContactFacade().saveContact(contact); + getContactFacade().save(contact); Contact updatedContact = getContactService().getByUuid(contact.getUuid()); @@ -341,8 +343,8 @@ private void assertNotPseudonymized(ContactDto contact, boolean caseInJurisdicti assertThat(contact.getPerson().getFirstName(), is("James")); assertThat(contact.getPerson().getLastName(), is("Smith")); - assertThat(contact.getCaze().getFirstName(), caseInJurisdiction ? is("James") : isEmptyString()); - assertThat(contact.getCaze().getLastName(), caseInJurisdiction ? is("Smith") : isEmptyString()); + assertThat(contact.getCaze().getFirstName(), caseInJurisdiction ? is("James") : equalTo(CONFIDENTIAL)); + assertThat(contact.getCaze().getLastName(), caseInJurisdiction ? is("Smith") : equalTo(CONFIDENTIAL)); // sensitive data assertThat(contact.getReportingUser().getUuid(), is(user2.getUuid())); @@ -356,11 +358,11 @@ private void assertNotPseudonymized(ContactDto contact, boolean caseInJurisdicti private void assertPseudonymized(ContactDto contact) { - assertThat(contact.getPerson().getFirstName(), isEmptyString()); - assertThat(contact.getPerson().getLastName(), isEmptyString()); + Assert.assertEquals(contact.getPerson().getFirstName(), CONFIDENTIAL); + Assert.assertEquals(contact.getPerson().getLastName(), CONFIDENTIAL); - assertThat(contact.getCaze().getFirstName(), isEmptyString()); - assertThat(contact.getCaze().getLastName(), isEmptyString()); + Assert.assertEquals(contact.getCaze().getLastName(), CONFIDENTIAL); + Assert.assertEquals(contact.getCaze().getLastName(), CONFIDENTIAL); // sensitive data assertThat(contact.getReportingUser(), is(nullValue())); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java index 1c169497229..3f001329191 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java @@ -150,7 +150,7 @@ public void testGetMatchingContacts() { ContactDto contact1 = creator.createContact(user.toReference(), user.toReference(), contactPerson.toReference(), caze, new Date(), new Date(), null); contact1.setContactClassification(ContactClassification.CONFIRMED); - getContactFacade().saveContact(contact1); + getContactFacade().save(contact1); ContactDto contact2 = creator.createContact( user.toReference(), user.toReference(), @@ -212,7 +212,7 @@ public void testUpdateContactStatus() { // drop contact.setContactClassification(ContactClassification.NO_CONTACT); - contact = getContactFacade().saveContact(contact); + contact = getContactFacade().save(contact); assertEquals(ContactStatus.DROPPED, contact.getContactStatus()); // add result case @@ -226,7 +226,7 @@ public void testUpdateContactStatus() { rdcf); contact.setContactClassification(ContactClassification.CONFIRMED); contact.setResultingCase(getCaseFacade().getReferenceByUuid(resultingCaze.getUuid())); - contact = getContactFacade().saveContact(contact); + contact = getContactFacade().save(contact); assertEquals(ContactStatus.CONVERTED, contact.getContactStatus()); } @@ -254,7 +254,7 @@ public void testContactFollowUpStatusCanceledWhenContactDropped() { contact.setContactClassification(ContactClassification.CONFIRMED); contact.setContactStatus(ContactStatus.DROPPED); - contact = getContactFacade().saveContact(contact); + contact = getContactFacade().save(contact); assertEquals(ContactClassification.CONFIRMED, contact.getContactClassification()); assertEquals(ContactStatus.DROPPED, contact.getContactStatus()); assertEquals(FollowUpStatus.CANCELED, contact.getFollowUpStatus()); @@ -284,7 +284,7 @@ public void testContactFollowUpStatusCanceledWhenContactConvertedToCase() { assertNull(contact.getResultingCase()); contact.setContactClassification(ContactClassification.CONFIRMED); - contact = getContactFacade().saveContact(contact); + contact = getContactFacade().save(contact); final CaseDataDto resultingCase = creator.createCase( user.toReference(), @@ -295,7 +295,7 @@ public void testContactFollowUpStatusCanceledWhenContactConvertedToCase() { new Date(), rdcf); contact.setResultingCase(resultingCase.toReference()); - contact = getContactFacade().saveContact(contact); + contact = getContactFacade().save(contact); assertEquals(ContactClassification.CONFIRMED, contact.getContactClassification()); assertEquals(ContactStatus.CONVERTED, contact.getContactStatus()); assertEquals(FollowUpStatus.CANCELED, contact.getFollowUpStatus()); @@ -437,7 +437,7 @@ public void testContactDeletion() { getSampleFacade().saveSample(sample2); // Database should contain the created contact, visit and task - assertNotNull(getContactFacade().getContactByUuid(contact.getUuid())); + assertNotNull(getContactFacade().getByUuid(contact.getUuid())); assertNotNull(getTaskFacade().getByUuid(task.getUuid())); assertNotNull(getVisitFacade().getVisitByUuid(visit.getUuid())); assertNotNull(getSampleFacade().getSampleByUuid(sample.getUuid())); @@ -657,11 +657,11 @@ public void updateContactJurisdictionAndCase( DistrictReferenceDto districtReferenceDto, CaseReferenceDto caze) { - ContactDto contactDto = getContactFacade().getContactByUuid(contactUuid); + ContactDto contactDto = getContactFacade().getByUuid(contactUuid); contactDto.setRegion(regionReferenceDto); contactDto.setDistrict(districtReferenceDto); contactDto.setCaze(caze); - contactDto = getContactFacade().saveContact(contactDto); + contactDto = getContactFacade().save(contactDto); } @Test @@ -871,7 +871,7 @@ public void testGetNonSourceCaseCountForDashboard() { new Date(), rdcf); contact.setResultingCase(caseWithContact.toReference()); - contact = getContactFacade().saveContact(contact); + contact = getContactFacade().save(contact); assertThat(cut.getNonSourceCaseCountForDashboard(Arrays.asList(caseWithoutContact.getUuid(), caseWithContact.getUuid())), equalTo(1)); // 3. Some more cases @@ -895,7 +895,7 @@ public void testGetNonSourceCaseCountForDashboard() { new Date(), rdcf); contact2.setResultingCase(caseWithContact2.toReference()); - contact2 = getContactFacade().saveContact(contact2); + contact2 = getContactFacade().save(contact2); ContactDto contact3 = creator.createContact(user.toReference(), person.toReference(), disease); CaseDataDto caseWithContact3 = creator.createCase( @@ -907,7 +907,7 @@ public void testGetNonSourceCaseCountForDashboard() { new Date(), rdcf); contact3.setResultingCase(caseWithContact3.toReference()); - contact3 = getContactFacade().saveContact(contact3); + contact3 = getContactFacade().save(contact3); assertThat( cut.getNonSourceCaseCountForDashboard( @@ -968,9 +968,9 @@ public void testCreatedContactExistWhenValidatedByUUID() { creator.createContact(user.toReference(), user.toReference(), contactPerson.toReference(), caze, new Date(), new Date(), null); // database contains the created contact - assertEquals(true, getContactFacade().isValidContactUuid(contact.getUuid())); + assertEquals(true, getContactFacade().exists(contact.getUuid())); // database contains the created contact - assertEquals(false, getContactFacade().isValidContactUuid("nonExistingContactUUID")); + assertEquals(false, getContactFacade().exists("nonExistingContactUUID")); } @Test @@ -1009,7 +1009,7 @@ public void testGetExportList() { travels.add(exposure); epiData.setExposures(travels); contact.setEpiData(epiData); - getContactFacade().saveContact(contact); + getContactFacade().save(contact); contactPerson.getAddress().setRegion(new RegionReferenceDto(rdcf.region.getUuid(), null, null)); contactPerson.getAddress().setDistrict(new DistrictReferenceDto(rdcf.district.getUuid(), null, null)); @@ -1280,7 +1280,7 @@ public void testArchiveOrDearchiveContact() { when(MockProducer.getPrincipal().getName()).thenReturn("SurvSup"); // getAllActiveContacts and getAllUuids should return length 1 - assertEquals(1, getContactFacade().getAllActiveContactsAfter(null).size()); + assertEquals(1, getContactFacade().getAllAfter(null).size()); assertEquals(1, getContactFacade().getAllActiveUuids().size()); assertEquals(1, getVisitFacade().getAllActiveVisitsAfter(null).size()); assertEquals(1, getVisitFacade().getAllActiveUuids().size()); @@ -1288,7 +1288,7 @@ public void testArchiveOrDearchiveContact() { getCaseFacade().archiveOrDearchiveCase(caze.getUuid(), true); // getAllActiveContacts and getAllUuids should return length 0 - assertEquals(0, getContactFacade().getAllActiveContactsAfter(null).size()); + assertEquals(0, getContactFacade().getAllAfter(null).size()); assertEquals(0, getContactFacade().getAllActiveUuids().size()); assertEquals(0, getVisitFacade().getAllActiveVisitsAfter(null).size()); assertEquals(0, getVisitFacade().getAllActiveUuids().size()); @@ -1296,7 +1296,7 @@ public void testArchiveOrDearchiveContact() { getCaseFacade().archiveOrDearchiveCase(caze.getUuid(), false); // getAllActiveContacts and getAllUuids should return length 1 - assertEquals(1, getContactFacade().getAllActiveContactsAfter(null).size()); + assertEquals(1, getContactFacade().getAllAfter(null).size()); assertEquals(1, getContactFacade().getAllActiveUuids().size()); assertEquals(1, getVisitFacade().getAllActiveVisitsAfter(null).size()); assertEquals(1, getVisitFacade().getAllActiveUuids().size()); @@ -1317,19 +1317,19 @@ public void testUpdateContactVisitAssociations() { // Updating the contact but not changing the report date or last contact date should not alter the association contact.setDescription("Description"); - getContactFacade().saveContact(contact); + getContactFacade().save(contact); assertThat(getVisitService().getAllByContact(contactEntity), hasSize(1)); // Changing the report date to a value beyond the threshold should remove the association contact.setReportDateTime(DateHelper.addDays(visit.getVisitDateTime(), FollowUpLogic.ALLOWED_DATE_OFFSET + 20)); - getContactFacade().saveContact(contact); + getContactFacade().save(contact); assertThat(getVisitService().getAllByContact(contactEntity), empty()); // Changing the report date back to a value in the threshold should re-add the association contact.setReportDateTime(new Date()); - getContactFacade().saveContact(contact); + getContactFacade().save(contact); assertThat(getVisitService().getAllByContact(contactEntity), hasSize(1)); @@ -1355,7 +1355,7 @@ public void testUpdateContactVisitAssociations() { // Changing the contact disease should decrease the collection size contact2.setDisease(Disease.CSM); - getContactFacade().saveContact(contact2); + getContactFacade().save(contact2); assertThat(getContactService().getAllByVisit(visitEntity), hasSize(1)); } @@ -1366,7 +1366,7 @@ public void testSearchContactsWithExtendedQuarantine() { ContactDto contact = creator.createContact(creator.createUser(rdcf, UserRole.SURVEILLANCE_OFFICER).toReference(), creator.createPerson().toReference()); contact.setQuarantineExtended(true); - getContactFacade().saveContact(contact); + getContactFacade().save(contact); List indexList = getContactFacade().getIndexList(new ContactCriteria(), 0, 100, Collections.emptyList()); assertThat(indexList.get(0).getUuid(), is(contact.getUuid())); @@ -1384,7 +1384,7 @@ public void testSearchContactsWithReducedQuarantine() { ContactDto contact = creator.createContact(creator.createUser(rdcf, UserRole.SURVEILLANCE_OFFICER).toReference(), creator.createPerson().toReference()); contact.setQuarantineReduced(true); - getContactFacade().saveContact(contact); + getContactFacade().save(contact); List indexList = getContactFacade().getIndexList(new ContactCriteria(), 0, 100, Collections.emptyList()); assertThat(indexList.get(0).getUuid(), is(contact.getUuid())); @@ -1409,7 +1409,7 @@ public void testCreateWithoutUuid() { contact.setDistrict(rdcf.district); contact.setHealthConditions(new HealthConditionsDto()); - ContactDto savedContact = getContactFacade().saveContact(contact); + ContactDto savedContact = getContactFacade().save(contact); assertThat(savedContact.getUuid(), not(isEmptyOrNullString())); assertThat(savedContact.getHealthConditions().getUuid(), not(isEmptyOrNullString())); @@ -1421,10 +1421,10 @@ public void testGetContactsByPersonUuids() { UserReferenceDto user = creator.createUser(creator.createRDCFEntities(), UserRole.SURVEILLANCE_SUPERVISOR).toReference(); PersonReferenceDto person1 = creator.createPerson().toReference(); - ContactDto contact1 = getContactFacade().saveContact(creator.createContact(user, person1)); + ContactDto contact1 = getContactFacade().save(creator.createContact(user, person1)); PersonReferenceDto person2 = creator.createPerson().toReference(); - ContactDto contact2 = getContactFacade().saveContact(creator.createContact(user, person2)); + ContactDto contact2 = getContactFacade().save(creator.createContact(user, person2)); List contactsByPerson = getContactFacade().getByPersonUuids(Collections.singletonList(person1.getUuid())); @@ -1476,7 +1476,7 @@ public void testMergeContact() throws IOException { c.setAdditionalDetails("Test additional details"); c.setFollowUpComment("Test followup comment"); }); - getContactFacade().saveContact(leadContact); + getContactFacade().save(leadContact); VisitDto leadVisit = creator.createVisit(leadContact.getDisease(), leadContact.getPerson(), leadContact.getReportDateTime()); getVisitFacade().saveVisit(leadVisit); @@ -1521,7 +1521,7 @@ public void testMergeContact() throws IOException { new EventReferenceDto(), new Date(), otherUserReference); - getContactFacade().saveContact(otherContact); + getContactFacade().save(otherContact); VisitDto otherVisit = creator.createVisit(otherContact.getDisease(), otherContact.getPerson(), otherContact.getReportDateTime()); otherVisit.getSymptoms().setAbdominalPain(SymptomState.YES); getVisitFacade().saveVisit(otherVisit); @@ -1549,7 +1549,7 @@ public void testMergeContact() throws IOException { // 3. Test - ContactDto mergedContact = getContactFacade().getContactByUuid(leadContact.getUuid()); + ContactDto mergedContact = getContactFacade().getByUuid(leadContact.getUuid()); PersonDto mergedPerson = getPersonFacade().getPersonByUuid(mergedContact.getPerson().getUuid()); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactServiceTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactServiceTest.java index c166c94bd9c..857f326e4e3 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactServiceTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactServiceTest.java @@ -67,13 +67,13 @@ public void testGetAllRelevantContacts() { // Contacts with a report/last contact date after the reference date should not be included ContactDto contact1 = creator.createContact(user.toReference(), contactPerson.toReference()); contact1.setReportDateTime(DateHelper.addDays(referenceDate, FollowUpLogic.ALLOWED_DATE_OFFSET + 1)); - contact1 = getContactFacade().saveContact(contact1); + contact1 = getContactFacade().save(contact1); ContactDto contact2 = creator.createContact(user.toReference(), contactPerson.toReference()); contact2.setReportDateTime(referenceDate); contact2.setFirstContactDate(DateHelper.addDays(referenceDate, FollowUpLogic.ALLOWED_DATE_OFFSET)); contact2.setLastContactDate(DateHelper.addDays(referenceDate, FollowUpLogic.ALLOWED_DATE_OFFSET + 1)); - contact2 = getContactFacade().saveContact(contact2); + contact2 = getContactFacade().save(contact2); Set contacts = getContactService().getAllRelevantContacts(contactPersonEntity, contact1.getDisease(), referenceDate); assertThat(contacts, empty()); @@ -81,8 +81,8 @@ public void testGetAllRelevantContacts() { // Contacts with a report/last contact date after the reference date but within the offset should be included contact1.setReportDateTime(DateHelper.addDays(referenceDate, FollowUpLogic.ALLOWED_DATE_OFFSET)); contact2.setLastContactDate(DateHelper.addDays(referenceDate, FollowUpLogic.ALLOWED_DATE_OFFSET)); - contact1 = getContactFacade().saveContact(contact1); - contact2 = getContactFacade().saveContact(contact2); + contact1 = getContactFacade().save(contact1); + contact2 = getContactFacade().save(contact2); contacts = getContactService().getAllRelevantContacts(contactPersonEntity, contact1.getDisease(), referenceDate); assertThat(contacts, hasSize(2)); @@ -90,8 +90,8 @@ public void testGetAllRelevantContacts() { // Contacts with a report/last contact date before the reference date should be included contact1.setReportDateTime(DateHelper.subtractDays(referenceDate, FollowUpLogic.ALLOWED_DATE_OFFSET + 1)); contact2.setLastContactDate(DateHelper.subtractDays(referenceDate, FollowUpLogic.ALLOWED_DATE_OFFSET + 1)); - contact1 = getContactFacade().saveContact(contact1); - contact2 = getContactFacade().saveContact(contact2); + contact1 = getContactFacade().save(contact1); + contact2 = getContactFacade().save(contact2); contacts = getContactService().getAllRelevantContacts(contactPersonEntity, contact1.getDisease(), referenceDate); assertThat(contacts, hasSize(2)); @@ -99,8 +99,8 @@ public void testGetAllRelevantContacts() { // Contacts with a follow-up until date after the reference date should be included contact1.setFollowUpUntil(DateHelper.addDays(referenceDate, FollowUpLogic.ALLOWED_DATE_OFFSET + 1)); contact2.setFollowUpUntil(DateHelper.addDays(referenceDate, FollowUpLogic.ALLOWED_DATE_OFFSET + 1)); - contact1 = getContactFacade().saveContact(contact1); - contact2 = getContactFacade().saveContact(contact2); + contact1 = getContactFacade().save(contact1); + contact2 = getContactFacade().save(contact2); contacts = getContactService().getAllRelevantContacts(contactPersonEntity, contact1.getDisease(), referenceDate); assertThat(contacts, hasSize(2)); @@ -112,8 +112,8 @@ public void testGetAllRelevantContacts() { contact2.setReportDateTime(DateHelper.subtractDays(referenceDate, FollowUpLogic.ALLOWED_DATE_OFFSET * 2)); contact2.setLastContactDate(DateHelper.subtractDays(referenceDate, FollowUpLogic.ALLOWED_DATE_OFFSET * 2)); contact2.setFollowUpUntil(DateHelper.subtractDays(referenceDate, FollowUpLogic.ALLOWED_DATE_OFFSET * 2)); - contact1 = getContactFacade().saveContact(contact1); - contact2 = getContactFacade().saveContact(contact2); + contact1 = getContactFacade().save(contact1); + contact2 = getContactFacade().save(contact2); contacts = getContactService().getAllRelevantContacts(contactPersonEntity, contact1.getDisease(), referenceDate); assertThat(contacts, empty()); @@ -122,11 +122,11 @@ public void testGetAllRelevantContacts() { PersonDto contactPerson2 = creator.createPerson(); ContactDto contact3 = creator.createContact(user.toReference(), contactPerson2.toReference()); contact3.setReportDateTime(referenceDate); - contact3 = getContactFacade().saveContact(contact3); + contact3 = getContactFacade().save(contact3); ContactDto contact4 = creator.createContact(user.toReference(), contactPerson.toReference(), Disease.CSM); contact4.setReportDateTime(referenceDate); - contact4 = getContactFacade().saveContact(contact4); + contact4 = getContactFacade().save(contact4); contacts = getContactService().getAllRelevantContacts(contactPersonEntity, contact1.getDisease(), referenceDate); assertThat(contacts, empty()); @@ -162,7 +162,7 @@ public void testUpdateFollowUpUntilAndStatus() { VisitOrigin.USER); // Follow-up until should be increased by one day - contact = getContactFacade().getContactByUuid(contact.getUuid()); + contact = getContactFacade().getByUuid(contact.getUuid()); assertEquals(FollowUpStatus.FOLLOW_UP, contact.getFollowUpStatus()); assertEquals(LocalDate.now().plusDays(21 + 1), DateHelper8.toLocalDate(contact.getFollowUpUntil())); @@ -170,14 +170,14 @@ public void testUpdateFollowUpUntilAndStatus() { visit = getVisitFacade().saveVisit(visit); // Follow-up until should be back at the original date and follow-up should be completed - contact = getContactFacade().getContactByUuid(contact.getUuid()); + contact = getContactFacade().getByUuid(contact.getUuid()); assertEquals(FollowUpStatus.COMPLETED, contact.getFollowUpStatus()); assertEquals(LocalDate.now().plusDays(21), DateHelper8.toLocalDate(contact.getFollowUpUntil())); // Manually overwrite and increase the follow-up until date contact.setFollowUpUntil(DateUtils.addDays(new Date(), 23)); contact.setOverwriteFollowUpUntil(true); - contact = getContactFacade().saveContact(contact); + contact = getContactFacade().save(contact); assertEquals(FollowUpStatus.FOLLOW_UP, contact.getFollowUpStatus()); assertTrue(contact.isOverwriteFollowUpUntil()); @@ -185,7 +185,7 @@ public void testUpdateFollowUpUntilAndStatus() { visit.setVisitStatus(VisitStatus.UNAVAILABLE); visit.setVisitDateTime(contact.getFollowUpUntil()); getVisitFacade().saveVisit(visit); - contact = getContactFacade().getContactByUuid(contact.getUuid()); + contact = getContactFacade().getByUuid(contact.getUuid()); assertEquals(FollowUpStatus.FOLLOW_UP, contact.getFollowUpStatus()); creator.createVisit( caze.getDisease(), @@ -193,20 +193,20 @@ public void testUpdateFollowUpUntilAndStatus() { DateUtils.addDays(new Date(), 24), VisitStatus.COOPERATIVE, VisitOrigin.USER); - contact = getContactFacade().getContactByUuid(contact.getUuid()); + contact = getContactFacade().getByUuid(contact.getUuid()); assertEquals(FollowUpStatus.COMPLETED, contact.getFollowUpStatus()); assertFalse(contact.isOverwriteFollowUpUntil()); // Increasing the last contact date should extend follow-up contact.setLastContactDate(DateHelper.addDays(contact.getLastContactDate(), 10)); - contact = getContactFacade().saveContact(contact); + contact = getContactFacade().save(contact); assertEquals(FollowUpStatus.FOLLOW_UP, contact.getFollowUpStatus()); assertEquals(LocalDate.now().plusDays(21 + 10), DateHelper8.toLocalDate(contact.getFollowUpUntil())); PersonDto person2 = creator.createPerson(); ContactDto contact2 = creator.createContact(user.toReference(), person2.toReference()); contact2.setContactStatus(ContactStatus.CONVERTED); - contact2 = getContactFacade().saveContact(contact2); + contact2 = getContactFacade().save(contact2); // Follow-up should be canceled when contact is converted to a case and should have a generated follow-up comment assertThat(contact2.getFollowUpStatus(), is(FollowUpStatus.CANCELED)); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjbTest.java index 12e643f7989..8756d7a1750 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjbTest.java @@ -125,7 +125,7 @@ public void setup() throws URISyntaxException { contactDto.setQuarantineFrom(parseDate("10/09/2020")); contactDto.setQuarantineTo(parseDate("24/09/2020")); contactDto.setQuarantineOrderedOfficialDocumentDate(parseDate("09/09/2020")); - getContactFacade().saveContact(contactDto); + getContactFacade().save(contactDto); EventDto eventDto = creator.createEvent(userDto.toReference()); eventDto.setEventTitle("An event"); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbPseudonymizationTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbPseudonymizationTest.java index 777ce7be98e..6da05a294e0 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbPseudonymizationTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbPseudonymizationTest.java @@ -247,7 +247,7 @@ public void testGetContactPersonOutsideJurisdiction() { loginWith(districtUser1); CaseDataDto caze = creator.createCase(districtUser1.toReference(), creator.createPerson().toReference(), rdcf2); contact.setCaze(caze.toReference()); - contact = getContactFacade().saveContact(contact); + contact = getContactFacade().save(contact); loginWith(districtUser2); assertNotPseudonymized(getPersonFacade().getPersonByUuid(person.getUuid())); @@ -255,7 +255,7 @@ public void testGetContactPersonOutsideJurisdiction() { loginWith(districtUser1); contact.setRegion(rdcf2.region); contact.setDistrict(rdcf2.district); - contact = getContactFacade().saveContact(contact); + contact = getContactFacade().save(contact); loginWith(districtUser2); assertNotPseudonymized(getPersonFacade().getPersonByUuid(person.getUuid())); @@ -263,7 +263,7 @@ public void testGetContactPersonOutsideJurisdiction() { loginWith(districtUser1); contact.setRegion(null); contact.setDistrict(null); - contact = getContactFacade().saveContact(contact); + contact = getContactFacade().save(contact); loginWith(districtUser2); assertNotPseudonymized(getPersonFacade().getPersonByUuid(person.getUuid())); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java index 32fe8460cb4..46fbd5e9e59 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java @@ -451,9 +451,9 @@ public void testGetFollowUpEndDatesContactsOnly() { contact12.setFollowUpUntil(DateHelper.subtractDays(now, 8)); contact2.setFollowUpUntil(now); - getContactFacade().saveContact(contact11); - getContactFacade().saveContact(contact12); - getContactFacade().saveContact(contact2); + getContactFacade().save(contact11); + getContactFacade().save(contact12); + getContactFacade().save(contact2); List followUpEndDtos = getPersonFacade().getLatestFollowUpEndDates(null, false); @@ -502,8 +502,8 @@ public void testGetPersonForJournal() { contact2.setFollowUpUntil(DateHelper.subtractDays(now, 8)); getPersonFacade().savePerson(person); - getContactFacade().saveContact(contact1); - getContactFacade().saveContact(contact2); + getContactFacade().save(contact1); + getContactFacade().save(contact2); JournalPersonDto exportPerson = getPersonFacade().getPersonForJournal(person.getUuid()); assertEquals(person.getFirstName(), exportPerson.getFirstName()); @@ -606,10 +606,10 @@ public void testGetFollowUpEndDatesContactsAndCases() { case5.setFollowUpStatus(FollowUpStatus.CANCELED); contact4.setFollowUpUntil(now); - getContactFacade().saveContact(contact1); - getContactFacade().saveContact(contact2); - getContactFacade().saveContact(contact3); - getContactFacade().saveContact(contact4); + getContactFacade().save(contact1); + getContactFacade().save(contact2); + getContactFacade().save(contact3); + getContactFacade().save(contact4); getCaseFacade().saveCase(case1); getCaseFacade().saveCase(case2); getCaseFacade().saveCase(case3); @@ -643,7 +643,7 @@ public void testGetPersonsAfter() throws InterruptedException { PersonDto person1 = creator.createPerson(); person1 = getPersonFacade().savePerson(person1); final ContactDto contact1 = creator.createContact(natUser.toReference(), person1.toReference()); - getContactFacade().saveContact(contact1); + getContactFacade().save(contact1); List personsAfterT1 = getPersonFacade().getPersonsAfter(t1); assertEquals(1, personsAfterT1.size()); @@ -654,7 +654,7 @@ public void testGetPersonsAfter() throws InterruptedException { PersonDto person2 = creator.createPerson(); person2 = getPersonFacade().savePerson(person2); final ContactDto contact2 = creator.createContact(natUser.toReference(), person2.toReference()); - getContactFacade().saveContact(contact2); + getContactFacade().save(contact2); List personsAfterT2 = getPersonFacade().getPersonsAfter(t2); assertEquals(1, personsAfterT2.size()); @@ -733,7 +733,7 @@ public void testGetMostRelevantFollowUpStatusByUuid() { for (FollowUpStatus status : FollowUpStatus.values()) { contact1.setFollowUpStatus(status); - getContactFacade().saveContact(contact1); + getContactFacade().save(contact1); if (FollowUpStatus.COMPLETED.equals(status) || FollowUpStatus.NO_FOLLOW_UP.equals(status)) { // In this case the status is automatically updated to FOLLOW_UP, because the end of the follow up period has not yet been reached. @@ -805,9 +805,9 @@ public void testMergePerson() { } private void updateFollowUpStatus(ContactDto contact, FollowUpStatus status) { - contact = getContactFacade().getContactByUuid(contact.getUuid()); + contact = getContactFacade().getByUuid(contact.getUuid()); contact.setFollowUpStatus(status); - getContactFacade().saveContact(contact); + getContactFacade().save(contact); } private void updateFollowUpStatus(CaseDataDto caze, FollowUpStatus status) { diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbUserFilterTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbUserFilterTest.java index 5957f141e23..15e6fd12cd5 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbUserFilterTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbUserFilterTest.java @@ -146,12 +146,12 @@ public void testGetPersonIndexListPersonNotIncludedIfContactOutsideJurisdiction( creator.createContact(nationalUser.toReference(), null, person1.toReference(), caze, new Date(), new Date(), Disease.CORONAVIRUS, rdcf1); contactInJurisdiction1.setRegion(rdcf1.region); contactInJurisdiction1.setDistrict(rdcf1.district); - getContactFacade().saveContact(contactInJurisdiction1); + getContactFacade().save(contactInJurisdiction1); ContactDto contactInJurisdiction2 = creator.createContact(nationalUser.toReference(), null, person2.toReference(), caze, new Date(), new Date(), Disease.CORONAVIRUS, rdcf2); contactInJurisdiction2.setRegion(rdcf2.region); contactInJurisdiction2.setDistrict(rdcf2.district); - getContactFacade().saveContact(contactInJurisdiction2); + getContactFacade().save(contactInJurisdiction2); loginWith(districtUser1); List indexListForDistrictUser1 = getPersonFacade().getIndexList(null, null, null, null); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/sormastosormas/entities/SormasToSormasCaseFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/sormastosormas/entities/SormasToSormasCaseFacadeEjbTest.java index c3251325732..4597f94a7aa 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/sormastosormas/entities/SormasToSormasCaseFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/sormastosormas/entities/SormasToSormasCaseFacadeEjbTest.java @@ -445,7 +445,7 @@ public void testSaveSharedCaseWithContacts() throws SormasToSormasException, Sor getSormasToSormasCaseFacade().saveSharedEntities(encryptedData); CaseDataDto savedCase = getCaseFacade().getCaseDataByUuid(caze.getUuid()); - ContactDto savedContact = getContactFacade().getContactByUuid(contact.getUuid()); + ContactDto savedContact = getContactFacade().getByUuid(contact.getUuid()); assertThat(savedContact, is(notNullValue())); assertThat(savedContact.getRegion(), is(rdcf.region)); @@ -623,7 +623,7 @@ public void testReturnCase() throws SormasToSormasException { assertThat(sharedCase.getSormasToSormasOriginInfo().isOwnershipHandedOver(), is(false)); // contact ownership should be lost - sharedContact = getContactFacade().getContactByUuid(sharedContact.getUuid()); + sharedContact = getContactFacade().getByUuid(sharedContact.getUuid()); assertThat(sharedContact.getSormasToSormasOriginInfo().isOwnershipHandedOver(), is(false)); // sample ownership should be lost @@ -706,10 +706,10 @@ public void testSaveReturnedCase() throws SormasToSormasException { getSormasToSormasShareInfoFacade().getIndexList(new SormasToSormasShareInfoCriteria().contact(sharedContact.toReference()), 0, 100); assertThat(contactShares.get(0).isOwnershipHandedOver(), is(false)); - ContactDto returnedNewContact = getContactFacade().getContactByUuid(newContact.getUuid()); + ContactDto returnedNewContact = getContactFacade().getByUuid(newContact.getUuid()); assertThat(returnedNewContact.getSormasToSormasOriginInfo().isOwnershipHandedOver(), is(true)); - ContactDto returnedNewContact2 = getContactFacade().getContactByUuid(newContact.getUuid()); + ContactDto returnedNewContact2 = getContactFacade().getByUuid(newContact.getUuid()); assertThat(returnedNewContact2.getSormasToSormasOriginInfo().isOwnershipHandedOver(), is(true)); List sampleShares = diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/sormastosormas/entities/SormasToSormasContactFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/sormastosormas/entities/SormasToSormasContactFacadeEjbTest.java index 67ca7446246..d44a01ca069 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/sormastosormas/entities/SormasToSormasContactFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/sormastosormas/entities/SormasToSormasContactFacadeEjbTest.java @@ -205,7 +205,7 @@ public void testSaveSharedContact() throws SormasToSormasException, SormasToSorm SormasToSormasEncryptedDataDto encryptedData = encryptShareData(shareData); getSormasToSormasContactFacade().saveSharedEntities(encryptedData); - ContactDto savedContact = getContactFacade().getContactByUuid(contact.getUuid()); + ContactDto savedContact = getContactFacade().getByUuid(contact.getUuid()); assertThat(savedContact, is(notNullValue())); assertThat(savedContact.getRegion(), is(rdcf.region)); @@ -241,7 +241,7 @@ public void testSaveSharedContactWithSamples() throws SormasToSormasException, S SormasToSormasEncryptedDataDto encryptedData = encryptShareData(shareData); getSormasToSormasContactFacade().saveSharedEntities(encryptedData); - ContactDto savedContact = getContactFacade().getContactByUuid(contact.getUuid()); + ContactDto savedContact = getContactFacade().getByUuid(contact.getUuid()); SampleDto savedSample = getSampleFacade().getSampleByUuid(sample.getEntity().getUuid()); assertThat(savedSample, is(notNullValue())); @@ -294,7 +294,7 @@ public void testReturnContact() throws SormasToSormasException { getSormasToSormasContactFacade().share(Collections.singletonList(contact.getUuid()), options); // contact ownership should be lost - ContactDto sharedContact = getContactFacade().getContactByUuid(contact.getUuid()); + ContactDto sharedContact = getContactFacade().getByUuid(contact.getUuid()); assertThat(sharedContact.getSormasToSormasOriginInfo().isOwnershipHandedOver(), is(false)); // sample ownership should be lost @@ -344,7 +344,7 @@ public void testSaveReturnedContact() throws SormasToSormasException, SormasToSo getSormasToSormasContactFacade().saveSharedEntities(encryptedData); - ContactDto returnedContact = getContactFacade().getContactByUuid(contact.getUuid()); + ContactDto returnedContact = getContactFacade().getByUuid(contact.getUuid()); assertThat(returnedContact.getQuarantine(), is(QuarantineType.HOTEL)); assertThat(returnedContact.getReportingUser(), is(officer)); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/vaccination/VaccinationFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/vaccination/VaccinationFacadeEjbTest.java index 2d5a076d0db..7b71472b14d 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/vaccination/VaccinationFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/vaccination/VaccinationFacadeEjbTest.java @@ -324,10 +324,10 @@ public void testUpdateVaccinationStatuses() { assertNull(getCaseFacade().getByUuid(case12.getUuid()).getVaccinationStatus()); assertNull(getCaseFacade().getByUuid(case2.getUuid()).getVaccinationStatus()); assertNull(getCaseFacade().getByUuid(case3.getUuid()).getVaccinationStatus()); - assertNull(getContactFacade().getContactByUuid(contact11.getUuid()).getVaccinationStatus()); - assertNull(getContactFacade().getContactByUuid(contact12.getUuid()).getVaccinationStatus()); - assertNull(getContactFacade().getContactByUuid(contact2.getUuid()).getVaccinationStatus()); - assertNull(getContactFacade().getContactByUuid(contact3.getUuid()).getVaccinationStatus()); + assertNull(getContactFacade().getByUuid(contact11.getUuid()).getVaccinationStatus()); + assertNull(getContactFacade().getByUuid(contact12.getUuid()).getVaccinationStatus()); + assertNull(getContactFacade().getByUuid(contact2.getUuid()).getVaccinationStatus()); + assertNull(getContactFacade().getByUuid(contact3.getUuid()).getVaccinationStatus()); assertNull(getEventParticipantFacade().getByUuid(ep111.getUuid()).getVaccinationStatus()); assertNull(getEventParticipantFacade().getByUuid(ep112.getUuid()).getVaccinationStatus()); assertNull(getEventParticipantFacade().getByUuid(ep121.getUuid()).getVaccinationStatus()); @@ -342,8 +342,8 @@ public void testUpdateVaccinationStatuses() { assertNull(getCaseFacade().getByUuid(case11.getUuid()).getVaccinationStatus()); assertThat(getCaseFacade().getByUuid(case12.getUuid()).getVaccinationStatus(), is(VaccinationStatus.VACCINATED)); - assertNull(getContactFacade().getContactByUuid(contact11.getUuid()).getVaccinationStatus()); - assertThat(getContactFacade().getContactByUuid(contact12.getUuid()).getVaccinationStatus(), is(VaccinationStatus.VACCINATED)); + assertNull(getContactFacade().getByUuid(contact11.getUuid()).getVaccinationStatus()); + assertThat(getContactFacade().getByUuid(contact12.getUuid()).getVaccinationStatus(), is(VaccinationStatus.VACCINATED)); assertNull(getEventParticipantFacade().getByUuid(ep111.getUuid()).getVaccinationStatus()); assertNull(getEventParticipantFacade().getByUuid(ep121.getUuid()).getVaccinationStatus()); assertNull(getEventParticipantFacade().getByUuid(ep131.getUuid()).getVaccinationStatus()); @@ -355,7 +355,7 @@ public void testUpdateVaccinationStatuses() { getVaccinationFacade().createWithImmunization(vaccination3, rdcf1.region, rdcf1.district, person1.toReference(), Disease.EVD); assertThat(getCaseFacade().getByUuid(case11.getUuid()).getVaccinationStatus(), is(VaccinationStatus.VACCINATED)); - assertThat(getContactFacade().getContactByUuid(contact11.getUuid()).getVaccinationStatus(), is(VaccinationStatus.VACCINATED)); + assertThat(getContactFacade().getByUuid(contact11.getUuid()).getVaccinationStatus(), is(VaccinationStatus.VACCINATED)); assertNull(getEventParticipantFacade().getByUuid(ep111.getUuid()).getVaccinationStatus()); assertThat(getEventParticipantFacade().getByUuid(ep121.getUuid()).getVaccinationStatus(), is(VaccinationStatus.VACCINATED)); assertThat(getEventParticipantFacade().getByUuid(ep131.getUuid()).getVaccinationStatus(), is(VaccinationStatus.VACCINATED)); diff --git a/sormas-rest/src/main/java/de/symeda/sormas/rest/ContactResource.java b/sormas-rest/src/main/java/de/symeda/sormas/rest/ContactResource.java index dd70465b601..6405d53ee82 100644 --- a/sormas-rest/src/main/java/de/symeda/sormas/rest/ContactResource.java +++ b/sormas-rest/src/main/java/de/symeda/sormas/rest/ContactResource.java @@ -135,7 +135,7 @@ public List delete(List uuids) { @GET @Path("/{uuid}") public ContactDto getByUuid(@PathParam("uuid") String uuid) { - return FacadeProvider.getContactFacade().getContactByUuid(uuid); + return FacadeProvider.getContactFacade().getByUuid(uuid); } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java index 0c36a16c4d9..eccb1dd2055 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java @@ -230,7 +230,7 @@ public void createFromContact(ContactDto contact) { if (uuid == null) { CommitDiscardWrapperComponent caseCreateComponent = getCaseCreateComponent(contact, null, null, null, false); caseCreateComponent.addCommitListener(() -> { - ContactDto contactDto = FacadeProvider.getContactFacade().getContactByUuid(contact.getUuid()); + ContactDto contactDto = FacadeProvider.getContactFacade().getByUuid(contact.getUuid()); if (contactDto.getResultingCase() != null) { String caseUuid = contactDto.getResultingCase().getUuid(); CaseDataDto caze = FacadeProvider.getCaseFacade().getCaseDataByUuid(caseUuid); @@ -245,11 +245,11 @@ public void createFromContact(ContactDto contact) { selectedCase.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); FacadeProvider.getCaseFacade().saveCase(selectedCase); - ContactDto updatedContact = FacadeProvider.getContactFacade().getContactByUuid(contact.getUuid()); + ContactDto updatedContact = FacadeProvider.getContactFacade().getByUuid(contact.getUuid()); updatedContact.setContactStatus(ContactStatus.CONVERTED); updatedContact.setResultingCase(selectedCase.toReference()); updatedContact.setResultingCaseUser(UserProvider.getCurrent().getUserReference()); - FacadeProvider.getContactFacade().saveContact(updatedContact); + FacadeProvider.getContactFacade().save(updatedContact); FacadeProvider.getCaseFacade().setSampleAssociations(updatedContact.toReference(), selectedCase.toReference()); @@ -385,7 +385,7 @@ private void setResultingCase( contact.setContactStatus(ContactStatus.CONVERTED); contact.setResultingCase(caze.toReference()); contact.setResultingCaseUser(UserProvider.getCurrent().getUserReference()); - FacadeProvider.getContactFacade().saveContact(contact); + FacadeProvider.getContactFacade().save(contact); } } @@ -664,12 +664,12 @@ public CommitDiscardWrapperComponent getCaseCreateComponent( saveCase(dto); // retrieve the contact just in case it has been changed during case saving - ContactDto updatedContact = FacadeProvider.getContactFacade().getContactByUuid(convertedContact.getUuid()); + ContactDto updatedContact = FacadeProvider.getContactFacade().getByUuid(convertedContact.getUuid()); // automatically change the contact status to "converted" updatedContact.setContactStatus(ContactStatus.CONVERTED); // set resulting case on contact and save it updatedContact.setResultingCase(dto.toReference()); - FacadeProvider.getContactFacade().saveContact(updatedContact); + FacadeProvider.getContactFacade().save(updatedContact); FacadeProvider.getCaseFacade().setSampleAssociations(updatedContact.toReference(), dto.toReference()); Notification.show(I18nProperties.getString(Strings.messageCaseCreated), Type.ASSISTIVE_NOTIFICATION); if (!createdFromLabMessage) { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/DevModeView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/DevModeView.java index c3e9600b648..3d189cd5e5d 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/DevModeView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/DevModeView.java @@ -1209,7 +1209,7 @@ private void generateContacts() { contact.setDescription("Contact generated using DevMode on " + LocalDate.now()); FacadeProvider.getPersonFacade().savePerson(person); - contact = FacadeProvider.getContactFacade().saveContact(contact); + contact = FacadeProvider.getContactFacade().save(contact); if (FacadeProvider.getDiseaseConfigurationFacade().hasFollowUp(contact.getDisease())) { contact.setFollowUpStatus(random(FollowUpStatus.values())); @@ -1370,7 +1370,7 @@ private void generateEvents() { contact.setReportingUser(UserProvider.getCurrent().getUserReference()); contact.setReportDateTime(Date.from(referenceDateTime.atZone(ZoneId.systemDefault()).toInstant())); contact.setDescription("Contact generated using DevMode on " + LocalDate.now()); - FacadeProvider.getContactFacade().saveContact(contact); + FacadeProvider.getContactFacade().save(contact); generatedContacts++; } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/AbstractContactView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/AbstractContactView.java index 321d5ba39d2..a59ada001e5 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/AbstractContactView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/AbstractContactView.java @@ -67,7 +67,7 @@ public void refreshMenu(SubMenu menu, String params) { return; } - ContactDto contact = FacadeProvider.getContactFacade().getContactByUuid(getReference().getUuid()); + ContactDto contact = FacadeProvider.getContactFacade().getByUuid(getReference().getUuid()); menu.removeAllViews(); menu.addView(ContactsView.VIEW_NAME, I18nProperties.getCaption(Captions.contactContactsList)); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactController.java index 88e2ee49dc4..5ade156687e 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactController.java @@ -149,7 +149,7 @@ private void saveContactsFromLineListing(LineListingLayout lineListingForm, List selectOrCreateContact(newContact, FacadeProvider.getPersonFacade().getPersonByUuid(selectedPerson.getUuid()), uuid -> { if (uuid == null) { - FacadeProvider.getContactFacade().saveContact(newContact); + FacadeProvider.getContactFacade().save(newContact); Notification.show(I18nProperties.getString(Strings.messageContactCreated), Type.ASSISTIVE_NOTIFICATION); } }); @@ -203,7 +203,7 @@ private void saveContactsFromEventParticipantsLineListing(LineListingLayout line selectOrCreateContact(newContact, contactLineDto.getPerson(), uuid -> { if (uuid == null) { - FacadeProvider.getContactFacade().saveContact(newContact); + FacadeProvider.getContactFacade().save(newContact); Notification.show(I18nProperties.getString(Strings.messageContactCreated), Type.ASSISTIVE_NOTIFICATION); } }); @@ -392,12 +392,12 @@ public CommitDiscardWrapperComponent getContactCreateComponen if (asSourceContact && alternativeCallback != null && casePerson != null) { selectOrCreateContact(dto, casePerson, selectedContactUuid -> { if (selectedContactUuid != null) { - ContactDto selectedContact = FacadeProvider.getContactFacade().getContactByUuid(selectedContactUuid); + ContactDto selectedContact = FacadeProvider.getContactFacade().getByUuid(selectedContactUuid); selectedContact.setResultingCase(caze.toReference()); selectedContact.setResultingCaseUser(UserProvider.getCurrent().getUserReference()); selectedContact.setContactStatus(ContactStatus.CONVERTED); selectedContact.setContactClassification(ContactClassification.CONFIRMED); - FacadeProvider.getContactFacade().saveContact(selectedContact); + FacadeProvider.getContactFacade().save(selectedContact); // Avoid asking the user to discard unsaved changes createComponent.discard(); @@ -535,7 +535,7 @@ public void selectOrCreateContact(final ContactDto contact, final PersonDto pers } private void createNewContact(ContactDto contact, Consumer resultConsumer) { - final ContactDto savedContact = FacadeProvider.getContactFacade().saveContact(contact); + final ContactDto savedContact = FacadeProvider.getContactFacade().save(contact); Notification.show(I18nProperties.getString(Strings.messageContactCreated), Type.WARNING_MESSAGE); resultConsumer.accept(savedContact.getUuid()); } @@ -546,7 +546,7 @@ public CommitDiscardWrapperComponent getContactDataEditComponen boolean isPsuedonymized) { //editForm.setWidth(editForm.getWidth() * 8/12, Unit.PIXELS); - ContactDto contact = FacadeProvider.getContactFacade().getContactByUuid(contactUuid); + ContactDto contact = FacadeProvider.getContactFacade().getByUuid(contactUuid); ContactDataForm editForm = new ContactDataForm(contact.getDisease(), viewMode, isPsuedonymized); editForm.setValue(contact); final CommitDiscardWrapperComponent editComponent = new CommitDiscardWrapperComponent( @@ -560,7 +560,7 @@ public CommitDiscardWrapperComponent getContactDataEditComponen fillPersonAddressIfEmpty(dto, () -> FacadeProvider.getPersonFacade().getPersonByUuid(dto.getPerson().getUuid())); - FacadeProvider.getContactFacade().saveContact(dto); + FacadeProvider.getContactFacade().save(dto); Notification.show(I18nProperties.getString(Strings.messageContactSaved), Type.WARNING_MESSAGE); SormasUI.refreshView(); @@ -613,7 +613,7 @@ public void showBulkContactDataEditComponent(Collection { ContactBulkEditData updatedBulkEditData = form.getValue(); for (ContactIndexDto indexDto : selectedContacts) { - ContactDto contactDto = FacadeProvider.getContactFacade().getContactByUuid(indexDto.getUuid()); + ContactDto contactDto = FacadeProvider.getContactFacade().getByUuid(indexDto.getUuid()); if (form.getClassificationCheckBox().getValue() == true) { contactDto.setContactClassification(updatedBulkEditData.getContactClassification()); } @@ -622,7 +622,7 @@ public void showBulkContactDataEditComponent(Collection getEpiDataComponent(final String contactUuid) { - ContactDto contact = FacadeProvider.getContactFacade().getContactByUuid(contactUuid); + ContactDto contact = FacadeProvider.getContactFacade().getByUuid(contactUuid); EpiDataForm epiDataForm = new EpiDataForm(contact.getDisease(), ContactDto.class, contact.getEpiData().isPseudonymized(), null); epiDataForm.setValue(contact.getEpiData()); @@ -768,9 +768,9 @@ public CommitDiscardWrapperComponent getEpiDataComponent(final Stri epiDataForm.getFieldGroup()); editView.addCommitListener(() -> { - ContactDto contactDto = FacadeProvider.getContactFacade().getContactByUuid(contactUuid); + ContactDto contactDto = FacadeProvider.getContactFacade().getByUuid(contactUuid); contactDto.setEpiData(epiDataForm.getValue()); - FacadeProvider.getContactFacade().saveContact(contactDto); + FacadeProvider.getContactFacade().save(contactDto); Notification.show(I18nProperties.getString(Strings.messageContactSaved), Type.WARNING_MESSAGE); SormasUI.refreshView(); }); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataView.java index ba2049d6f58..62c0fa6b8a2 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataView.java @@ -113,7 +113,7 @@ protected void initView(String params) { layout.setHeightUndefined(); container.addComponent(layout); - ContactDto contactDto = FacadeProvider.getContactFacade().getContactByUuid(getContactRef().getUuid()); + ContactDto contactDto = FacadeProvider.getContactFacade().getByUuid(getContactRef().getUuid()); editComponent = ControllerProvider.getContactController() .getContactDataEditComponent(getContactRef().getUuid(), ViewMode.NORMAL, contactDto.isPseudonymized()); @@ -159,9 +159,9 @@ protected void initView(String params) { ControllerProvider.getContactController().openSelectCaseForContactWindow(selectedDisease, selectedCase -> { if (selectedCase != null) { ((ContactDataForm) editComponent.getWrappedComponent()).setSourceCase(selectedCase.toReference()); - ContactDto contactToChange = FacadeProvider.getContactFacade().getContactByUuid(getContactRef().getUuid()); + ContactDto contactToChange = FacadeProvider.getContactFacade().getByUuid(getContactRef().getUuid()); contactToChange.setCaze(selectedCase.toReference()); - FacadeProvider.getContactFacade().saveContact(contactToChange); + FacadeProvider.getContactFacade().save(contactToChange); layout.addComponent(createCaseInfoLayout(selectedCase.getUuid()), CASE_LOC); removeCaseButton.setVisible(true); chooseCaseButton.setCaption(I18nProperties.getCaption(Captions.contactChangeCase)); @@ -191,9 +191,9 @@ protected void initView(String params) { editComponent.discard(); layout.removeComponent(CASE_LOC); ((ContactDataForm) editComponent.getWrappedComponent()).setSourceCase(null); - ContactDto contactToChange = FacadeProvider.getContactFacade().getContactByUuid(getContactRef().getUuid()); + ContactDto contactToChange = FacadeProvider.getContactFacade().getByUuid(getContactRef().getUuid()); contactToChange.setCaze(null); - FacadeProvider.getContactFacade().saveContact(contactToChange); + FacadeProvider.getContactFacade().save(contactToChange); removeCaseButton.setVisible(false); chooseCaseButton.setCaption(I18nProperties.getCaption(Captions.contactChooseSourceCase)); ControllerProvider.getContactController().navigateToData(contactDto.getUuid()); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactPersonView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactPersonView.java index d23a6ef3489..4c00de23cdd 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactPersonView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactPersonView.java @@ -38,7 +38,7 @@ public ContactPersonView() { @Override protected void initView(String params) { - ContactDto dto = FacadeProvider.getContactFacade().getContactByUuid(getContactRef().getUuid()); + ContactDto dto = FacadeProvider.getContactFacade().getByUuid(getContactRef().getUuid()); CommitDiscardWrapperComponent contactPersonComponent = ControllerProvider.getPersonController() .getPersonEditComponent(PersonContext.CONTACT,dto.getPerson().getUuid(), dto.getDisease(), dto.getDiseaseDetails(), UserRight.CONTACT_EDIT, null); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactVisitsView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactVisitsView.java index d5de50f24db..7928877516c 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactVisitsView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactVisitsView.java @@ -156,7 +156,7 @@ public void run() { topLayout.addComponent(newButton); topLayout.setComponentAlignment(newButton, Alignment.MIDDLE_RIGHT); - final ContactDto contactDto = FacadeProvider.getContactFacade().getContactByUuid(this.getContactRef().getUuid()); + final ContactDto contactDto = FacadeProvider.getContactFacade().getByUuid(this.getContactRef().getUuid()); if (contactDto.getResultingCase() != null) { newButton.setEnabled(false); final Label label = new Label(VaadinIcons.INFO_CIRCLE.getHtml(), ContentMode.HTML); @@ -190,7 +190,7 @@ protected void initView(String params) { // Hide the "New visit" button for converted contacts if (newButton != null - && FacadeProvider.getContactFacade().getContactByUuid(getContactRef().getUuid()).getContactStatus() == ContactStatus.CONVERTED) { + && FacadeProvider.getContactFacade().getByUuid(getContactRef().getUuid()).getContactStatus() == ContactStatus.CONVERTED) { newButton.setVisible(false); } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/importer/ContactImporter.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/importer/ContactImporter.java index 6ebccb2c008..1e41b2315b6 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/importer/ContactImporter.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/importer/ContactImporter.java @@ -230,13 +230,13 @@ protected ImportLineResult importDataFromCsvLine( } if (ImportSimilarityResultOption.PICK.equals(resultOption)) { - newContact = FacadeProvider.getContactFacade().getContactByUuid(consumer.result.getMatchingContact().getUuid()); + newContact = FacadeProvider.getContactFacade().getByUuid(consumer.result.getMatchingContact().getUuid()); } } // Workaround: Reset the change date to avoid OutdatedEntityExceptions newContact.setChangeDate(new Date()); - FacadeProvider.getContactFacade().saveContact(newContact, true, false); + FacadeProvider.getContactFacade().save(newContact, true, false); consumer.result = null; return ImportLineResult.SUCCESS; diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/eventLink/EventListComponent.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/eventLink/EventListComponent.java index a68fde4c36b..3fe5c3e7376 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/eventLink/EventListComponent.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/eventLink/EventListComponent.java @@ -68,7 +68,7 @@ public EventListComponent(CaseReferenceDto caseRef) { public EventListComponent(ContactReferenceDto contactRef) { - ContactDto contact = FacadeProvider.getContactFacade().getContactByUuid(contactRef.getUuid()); + ContactDto contact = FacadeProvider.getContactFacade().getByUuid(contactRef.getUuid()); EventList eventList = new EventList(contact.getPerson()); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/labmessage/LabMessageController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/labmessage/LabMessageController.java index bcfe5d1bace..6b3b3a9cbbe 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/labmessage/LabMessageController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/labmessage/LabMessageController.java @@ -350,7 +350,7 @@ private void pickOrCreateEntry( pickOrCreateSample(caseDto, labMessageDto, samples); } } else if (similarEntriesDto.getContact() != null) { - ContactDto contactDto = FacadeProvider.getContactFacade().getContactByUuid(similarEntriesDto.getContact().getUuid()); + ContactDto contactDto = FacadeProvider.getContactFacade().getByUuid(similarEntriesDto.getContact().getUuid()); ContactReferenceDto contactRef = contactDto.toReference(); List samples = diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/AbstractSampleForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/AbstractSampleForm.java index ba7c59ba260..ad8c632337a 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/AbstractSampleForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/AbstractSampleForm.java @@ -179,7 +179,7 @@ protected void defaultValueChangeListener() { } else { final ContactReferenceDto associatedContact = getValue().getAssociatedContact(); if (associatedContact != null) { - disease = FacadeProvider.getContactFacade().getContactByUuid(associatedContact.getUuid()).getDisease(); + disease = FacadeProvider.getContactFacade().getByUuid(associatedContact.getUuid()).getDisease(); } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java index 97e3a078aec..b255df72fb4 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java @@ -268,7 +268,7 @@ private void handleAssociatedContact( // a.2) If contact is not converted (or there already is a resulting case), ask user whether to update the sample pathogen test result // b) Tested disease != contact disease: Ask user to create a new case for the tested disease - final ContactDto contact = FacadeProvider.getContactFacade().getContactByUuid(associatedContact.getUuid()); + final ContactDto contact = FacadeProvider.getContactFacade().getByUuid(associatedContact.getUuid()); final boolean equalDisease = dto.getTestedDisease() == contact.getDisease(); Runnable callback = () -> { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleController.java index 810729402b1..6f539f0c922 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleController.java @@ -451,7 +451,7 @@ public void buttonClick(ClickEvent event) { final CaseDataDto caseDto = FacadeProvider.getCaseFacade().getCaseDataByUuid(associatedCase.getUuid()); ControllerProvider.getTaskController().createSampleCollectionTask(TaskContext.CASE, associatedCase, dto, caseDto.getDisease()); } else if (associatedContact != null) { - final ContactDto contactDto = FacadeProvider.getContactFacade().getContactByUuid(associatedContact.getUuid()); + final ContactDto contactDto = FacadeProvider.getContactFacade().getByUuid(associatedContact.getUuid()); ControllerProvider.getTaskController() .createSampleCollectionTask(TaskContext.CONTACT, associatedContact, dto, contactDto.getDisease()); } else if (associatedEventParticipant != null) { @@ -579,7 +579,7 @@ public Disease getDiseaseOf(SampleDto sample) { } ContactReferenceDto contactRef = sample.getAssociatedContact(); if (contactRef != null) { - return FacadeProvider.getContactFacade().getContactByUuid(contactRef.getUuid()).getDisease(); + return FacadeProvider.getContactFacade().getByUuid(contactRef.getUuid()).getDisease(); } EventParticipantReferenceDto eventPartRef = sample.getAssociatedEventParticipant(); if (eventPartRef != null) { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleDataView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleDataView.java index 96b45070e55..18a412ee534 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleDataView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleDataView.java @@ -107,7 +107,7 @@ protected void initView(String params) { } final ContactReferenceDto associatedContact = sampleDto.getAssociatedContact(); if (associatedContact != null) { - final ContactDto contactDto = FacadeProvider.getContactFacade().getContactByUuid(associatedContact.getUuid()); + final ContactDto contactDto = FacadeProvider.getContactFacade().getByUuid(associatedContact.getUuid()); disease = contactDto.getDisease(); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/visit/VisitController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/visit/VisitController.java index 1f92de3bb07..7fb3aba50be 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/visit/VisitController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/visit/VisitController.java @@ -58,7 +58,7 @@ public void editVisit(String visitUuid, ContactReferenceDto contactRef, CaseRefe VisitDto visit = FacadeProvider.getVisitFacade().getVisitByUuid(visitUuid); VisitEditForm editForm; if (contactRef != null) { - ContactDto contact = FacadeProvider.getContactFacade().getContactByUuid(contactRef.getUuid()); + ContactDto contact = FacadeProvider.getContactFacade().getByUuid(contactRef.getUuid()); PersonDto visitPerson = FacadeProvider.getPersonFacade().getPersonByUuid(visit.getPerson().getUuid()); editForm = new VisitEditForm(visit.getDisease(), contact, visitPerson, false, !contact.isPseudonymized()); } else if (caseRef != null) { @@ -134,7 +134,7 @@ private void createVisit(VisitEditForm createForm, Consumer d public void createVisit(ContactReferenceDto contactRef, Consumer doneConsumer) { VisitDto visit = createNewVisit(contactRef); - ContactDto contact = FacadeProvider.getContactFacade().getContactByUuid(contactRef.getUuid()); + ContactDto contact = FacadeProvider.getContactFacade().getByUuid(contactRef.getUuid()); PersonDto contactPerson = FacadeProvider.getPersonFacade().getPersonByUuid(contact.getPerson().getUuid()); VisitEditForm createForm = new VisitEditForm(visit.getDisease(), contact, contactPerson, true, true); createForm.setValue(visit); @@ -160,7 +160,7 @@ private VisitDto createNewVisit(PersonReferenceDto personRef, Disease disease) { } private VisitDto createNewVisit(ContactReferenceDto contactRef) { - ContactDto contact = FacadeProvider.getContactFacade().getContactByUuid(contactRef.getUuid()); + ContactDto contact = FacadeProvider.getContactFacade().getByUuid(contactRef.getUuid()); return createNewVisit(contact.getPerson(), contact.getDisease()); } diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/TestDataCreator.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/TestDataCreator.java index eee80d3a038..175a0c33cb9 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/TestDataCreator.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/TestDataCreator.java @@ -211,7 +211,7 @@ public ContactDto createContact( customConfig.accept(contact); } - contact = FacadeProvider.getContactFacade().saveContact(contact); + contact = FacadeProvider.getContactFacade().save(contact); return contact; } @@ -253,7 +253,7 @@ public ContactDto createContact( contact.setReportDateTime(reportDateTime); contact.setLastContactDate(lastContactDate); - contact = FacadeProvider.getContactFacade().saveContact(contact); + contact = FacadeProvider.getContactFacade().save(contact); return contact; } diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/importexport/ImportExportTest.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/importexport/ImportExportTest.java index a63636b8219..ed1dcf55119 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/importexport/ImportExportTest.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/importexport/ImportExportTest.java @@ -261,7 +261,7 @@ public void testImportExportedContact() throws IOException, CsvException, Invali contact.setFollowUpStatus(FollowUpStatus.FOLLOW_UP); contact.setFollowUpUntil(dateNow); - getContactFacade().saveContact(contact); + getContactFacade().save(contact); person.setSex(Sex.MALE); person.setBirthdateDD(11); From e7055f9b69f6c9029347989698cd6db8bd510a25 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Wed, 2 Feb 2022 16:14:59 +0200 Subject: [PATCH 010/253] #7246 - move case facade methods to new core facade --- .../de/symeda/sormas/api/caze/CaseFacade.java | 11 +- .../resources/doc/SORMAS_Data_Dictionary.xlsx | Bin 254252 -> 253756 bytes .../resources/doc/SORMAS_User_Rights.xlsx | Bin 19067 -> 19067 bytes .../sormas/backend/caze/CaseFacadeEjb.java | 192 ++++++++---------- .../sormas/backend/caze/CaseService.java | 5 +- .../backend/common/AbstractCoreEjb.java | 44 +++- .../backend/contact/ContactFacadeEjb.java | 8 +- .../AbstractCoreEntityFacade.java | 58 ------ .../CoreEntityDeletionService.java | 7 +- .../sormas/backend/event/EventFacadeEjb.java | 3 - .../event/EventParticipantFacadeEjb.java | 3 +- .../immunization/ImmunizationFacadeEjb.java | 4 - .../backend/person/PersonFacadeEjb.java | 10 +- .../backend/sample/PathogenTestFacadeEjb.java | 2 +- .../backend/sample/SampleFacadeEjb.java | 2 +- .../entities/caze/ReceivedCaseProcessor.java | 6 +- .../SormasToSormasShareInfoService.java | 4 +- .../travelentry/TravelEntryFacadeEjb.java | 3 +- .../sormas/backend/visit/VisitFacadeEjb.java | 2 +- 19 files changed, 161 insertions(+), 203 deletions(-) delete mode 100644 sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/AbstractCoreEntityFacade.java diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java index 5cd6f17bcb6..af579eaef00 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java @@ -31,6 +31,7 @@ import com.fasterxml.jackson.databind.JsonNode; import de.symeda.sormas.api.CaseMeasure; +import de.symeda.sormas.api.CoreBaseFacade; import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.Language; import de.symeda.sormas.api.common.Page; @@ -52,7 +53,7 @@ import de.symeda.sormas.api.utils.ValidationRuntimeException; @Remote -public interface CaseFacade { +public interface CaseFacade extends CoreBaseFacade { List getAllActiveCasesAfter(Date date); @@ -61,12 +62,8 @@ public interface CaseFacade { */ List getAllActiveCasesAfter(Date date, boolean includeExtendedChangeDateFilters); - long count(CaseCriteria caseCriteria); - long count(CaseCriteria caseCriteria, boolean ignoreUserFilter); - List getIndexList(CaseCriteria caseCriteria, Integer first, Integer max, List sortProperties); - List getCaseSelectionList(CaseCriteria caseCriteria); List getEntriesList(String personUuid, Integer first, Integer max); @@ -112,10 +109,6 @@ List getExportList( List getAllActiveCasesAfter(Date date, Integer batchSize, String lastSynchronizedUuid); - List getByUuids(List uuids); - - CaseDataDto getByUuid(String uuid); - String getUuidByUuidEpidNumberOrExternalId(String searchTerm, CaseCriteria caseCriteria); List getCasesForMap( diff --git a/sormas-api/src/main/resources/doc/SORMAS_Data_Dictionary.xlsx b/sormas-api/src/main/resources/doc/SORMAS_Data_Dictionary.xlsx index 956dd39aaad4aa3b6159730c7ba73aa767705ecf..db1446a7a0b7256db67f72ea7504c26cd9b3d568 100644 GIT binary patch delta 209858 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

6{y9#vzm?_#D)4OysLJ(#_=Q6(C~44%mi~3 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

7i^E-3?B=C7$tG%i=a{jGxg@fp2S~;VJ2N42= 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 B4yFLt7F>y*=_&FDrByjJd3m4W`WP5hStTs z+CTl~oqj#L%zIXon5)FY5^TffYBBbS$+ryKqu{p?xw z0BDSWhM}9B&Y@s#V8>qFkL4sY77d-I$_nx z30|z5_q*wWL-(D#IY?OD!yZIsc-U~p}G7)l6qWR28#Mz3P*FbGK+~ zEqtqVs%gQF2VLFeijudJK06D&eRq5IwXIEDJ3XFR7tiq7YWJeCW&!_RQ&Zg{H%_U{ z(EMAo?B1H)R8>{vT6`pd_u7|^#&xs3tn}6%U%Q>J_Ko3$Cx(sQ;g|K?jx#pB3Fw}n zerU;ut5v#5RlmgMOvqp4sv&93-Wyo2A;{`;=!~vgRgl(Bjk~+$(;6o=FlU(fDtaf1P?C&*)!0(_2_{!~Xr%bK1{W8UKw{%3U>imUq9>A|=lQk1sBr zTBCk`_3PPp+sst8PxttyAJ?<6e!Qk)<%975Dt~rG-;Y_^TH>*df4lJZDcV0aKYJz| z;4Q_@aciA911lo~!$u%R4z$htSbVuap~lOv%mkv11l7Qy7$u|xrt5@7jX}X!C#*U- z!HaeCem7lk=)Q9|2MMct*n_AH4;zjK52p~2HIvtPfTf;#IDl1nT7sw~Piqi0-_s35 MJ@<40QMz7!020BsKmY&$ diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java index 7c5fe7560e8..f29ef89fb16 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java @@ -52,8 +52,7 @@ import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.enterprise.concurrent.ManagedScheduledExecutorService; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; +import javax.inject.Inject; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; @@ -210,6 +209,7 @@ import de.symeda.sormas.backend.clinicalcourse.ClinicalVisitFacadeEjb.ClinicalVisitFacadeEjbLocal; import de.symeda.sormas.backend.clinicalcourse.ClinicalVisitService; import de.symeda.sormas.backend.clinicalcourse.HealthConditions; +import de.symeda.sormas.backend.common.AbstractCoreEjb; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; @@ -219,11 +219,9 @@ import de.symeda.sormas.backend.common.messaging.MessagingService; import de.symeda.sormas.backend.common.messaging.NotificationDeliveryFailedException; import de.symeda.sormas.backend.contact.Contact; -import de.symeda.sormas.backend.contact.ContactFacadeEjb; import de.symeda.sormas.backend.contact.ContactFacadeEjb.ContactFacadeEjbLocal; import de.symeda.sormas.backend.contact.ContactService; import de.symeda.sormas.backend.contact.VisitSummaryExportDetails; -import de.symeda.sormas.backend.deletionconfiguration.AbstractCoreEntityFacade; import de.symeda.sormas.backend.disease.DiseaseConfigurationFacadeEjb.DiseaseConfigurationFacadeEjbLocal; import de.symeda.sormas.backend.document.Document; import de.symeda.sormas.backend.document.DocumentService; @@ -327,28 +325,22 @@ import de.symeda.sormas.utils.CaseJoins; @Stateless(name = "CaseFacade") -public class CaseFacadeEjb extends AbstractCoreEntityFacade implements CaseFacade { +public class CaseFacadeEjb extends AbstractCoreEjb + implements CaseFacade { private static final int ARCHIVE_BATCH_SIZE = 1000; private final Logger logger = LoggerFactory.getLogger(getClass()); - @PersistenceContext(unitName = ModelConstants.PERSISTENCE_UNIT_NAME) - private EntityManager em; - @EJB private CaseClassificationFacadeEjbLocal caseClassificationFacade; @EJB - private CaseService caseService; - @EJB private CaseListCriteriaBuilder listQueryBuilder; @EJB private PersonService personService; @EJB private FacilityService facilityService; @EJB - private UserService userService; - @EJB private VisitService visitService; @EJB private VisitFacadeEjbLocal visitFacade; @@ -456,7 +448,11 @@ public class CaseFacadeEjb extends AbstractCoreEntityFacade implements Cas private ManagedScheduledExecutorService executorService; public CaseFacadeEjb() { - super(Case.class); + } + + @Inject + public CaseFacadeEjb(CaseService service, UserService userService) { + super(Case.class, CaseDataDto.class, service, userService); } @Override @@ -485,21 +481,15 @@ private List getAllActiveCasesAfter( } Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); - return caseService.getAllActiveCasesAfter(date, includeExtendedChangeDateFilters, batchSize, lastSynchronizedUuid) + return service.getAllActiveCasesAfter(date, includeExtendedChangeDateFilters, batchSize, lastSynchronizedUuid) .stream() .map(c -> convertToDto(c, pseudonymizer)) .collect(Collectors.toList()); } @Override - public List getByUuids(List uuids) { - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); - return caseService.getByUuids(uuids).stream().map(c -> convertToDto(c, pseudonymizer)).collect(Collectors.toList()); - } + protected void selectDtoFields(CriteriaQuery cq, Root root) { - public CaseDataDto getByUuid(String uuid) { - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); - return convertToDto(caseService.getByUuid(uuid), pseudonymizer); } public Page getIndexPage(CaseCriteria caseCriteria, Integer offset, Integer size, List sortProperties) { @@ -510,7 +500,7 @@ public Page getIndexPage(CaseCriteria caseCriteria, Integer offset @Override public String getUuidByUuidEpidNumberOrExternalId(String searchTerm, CaseCriteria caseCriteria) { - return caseService.getUuidByUuidEpidNumberOrExternalId(searchTerm, caseCriteria); + return service.getUuidByUuidEpidNumberOrExternalId(searchTerm, caseCriteria); } @Override @@ -535,11 +525,11 @@ public long count(CaseCriteria caseCriteria, boolean ignoreUserFilter) { if (caseCriteria != null) { caseUserFilterCriteria.setIncludeCasesFromOtherJurisdictions(caseCriteria.getIncludeCasesFromOtherJurisdictions()); } - filter = caseService.createUserFilter(cb, cq, root, caseUserFilterCriteria); + filter = service.createUserFilter(cb, cq, root, caseUserFilterCriteria); } if (caseCriteria != null) { - Predicate criteriaFilter = caseService.createCriteriaFilter(caseCriteria, caseQueryContext); + Predicate criteriaFilter = service.createCriteriaFilter(caseCriteria, caseQueryContext); filter = CriteriaBuilderHelper.and(cb, filter, criteriaFilter); } if (filter != null) { @@ -655,7 +645,7 @@ public List getIndexDetailedList(CaseCriteria caseCriteria @Override public List getCaseSelectionList(CaseCriteria caseCriteria) { - List entries = caseService.getCaseSelectionList(caseCriteria); + List entries = service.getCaseSelectionList(caseCriteria); Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight, I18nProperties.getCaption(Captions.inaccessibleValue)); pseudonymizer.pseudonymizeDtoCollection(CaseSelectionDto.class, entries, CaseSelectionDto::isInJurisdiction, null); @@ -667,7 +657,7 @@ public List getCaseSelectionList(CaseCriteria caseCriteria) { public List getEntriesList(String personUuid, Integer first, Integer max) { Long personId = personFacade.getPersonIdByUuid(personUuid); - List entries = caseService.getEntriesList(personId, first, max); + List entries = service.getEntriesList(personId, first, max); Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight, I18nProperties.getCaption(Captions.inaccessibleValue)); pseudonymizer.pseudonymizeDtoCollection(CaseListEntryDto.class, entries, CaseListEntryDto::isInJurisdiction, null); @@ -798,15 +788,15 @@ public List getExportList( joins.getFollowUpStatusChangeUser().get(User.ID), caseRoot.get(Case.PREVIOUS_QUARANTINE_TO), caseRoot.get(Case.QUARANTINE_CHANGE_COMMENT), - JurisdictionHelper.booleanSelector(cb, caseService.inJurisdictionOrOwned(caseQueryContext))); + JurisdictionHelper.booleanSelector(cb, service.inJurisdictionOrOwned(caseQueryContext))); //@formatter:on cq.distinct(true); - Predicate filter = caseService.createUserFilter(cb, cq, caseRoot); + Predicate filter = service.createUserFilter(cb, cq, caseRoot); if (caseCriteria != null) { - Predicate criteriaFilter = caseService.createCriteriaFilter(caseCriteria, caseQueryContext); + Predicate criteriaFilter = service.createCriteriaFilter(caseCriteria, caseQueryContext); filter = CriteriaBuilderHelper.and(cb, filter, criteriaFilter); } filter = CriteriaBuilderHelper.andInValues(selectedRows, filter, cb, caseRoot.get(Case.UUID)); @@ -1241,7 +1231,7 @@ public List getAllActiveUuids() { return Collections.emptyList(); } - return caseService.getAllActiveUuids(); + return service.getAllActiveUuids(); } public Long countCasesForMap( @@ -1254,7 +1244,7 @@ public Long countCasesForMap( Region region = regionService.getByReferenceDto(regionRef); District district = districtService.getByReferenceDto(districtRef); - return caseService.countCasesForMap(region, district, disease, from, to, dateType); + return service.countCasesForMap(region, district, disease, from, to, dateType); } @Override @@ -1269,7 +1259,7 @@ public List getCasesForMap( Region region = regionService.getByReferenceDto(regionRef); District district = districtService.getByReferenceDto(districtRef); - List cases = caseService.getCasesForMap(region, district, disease, from, to, dateType); + List cases = service.getCasesForMap(region, district, disease, from, to, dateType); Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); pseudonymizer.pseudonymizeDtoCollection( @@ -1286,7 +1276,7 @@ public List getAllCasesOfPerson(String personUuid) { Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); - return caseService.findBy(new CaseCriteria().person(new PersonReferenceDto(personUuid)), false) + return service.findBy(new CaseCriteria().person(new PersonReferenceDto(personUuid)), false) .stream() .map(c -> convertToDto(c, pseudonymizer)) .collect(Collectors.toList()); @@ -1301,8 +1291,8 @@ public List getRandomCaseReferences(CaseCriteria criteria, int final CaseQueryContext caseQueryContext = new CaseQueryContext(cb, cq, caze); - Predicate filter = caseService.createUserFilter(cb, cq, caze, new CaseUserFilterCriteria().excludeCasesFromContacts(true)); - filter = CriteriaBuilderHelper.and(cb, filter, caseService.createCriteriaFilter(criteria, caseQueryContext)); + Predicate filter = service.createUserFilter(cb, cq, caze, new CaseUserFilterCriteria().excludeCasesFromContacts(true)); + filter = CriteriaBuilderHelper.and(cb, filter, service.createCriteriaFilter(criteria, caseQueryContext)); if (filter != null) { cq.where(filter); } @@ -1321,7 +1311,7 @@ public List getRandomCaseReferences(CaseCriteria criteria, int @Override public List getSimilarCases(CaseSimilarityCriteria criteria) { - List entries = caseService.getSimilarCases(criteria); + List entries = service.getSimilarCases(criteria); Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight, I18nProperties.getCaption(Captions.inaccessibleValue)); pseudonymizer.pseudonymizeDtoCollection(CaseSelectionDto.class, entries, CaseSelectionDto::isInJurisdiction, null); @@ -1332,25 +1322,25 @@ public List getSimilarCases(CaseSimilarityCriteria criteria) { @Override public List getCasesForDuplicateMerging(CaseCriteria criteria, boolean ignoreRegion) { - return caseService.getCasesForDuplicateMerging(criteria, ignoreRegion, configFacade.getNameSimilarityThreshold()); + return service.getCasesForDuplicateMerging(criteria, ignoreRegion, configFacade.getNameSimilarityThreshold()); } public void updateCompleteness(String caseUuid) { - caseService.updateCompleteness(caseUuid); + service.updateCompleteness(caseUuid); } @Override public CaseDataDto getCaseDataByUuid(String uuid) { - return convertToDto(caseService.getByUuid(uuid), Pseudonymizer.getDefault(userService::hasRight)); + return convertToDto(service.getByUuid(uuid), Pseudonymizer.getDefault(userService::hasRight)); } private CaseDataDto getCaseDataWithoutPseudonyimization(String uuid) { - return toDto(caseService.getByUuid(uuid)); + return toDto(service.getByUuid(uuid)); } @Override public CaseReferenceDto getReferenceByUuid(String uuid) { - return convertToReferenceDto(caseService.getByUuid(uuid)); + return convertToReferenceDto(service.getByUuid(uuid)); } @Override @@ -1374,7 +1364,7 @@ public void saveBulkCase( throws ValidationRuntimeException { for (String caseUuid : caseUuidList) { - Case caze = caseService.getByUuid(caseUuid); + Case caze = service.getByUuid(caseUuid); CaseDataDto existingCaseDto = toDto(caze); updateCaseWithBulkData( @@ -1408,7 +1398,7 @@ public void saveBulkEditWithFacilities( } for (String caseUuid : caseUuidList) { - Case caze = caseService.getByUuid(caseUuid); + Case caze = service.getByUuid(caseUuid); CaseDataDto existingCaseDto = toDto(caze); updateCaseWithBulkData( @@ -1479,9 +1469,9 @@ public CaseDataDto saveCase(@Valid CaseDataDto dto, boolean handleChanges, boole public CaseDataDto saveCase(@Valid CaseDataDto dto, boolean handleChanges, boolean checkChangeDate, boolean internal, Boolean systemSave) throws ValidationRuntimeException { - Case existingCase = caseService.getByUuid(dto.getUuid()); + Case existingCase = service.getByUuid(dto.getUuid()); - if (!systemSave && internal && existingCase != null && !caseService.isCaseEditAllowed(existingCase)) { + if (!systemSave && internal && existingCase != null && !service.isCaseEditAllowed(existingCase)) { throw new AccessDeniedException(I18nProperties.getString(Strings.errorCaseNotEditable)); } @@ -1500,7 +1490,7 @@ private CaseDataDto caseSave( throws ValidationRuntimeException { SymptomsHelper.updateIsSymptomatic(dto.getSymptoms()); - restorePseudonymizedDto(dto, existingCaze, existingCaseDto); + restorePseudonymizedDto(dto, existingCaseDto, existingCaze, Pseudonymizer.getDefault(userService::hasRight)); validate(dto); @@ -1523,10 +1513,10 @@ public void syncSharesAsync(ShareTreeCriteria criteria) { } private void doSave(Case caze, boolean handleChanges, CaseDataDto existingCaseDto, boolean syncShares) { - caseService.ensurePersisted(caze); + service.ensurePersisted(caze); if (handleChanges) { updateCaseVisitAssociations(existingCaseDto, caze); - caseService.updateFollowUpDetails(caze, existingCaseDto != null && caze.getFollowUpStatus() != existingCaseDto.getFollowUpStatus()); + service.updateFollowUpDetails(caze, existingCaseDto != null && caze.getFollowUpStatus() != existingCaseDto.getFollowUpStatus()); onCaseChanged(existingCaseDto, caze, syncShares); } @@ -1564,7 +1554,7 @@ public void setSampleAssociations(ContactReferenceDto sourceContact, CaseReferen if (sourceContact != null) { final Contact contact = contactService.getByUuid(sourceContact.getUuid()); - final Case caze = caseService.getByUuid(cazeRef.getUuid()); + final Case caze = service.getByUuid(cazeRef.getUuid()); contact.getSamples().forEach(sample -> sample.setAssociatedCase(caze)); } } @@ -1573,7 +1563,7 @@ public void setSampleAssociations(ContactReferenceDto sourceContact, CaseReferen public void setSampleAssociations(EventParticipantReferenceDto sourceEventParticipant, CaseReferenceDto cazeRef) { if (sourceEventParticipant != null) { final EventParticipant eventParticipant = eventParticipantService.getByUuid(sourceEventParticipant.getUuid()); - final Case caze = caseService.getByUuid(cazeRef.getUuid()); + final Case caze = service.getByUuid(cazeRef.getUuid()); eventParticipant.getSamples().forEach(sample -> sample.setAssociatedCase(caze)); } } @@ -1581,7 +1571,7 @@ public void setSampleAssociations(EventParticipantReferenceDto sourceEventPartic @Override public void setSampleAssociationsUnrelatedDisease(EventParticipantReferenceDto sourceEventParticipant, CaseReferenceDto cazeRef) { final EventParticipant eventParticipant = eventParticipantService.getByUuid(sourceEventParticipant.getUuid()); - final Case caze = caseService.getByUuid(cazeRef.getUuid()); + final Case caze = service.getByUuid(cazeRef.getUuid()); final Disease disease = caze.getDisease(); eventParticipant.getSamples() .stream() @@ -1681,7 +1671,7 @@ public void validate(CaseDataDto caze) throws ValidationRuntimeException { @Override public void archiveOrDearchiveCase(String caseUuid, boolean archive) { - caseService.updateArchived(Collections.singletonList(caseUuid), archive); + service.updateArchived(Collections.singletonList(caseUuid), archive); } /** @@ -2085,7 +2075,7 @@ public void reassignTasksOfCase(Case caze, boolean forceReassignment) { User taskAssignee = task.getAssigneeUser(); - if (forceReassignment || taskAssignee == null || !caseService.inJurisdiction(caze, taskAssignee)) { + if (forceReassignment || taskAssignee == null || !service.inJurisdiction(caze, taskAssignee)) { // if there is any mismatch between the jurisdiction of the case and the assigned user, // we need to reassign the tasks assignOfficerOrSupervisorToTask(caze, task); @@ -2100,7 +2090,7 @@ public void reassignTasksOfCase(Case caze, boolean forceReassignment) { public int updateCompleteness() { List getCompletenessCheckCaseList = getCompletenessCheckNeededCaseList(); - IterableHelper.executeBatched(getCompletenessCheckCaseList, 10, caseCompletionBatch -> caseService.updateCompleteness(caseCompletionBatch)); + IterableHelper.executeBatched(getCompletenessCheckCaseList, 10, caseCompletionBatch -> service.updateCompleteness(caseCompletionBatch)); return getCompletenessCheckCaseList.size(); } @@ -2108,7 +2098,7 @@ public int updateCompleteness() { @Override public PreviousCaseDto getMostRecentPreviousCase(PersonReferenceDto person, Disease disease, Date startDate) { - return caseService.getMostRecentPreviousCase(person.getUuid(), disease, startDate); + return service.getMostRecentPreviousCase(person.getUuid(), disease, startDate); } private List getCompletenessCheckNeededCaseList() { @@ -2145,7 +2135,7 @@ private String generateEpidNumber(String newEpidNumber, String caseUuid, Disease } // Generate a suffix number - String highestEpidNumber = caseService.getHighestEpidNumber(newEpidNumber, caseUuid, disease); + String highestEpidNumber = service.getHighestEpidNumber(newEpidNumber, caseUuid, disease); if (highestEpidNumber == null || highestEpidNumber.endsWith("-")) { // If there is not yet a case with a suffix for this epid number in the database, use 001 newEpidNumber = newEpidNumber + "001"; @@ -2270,7 +2260,7 @@ public void deleteCase(String caseUuid) throws ExternalSurveillanceToolException throw new UnsupportedOperationException("User " + userService.getCurrentUser().getUuid() + " is not allowed to delete cases."); } - Case caze = caseService.getByUuid(caseUuid); + Case caze = service.getByUuid(caseUuid); deleteCase(caze); } @@ -2283,7 +2273,7 @@ private void deleteCase(Case caze) throws ExternalSurveillanceToolException { } } - caseService.delete(caze); + service.delete(caze); } public List deleteCases(List caseUuids) { @@ -2291,7 +2281,7 @@ public List deleteCases(List caseUuids) { throw new UnsupportedOperationException("User " + userService.getCurrentUser().getUuid() + " is not allowed to delete cases."); } List deletedCasesUuids = new ArrayList<>(); - List casesToBeDeleted = caseService.getByUuids(caseUuids); + List casesToBeDeleted = service.getByUuids(caseUuids); if (casesToBeDeleted != null) { casesToBeDeleted.forEach(caseToBeDeleted -> { if (!caseToBeDeleted.isDeleted()) { @@ -2310,10 +2300,10 @@ public List deleteCases(List caseUuids) { @Override public void deleteCaseAsDuplicate(String caseUuid, String duplicateOfCaseUuid) throws ExternalSurveillanceToolException { - Case caze = caseService.getByUuid(caseUuid); - Case duplicateOfCase = caseService.getByUuid(duplicateOfCaseUuid); + Case caze = service.getByUuid(caseUuid); + Case duplicateOfCase = service.getByUuid(duplicateOfCaseUuid); caze.setDuplicateOf(duplicateOfCase); - caseService.ensurePersisted(caze); + service.ensurePersisted(caze); deleteCase(caseUuid); } @@ -2325,7 +2315,7 @@ public List getArchivedUuidsSince(Date since) { return Collections.emptyList(); } - return caseService.getArchivedUuidsSince(since); + return service.getArchivedUuidsSince(since); } @Override @@ -2334,7 +2324,7 @@ public List getDeletedUuidsSince(Date since) { if (userService.getCurrentUser() == null) { return Collections.emptyList(); } - return caseService.getDeletedUuidsSince(since); + return service.getDeletedUuidsSince(since); } public static CaseReferenceDto toReferenceDto(Case entity) { @@ -2346,18 +2336,9 @@ public static CaseReferenceDto toReferenceDto(Case entity) { return entity.toReference(); } - public CaseDataDto convertToDto(Case source, Pseudonymizer pseudonymizer) { - - CaseDataDto dto = toDto(source); - - pseudonymizeDto(source, dto, pseudonymizer); - - return dto; - } - - private void pseudonymizeDto(Case source, CaseDataDto dto, Pseudonymizer pseudonymizer) { + public void pseudonymizeDto(Case source, CaseDataDto dto, Pseudonymizer pseudonymizer) { if (dto != null) { - boolean inJurisdiction = caseService.inJurisdictionOrOwned(source); + boolean inJurisdiction = service.inJurisdictionOrOwned(source); pseudonymizer.pseudonymizeDto(CaseDataDto.class, dto, inJurisdiction, c -> { User currentUser = userService.getCurrentUser(); @@ -2388,10 +2369,10 @@ private void pseudonymizeDto(Case source, CaseDataDto dto, Pseudonymizer pseudon } } - private void restorePseudonymizedDto(CaseDataDto dto, Case caze, CaseDataDto existingCaseDto) { + public void restorePseudonymizedDto(CaseDataDto dto, CaseDataDto existingCaseDto, Case caze , Pseudonymizer pseudonymizer) { if (existingCaseDto != null) { - boolean inJurisdiction = caseService.inJurisdictionOrOwned(caze); - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); + boolean inJurisdiction = service.inJurisdictionOrOwned(caze); + User currentUser = userService.getCurrentUser(); pseudonymizer.restoreUser(caze.getReportingUser(), currentUser, dto, dto::setReportingUser); @@ -2447,14 +2428,14 @@ public CaseReferenceDto convertToReferenceDto(Case source) { CaseReferenceDto dto = toReferenceDto(source); if (dto != null) { - boolean inJurisdiction = caseService.inJurisdictionOrOwned(source); + boolean inJurisdiction = service.inJurisdictionOrOwned(source); Pseudonymizer.getDefault(userService::hasRight).pseudonymizeDto(CaseReferenceDto.class, dto, inJurisdiction, null); } return dto; } - public static CaseDataDto toDto(Case source) { + public CaseDataDto toDto(Case source) { if (source == null) { return null; @@ -2621,6 +2602,11 @@ public static CaseDataDto toDto(Case source) { return target; } + @Override + public CaseReferenceDto toRefDto(Case aCase) { + return convertToReferenceDto(aCase); + } + public Case fillOrBuildEntity(@NotNull CaseDataDto source, Case target, boolean checkChangeDate) { target = DtoHelper.fillOrBuildEntity(source, target, () -> { @@ -3048,7 +3034,7 @@ public boolean doesEpidNumberExist(String epidNumber, String caseUuid, Disease c @Override public boolean doesExternalTokenExist(String externalToken, String caseUuid) { - return caseService.exists( + return service.exists( (cb, caseRoot, cq) -> CriteriaBuilderHelper.and( cb, cb.equal(caseRoot.get(Case.EXTERNAL_TOKEN), externalToken), @@ -3064,9 +3050,9 @@ public List> getCaseMeasurePerDistrict(Date fromDa Root caseRoot = cq.from(Case.class); Root districtRoot = cq.from(District.class); - Predicate filter = caseService.createDefaultFilter(cb, caseRoot); + Predicate filter = service.createDefaultFilter(cb, caseRoot); if (fromDate != null || toDate != null) { - filter = caseService.createCaseRelevanceFilter(cb, caseRoot, fromDate, toDate); + filter = service.createCaseRelevanceFilter(cb, caseRoot, fromDate, toDate); } if (disease != null) { @@ -3236,8 +3222,8 @@ private void mergeCase(CaseDataDto leadCaseData, CaseDataDto otherCaseData, bool } // 2 Change CaseReference - Case leadCase = caseService.getByUuid(leadCaseData.getUuid()); - Case otherCase = caseService.getByUuid(otherCaseData.getUuid()); + Case leadCase = service.getByUuid(leadCaseData.getUuid()); + Case otherCase = service.getByUuid(otherCaseData.getUuid()); // 2.1 Contacts List contacts = contactService.findBy(new ContactCriteria().caze(otherCase.toReference()), null); @@ -3441,11 +3427,11 @@ void archiveAllArchivableCases(int daysAfterCaseGetsArchived, LocalDate referenc Root from = cq.from(Case.class); Timestamp notChangedTimestamp = Timestamp.valueOf(notChangedSince.atStartOfDay()); - cq.where(cb.equal(from.get(Case.ARCHIVED), false), cb.not(caseService.createChangeDateFilter(cb, from, notChangedTimestamp, true))); + cq.where(cb.equal(from.get(Case.ARCHIVED), false), cb.not(service.createChangeDateFilter(cb, from, notChangedTimestamp, true))); cq.select(from.get(Case.UUID)); List caseUuids = em.createQuery(cq).getResultList(); - IterableHelper.executeBatched(caseUuids, ARCHIVE_BATCH_SIZE, batchedCaseUuids -> caseService.updateArchived(batchedCaseUuids, true)); + IterableHelper.executeBatched(caseUuids, ARCHIVE_BATCH_SIZE, batchedCaseUuids -> service.updateArchived(batchedCaseUuids, true)); logger.debug( "archiveAllArchivableCases() finished. caseCount = {}, daysAfterCaseGetsArchived = {}, {}ms", caseUuids.size(), @@ -3458,7 +3444,7 @@ public void updateArchived(List caseUuids, boolean archived) { long startTime = DateHelper.startTime(); - IterableHelper.executeBatched(caseUuids, ARCHIVE_BATCH_SIZE, batchedCaseUuids -> caseService.updateArchived(batchedCaseUuids, archived)); + IterableHelper.executeBatched(caseUuids, ARCHIVE_BATCH_SIZE, batchedCaseUuids -> service.updateArchived(batchedCaseUuids, archived)); logger.debug( "updateArchived() finished. caseCount = {}, archived = {}, {}ms", caseUuids.size(), @@ -3466,11 +3452,6 @@ public void updateArchived(List caseUuids, boolean archived) { DateHelper.durationMillies(startTime)); } - @Override - public boolean exists(String uuid) { - return caseService.exists(uuid); - } - @Override public boolean hasPositiveLabResult(String caseUuid) { final CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); @@ -3511,10 +3492,10 @@ public List getCaseFollowUpList( caze.get(Case.FOLLOW_UP_UNTIL), joins.getPerson().get(Person.SYMPTOM_JOURNAL_STATUS), caze.get(Case.DISEASE), - JurisdictionHelper.booleanSelector(cb, caseService.inJurisdictionOrOwned(caseQueryContext))); + JurisdictionHelper.booleanSelector(cb, service.inJurisdictionOrOwned(caseQueryContext))); Predicate filter = CriteriaBuilderHelper - .and(cb, caseService.createUserFilter(cb, cq, caze), caseService.createCriteriaFilter(caseCriteria, caseQueryContext)); + .and(cb, service.createUserFilter(cb, cq, caze), service.createCriteriaFilter(caseCriteria, caseQueryContext)); if (filter != null) { cq.where(filter); @@ -3612,15 +3593,15 @@ public FollowUpPeriodDto calculateFollowUpUntilDate(CaseDataDto caseDto, boolean } public boolean isCaseEditAllowed(String caseUuid) { - Case caze = caseService.getByUuid(caseUuid); + Case caze = service.getByUuid(caseUuid); - return caseService.isCaseEditAllowed(caze); + return service.isCaseEditAllowed(caze); } @Override public void sendMessage(List caseUuids, String subject, String messageContent, MessageType... messageTypes) { caseUuids.forEach(uuid -> { - final Case aCase = caseService.getByUuid(uuid); + final Case aCase = service.getByUuid(uuid); final Person person = aCase.getPerson(); try { @@ -3840,28 +3821,35 @@ public List getDuplicates(@Valid CasePersonDto casePerson) { @Override public List getByPersonUuids(List personUuids) { - return caseService.getByPersonUuids(personUuids).stream().map(CaseFacadeEjb::toDto).collect(Collectors.toList()); + return service.getByPersonUuids(personUuids).stream().map(c->toDto(c)).collect(Collectors.toList()); } @Override public List getByExternalId(String externalId) { Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); - return caseService.getByExternalId(externalId).stream().map(c -> convertToDto(c, pseudonymizer)).collect(Collectors.toList()); + return service.getByExternalId(externalId).stream().map(c -> convertToDto(c, pseudonymizer)).collect(Collectors.toList()); } @Override public void updateExternalData(@Valid List externalData) throws ExternalDataUpdateException { - caseService.updateExternalData(externalData); + service.updateExternalData(externalData); } @Override protected void delete(Case entity) { - caseService.delete(entity); + service.delete(entity); } @LocalBean @Stateless public static class CaseFacadeEjbLocal extends CaseFacadeEjb { + public CaseFacadeEjbLocal() { + } + + @Inject + public CaseFacadeEjbLocal(CaseService service, UserService userService) { + super(service, userService); + } } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java index ca267e48ef7..50ccb941297 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java @@ -53,6 +53,7 @@ import javax.transaction.Transactional; import javax.validation.constraints.NotNull; +import de.symeda.sormas.backend.common.AbstractCoreAdoService; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -158,7 +159,7 @@ @Stateless @LocalBean -public class CaseService extends AbstractDeletableAdoService { +public class CaseService extends AbstractCoreAdoService { private static final long SECONDS_30_DAYS = 30L * 24L * 60L * 60L; @@ -1244,7 +1245,7 @@ public void updateFollowUpDetails(Case caze, boolean followUpStatusChangedByUser statusChangedBySystem = true; } } else { - CaseDataDto caseDto = CaseFacadeEjbLocal.toDto(caze); + CaseDataDto caseDto = caseFacade.toDto(caze); Date currentFollowUpUntil = caseDto.getFollowUpUntil(); Date earliestSampleDate = null; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java index f3ea1287f68..c3d15c72298 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java @@ -20,15 +20,22 @@ import java.util.List; import java.util.stream.Collectors; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + import de.symeda.sormas.api.EntityDto; import de.symeda.sormas.api.ReferenceDto; +import de.symeda.sormas.api.deletionconfiguration.DeletionReference; +import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.api.utils.ValidationRuntimeException; import de.symeda.sormas.api.utils.criteria.BaseCriteria; +import de.symeda.sormas.backend.deletionconfiguration.DeletionConfiguration; import de.symeda.sormas.backend.user.UserService; import de.symeda.sormas.backend.util.Pseudonymizer; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import de.symeda.sormas.backend.util.QueryHelper; public abstract class AbstractCoreEjb, CRITERIA extends BaseCriteria> extends AbstractBaseEjb { @@ -109,6 +116,37 @@ public DTO convertToDto(ADO source, Pseudonymizer pseudonymizer) { return dto; } + public void executeAutomaticDeletion(DeletionConfiguration entityConfig) { + + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(adoClass); + Root from = cq.from(adoClass); + + Date referenceDeletionDate = DateHelper.subtractDays(new Date(), entityConfig.getDeletionPeriod()); + cq.where(cb.lessThanOrEqualTo(from.get(getDeleteReferenceField(entityConfig.getDeletionReference())), referenceDeletionDate)); + + List toDeleteEntities = QueryHelper.getResultList(em, cq, null, null); + + toDeleteEntities.forEach(entity -> { + delete(entity); + }); + } + + protected void delete(ADO entity) { + service.delete(entity); + } + + protected String getDeleteReferenceField(DeletionReference deletionReference) { + switch (deletionReference) { + case CREATION: + return AbstractDomainObject.CREATION_DATE; + case END: + return AbstractDomainObject.CHANGE_DATE; + default: + throw new IllegalArgumentException("deletion reference " + deletionReference + " not supported in " + getClass().getSimpleName()); + } + } + protected abstract void pseudonymizeDto(ADO source, DTO dto, Pseudonymizer pseudonymizer); protected abstract void restorePseudonymizedDto(DTO dto, DTO existingDto, ADO entity, Pseudonymizer pseudonymizer); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java index 521a02e48f7..2716d898719 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java @@ -89,7 +89,6 @@ import de.symeda.sormas.api.contact.MergeContactIndexDto; import de.symeda.sormas.api.contact.SimilarContactDto; import de.symeda.sormas.api.dashboard.DashboardContactDto; -import de.symeda.sormas.api.deletionconfiguration.DeletionReference; import de.symeda.sormas.api.document.DocumentRelatedEntityType; import de.symeda.sormas.api.epidata.EpiDataDto; import de.symeda.sormas.api.epidata.EpiDataHelper; @@ -144,7 +143,6 @@ import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.common.TaskCreationException; -import de.symeda.sormas.backend.deletionconfiguration.AbstractCoreEntityFacade; import de.symeda.sormas.backend.disease.DiseaseConfigurationFacadeEjb.DiseaseConfigurationFacadeEjbLocal; import de.symeda.sormas.backend.document.Document; import de.symeda.sormas.backend.document.DocumentService; @@ -371,7 +369,7 @@ public ContactDto save(ContactDto dto, boolean handleChanges, boolean handleCase service.udpateContactStatus(entity); if (handleCaseChanges && entity.getCaze() != null) { - caseFacade.onCaseChanged(CaseFacadeEjbLocal.toDto(entity.getCaze()), entity.getCaze(), internal); + caseFacade.onCaseChanged(caseFacade.toDto(entity.getCaze()), entity.getCaze(), internal); } onContactChanged(existingContactDto, entity, internal); @@ -495,7 +493,7 @@ private void deleteContact(Contact contact) { externalJournalService.handleExternalJournalPersonUpdateAsync(contact.getPerson().toReference()); service.delete(contact); if (contact.getCaze() != null) { - caseFacade.onCaseChanged(CaseFacadeEjbLocal.toDto(contact.getCaze()), contact.getCaze()); + caseFacade.onCaseChanged(caseFacade.toDto(contact.getCaze()), contact.getCaze()); } } @@ -2080,7 +2078,7 @@ public void updateExternalData(@Valid List externalData) throws @Override protected void delete(Contact entity) { - contactService.delete(entity); + service.delete(entity); } private float calculateCompleteness(Contact contact) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/AbstractCoreEntityFacade.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/AbstractCoreEntityFacade.java deleted file mode 100644 index ad42db0fd0e..00000000000 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/AbstractCoreEntityFacade.java +++ /dev/null @@ -1,58 +0,0 @@ -package de.symeda.sormas.backend.deletionconfiguration; - -import java.util.Date; -import java.util.List; - -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.Root; - -import de.symeda.sormas.api.deletionconfiguration.DeletionReference; -import de.symeda.sormas.api.utils.DateHelper; -import de.symeda.sormas.backend.common.AbstractDomainObject; -import de.symeda.sormas.backend.common.CoreAdo; -import de.symeda.sormas.backend.util.ModelConstants; -import de.symeda.sormas.backend.util.QueryHelper; - -public abstract class AbstractCoreEntityFacade { - - private Class entityClass; - - @PersistenceContext(unitName = ModelConstants.PERSISTENCE_UNIT_NAME) - protected EntityManager em; - - protected AbstractCoreEntityFacade(Class entityClass) { - this.entityClass = entityClass; - } - - public void executeAutomaticDeletion(DeletionConfiguration entityConfig) { - - CriteriaBuilder cb = em.getCriteriaBuilder(); - CriteriaQuery cq = cb.createQuery(entityClass); - Root from = cq.from(entityClass); - - Date referenceDeletionDate = DateHelper.subtractDays(new Date(), entityConfig.deletionPeriod); - cq.where(cb.lessThanOrEqualTo(from.get(getDeleteReferenceField(entityConfig.deletionReference)), referenceDeletionDate)); - - List toDeleteEntities = QueryHelper.getResultList(em, cq, null, null); - - toDeleteEntities.forEach(entity -> { - delete(entity); - }); - } - - protected abstract void delete(T entity); - - protected String getDeleteReferenceField(DeletionReference deletionReference) { - switch (deletionReference) { - case CREATION: - return AbstractDomainObject.CREATION_DATE; - case END: - return AbstractDomainObject.CHANGE_DATE; - default: - throw new IllegalArgumentException("deletion reference " + deletionReference + " not supported in " + getClass().getSimpleName()); - } - } -} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/CoreEntityDeletionService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/CoreEntityDeletionService.java index 4b8f2e9916d..7ba51d4688e 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/CoreEntityDeletionService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/CoreEntityDeletionService.java @@ -9,6 +9,7 @@ import javax.inject.Inject; import de.symeda.sormas.backend.caze.CaseFacadeEjb; +import de.symeda.sormas.backend.common.AbstractCoreEjb; import de.symeda.sormas.backend.contact.ContactFacadeEjb; import de.symeda.sormas.backend.event.EventFacadeEjb; import de.symeda.sormas.backend.event.EventParticipantFacadeEjb; @@ -58,14 +59,14 @@ public void executeAutomaticDeletion() { private static final class EntityTypeFacadePair { private final CoreEntityType coreEntityType; - private final AbstractCoreEntityFacade entityFacade; + private final AbstractCoreEjb entityFacade; - private EntityTypeFacadePair(CoreEntityType coreEntityType, AbstractCoreEntityFacade entityFacade) { + private EntityTypeFacadePair(CoreEntityType coreEntityType, AbstractCoreEjb entityFacade) { this.coreEntityType = coreEntityType; this.entityFacade = entityFacade; } - public static EntityTypeFacadePair of(CoreEntityType coreEntityType, AbstractCoreEntityFacade entityFacade) { + public static EntityTypeFacadePair of(CoreEntityType coreEntityType, AbstractCoreEjb entityFacade) { return new EntityTypeFacadePair(coreEntityType, entityFacade); } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java index 28c0cce21f7..6aa9b3a0dd1 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java @@ -43,8 +43,6 @@ import javax.ejb.TransactionAttributeType; import javax.enterprise.concurrent.ManagedScheduledExecutorService; import javax.inject.Inject; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.CriteriaUpdate; @@ -97,7 +95,6 @@ import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.contact.Contact; -import de.symeda.sormas.backend.deletionconfiguration.AbstractCoreEntityFacade; import de.symeda.sormas.backend.externalsurveillancetool.ExternalSurveillanceToolGatewayFacadeEjb.ExternalSurveillanceToolGatewayFacadeEjbLocal; import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal; import de.symeda.sormas.backend.infrastructure.community.Community; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java index 1025891c1dc..1d1c559aa1f 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java @@ -98,7 +98,6 @@ import de.symeda.sormas.backend.common.messaging.NotificationDeliveryFailedException; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.contact.ContactService; -import de.symeda.sormas.backend.deletionconfiguration.AbstractCoreEntityFacade; import de.symeda.sormas.backend.event.EventFacadeEjb.EventFacadeEjbLocal; import de.symeda.sormas.backend.immunization.ImmunizationEntityHelper; import de.symeda.sormas.backend.immunization.entity.Immunization; @@ -855,7 +854,7 @@ public boolean exists(String personUuid, String eventUuid) { @Override public EventParticipantReferenceDto getReferenceByUuid(String uuid) { - EventParticipant eventParticipant = eventParticipantService.getByUuid(uuid); + EventParticipant eventParticipant = service.getByUuid(uuid); return new EventParticipantReferenceDto(eventParticipant.getUuid()); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java index 4deab4a23f6..10bd8d2c019 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java @@ -76,10 +76,6 @@ import de.symeda.sormas.backend.caze.CaseFacadeEjb; import de.symeda.sormas.backend.caze.CaseService; import de.symeda.sormas.backend.common.AbstractCoreEjb; -import de.symeda.sormas.backend.contact.ContactService; -import de.symeda.sormas.backend.deletionconfiguration.AbstractCoreEntityFacade; -import de.symeda.sormas.backend.event.EventParticipantService; -import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb; import de.symeda.sormas.backend.immunization.entity.Immunization; import de.symeda.sormas.backend.infrastructure.community.CommunityFacadeEjb; import de.symeda.sormas.backend.infrastructure.community.CommunityService; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java index b0e19672bc8..5dc46958743 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java @@ -1073,7 +1073,7 @@ public void onPersonChanged(PersonDto existingPerson, Person newPerson, boolean // Call onCaseChanged once for every case to update case classification // Attention: this may lead to infinite recursion when not properly implemented for (Case personCase : personCases) { - CaseDataDto existingCase = CaseFacadeEjbLocal.toDto(personCase); + CaseDataDto existingCase = caseFacade.toDto(personCase); caseFacade.onCaseChanged(existingCase, personCase, syncShares); } @@ -1120,7 +1120,7 @@ public void onPersonChanged(PersonDto existingPerson, Person newPerson, boolean && personCase.getOutcome() != CaseOutcome.DECEASED && (personCase.getReportDate().before(DateHelper.addDays(newPerson.getDeathDate(), 30)) && personCase.getReportDate().after(DateHelper.subtractDays(newPerson.getDeathDate(), 30)))) { - CaseDataDto existingCase = CaseFacadeEjbLocal.toDto(personCase); + CaseDataDto existingCase = caseFacade.toDto(personCase); personCase.setOutcome(CaseOutcome.DECEASED); personCase.setOutcomeDate(newPerson.getDeathDate()); caseFacade.onCaseChanged(existingCase, personCase, syncShares); @@ -1138,7 +1138,7 @@ public void onPersonChanged(PersonDto existingPerson, Person newPerson, boolean newPerson.setCauseOfDeathDisease(null); // update the latest associated case, if it was set to deceased && and if the case-disease was also the causeofdeath-disease if (personCase != null && personCase.getOutcome() == CaseOutcome.DECEASED) { - CaseDataDto existingCase = CaseFacadeEjbLocal.toDto(personCase); + CaseDataDto existingCase = caseFacade.toDto(personCase); personCase.setOutcome(CaseOutcome.NO_OUTCOME); personCase.setOutcomeDate(null); caseFacade.onCaseChanged(existingCase, personCase, syncShares); @@ -1154,7 +1154,7 @@ public void onPersonChanged(PersonDto existingPerson, Person newPerson, boolean if (personCase != null && personCase.getOutcome() == CaseOutcome.DECEASED && newPerson.getCauseOfDeath() == CauseOfDeath.EPIDEMIC_DISEASE) { - CaseDataDto existingCase = CaseFacadeEjbLocal.toDto(personCase); + CaseDataDto existingCase = caseFacade.toDto(personCase); personCase.setOutcomeDate(newPerson.getDeathDate()); caseFacade.onCaseChanged(existingCase, personCase, syncShares); } @@ -1175,7 +1175,7 @@ public void onPersonChanged(PersonDto existingPerson, Person newPerson, boolean // Update case list after previous onCaseChanged personCases = caseService.findBy(new CaseCriteria().person(new PersonReferenceDto(newPerson.getUuid())), true); for (Case personCase : personCases) { - CaseDataDto existingCase = CaseFacadeEjbLocal.toDto(personCase); + CaseDataDto existingCase = caseFacade.toDto(personCase); if (newPerson.getApproximateAge() == null) { personCase.setCaseAge(null); } else if (newPerson.getApproximateAgeType() == ApproximateAgeType.MONTHS) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java index bfe305a05db..160ffbd1435 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java @@ -254,7 +254,7 @@ private void handleAssotiatedObjectChanges(PathogenTest pathogenTest, boolean sy // Update case classification if necessary final Case associatedCase = pathogenTest.getSample().getAssociatedCase(); if (associatedCase != null) { - caseFacade.onCaseChanged(CaseFacadeEjbLocal.toDto(associatedCase), associatedCase, syncShares); + caseFacade.onCaseChanged(caseFacade.toDto(associatedCase), associatedCase, syncShares); } // update contact if necessary diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java index 6bdb551b5c3..8dcfc4de807 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java @@ -981,7 +981,7 @@ private void onSampleChanged(SampleDto existingSample, Sample newSample, boolean private void handleAssotiatedObjectChanges(Sample newSample, boolean syncShares) { if (newSample.getAssociatedCase() != null) { - caseFacade.onCaseChanged(CaseFacadeEjb.toDto(newSample.getAssociatedCase()), newSample.getAssociatedCase(), syncShares); + caseFacade.onCaseChanged(caseFacade.toDto(newSample.getAssociatedCase()), newSample.getAssociatedCase(), syncShares); } if (newSample.getAssociatedContact() != null) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/caze/ReceivedCaseProcessor.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/caze/ReceivedCaseProcessor.java index d909441390a..c56382da14c 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/caze/ReceivedCaseProcessor.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/caze/ReceivedCaseProcessor.java @@ -17,6 +17,7 @@ import java.util.Optional; +import javax.ejb.EJB; import javax.ejb.LocalBean; import javax.ejb.Stateless; import javax.inject.Inject; @@ -42,6 +43,9 @@ public class ReceivedCaseProcessor extends ReceivedDataProcessor { + @EJB + private CaseFacadeEjb.CaseFacadeEjbLocal caseFacade; + public ReceivedCaseProcessor() { } @@ -56,7 +60,7 @@ protected ReceivedCaseProcessor( @Override public void handleReceivedData(SormasToSormasCaseDto sharedData, Case existingCase) { - handleIgnoredProperties(sharedData.getEntity(), CaseFacadeEjb.toDto(existingCase)); + handleIgnoredProperties(sharedData.getEntity(), caseFacade.toDto(existingCase)); handleIgnoredProperties( sharedData.getPerson(), diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/share/shareinfo/SormasToSormasShareInfoService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/share/shareinfo/SormasToSormasShareInfoService.java index 9792732e760..fe876a75e8b 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/share/shareinfo/SormasToSormasShareInfoService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/share/shareinfo/SormasToSormasShareInfoService.java @@ -56,6 +56,8 @@ public class SormasToSormasShareInfoService extends AdoServiceWithUserFilter 0) { - externalSurveillanceToolGatewayFacade.deleteCases(cases.stream().map(CaseFacadeEjb::toDto).collect(Collectors.toList())); + externalSurveillanceToolGatewayFacade.deleteCases(cases.stream().map(caseFacade::toDto).collect(Collectors.toList())); } if (events.size() > 0) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java index 5f912776772..15d2d8d4a65 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java @@ -29,7 +29,6 @@ import de.symeda.sormas.backend.caze.CaseFacadeEjb; import de.symeda.sormas.backend.caze.CaseService; import de.symeda.sormas.backend.common.AbstractCoreEjb; -import de.symeda.sormas.backend.deletionconfiguration.AbstractCoreEntityFacade; import de.symeda.sormas.backend.infrastructure.community.CommunityFacadeEjb; import de.symeda.sormas.backend.infrastructure.community.CommunityService; import de.symeda.sormas.backend.infrastructure.district.DistrictFacadeEjb; @@ -122,7 +121,7 @@ public void deleteTravelEntry(String travelEntryUuid) { service.delete(travelEntry); if (travelEntry.getResultingCase() != null) { - caseFacade.onCaseChanged(CaseFacadeEjb.toDto(travelEntry.getResultingCase()), travelEntry.getResultingCase()); + caseFacade.onCaseChanged(caseFacade.toDto(travelEntry.getResultingCase()), travelEntry.getResultingCase()); } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/visit/VisitFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/visit/VisitFacadeEjb.java index e05aac88b42..3815108d393 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/visit/VisitFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/visit/VisitFacadeEjb.java @@ -627,7 +627,7 @@ private void onVisitChanged(VisitDto existingVisit, Visit newVisit) { if (newVisit.getCaze() != null) { // Update case symptoms - CaseDataDto caze = CaseFacadeEjb.toDto(newVisit.getCaze()); + CaseDataDto caze = caseFacade.toDto(newVisit.getCaze()); SymptomsDto caseSymptoms = caze.getSymptoms(); SymptomsHelper.updateSymptoms(toDto(newVisit).getSymptoms(), caseSymptoms); caseFacade.saveCase(caze, true); From 4b71493bfebb7a843764f8fa5438f8d5da839ba1 Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Wed, 2 Feb 2022 17:32:15 +0100 Subject: [PATCH 011/253] I changed a methods in PersonDirectorySteps and maked a change in scenario PersonDirectorySteps. Also I modified PresentCondition enum --- .../e2etests/enums/PresentCondition.java | 2 +- .../persons/PersonDirectorySteps.java | 81 ++++++++++++++----- .../features/sanity/web/Persons.feature | 18 +++-- 3 files changed, 70 insertions(+), 31 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PresentCondition.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PresentCondition.java index dfaa6b87608..add9c5a3fb3 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PresentCondition.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PresentCondition.java @@ -37,7 +37,7 @@ public enum PresentCondition { public static String getRandomPresentCondition() { Random random = new Random(); - return String.valueOf(PresentCondition.values()[random.nextInt(values().length)]); + return String.valueOf(PresentCondition.values()[random.nextInt(values().length)].condition); } @SneakyThrows diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java index a23ccc7d312..b897ab10420 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java @@ -23,6 +23,7 @@ import static org.sormas.e2etests.pages.application.persons.EditPersonPage.getByPersonUuid; import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.*; +import com.github.javafaker.Faker; import cucumber.api.java8.En; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -52,6 +53,7 @@ public PersonDirectorySteps( @Named("ENVIRONMENT_URL") String environmentUrl, ApiState apiState, DataOperations dataOperations, + Faker faker, AssertHelpers assertHelpers) { this.webDriverHelpers = webDriverHelpers; @@ -88,6 +90,7 @@ public PersonDirectorySteps( "I choose random value for Month of birth filter in Persons for the last created person by API", () -> { String monthOfBirth = apiState.getLastCreatedPerson().getBirthdateMM().toString(); + webDriverHelpers.waitForPageLoaded(); webDriverHelpers.selectFromCombobox(BIRTH_MONTH_COMBOBOX, monthOfBirth); }); @@ -95,13 +98,26 @@ public PersonDirectorySteps( "I choose random value for Day of birth filter in Persons for the last created person by API", () -> { String dayOfBirth = apiState.getLastCreatedPerson().getBirthdateDD().toString(); + webDriverHelpers.waitForPageLoaded(); webDriverHelpers.selectFromCombobox(BIRTH_DAY_COMBOBOX, dayOfBirth); }); + Then( + "I fill Persons UUID for the last created person by API", + () -> { + String personUUID = + dataOperations.getPartialUuidFromAssociatedLink( + apiState.getLastCreatedPerson().getUuid()); + System.out.println(personUUID); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.fillInWebElement(MULTIPLE_OPTIONS_SEARCH_INPUT, personUUID); + }); + Then( "I choose present condition field from specific range for the last created person by API", () -> { String presentCondition = apiState.getLastCreatedPerson().getPresentCondition(); + webDriverHelpers.waitForPageLoaded(); webDriverHelpers.selectFromCombobox( PRESENT_CONDITION, PresentCondition.getValueFor(presentCondition)); }); @@ -110,6 +126,7 @@ public PersonDirectorySteps( "I choose random value of Region in Persons for the last created person by API", () -> { String regionName = apiState.getLastCreatedPerson().getAddress().getRegion(); + webDriverHelpers.waitForPageLoaded(); webDriverHelpers.selectFromCombobox( REGIONS_COMBOBOX, RegionsValues.getValueFor(regionName)); }); @@ -118,6 +135,7 @@ public PersonDirectorySteps( "I choose random value of District in Persons for the last created person by API", () -> { String districtName = apiState.getLastCreatedPerson().getAddress().getDistrict(); + webDriverHelpers.waitForPageLoaded(); webDriverHelpers.selectFromCombobox( DISTRICTS_COMBOBOX, DistrictsValues.getValueFor(districtName)); }); @@ -126,19 +144,23 @@ public PersonDirectorySteps( "I choose random value of Community in Persons for the last created person by API", () -> { String communityName = apiState.getLastCreatedPerson().getAddress().getCommunity(); + webDriverHelpers.waitForPageLoaded(); webDriverHelpers.selectFromCombobox( COMMUNITY_PERSON_COMBOBOX, CommunityValues.getValueFor(communityName)); }); Then( "I check that number of displayed Person results is {int}", - (Integer number) -> - assertHelpers.assertWithPoll20Second( - () -> - Assert.assertEquals( - webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), - number.intValue(), - "Number of displayed persons is not correct"))); + (Integer number) -> { + webDriverHelpers.waitForPageLoaded(); + assertHelpers.assertWithPoll20Second( + () -> + Assert.assertEquals( + webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), + number.intValue(), + "Number of displayed persons is not correct")); + }); + When( "I click on the APPLY FILTERS button for Person", () -> { @@ -149,27 +171,42 @@ public PersonDirectorySteps( }); Then( - "I change Year of birth filter to {string} for Person", - (String yearOfBirth) -> - webDriverHelpers.selectFromCombobox(BIRTH_YEAR_COMBOBOX, yearOfBirth)); + "I change Year of birth filter by random value for Person", + () -> { + Integer yearOfBirth = faker.number().numberBetween(1900, 2022); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(BIRTH_YEAR_COMBOBOX, yearOfBirth.toString()); + }); Then( - "I change Month of birth filter to {string} for Person", - (String monthOfBirth) -> - webDriverHelpers.selectFromCombobox(BIRTH_MONTH_COMBOBOX, monthOfBirth)); + "I change Month of birth filter by random value for Person", + () -> { + Integer monthOfBirth = faker.number().numberBetween(1, 12); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(BIRTH_MONTH_COMBOBOX, monthOfBirth.toString()); + }); Then( - "I change Day of birth filter to {string} for Person", - (String dayOfBirth) -> webDriverHelpers.selectFromCombobox(BIRTH_DAY_COMBOBOX, dayOfBirth)); + "I change Day of birth filter by random value for Person", + () -> { + Integer dayOfBirth = faker.number().numberBetween(1, 29); + webDriverHelpers.selectFromCombobox(BIRTH_DAY_COMBOBOX, dayOfBirth.toString()); + }); Then( - "I change present condition filter to {string} for Person", - (String presentCondition) -> - webDriverHelpers.selectFromCombobox(PRESENT_CONDITION, presentCondition)); + "I change present condition filter to random for Person", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + PRESENT_CONDITION, PresentCondition.getRandomPresentCondition()); + }); Then( "I change REGION filter to {string} for Person", - (String region) -> webDriverHelpers.selectFromCombobox(REGIONS_COMBOBOX, region)); + (String region) -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(REGIONS_COMBOBOX, region); + }); Then( "I change DISTRICT filter to {string} for Person", @@ -282,13 +319,13 @@ public PersonDirectorySteps( searchText = personUUID; break; case "full name": - searchText = "Tom Jerry"; + searchText = faker.name().fullName(); break; case "phone number": - searchText = "(06713) 6606268"; + searchText = faker.phoneNumber().phoneNumber(); break; case "email": - searchText = "Tom.Jerry@person.com"; + searchText = faker.name().fullName() + "@PERSON.com"; break; } webDriverHelpers.fillInWebElement(MULTIPLE_OPTIONS_SEARCH_INPUT, searchText); diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature index 68016d2fbae..8e3819bfd5a 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature @@ -31,36 +31,38 @@ Feature: Edit Persons Then I choose random value for Year of birth filter in Persons for the last created person by API And I choose random value for Month of birth filter in Persons for the last created person by API And I choose random value for Day of birth filter in Persons for the last created person by API - Then I search after last created person from API by factor "uuid" + Then I fill Persons UUID for the last created person by API And I choose present condition field from specific range for the last created person by API And I choose random value of Region in Persons for the last created person by API And I choose random value of District in Persons for the last created person by API And I choose random value of Community in Persons for the last created person by API Then I click on the APPLY FILTERS button for Person And I check that number of displayed Person results is 1 - And I change Year of birth filter to "1955" for Person + And I change Year of birth filter by random value for Person Then I click on the APPLY FILTERS button for Person And I check that number of displayed Person results is 0 Then I choose random value for Year of birth filter in Persons for the last created person by API Then I click on the APPLY FILTERS button for Person And I check that number of displayed Person results is 1 - And I change Month of birth filter to "4" for Person + And I change Month of birth filter by random value for Person Then I click on the APPLY FILTERS button for Person And I check that number of displayed Person results is 0 And I choose random value for Month of birth filter in Persons for the last created person by API Then I click on the APPLY FILTERS button for Person And I check that number of displayed Person results is 1 - And I change Day of birth filter to "13" for Person + And I change Day of birth filter by random value for Person Then I click on the APPLY FILTERS button for Person And I check that number of displayed Person results is 0 And I choose random value for Day of birth filter in Persons for the last created person by API Then I click on the APPLY FILTERS button for Person + And I search after last created person from API by factor "full name" + And I click on the APPLY FILTERS button for Person And I check that number of displayed Person results is 1 - Then I change "uuid" information data field for Person + Then I change "full name" information data field for Person And I click on the APPLY FILTERS button for Person And I check that number of displayed Person results is 0 - And I search after last created person from API by factor "uuid" - And I change present condition filter to "Unknown" for Person + Then I fill Persons UUID for the last created person by API + And I change present condition filter to random for Person And I click on the APPLY FILTERS button for Person And I check that number of displayed Person results is 0 And I choose present condition field from specific range for the last created person by API @@ -80,4 +82,4 @@ Feature: Edit Persons Then I click on the APPLY FILTERS button for Person And I check that number of displayed Person results is 1 And I click on the APPLY FILTERS button for Person - And I click on the RESET FILTERS button for Person \ No newline at end of file + And I click on the RESET FILTERS button for Person From 2c42a94280686071796e2e397c5ef3732cfcd25b Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Thu, 3 Feb 2022 08:26:56 +0200 Subject: [PATCH 012/253] #7246 - fix compilation issues --- .../main/java/de/symeda/sormas/rest/ContactResource.java | 6 +++--- .../de/symeda/sormas/ui/campaign/CampaignController.java | 6 +++--- .../java/de/symeda/sormas/ui/events/EventController.java | 8 ++++---- .../test/java/de/symeda/sormas/ui/TestDataCreator.java | 2 +- .../sormas/ui/contact/importer/ContactImporterTest.java | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/sormas-rest/src/main/java/de/symeda/sormas/rest/ContactResource.java b/sormas-rest/src/main/java/de/symeda/sormas/rest/ContactResource.java index 6405d53ee82..54ebd2d7956 100644 --- a/sormas-rest/src/main/java/de/symeda/sormas/rest/ContactResource.java +++ b/sormas-rest/src/main/java/de/symeda/sormas/rest/ContactResource.java @@ -62,13 +62,13 @@ public class ContactResource extends EntityDtoResource { @GET @Path("/all/{since}") public List getAllContacts(@PathParam("since") long since) { - return FacadeProvider.getContactFacade().getAllActiveContactsAfter(new Date(since)); + return FacadeProvider.getContactFacade().getAllAfter(new Date(since)); } @GET @Path("/all/{since}/{size}/{lastSynchronizedUuid}") public List getAllContacts(@PathParam("since") long since, @PathParam("size") int size, @PathParam("lastSynchronizedUuid") String lastSynchronizedUuid) { - return FacadeProvider.getContactFacade().getAllActiveContactsAfter(new Date(since), size, lastSynchronizedUuid); + return FacadeProvider.getContactFacade().getAllAfter(new Date(since), size, lastSynchronizedUuid); } @POST @@ -89,7 +89,7 @@ public List getByPersonUuids(List uuids) { @Path("/push") public List postContacts(@Valid List dtos) { - List result = savePushedDto(dtos, FacadeProvider.getContactFacade()::saveContact); + List result = savePushedDto(dtos, FacadeProvider.getContactFacade()::save); return result; } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/campaign/CampaignController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/campaign/CampaignController.java index a8650a232ab..7f8c9281aec 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/campaign/CampaignController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/campaign/CampaignController.java @@ -125,7 +125,7 @@ private void archiveOrDearchiveCampaign(String campaignUuid, boolean archive) { 640, e -> { if (e) { - FacadeProvider.getCampaignFacade().archiveOrDearchiveCampaign(campaignUuid, true); + FacadeProvider.getCampaignFacade().archive(campaignUuid); SormasUI.refreshView(); } }); @@ -143,7 +143,7 @@ private void archiveOrDearchiveCampaign(String campaignUuid, boolean archive) { 640, e -> { if (e) { - FacadeProvider.getCampaignFacade().archiveOrDearchiveCampaign(campaignUuid, false); + FacadeProvider.getCampaignFacade().dearchive(campaignUuid); SormasUI.refreshView(); } }); @@ -197,7 +197,7 @@ public void discard() { campaignComponent.addCommitListener(() -> { if (!campaignEditForm.getFieldGroup().isModified()) { CampaignDto dto = campaignEditForm.getValue(); - FacadeProvider.getCampaignFacade().saveCampaign(dto); + FacadeProvider.getCampaignFacade().save(dto); SormasUI.refreshView(); callback.run(); } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventController.java index 3be4ed642f0..9e8705f20a6 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventController.java @@ -891,7 +891,7 @@ private void archiveOrDearchiveEvent(String eventUuid, boolean archive) { 640, e -> { if (e.booleanValue() == true) { - FacadeProvider.getEventFacade().archiveOrDearchiveEvent(eventUuid, true); + FacadeProvider.getEventFacade().archive(eventUuid); Notification.show( String.format(I18nProperties.getString(Strings.messageEventArchived), I18nProperties.getString(Strings.entityEvent)), Type.ASSISTIVE_NOTIFICATION); @@ -912,7 +912,7 @@ private void archiveOrDearchiveEvent(String eventUuid, boolean archive) { 640, e -> { if (e.booleanValue()) { - FacadeProvider.getEventFacade().archiveOrDearchiveEvent(eventUuid, false); + FacadeProvider.getEventFacade().dearchive(eventUuid); Notification.show( String.format(I18nProperties.getString(Strings.messageEventDearchived), I18nProperties.getString(Strings.entityEvent)), Type.ASSISTIVE_NOTIFICATION); @@ -1025,7 +1025,7 @@ public void archiveAllSelectedItems(Collection selectedRows, Runn e -> { if (e.booleanValue() == true) { for (EventIndexDto selectedRow : selectedRows) { - FacadeProvider.getEventFacade().archiveOrDearchiveEvent(selectedRow.getUuid(), true); + FacadeProvider.getEventFacade().archive(selectedRow.getUuid()); } callback.run(); new Notification( @@ -1056,7 +1056,7 @@ public void dearchiveAllSelectedItems(Collection selectedRows, Ru e -> { if (e.booleanValue() == true) { for (EventIndexDto selectedRow : selectedRows) { - FacadeProvider.getEventFacade().archiveOrDearchiveEvent(selectedRow.getUuid(), false); + FacadeProvider.getEventFacade().dearchive(selectedRow.getUuid()); } callback.run(); new Notification( diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/TestDataCreator.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/TestDataCreator.java index 175a0c33cb9..32c0f16463d 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/TestDataCreator.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/TestDataCreator.java @@ -658,7 +658,7 @@ public CampaignDto createCampaign(UserDto user) { campaign.setName("CampaignName"); campaign.setDescription("Campaign description"); - campaign = FacadeProvider.getCampaignFacade().saveCampaign(campaign); + campaign = FacadeProvider.getCampaignFacade().save(campaign); return campaign; } diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/contact/importer/ContactImporterTest.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/contact/importer/ContactImporterTest.java index 7ea8cd74528..c98ce2a4a2d 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/contact/importer/ContactImporterTest.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/contact/importer/ContactImporterTest.java @@ -238,7 +238,7 @@ public void testImportCaseContactsDifferentAddressTypes() ContactImporter contactImporter = new ContactImporterExtension(csvFile, false, user, caze); ImportResultStatus importResult = contactImporter.runImport(); - List contacts = getContactFacade().getAllActiveContactsAfter(null); + List contacts = getContactFacade().getAllAfter(null); assertEquals(3, contacts.size()); From 02f9c9ece093655eb0b63243b18326a2fa76301b Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Thu, 3 Feb 2022 09:37:31 +0200 Subject: [PATCH 013/253] #7246 - move isArchived method to core facade --- .../de/symeda/sormas/api/CoreBaseFacade.java | 2 + .../sormas/api/campaign/CampaignFacade.java | 2 - .../de/symeda/sormas/api/caze/CaseFacade.java | 12 +- .../symeda/sormas/api/event/EventFacade.java | 2 - .../api/immunization/ImmunizationFacade.java | 4 - .../api/travelentry/TravelEntryFacade.java | 2 - .../resources/doc/SORMAS_Data_Dictionary.xlsx | Bin 253756 -> 253758 bytes .../resources/doc/SORMAS_User_Rights.xlsx | Bin 19067 -> 19069 bytes .../backend/campaign/CampaignFacadeEjb.java | 16 - .../sormas/backend/caze/CaseFacadeEjb.java | 40 +-- .../caze/caseimport/CaseImportFacadeEjb.java | 2 +- .../ClinicalVisitFacadeEjb.java | 2 +- .../common/AbstractCoreAdoService.java | 17 ++ .../backend/common/AbstractCoreEjb.java | 4 + .../sormas/backend/event/EventFacadeEjb.java | 15 - .../immunization/ImmunizationFacadeEjb.java | 12 - .../caze/ProcessedCaseDataPersister.java | 4 +- .../travelentry/TravelEntryFacadeEjb.java | 5 - .../services/TravelEntryService.java | 11 - .../sormas/backend/visit/VisitFacadeEjb.java | 3 +- .../sormas/backend/AbstractBeanTest.java | 2 +- .../sormas/backend/TestDataCreator.java | 4 +- .../caze/CaseClassificationLogicTest.java | 280 +++++++++--------- .../CaseFacadeEjbPseudonymizationTest.java | 13 +- .../backend/caze/CaseFacadeEjbTest.java | 84 +++--- .../backend/caze/CasePartialUpdateTest.java | 2 +- .../caze/CaseStatisticsFacadeEjbTest.java | 2 +- .../backend/contact/ContactFacadeEjbTest.java | 4 +- .../dashboard/DashboardFacadeEjbTest.java | 2 +- .../backend/person/PersonFacadeEjbTest.java | 22 +- .../sample/PathogenTestFacadeEjbTest.java | 2 +- .../backend/sample/SampleFacadeEjbTest.java | 6 +- .../backend/task/TaskFacadeEjbTest.java | 4 +- .../de/symeda/sormas/rest/CaseResource.java | 2 +- .../symeda/sormas/ui/caze/CaseController.java | 14 +- .../ui/clinicalcourse/ClinicalCourseView.java | 2 +- .../sormas/ui/configuration/DevModeView.java | 4 +- .../sormas/ui/contact/ContactController.java | 2 +- .../immunization/ImmunizationController.java | 4 +- .../ui/samples/PathogenTestController.java | 6 +- .../symeda/sormas/ui/therapy/TherapyView.java | 2 +- .../de/symeda/sormas/ui/TestDataCreator.java | 2 +- ...GermanCaseClassificationValidatorTest.java | 4 +- .../ui/caze/importer/CaseImporterTest.java | 2 +- .../ui/importexport/ImportExportTest.java | 2 +- 45 files changed, 274 insertions(+), 354 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/CoreBaseFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/CoreBaseFacade.java index 42b02745ace..83ec3c7989d 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/CoreBaseFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/CoreBaseFacade.java @@ -29,6 +29,8 @@ public interface CoreBaseFacade getAllAfter(Date date, Integer batchSize, String lastSynchronizedUuid); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/campaign/CampaignFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/campaign/CampaignFacade.java index 50f3d3b566f..7228556d5df 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/campaign/CampaignFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/campaign/CampaignFacade.java @@ -19,8 +19,6 @@ public interface CampaignFacade extends CoreBaseFacade getCampaignDashboardElements(String campaignUuid); - boolean isArchived(String uuid); - void deleteCampaign(String uuid); List getAllActiveUuids(); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java index af579eaef00..8f52d5aad69 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java @@ -91,9 +91,7 @@ List getExportList( CaseDataDto getCaseDataByUuid(String uuid); - CaseDataDto saveCase(@Valid CaseDataDto dto) throws ValidationRuntimeException; - - CaseDataDto saveCase(@Valid CaseDataDto dto, Boolean systemSave) throws ValidationRuntimeException; + CaseDataDto save(@Valid CaseDataDto dto, Boolean systemSave) throws ValidationRuntimeException; void setSampleAssociations(ContactReferenceDto sourceContact, CaseReferenceDto cazeRef); @@ -103,8 +101,6 @@ List getExportList( void validate(CaseDataDto dto) throws ValidationRuntimeException; - CaseReferenceDto getReferenceByUuid(String uuid); - List getAllActiveUuids(); List getAllActiveCasesAfter(Date date, Integer batchSize, String lastSynchronizedUuid); @@ -143,12 +139,8 @@ Long countCasesForMap( Date getOldestCaseOutcomeDate(); - boolean isArchived(String caseUuid); - boolean isDeleted(String caseUuid); - void archiveOrDearchiveCase(String caseUuid, boolean archive); - List getArchivedUuidsSince(Date since); List getDeletedUuidsSince(Date since); @@ -185,8 +177,6 @@ Long countCasesForMap( boolean isCaseEditAllowed(String caseUuid); - boolean exists(String uuid); - boolean hasPositiveLabResult(String caseUuid); List getCaseFollowUpList( diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java index 85768a22f19..db9e689ac9c 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java @@ -56,8 +56,6 @@ public interface EventFacade extends CoreBaseFacade getExportList(EventCriteria eventCriteria, Collection selectedRows, Integer first, Integer max); - boolean isArchived(String caseUuid); - boolean isDeleted(String eventUuid); List getArchivedUuidsSince(Date since); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/immunization/ImmunizationFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/immunization/ImmunizationFacade.java index 6988576348c..66b2d315660 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/immunization/ImmunizationFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/immunization/ImmunizationFacade.java @@ -37,10 +37,6 @@ public interface ImmunizationFacade extends CoreBaseFacade deleteImmunizations(List immunizationUuids); - boolean isArchived(String uuid); - - void archiveOrDearchiveImmunization(String uuid, boolean archive); - boolean isImmunizationEditAllowed(String uuid); List getSimilarImmunizations(ImmunizationSimilarityCriteria criteria); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/travelentry/TravelEntryFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/travelentry/TravelEntryFacade.java index 0e6fd516d10..f4a3cb8ed78 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/travelentry/TravelEntryFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/travelentry/TravelEntryFacade.java @@ -16,8 +16,6 @@ public interface TravelEntryFacade extends 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 O`=Y(s>($r*s{aFq^<#W|jIx@52TH zZU4PaeE)VSti5fU^OVK~76nEhqdm@TyP>AoS@!$;veK{sMfpk9^Q(8n?6l*t{ps-B zda?Gbr9DDdF0Jr07p=XOJBiz?Mj)#5UdEaig0`{Omu`uXYL8CW*>z!|`o+bz)3+_k z<(S4?ar2QvjTEQs;qb?7f{!knCbZTF*Yi4^yTQfA`8vYr24-v9Z7=kn$Iy_b|$1{J>y zUKzlrPJVk> z_Gp?)5oi6in0lrFZ+4DrC;q)-XJla52*fBMxOqQ|4;MHH`S_KXzzkzSRY;&l3n@Yv z^}-^?;83j>R+*gO#kzUFn=T}{-@BWEB{V$jz;vdEH779mL%{Y;Uh83|0OA!a>JsJU zVqlnN!oVQHfDE>Ckmuc!6sMm70`+G91IM+$m$rF`5720a`cN!Dsxhc z^(u060=yZSM1ZD2Q$on=6Opd3fm-^3+JS13fX3u{PdTvb7I;cC229@LsR?$K<&D$Q s7mXMgYWtZOB#_iIFq8;S?h}@pEbqkw)~4qr&DcHJ%S)T>kvm8o0P&#PEC2ui delta 635 zcmex6h4J?kM&1B#W)=|!4h{~68`Vx5d8HYdf%Il=#yT)#@*1WyAc4u%%qsPFy^a_N zxWzAhvTyDd(Tf+#1XCRYVm3T_6zg$p+l@aHTz3EdwybpR0w=vmKhMdi1?Tc*`Pg0f zdGN)oCz7h1S&2^;?4D(__4b!06}tl6pBX0Co^;I1ndKFs)^m8Su~@9c1@()IZH2d~ z)pAT@thl)NkzIF7-^0~~UF|@x3JO=7NI&o4hy)z-A$U9<8*_NRY+~DMA>H z!Xn1tFl`i8*}TWi2olgA-Oa#)S{`;_I@`mV6BzIzV7n%-_b^ic@d_4oiSlwWFibOH zU=U$I2AfzWUtkfNEbYkyF~(EchLN9vp(01WxTG>CwOFqrHz&ZGkx2xo4;tGcuTMm} zz6Ki75A+96EfP?h+~_GM53-T getCampaignDashboardElements(String campai return result.stream().sorted(Comparator.comparingInt(CampaignDashboardElement::getOrder)).collect(Collectors.toList()); } - @Override - public boolean isArchived(String uuid) { - - CriteriaBuilder cb = em.getCriteriaBuilder(); - CriteriaQuery cq = cb.createQuery(Long.class); - Root from = cq.from(Campaign.class); - - // Workaround for probable bug in Eclipse Link/Postgre that throws a - // NoResultException when trying to - // query for a true Boolean result - cq.where(cb.and(cb.equal(from.get(Campaign.ARCHIVED), true), cb.equal(from.get(AbstractDomainObject.UUID), uuid))); - cq.select(cb.count(from)); - long count = em.createQuery(cq).getSingleResult(); - return count > 0; - } - @Override public void deleteCampaign(String campaignUuid) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java index f29ef89fb16..4ac19f678a7 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java @@ -668,7 +668,7 @@ public List getEntriesList(String personUuid, Integer first, I public CaseDataDto postUpdate(String uuid, JsonNode caseDataDtoJson) { CaseDataDto existingCaseDto = getCaseDataWithoutPseudonyimization(uuid); PatchHelper.postUpdate(caseDataDtoJson, existingCaseDto); - return saveCase(existingCaseDto); + return this.save(existingCaseDto); } @@ -1344,13 +1344,13 @@ public CaseReferenceDto getReferenceByUuid(String uuid) { } @Override - public CaseDataDto saveCase(@Valid CaseDataDto dto) throws ValidationRuntimeException { - return saveCase(dto, true, true, true, false); + public CaseDataDto save(@Valid CaseDataDto dto) throws ValidationRuntimeException { + return save(dto, true, true, true, false); } @Override - public CaseDataDto saveCase(@Valid CaseDataDto dto, Boolean systemSave) throws ValidationRuntimeException { - return saveCase(dto, true, true, true, systemSave); + public CaseDataDto save(@Valid CaseDataDto dto, Boolean systemSave) throws ValidationRuntimeException { + return save(dto, true, true, true, systemSave); } public void saveBulkCase( @@ -1462,11 +1462,11 @@ private void updateCaseWithBulkData( } } - public CaseDataDto saveCase(@Valid CaseDataDto dto, boolean handleChanges, boolean checkChangeDate, Boolean systemSave) { - return saveCase(dto, handleChanges, checkChangeDate, true, systemSave); + public CaseDataDto save(@Valid CaseDataDto dto, boolean handleChanges, boolean checkChangeDate, Boolean systemSave) { + return save(dto, handleChanges, checkChangeDate, true, systemSave); } - public CaseDataDto saveCase(@Valid CaseDataDto dto, boolean handleChanges, boolean checkChangeDate, boolean internal, Boolean systemSave) + public CaseDataDto save(@Valid CaseDataDto dto, boolean handleChanges, boolean checkChangeDate, boolean internal, Boolean systemSave) throws ValidationRuntimeException { Case existingCase = service.getByUuid(dto.getUuid()); @@ -1668,12 +1668,6 @@ public void validate(CaseDataDto caze) throws ValidationRuntimeException { } } - @Override - public void archiveOrDearchiveCase(String caseUuid, boolean archive) { - - service.updateArchived(Collections.singletonList(caseUuid), archive); - } - /** * Handles potential changes of related tasks that needs to be done after * a case has been created/saved @@ -3169,22 +3163,6 @@ public Date getOldestCaseOutcomeDate() { return em.createQuery(cq).getSingleResult(); } - @Override - public boolean isArchived(String caseUuid) { - - CriteriaBuilder cb = em.getCriteriaBuilder(); - CriteriaQuery cq = cb.createQuery(Long.class); - Root from = cq.from(Case.class); - - // Workaround for probable bug in Eclipse Link/Postgre that throws a - // NoResultException when trying to - // query for a true Boolean result - cq.where(cb.and(cb.equal(from.get(Case.ARCHIVED), true), cb.equal(from.get(AbstractDomainObject.UUID), caseUuid))); - cq.select(cb.count(from)); - long count = em.createQuery(cq).getSingleResult(); - return count > 0; - } - @Override public boolean isDeleted(String caseUuid) { @@ -3210,7 +3188,7 @@ private void mergeCase(CaseDataDto leadCaseData, CaseDataDto otherCaseData, bool // 1.1 Case copyDtoValues(leadCaseData, otherCaseData, cloning); - saveCase(leadCaseData, !cloning, true, true, false); + save(leadCaseData, !cloning, true, true, false); // 1.2 Person - Only merge when the persons have different UUIDs if (!cloning && !DataHelper.equal(leadCaseData.getPerson().getUuid(), otherCaseData.getPerson().getUuid())) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/caseimport/CaseImportFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/caseimport/CaseImportFacadeEjb.java index 3e3963fd7b6..6dedaf51158 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/caseimport/CaseImportFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/caseimport/CaseImportFacadeEjb.java @@ -214,7 +214,7 @@ public ImportLineResultDto saveImportedEntities(@Valid CaseI // Workaround: Reset the change date to avoid OutdatedEntityExceptions // Should be changed when doing #2265 caze.setChangeDate(new Date()); - caseFacade.saveCase(caze); + caseFacade.save(caze); for (SampleDto sample : samples) { sampleFacade.saveSample(sample); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/ClinicalVisitFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/ClinicalVisitFacadeEjb.java index ab93311eccc..8299a2a16ac 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/ClinicalVisitFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/ClinicalVisitFacadeEjb.java @@ -237,7 +237,7 @@ public ClinicalVisitDto saveClinicalVisit(ClinicalVisitDto clinicalVisit, String CaseDataDto caze = caseFacade.getCaseDataByUuid(caseUuid); SymptomsDto caseSymptoms = caze.getSymptoms(); SymptomsHelper.updateSymptoms(clinicalVisit.getSymptoms(), caseSymptoms); - caseFacade.saveCase(caze); + caseFacade.save(caze); } return convertToDto(entity, Pseudonymizer.getDefault(userService::hasRight)); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java index 6096413e77c..b6e118dfe32 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java @@ -15,9 +15,26 @@ package de.symeda.sormas.backend.common; +import de.symeda.sormas.backend.travelentry.TravelEntry; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + public abstract class AbstractCoreAdoService extends AbstractDeletableAdoService { public AbstractCoreAdoService(Class elementClass) { super(elementClass); } + + public boolean isArchived(String uuid) { + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(Long.class); + Root from = cq.from(getElementClass()); + + cq.where(cb.and(cb.equal(from.get(CoreAdo.ARCHIVED), true), cb.equal(from.get(AbstractDomainObject.UUID), uuid))); + cq.select(cb.count(from)); + long count = em.createQuery(cq).getSingleResult(); + return count > 0; + } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java index c3d15c72298..d4dd45b8b8c 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java @@ -109,6 +109,10 @@ public void dearchive(String uuid) { } } + public boolean isArchived(String uuid) { + return service.isArchived(uuid); + } + public DTO convertToDto(ADO source, Pseudonymizer pseudonymizer) { DTO dto = toDto(source); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java index 6aa9b3a0dd1..173bcf879d6 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java @@ -845,21 +845,6 @@ public List getExportList(EventCriteria eventCriteria, Collectio return exportList; } - @Override - public boolean isArchived(String eventUuid) { - - CriteriaBuilder cb = em.getCriteriaBuilder(); - CriteriaQuery cq = cb.createQuery(Long.class); - Root from = cq.from(Event.class); - - // Workaround for probable bug in Eclipse Link/Postgre that throws a NoResultException when trying to - // query for a true Boolean result - cq.where(cb.and(cb.equal(from.get(Event.ARCHIVED), true), cb.equal(from.get(AbstractDomainObject.UUID), eventUuid))); - cq.select(cb.count(from)); - long count = em.createQuery(cq).getSingleResult(); - return count > 0; - } - @Override public boolean isDeleted(String eventUuid) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java index 10bd8d2c019..73f64c0282d 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java @@ -256,18 +256,6 @@ public void deleteImmunization(String uuid) { service.delete(immunization); } - @Override - public boolean isArchived(String uuid) { - return service.isArchived(uuid); - } - - @Override - public void archiveOrDearchiveImmunization(String uuid, boolean archive) { - Immunization immunization = service.getByUuid(uuid); - immunization.setArchived(archive); - service.ensurePersisted(immunization); - } - @Override public boolean isImmunizationEditAllowed(String uuid) { Immunization immunization = service.getByUuid(uuid); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/caze/ProcessedCaseDataPersister.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/caze/ProcessedCaseDataPersister.java index 1dfadc03c90..533f7513685 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/caze/ProcessedCaseDataPersister.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/caze/ProcessedCaseDataPersister.java @@ -69,11 +69,11 @@ private void persistProcessedData(SormasToSormasCaseDto caseData, boolean isCrea Captions.Person, buildCaseValidationGroupName(caze)); - handleValidationError(() -> caseFacade.saveCase(caze, true, false, false, false), Captions.CaseData, buildCaseValidationGroupName(caze)); + handleValidationError(() -> caseFacade.save(caze, true, false, false, false), Captions.CaseData, buildCaseValidationGroupName(caze)); } else { //save case first during update - handleValidationError(() -> caseFacade.saveCase(caze, true, false, false, false), Captions.CaseData, buildCaseValidationGroupName(caze)); + handleValidationError(() -> caseFacade.save(caze, true, false, false, false), Captions.CaseData, buildCaseValidationGroupName(caze)); handleValidationError( () -> personFacade.savePerson(caseData.getPerson(), false, false, false), Captions.Person, diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java index 15d2d8d4a65..37c04d08037 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java @@ -93,11 +93,6 @@ public boolean isDeleted(String travelEntryUuid) { return service.isDeleted(travelEntryUuid); } - @Override - public boolean isArchived(String travelEntryUuid) { - return service.isArchived(travelEntryUuid); - } - @Override public void archiveOrDearchiveTravelEntry(String travelEntryUuid, boolean archive) { TravelEntry travelEntry = service.getByUuid(travelEntryUuid); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/TravelEntryService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/TravelEntryService.java index fffae90b9f0..e5b0e434c86 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/TravelEntryService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/TravelEntryService.java @@ -221,17 +221,6 @@ public boolean isDeleted(String travelEntryUuid) { return count > 0; } - public boolean isArchived(String travelEntryUuid) { - CriteriaBuilder cb = em.getCriteriaBuilder(); - CriteriaQuery cq = cb.createQuery(Long.class); - Root from = cq.from(TravelEntry.class); - - cq.where(cb.and(cb.equal(from.get(TravelEntry.ARCHIVED), true), cb.equal(from.get(AbstractDomainObject.UUID), travelEntryUuid))); - cq.select(cb.count(from)); - long count = em.createQuery(cq).getSingleResult(); - return count > 0; - } - public TravelEntry getLastTravelEntry() { final CriteriaBuilder cb = em.getCriteriaBuilder(); final CriteriaQuery query = cb.createQuery(TravelEntry.class); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/visit/VisitFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/visit/VisitFacadeEjb.java index 3815108d393..ae8df4cd3b7 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/visit/VisitFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/visit/VisitFacadeEjb.java @@ -81,7 +81,6 @@ import de.symeda.sormas.api.visit.VisitReferenceDto; import de.symeda.sormas.api.visit.VisitStatus; import de.symeda.sormas.backend.caze.Case; -import de.symeda.sormas.backend.caze.CaseFacadeEjb; import de.symeda.sormas.backend.caze.CaseFacadeEjb.CaseFacadeEjbLocal; import de.symeda.sormas.backend.caze.CaseQueryContext; import de.symeda.sormas.backend.caze.CaseService; @@ -630,7 +629,7 @@ private void onVisitChanged(VisitDto existingVisit, Visit newVisit) { CaseDataDto caze = caseFacade.toDto(newVisit.getCaze()); SymptomsDto caseSymptoms = caze.getSymptoms(); SymptomsHelper.updateSymptoms(toDto(newVisit).getSymptoms(), caseSymptoms); - caseFacade.saveCase(caze, true); + caseFacade.save(caze, true); } } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java index b51d62daa7a..3aad79a656b 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java @@ -281,7 +281,7 @@ public ConfigFacade getConfigFacade() { return getBean(ConfigFacadeEjbLocal.class); } - public CaseFacade getCaseFacade() { + public CaseFacadeEjbLocal getCaseFacade() { return getBean(CaseFacadeEjbLocal.class); } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java index cd107e6b93b..659aa95efe8 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java @@ -398,7 +398,7 @@ public CaseDataDto createCase( final CaseDataDto aCase = createCase(user, cazePerson, disease, caseClassification, investigationStatus, reportAndOnsetDate, new RDCF(rdcf)); aCase.setHealthFacilityDetails(healthFacilityDetails); - return beanTest.getCaseFacade().saveCase(aCase); + return beanTest.getCaseFacade().save(aCase); } public CaseDataDto createCase( @@ -440,7 +440,7 @@ public CaseDataDto createCase( setCustomFields.accept(caze); } - caze = beanTest.getCaseFacade().saveCase(caze); + caze = beanTest.getCaseFacade().save(caze); return caze; } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseClassificationLogicTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseClassificationLogicTest.java index 65b96e22eb5..5b86bbf7d14 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseClassificationLogicTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseClassificationLogicTest.java @@ -73,43 +73,43 @@ public void testAutomaticClassificationForEVD() { CaseDataDto caze = buildSuspectCaseBasis(Disease.EVD); caze.getSymptoms().setDiarrhea(SymptomState.YES); caze.getSymptoms().setBloodyBlackStool(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.EVD); caze.getSymptoms().setGumsBleeding(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.EVD); caze.getSymptoms().setSkinBruising(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.EVD); caze.getSymptoms().setEyesBleeding(SymptomState.YES); caze.getSymptoms().setBloodUrine(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); // Probable caze = buildProbableCaseBasis(Disease.EVD); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.PROBABLE, caze.getCaseClassification()); caze = buildProbableCaseBasis(Disease.EVD); ExposureDto exposure = ExposureDto.build(ExposureType.WORK); exposure.setHandlingSamples(YesNoUnknown.YES); caze.getEpiData().getExposures().add(exposure); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.PROBABLE, caze.getCaseClassification()); caze = buildProbableCaseBasis(Disease.EVD); exposure = ExposureDto.build(ExposureType.WORK); exposure.setPercutaneous(YesNoUnknown.YES); caze.getEpiData().getExposures().add(exposure); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.PROBABLE, caze.getCaseClassification()); caze = buildProbableCaseBasis(Disease.EVD); @@ -119,21 +119,21 @@ public void testAutomaticClassificationForEVD() { ExposureDto exposure2 = ExposureDto.build(ExposureType.BURIAL); exposure2.setPhysicalContactWithBody(YesNoUnknown.YES); caze.getEpiData().getExposures().add(exposure2); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.PROBABLE, caze.getCaseClassification()); // Confirmed - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.EVD)); + caze = getCaseFacade().save(buildSuspectCase(Disease.EVD)); creator.createPathogenTest(caze, Disease.EVD, PathogenTestType.IGM_SERUM_ANTIBODY, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.EVD)); + caze = getCaseFacade().save(buildSuspectCase(Disease.EVD)); creator.createPathogenTest(caze, Disease.EVD, PathogenTestType.PCR_RT_PCR, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.EVD)); + caze = getCaseFacade().save(buildSuspectCase(Disease.EVD)); creator.createPathogenTest(caze, Disease.EVD, PathogenTestType.ISOLATION, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); @@ -146,20 +146,20 @@ public void ruleOutFalsePositivesForEVD() { CaseDataDto caze = creator.createUnclassifiedCase(Disease.EVD); fillSymptoms(caze.getSymptoms()); caze.getSymptoms().setFever(SymptomState.NO); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); caze.getSymptoms().setFever(SymptomState.YES); caze.getSymptoms().setDiarrhea(SymptomState.NO); caze.getSymptoms().setGumsBleeding(SymptomState.NO); caze.getSymptoms().setSkinBruising(SymptomState.NO); caze.getSymptoms().setEyesBleeding(SymptomState.NO); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); // Probable caze = buildSuspectCase(Disease.EVD); caze.setOutcome(CaseOutcome.DECEASED); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); fillEpiData(caze.getEpiData()); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.NO); @@ -170,16 +170,16 @@ public void ruleOutFalsePositivesForEVD() { ExposureDto exposure2 = ExposureDto.build(ExposureType.TRAVEL); exposure2.setRiskArea(YesNoUnknown.NO); caze.getEpiData().getExposures().add(exposure2); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze.setOutcome(CaseOutcome.NO_OUTCOME); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); // Confirmed caze = buildSuspectCase(Disease.EVD); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); createSampleTestsForAllTestTypesExcept( caze, Disease.EVD, @@ -196,33 +196,33 @@ public void testAutomaticClassificationForCSM() { // Suspect CaseDataDto caze = buildSuspectCaseBasis(Disease.CSM); caze.getSymptoms().setNeckStiffness(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.CSM); caze.getSymptoms().setAlteredConsciousness(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.CSM); caze.getSymptoms().setMeningealSigns(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.CSM); caze.getSymptoms().setBulgingFontanelle(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); // Probable caze = buildSuspectCase(Disease.CSM); caze.setOutcome(CaseOutcome.DECEASED); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.PROBABLE, caze.getCaseClassification()); // Confirmed - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.CSM)); + caze = getCaseFacade().save(buildSuspectCase(Disease.CSM)); creator.createPathogenTest(caze, Disease.CSM, PathogenTestType.ISOLATION, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); @@ -236,33 +236,33 @@ public void ruleOutFalsePositivesForCSM() { CaseDataDto caze = creator.createUnclassifiedCase(Disease.CSM); fillSymptoms(caze.getSymptoms()); caze.getSymptoms().setFever(SymptomState.NO); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); caze.getSymptoms().setFever(SymptomState.YES); caze.getSymptoms().setNeckStiffness(SymptomState.NO); caze.getSymptoms().setAlteredConsciousness(SymptomState.NO); caze.getSymptoms().setMeningealSigns(SymptomState.NO); caze.getSymptoms().setBulgingFontanelle(SymptomState.NO); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); // Probable caze = buildSuspectCase(Disease.CSM); caze.setOutcome(CaseOutcome.DECEASED); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); fillEpiData(caze.getEpiData()); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.NO); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze.setOutcome(CaseOutcome.NO_OUTCOME); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); // Confirmed caze = buildSuspectCase(Disease.CSM); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); createSampleTestsForAllTestTypesExcept(caze, Disease.CSM, PathogenTestType.ISOLATION); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); @@ -275,87 +275,87 @@ public void testAutomaticClassificationForLassa() { CaseDataDto caze = buildSuspectCaseBasis(Disease.LASSA); caze.getSymptoms().setFatigueWeakness(SymptomState.YES); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.LASSA); caze.getSymptoms().setFever(SymptomState.YES); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.LASSA); caze.getSymptoms().setHeadache(SymptomState.YES); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.LASSA); caze.getSymptoms().setSoreThroat(SymptomState.YES); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.LASSA); caze.getSymptoms().setCough(SymptomState.YES); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.LASSA); caze.getSymptoms().setNausea(SymptomState.YES); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.LASSA); caze.getSymptoms().setVomiting(SymptomState.YES); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.LASSA); caze.getSymptoms().setDiarrhea(SymptomState.YES); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.LASSA); caze.getSymptoms().setMusclePain(SymptomState.YES); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.LASSA); caze.getSymptoms().setChestPain(SymptomState.YES); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.LASSA); caze.getSymptoms().setHearingloss(SymptomState.YES); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); // Probable caze = buildSuspectCase(Disease.LASSA); caze.setOutcome(CaseOutcome.DECEASED); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.PROBABLE, caze.getCaseClassification()); // Confirmed - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.LASSA)); + caze = getCaseFacade().save(buildSuspectCase(Disease.LASSA)); creator.createPathogenTest(caze, Disease.LASSA, PathogenTestType.IGM_SERUM_ANTIBODY, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.LASSA)); + caze = getCaseFacade().save(buildSuspectCase(Disease.LASSA)); creator.createPathogenTest(caze, Disease.LASSA, PathogenTestType.PCR_RT_PCR, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.LASSA)); + caze = getCaseFacade().save(buildSuspectCase(Disease.LASSA)); creator.createPathogenTest(caze, Disease.LASSA, PathogenTestType.ISOLATION, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); @@ -382,23 +382,23 @@ public void ruleOutFalsePositivesForLassa() { ExposureDto exposure = creator.buildAnimalContactExposure(TypeOfAnimal.BAT); caze.getEpiData().getExposures().add(exposure); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.NO); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); caze.getSymptoms().setFever(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); caze.getSymptoms().setFever(SymptomState.NO); ExposureDto exposure2 = creator.buildAnimalContactExposure(TypeOfAnimal.RODENT); caze.getEpiData().getExposures().add(exposure2); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); // Probable doesn't need to be tested // Confirmed caze = buildSuspectCase(Disease.LASSA); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); createSampleTestsForAllTestTypesExcept( caze, Disease.LASSA, @@ -415,7 +415,7 @@ public void testAutomaticClassificationForYellowFever() { // Suspect CaseDataDto caze = buildSuspectCaseBasis(Disease.YELLOW_FEVER); caze.getSymptoms().setJaundice(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); // Probable @@ -423,47 +423,47 @@ public void testAutomaticClassificationForYellowFever() { ExposureDto exposure = ExposureDto.build(ExposureType.TRAVEL); exposure.setRiskArea(YesNoUnknown.YES); caze.getEpiData().getExposures().add(exposure); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.PROBABLE, caze.getCaseClassification()); caze = buildSuspectCase(Disease.YELLOW_FEVER); caze.setOutcome(CaseOutcome.DECEASED); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); creator.createPathogenTest(caze, Disease.YELLOW_FEVER, PathogenTestType.HISTOPATHOLOGY, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.PROBABLE, caze.getCaseClassification()); // Confirmed - caze = getCaseFacade().saveCase(buildConfirmedCaseBasis(Disease.YELLOW_FEVER)); + caze = getCaseFacade().save(buildConfirmedCaseBasis(Disease.YELLOW_FEVER)); creator.createPathogenTest(caze, Disease.YELLOW_FEVER, PathogenTestType.IGM_SERUM_ANTIBODY, PathogenTestResultType.POSITIVE); creator.createPathogenTest(caze, Disease.DENGUE, PathogenTestType.IGM_SERUM_ANTIBODY, PathogenTestResultType.NEGATIVE); creator.createPathogenTest(caze, Disease.WEST_NILE_FEVER, PathogenTestType.IGM_SERUM_ANTIBODY, PathogenTestResultType.NEGATIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); - caze = getCaseFacade().saveCase(buildConfirmedCaseBasis(Disease.YELLOW_FEVER)); + caze = getCaseFacade().save(buildConfirmedCaseBasis(Disease.YELLOW_FEVER)); creator.createPathogenTest(caze, Disease.YELLOW_FEVER, PathogenTestType.NEUTRALIZING_ANTIBODIES, PathogenTestResultType.POSITIVE); creator.createPathogenTest(caze, Disease.DENGUE, PathogenTestType.NEUTRALIZING_ANTIBODIES, PathogenTestResultType.NEGATIVE); creator.createPathogenTest(caze, Disease.WEST_NILE_FEVER, PathogenTestType.NEUTRALIZING_ANTIBODIES, PathogenTestResultType.NEGATIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); - caze = getCaseFacade().saveCase(buildConfirmedCaseBasis(Disease.YELLOW_FEVER)); + caze = getCaseFacade().save(buildConfirmedCaseBasis(Disease.YELLOW_FEVER)); creator.createPathogenTest(caze, Disease.YELLOW_FEVER, PathogenTestType.PCR_RT_PCR, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); - caze = getCaseFacade().saveCase(buildConfirmedCaseBasis(Disease.YELLOW_FEVER)); + caze = getCaseFacade().save(buildConfirmedCaseBasis(Disease.YELLOW_FEVER)); creator.createPathogenTest(caze, Disease.YELLOW_FEVER, PathogenTestType.ANTIGEN_DETECTION, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); - caze = getCaseFacade().saveCase(buildConfirmedCaseBasis(Disease.YELLOW_FEVER)); + caze = getCaseFacade().save(buildConfirmedCaseBasis(Disease.YELLOW_FEVER)); creator.createPathogenTest(caze, Disease.YELLOW_FEVER, PathogenTestType.ISOLATION, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); - caze = getCaseFacade().saveCase(buildConfirmedCaseBasis(Disease.YELLOW_FEVER)); + caze = getCaseFacade().save(buildConfirmedCaseBasis(Disease.YELLOW_FEVER)); PathogenTestDto sampleTest = creator.createPathogenTest(caze, Disease.YELLOW_FEVER, PathogenTestType.IGM_SERUM_ANTIBODY, PathogenTestResultType.POSITIVE); sampleTest.setFourFoldIncreaseAntibodyTiter(true); @@ -471,7 +471,7 @@ public void testAutomaticClassificationForYellowFever() { caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); - caze = getCaseFacade().saveCase(buildConfirmedCaseBasis(Disease.YELLOW_FEVER)); + caze = getCaseFacade().save(buildConfirmedCaseBasis(Disease.YELLOW_FEVER)); sampleTest = creator.createPathogenTest(caze, Disease.YELLOW_FEVER, PathogenTestType.IGG_SERUM_ANTIBODY, PathogenTestResultType.POSITIVE); sampleTest.setFourFoldIncreaseAntibodyTiter(true); getSampleTestFacade().savePathogenTest(sampleTest); @@ -486,11 +486,11 @@ public void ruleOutFalsePositivesForYellowFever() { CaseDataDto caze = creator.createUnclassifiedCase(Disease.YELLOW_FEVER); fillSymptoms(caze.getSymptoms()); caze.getSymptoms().setFever(SymptomState.NO); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); caze.getSymptoms().setFever(SymptomState.YES); caze.getSymptoms().setJaundice(SymptomState.NO); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); // Probable @@ -499,23 +499,23 @@ public void ruleOutFalsePositivesForYellowFever() { ExposureDto exposure = ExposureDto.build(ExposureType.TRAVEL); exposure.setRiskArea(YesNoUnknown.NO); caze.getEpiData().getExposures().add(exposure); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze.setOutcome(CaseOutcome.DECEASED); caze.setVaccinationStatus(VaccinationStatus.VACCINATED); createImmunizationWithVaccination(caze, DateHelper.subtractDays(new Date(), 1)); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); createSampleTestsForAllTestTypesExcept(caze, Disease.YELLOW_FEVER, PathogenTestType.HISTOPATHOLOGY); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze.setOutcome(CaseOutcome.NO_OUTCOME); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); creator.createPathogenTest(caze, Disease.YELLOW_FEVER, PathogenTestType.HISTOPATHOLOGY, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); // Confirmed - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.YELLOW_FEVER)); + caze = getCaseFacade().save(buildSuspectCase(Disease.YELLOW_FEVER)); createSampleTestsForAllTestTypesExcept( caze, Disease.YELLOW_FEVER, @@ -536,7 +536,7 @@ public void ruleOutFalsePositivesForYellowFever() { caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); caze.setVaccinationStatus(VaccinationStatus.VACCINATED); createImmunizationWithVaccination(caze, DateHelper.subtractDays(new Date(), 1)); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); } @@ -547,26 +547,26 @@ public void testAutomaticClassificationForDengueFever() { CaseDataDto caze = buildSuspectCaseBasis(Disease.DENGUE); caze.getSymptoms().setHeadache(SymptomState.YES); caze.getSymptoms().setEyePainLightSensitive(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.DENGUE); caze.getSymptoms().setNausea(SymptomState.YES); caze.getSymptoms().setVomiting(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.DENGUE); caze.getSymptoms().setSwollenGlands(SymptomState.YES); caze.getSymptoms().setSkinRash(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.DENGUE); caze.getSymptoms().setSkinRash(SymptomState.YES); caze.getSymptoms().setMusclePain(SymptomState.YES); caze.getSymptoms().setJointPain(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); // Probable @@ -574,28 +574,28 @@ public void testAutomaticClassificationForDengueFever() { ExposureDto exposure = ExposureDto.build(ExposureType.TRAVEL); exposure.setRiskArea(YesNoUnknown.YES); caze.getEpiData().getExposures().add(exposure); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.PROBABLE, caze.getCaseClassification()); // Confirmed - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.DENGUE)); + caze = getCaseFacade().save(buildSuspectCase(Disease.DENGUE)); creator.createPathogenTest(caze, Disease.DENGUE, PathogenTestType.IGM_SERUM_ANTIBODY, PathogenTestResultType.POSITIVE); creator.createPathogenTest(caze, Disease.YELLOW_FEVER, PathogenTestType.IGM_SERUM_ANTIBODY, PathogenTestResultType.NEGATIVE); creator.createPathogenTest(caze, Disease.WEST_NILE_FEVER, PathogenTestType.IGM_SERUM_ANTIBODY, PathogenTestResultType.NEGATIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.DENGUE)); + caze = getCaseFacade().save(buildSuspectCase(Disease.DENGUE)); creator.createPathogenTest(caze, Disease.DENGUE, PathogenTestType.PCR_RT_PCR, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.DENGUE)); + caze = getCaseFacade().save(buildSuspectCase(Disease.DENGUE)); creator.createPathogenTest(caze, Disease.DENGUE, PathogenTestType.ISOLATION, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.DENGUE)); + caze = getCaseFacade().save(buildSuspectCase(Disease.DENGUE)); PathogenTestDto sampleTest = creator.createPathogenTest(caze, Disease.DENGUE, PathogenTestType.IGG_SERUM_ANTIBODY, PathogenTestResultType.POSITIVE); sampleTest.setFourFoldIncreaseAntibodyTiter(true); @@ -611,7 +611,7 @@ public void ruleOutFalsePositivesForDengueFever() { CaseDataDto caze = creator.createUnclassifiedCase(Disease.DENGUE); fillSymptoms(caze.getSymptoms()); caze.getSymptoms().setFever(SymptomState.NO); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); caze.getSymptoms().setFever(SymptomState.YES); caze.getSymptoms().setHeadache(SymptomState.NO); @@ -621,7 +621,7 @@ public void ruleOutFalsePositivesForDengueFever() { caze.getSymptoms().setSwollenGlands(SymptomState.NO); caze.getSymptoms().setJointPain(SymptomState.NO); caze.getSymptoms().setSkinRash(SymptomState.NO); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); // Probable @@ -630,11 +630,11 @@ public void ruleOutFalsePositivesForDengueFever() { ExposureDto exposure = ExposureDto.build(ExposureType.TRAVEL); exposure.setRiskArea(YesNoUnknown.NO); caze.getEpiData().getExposures().add(exposure); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); // Confirmed - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.DENGUE)); + caze = getCaseFacade().save(buildSuspectCase(Disease.DENGUE)); createSampleTestsForAllTestTypesExcept( caze, Disease.DENGUE, @@ -656,25 +656,25 @@ public void testAutomaticClassificationForNewFlu() { CaseDataDto caze = buildSuspectCaseBasis(Disease.NEW_INFLUENZA); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); caze.getSymptoms().setCough(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.NEW_INFLUENZA); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); caze.getSymptoms().setDifficultyBreathing(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.NEW_INFLUENZA); caze.getSymptoms().setCough(SymptomState.YES); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.NEW_INFLUENZA); caze.getSymptoms().setCough(SymptomState.YES); caze.getEpiData().setAreaInfectedAnimals(YesNoUnknown.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.NEW_INFLUENZA); @@ -682,27 +682,27 @@ public void testAutomaticClassificationForNewFlu() { ExposureDto exposure = ExposureDto.build(ExposureType.WORK); exposure.setHandlingSamples(YesNoUnknown.YES); caze.getEpiData().getExposures().add(exposure); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); // Probable caze = buildProbableCaseBasis(Disease.NEW_INFLUENZA); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.PROBABLE, caze.getCaseClassification()); // Confirmed - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.NEW_INFLUENZA)); + caze = getCaseFacade().save(buildSuspectCase(Disease.NEW_INFLUENZA)); creator.createPathogenTest(caze, Disease.NEW_INFLUENZA, PathogenTestType.ISOLATION, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.NEW_INFLUENZA)); + caze = getCaseFacade().save(buildSuspectCase(Disease.NEW_INFLUENZA)); creator.createPathogenTest(caze, Disease.NEW_INFLUENZA, PathogenTestType.PCR_RT_PCR, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.NEW_INFLUENZA)); + caze = getCaseFacade().save(buildSuspectCase(Disease.NEW_INFLUENZA)); PathogenTestDto sampleTest = creator.createPathogenTest(caze, Disease.NEW_INFLUENZA, PathogenTestType.IGG_SERUM_ANTIBODY, PathogenTestResultType.POSITIVE); sampleTest.setFourFoldIncreaseAntibodyTiter(true); @@ -719,12 +719,12 @@ public void ruleOutFalsePositivesForNewFlu() { fillSymptoms(caze.getSymptoms()); fillEpiData(caze.getEpiData()); caze.getSymptoms().setFever(SymptomState.NO); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); caze.getSymptoms().setFever(SymptomState.YES); caze.getSymptoms().setCough(SymptomState.NO); caze.getSymptoms().setDifficultyBreathing(SymptomState.NO); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); caze.getSymptoms().setCough(SymptomState.YES); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.NO); @@ -732,23 +732,23 @@ public void ruleOutFalsePositivesForNewFlu() { ExposureDto exposure = ExposureDto.build(ExposureType.WORK); exposure.setHandlingSamples(YesNoUnknown.NO); caze.getEpiData().getExposures().add(exposure); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); // Probable caze = buildSuspectCase(Disease.NEW_INFLUENZA); caze.setOutcome(CaseOutcome.UNKNOWN); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze.setOutcome(CaseOutcome.NO_OUTCOME); fillEpiData(caze.getEpiData()); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.NO); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); // Confirmed caze = buildSuspectCase(Disease.NEW_INFLUENZA); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); createSampleTestsForAllTestTypesExcept( caze, Disease.NEW_INFLUENZA, @@ -765,27 +765,27 @@ public void testAutomaticClassificationForMeasles() { // Suspect CaseDataDto caze = buildSuspectCaseBasis(Disease.MEASLES); caze.getSymptoms().setCough(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.MEASLES); caze.getSymptoms().setRunnyNose(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.MEASLES); caze.getSymptoms().setConjunctivitis(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); // Probable caze = buildSuspectCase(Disease.MEASLES); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.PROBABLE, caze.getCaseClassification()); // Confirmed - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.MEASLES)); + caze = getCaseFacade().save(buildSuspectCase(Disease.MEASLES)); creator.createPathogenTest(caze, Disease.MEASLES, PathogenTestType.IGM_SERUM_ANTIBODY, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); @@ -800,27 +800,27 @@ public void ruleOutFalsePositivesForMeasles() { caze.getSymptoms().setCough(SymptomState.NO); caze.getSymptoms().setRunnyNose(SymptomState.NO); caze.getSymptoms().setConjunctivitis(SymptomState.NO); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); caze.getSymptoms().setCough(SymptomState.YES); caze.getSymptoms().setFever(SymptomState.NO); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); caze.getSymptoms().setFever(SymptomState.YES); caze.getSymptoms().setSkinRash(SymptomState.NO); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); // Probable caze = buildSuspectCase(Disease.MEASLES); fillEpiData(caze.getEpiData()); caze.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.NO); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); // Confirmed caze = buildSuspectCase(Disease.MEASLES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); createSampleTestsForAllTestTypesExcept(caze, Disease.MEASLES, PathogenTestType.IGM_SERUM_ANTIBODY); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); @@ -832,13 +832,13 @@ public void testAutomaticClassificationForCholera() { // Suspect CaseDataDto caze = buildSuspectCaseBasis(Disease.CHOLERA); caze.getSymptoms().setDehydration(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.CHOLERA); caze.getSymptoms().setDiarrhea(SymptomState.YES); caze.setOutcome(CaseOutcome.DECEASED); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.CHOLERA); @@ -846,11 +846,11 @@ public void testAutomaticClassificationForCholera() { ExposureDto exposure = ExposureDto.build(ExposureType.TRAVEL); exposure.setRiskArea(YesNoUnknown.YES); caze.getEpiData().getExposures().add(exposure); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); // Confirmed - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.CHOLERA)); + caze = getCaseFacade().save(buildSuspectCase(Disease.CHOLERA)); creator.createPathogenTest(caze, Disease.CHOLERA, PathogenTestType.ISOLATION, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); @@ -872,21 +872,21 @@ public void ruleOutFalsePositivesForCholera() { casePerson.setApproximateAge(5); casePerson.setApproximateAgeType(ApproximateAgeType.YEARS); getPersonFacade().savePerson(casePerson); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); casePerson.setApproximateAge(0); getPersonFacade().savePerson(casePerson); caze.setOutcome(CaseOutcome.DECEASED); caze.getEpiData().getExposures().get(0).setRiskArea(YesNoUnknown.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); caze.getSymptoms().setDiarrhea(SymptomState.YES); caze.getSymptoms().setDehydration(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); // Confirmed - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.CHOLERA)); + caze = getCaseFacade().save(buildSuspectCase(Disease.CHOLERA)); createSampleTestsForAllTestTypesExcept(caze, Disease.CHOLERA, PathogenTestType.ISOLATION); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); @@ -898,21 +898,21 @@ public void testAutomaticClassificationForMonkeypox() { // Suspect CaseDataDto caze = buildSuspectCaseBasis(Disease.MONKEYPOX); caze.getSymptoms().setSkinRash(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); // Confirmed - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.MONKEYPOX)); + caze = getCaseFacade().save(buildSuspectCase(Disease.MONKEYPOX)); creator.createPathogenTest(caze, Disease.MONKEYPOX, PathogenTestType.ISOLATION, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.MONKEYPOX)); + caze = getCaseFacade().save(buildSuspectCase(Disease.MONKEYPOX)); creator.createPathogenTest(caze, Disease.MONKEYPOX, PathogenTestType.IGM_SERUM_ANTIBODY, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.MONKEYPOX)); + caze = getCaseFacade().save(buildSuspectCase(Disease.MONKEYPOX)); creator.createPathogenTest(caze, Disease.MONKEYPOX, PathogenTestType.PCR_RT_PCR, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); @@ -925,16 +925,16 @@ public void ruleOutFalsePositivesForMonkeypox() { CaseDataDto caze = creator.createUnclassifiedCase(Disease.MONKEYPOX); fillSymptoms(caze.getSymptoms()); caze.getSymptoms().setFever(SymptomState.NO); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); caze.getSymptoms().setFever(SymptomState.YES); caze.getSymptoms().setSkinRash(SymptomState.NO); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); // Confirmed caze = buildSuspectCase(Disease.MONKEYPOX); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); createSampleTestsForAllTestTypesExcept( caze, Disease.MONKEYPOX, @@ -952,35 +952,35 @@ public void testAutomaticClassificationForPlague() { CaseDataDto caze = buildSuspectCaseBasis(Disease.PLAGUE); caze.setPlagueType(PlagueType.BUBONIC); caze.getSymptoms().setPainfulLymphadenitis(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.PLAGUE); caze.setPlagueType(PlagueType.PNEUMONIC); caze.getSymptoms().setCough(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.PLAGUE); caze.setPlagueType(PlagueType.PNEUMONIC); caze.getSymptoms().setChestPain(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.PLAGUE); caze.setPlagueType(PlagueType.BUBONIC); caze.getSymptoms().setCoughingBlood(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); caze = buildSuspectCaseBasis(Disease.PLAGUE); caze.setPlagueType(PlagueType.SEPTICAEMIC); caze.getSymptoms().setChillsSweats(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); // Probable - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.PLAGUE)); + caze = getCaseFacade().save(buildSuspectCase(Disease.PLAGUE)); creator.createPathogenTest(caze, Disease.PLAGUE, PathogenTestType.ANTIGEN_DETECTION, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.PROBABLE, caze.getCaseClassification()); @@ -989,17 +989,17 @@ public void testAutomaticClassificationForPlague() { ExposureDto exposure = ExposureDto.build(ExposureType.TRAVEL); exposure.setRiskArea(YesNoUnknown.YES); caze.getEpiData().getExposures().add(exposure); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.PROBABLE, caze.getCaseClassification()); // Confirmed - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.PLAGUE)); + caze = getCaseFacade().save(buildSuspectCase(Disease.PLAGUE)); creator.createPathogenTest(caze, Disease.PLAGUE, PathogenTestType.ISOLATION, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); - caze = getCaseFacade().saveCase(buildSuspectCase(Disease.PLAGUE)); + caze = getCaseFacade().save(buildSuspectCase(Disease.PLAGUE)); creator.createPathogenTest(caze, Disease.PLAGUE, PathogenTestType.PCR_RT_PCR, PathogenTestResultType.POSITIVE); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED, caze.getCaseClassification()); @@ -1013,13 +1013,13 @@ public void ruleOutFalsePositivesForPlague() { fillSymptoms(caze.getSymptoms()); caze.getSymptoms().setFever(SymptomState.NO); caze.setPlagueType(PlagueType.BUBONIC); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); caze.setPlagueType(PlagueType.PNEUMONIC); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); caze.setPlagueType(PlagueType.SEPTICAEMIC); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); caze.getSymptoms().setFever(SymptomState.YES); caze.getSymptoms().setPainfulLymphadenitis(SymptomState.NO); @@ -1028,7 +1028,7 @@ public void ruleOutFalsePositivesForPlague() { caze.getSymptoms().setCoughingBlood(SymptomState.NO); caze.getSymptoms().setChillsSweats(SymptomState.NO); caze.setPlagueType(PlagueType.BUBONIC); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.NOT_CLASSIFIED, caze.getCaseClassification()); // Probable & Confirmed @@ -1037,7 +1037,7 @@ public void ruleOutFalsePositivesForPlague() { ExposureDto exposure = ExposureDto.build(ExposureType.TRAVEL); exposure.setRiskArea(YesNoUnknown.NO); caze.getEpiData().getExposures().add(exposure); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification()); createSampleTestsForAllTestTypesExcept( caze, @@ -1053,7 +1053,7 @@ public void ruleOutFalsePositivesForPlague() { public void testFulfilledReferenceDefinitionGermanServer() { MockProducer.getProperties().setProperty(ConfigFacadeEjb.COUNTRY_LOCALE, "de"); CaseDataDto caze = buildSuspectCase(Disease.CORONAVIRUS); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); createSampleTestsForAllTestTypesExcept(caze, Disease.CORONAVIRUS, PathogenTestType.ISOLATION); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseReferenceDefinition.FULFILLED, caze.getCaseReferenceDefinition()); @@ -1065,7 +1065,7 @@ public void testFulfilledReferenceDefinitionGermanServerUnknownSymptoms1() { CaseDataDto caze = buildSuspectCase(Disease.CORONAVIRUS); caze.getSymptoms().setCough(null); caze.getSymptoms().setChillsSweats(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); createSampleTestsForAllTestTypesExcept(caze, Disease.CORONAVIRUS, PathogenTestType.ISOLATION); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED_UNKNOWN_SYMPTOMS, caze.getCaseClassification()); @@ -1078,7 +1078,7 @@ public void testFulfilledReferenceDefinitionGermanServerUnknownSymptoms2() { CaseDataDto caze = buildSuspectCase(Disease.CORONAVIRUS); caze.getSymptoms().setCough(SymptomState.UNKNOWN); caze.getSymptoms().setChillsSweats(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); createSampleTestsForAllTestTypesExcept(caze, Disease.CORONAVIRUS, PathogenTestType.ISOLATION); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED_UNKNOWN_SYMPTOMS, caze.getCaseClassification()); @@ -1092,7 +1092,7 @@ public void testFulfilledReferenceDefinitionGermanServerUnknownSymptoms3() { caze.getSymptoms().setCough(null); caze.getSymptoms().setChillsSweats(SymptomState.YES); caze.getSymptoms().setOxygenSaturationLower94(SymptomState.UNKNOWN); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); createSampleTestsForAllTestTypesExcept(caze, Disease.CORONAVIRUS, PathogenTestType.ISOLATION); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED_UNKNOWN_SYMPTOMS, caze.getCaseClassification()); @@ -1105,7 +1105,7 @@ public void testFulfilledReferenceDefinitionGermanServerNoSymptoms1() { CaseDataDto caze = buildSuspectCase(Disease.CORONAVIRUS); caze.getSymptoms().setCough(null); caze.getSymptoms().setChillsSweats(SymptomState.NO); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); createSampleTestsForAllTestTypesExcept(caze, Disease.CORONAVIRUS, PathogenTestType.ISOLATION); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED_NO_SYMPTOMS, caze.getCaseClassification()); @@ -1118,7 +1118,7 @@ public void testFulfilledReferenceDefinitionGermanServerNoSymptoms2() { CaseDataDto caze = buildSuspectCase(Disease.CORONAVIRUS); caze.getSymptoms().setCough(SymptomState.NO); caze.getSymptoms().setChillsSweats(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); createSampleTestsForAllTestTypesExcept(caze, Disease.CORONAVIRUS, PathogenTestType.ISOLATION); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(CaseClassification.CONFIRMED_NO_SYMPTOMS, caze.getCaseClassification()); @@ -1129,7 +1129,7 @@ public void testFulfilledReferenceDefinitionGermanServerNoSymptoms2() { public void testNotFulfilledReferenceDefinitionGermanServerCorrectPathogenTestesMissing() { MockProducer.getProperties().setProperty(ConfigFacadeEjb.COUNTRY_LOCALE, "de"); CaseDataDto caze = buildSuspectCase(Disease.CORONAVIRUS); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); createSampleTestsForAllTestTypesExcept( caze, Disease.CORONAVIRUS, @@ -1143,7 +1143,7 @@ public void testNotFulfilledReferenceDefinitionGermanServerCorrectPathogenTestes @Test public void testCalculationReferenceDefinitionNonGermanServer() { CaseDataDto caze = buildSuspectCase(Disease.CORONAVIRUS); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); createSampleTestsForAllTestTypesExcept(caze, Disease.CORONAVIRUS, PathogenTestType.ISOLATION); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); assertEquals(null, caze.getCaseReferenceDefinition()); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbPseudonymizationTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbPseudonymizationTest.java index c589c13b964..b6fe1e38475 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbPseudonymizationTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbPseudonymizationTest.java @@ -18,6 +18,7 @@ package de.symeda.sormas.backend.caze; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.isEmptyString; import static org.hamcrest.Matchers.not; @@ -267,7 +268,7 @@ public void testUpdateWithPseudonymizedDto() { caze.setReportLon(null); caze.setReportLatLonAccuracy(20F); - getCaseFacade().saveCase(caze); + getCaseFacade().save(caze); assertPseudonymizedDataNotUpdated(caze, rdcf2, user2); } @@ -413,11 +414,11 @@ private void assertPseudonymized(CaseDataDto caze) { assertThat(caze.getDistrict(), is(rdcf1.district)); assertThat(caze.getCommunity(), is(nullValue())); assertThat(caze.getHealthFacility(), is(nullValue())); - assertThat(caze.getHealthFacilityDetails(), is(isEmptyString())); + assertThat(caze.getHealthFacilityDetails(), equalTo(CONFIDENTIAL)); assertThat(caze.getPointOfEntry(), is(nullValue())); - assertThat(caze.getPointOfEntryDetails(), is(isEmptyString())); - assertThat(caze.getPerson().getFirstName(), is(isEmptyString())); - assertThat(caze.getPerson().getLastName(), is(isEmptyString())); + assertThat(caze.getPointOfEntryDetails(), equalTo(CONFIDENTIAL)); + assertThat(caze.getPerson().getFirstName(), equalTo(CONFIDENTIAL)); + assertThat(caze.getPerson().getLastName(), equalTo(CONFIDENTIAL)); //sensitive data assertThat(caze.getReportingUser(), is(nullValue())); @@ -448,7 +449,7 @@ private void updateCase(CaseDataDto caze, UserDto user) { caze.setReportLon(23.234); caze.setReportLatLonAccuracy(20F); - getCaseFacade().saveCase(caze); + getCaseFacade().save(caze); } private void assertPseudonymizedDataUpdated(CaseDataDto caze) { diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java index 4f0d92e7854..cc9f3d79a74 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java @@ -335,7 +335,7 @@ public void testDiseaseChangeUpdatesContacts() { assertEquals(LocalDate.now().plusDays(21), DateHelper8.toLocalDate(contact.getFollowUpUntil())); caze.setDisease(Disease.MEASLES); - getCaseFacade().saveCase(caze); + getCaseFacade().save(caze); // Follow-up status and duration should be set to no follow-up and null // respectively because @@ -418,7 +418,7 @@ public void testMovingCaseUpdatesTaskAssigneeAndCreatesPreviousHospitalization() caze.setSurveillanceOfficer(caseOfficer.toReference()); CaseDataDto oldCase = getCaseFacade().getCaseDataByUuid(caze.getUuid()); CaseLogic.handleHospitalization(caze, oldCase, true); - getCaseFacade().saveCase(caze); + getCaseFacade().save(caze); caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); pendingTask = getTaskFacade().getByUuid(pendingTask.getUuid()); @@ -681,7 +681,7 @@ public void testGetExportList() { exposure.setEndDate(new Date()); caze.getEpiData().getExposures().add(exposure); caze.getSymptoms().setAbdominalPain(SymptomState.YES); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); Calendar cal = Calendar.getInstance(); cal.add(Calendar.DATE, -1); creator.createSample(caze.toReference(), new Date(), new Date(), user.toReference(), SampleMaterial.BLOOD, rdcfEntities.facility); @@ -797,8 +797,6 @@ public void testGetExportList() { @Test public void testGetExportListNoDuplicates() { - CaseFacade cut = getCaseFacade(); - RDCFEntities rdcf = creator.createRDCFEntities("Region", "District", "Community", "Facility"); UserDto user = creator .createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); @@ -833,10 +831,10 @@ public void testGetExportListNoDuplicates() { caze.getEpiData().getExposures().add(exposure); } - caze = cut.saveCase(caze); + caze = getCaseFacade().save(caze); List result = - cut.getExportList(new CaseCriteria(), Collections.emptySet(), CaseExportType.CASE_SURVEILLANCE, 0, 100, null, Language.EN); + getCaseFacade().getExportList(new CaseCriteria(), Collections.emptySet(), CaseExportType.CASE_SURVEILLANCE, 0, 100, null, Language.EN); assertThat(result, hasSize(1)); CaseExportDto exportDto = result.get(0); assertNotNull(exportDto.getEpiDataId()); @@ -926,7 +924,7 @@ public void testOutcomePersonConditionUpdate() { // case deceased -> person should be set to dead, causeofdeath(disease) filled in firstCase.setOutcome(CaseOutcome.DECEASED); - firstCase = getCaseFacade().saveCase(firstCase); + firstCase = getCaseFacade().save(firstCase); cazePerson = getPersonFacade().getPersonByUuid(cazePerson.getUuid()); assertNull(firstCase.getOutcomeDate()); @@ -936,14 +934,14 @@ public void testOutcomePersonConditionUpdate() { // update just the outcomeDate -> person should also get the deathdate set firstCase.setOutcomeDate(today); - firstCase = getCaseFacade().saveCase(firstCase); + firstCase = getCaseFacade().save(firstCase); cazePerson = getPersonFacade().getPersonByUuid(cazePerson.getUuid()); assertTrue(DateHelper.isSameDay(firstCase.getOutcomeDate(), cazePerson.getDeathDate())); // case has no outcome again -> person should be alive firstCase.setOutcome(CaseOutcome.NO_OUTCOME); - firstCase = getCaseFacade().saveCase(firstCase); + firstCase = getCaseFacade().save(firstCase); cazePerson = getPersonFacade().getPersonByUuid(cazePerson.getUuid()); assertNull(firstCase.getOutcomeDate()); assertEquals(PresentCondition.ALIVE, cazePerson.getPresentCondition()); @@ -952,7 +950,7 @@ public void testOutcomePersonConditionUpdate() { // additional, newer cases for the the person firstCase.setReportDate(DateHelper.subtractDays(today, 17)); firstCase.getSymptoms().setOnsetDate(firstCase.getReportDate()); - firstCase = getCaseFacade().saveCase(firstCase); + firstCase = getCaseFacade().save(firstCase); CaseDataDto secondCase = creator.createCase( user.toReference(), cazePerson.toReference(), @@ -963,7 +961,7 @@ public void testOutcomePersonConditionUpdate() { rdcf); secondCase.setOutcome(CaseOutcome.RECOVERED); secondCase.setOutcomeDate(DateHelper.subtractDays(today, 10)); - secondCase = getCaseFacade().saveCase(secondCase); + secondCase = getCaseFacade().save(secondCase); CaseDataDto thirdCase = creator.createCase( user.toReference(), cazePerson.toReference(), @@ -974,7 +972,7 @@ public void testOutcomePersonConditionUpdate() { rdcf); thirdCase.setOutcome(CaseOutcome.DECEASED); thirdCase.setOutcomeDate(DateHelper.subtractDays(today, 5)); - thirdCase = getCaseFacade().saveCase(thirdCase); + thirdCase = getCaseFacade().save(thirdCase); // the newest case is set to deceased -> person should be dead cazePerson = getPersonFacade().getPersonByUuid(cazePerson.getUuid()); @@ -1004,12 +1002,12 @@ public void testOutcomePersonConditionUpdate() { firstCase.getSymptoms().setOnsetDate(firstCase.getReportDate()); thirdCase.setReportDate(DateHelper.subtractDays(today, 100)); thirdCase.getSymptoms().setOnsetDate(thirdCase.getReportDate()); - getCaseFacade().saveCase(firstCase); - getCaseFacade().saveCase(thirdCase); + getCaseFacade().save(firstCase); + getCaseFacade().save(thirdCase); // Set 2nd Case to deceased again secondCase.setOutcome(CaseOutcome.DECEASED); - secondCase = getCaseFacade().saveCase(secondCase); + secondCase = getCaseFacade().save(secondCase); cazePerson = getPersonFacade().getPersonByUuid(cazePerson.getUuid()); // manually set the persons deathdate to 32 days in the past @@ -1018,7 +1016,7 @@ public void testOutcomePersonConditionUpdate() { // Change Case to RECOVERD -> person should not change, because deathdate is over 30 days away from case reportdate secondCase.setOutcome(CaseOutcome.RECOVERED); - secondCase = getCaseFacade().saveCase(secondCase); + secondCase = getCaseFacade().save(secondCase); cazePerson = getPersonFacade().getPersonByUuid(cazePerson.getUuid()); assertEquals(PresentCondition.DEAD, cazePerson.getPresentCondition()); @@ -1062,7 +1060,7 @@ public void testOutcomePersonConditionUpdateForAppSync() throws InterruptedExcep // this should throw an exception exception.expect(OutdatedEntityException.class); - getCaseFacade().saveCase(firstCase); + getCaseFacade().save(firstCase); } @Test @@ -1085,7 +1083,7 @@ public void testArchiveAndDearchiveCase() { assertEquals(1, getCaseFacade().getAllActiveCasesAfter(null).size()); assertEquals(1, getCaseFacade().getAllActiveUuids().size()); - getCaseFacade().archiveOrDearchiveCase(caze.getUuid(), true); + getCaseFacade().archive(caze.getUuid()); // getAllActiveCases and getAllUuids should return length 0 assertEquals(0, getCaseFacade().getAllActiveCasesAfter(null).size()); @@ -1094,7 +1092,7 @@ public void testArchiveAndDearchiveCase() { // getArchivedUuidsSince should return length 1 assertEquals(1, getCaseFacade().getArchivedUuidsSince(testStartDate).size()); - getCaseFacade().archiveOrDearchiveCase(caze.getUuid(), false); + getCaseFacade().dearchive(caze.getUuid()); // getAllActiveCases and getAllUuids should return length 1 assertEquals(1, getCaseFacade().getAllActiveCasesAfter(null).size()); @@ -1242,21 +1240,21 @@ public void testGenerateEpidNumber() throws ExternalSurveillanceToolException { assertEquals("COU-REG-DIS-" + year + "-002", secondCaze.getEpidNumber()); secondCaze.setEpidNumber("COU-REG-DIS-" + year + "-0004"); - getCaseFacade().saveCase(secondCaze); + getCaseFacade().save(secondCaze); CaseDataDto thirdCaze = creator.createCase(user.toReference(), cazePerson.toReference(), rdcf); assertEquals("COU-REG-DIS-" + year + "-005", thirdCaze.getEpidNumber()); thirdCaze.setEpidNumber("COU-REG-DIS-" + year + "-3"); - getCaseFacade().saveCase(thirdCaze); + getCaseFacade().save(thirdCaze); CaseDataDto fourthCaze = creator.createCase(user.toReference(), cazePerson.toReference(), rdcf); assertEquals("COU-REG-DIS-" + year + "-005", fourthCaze.getEpidNumber()); fourthCaze.setEpidNumber("COU-REG-DIS-" + year + "-AAA"); - getCaseFacade().saveCase(fourthCaze); + getCaseFacade().save(fourthCaze); fourthCaze = getCaseFacade().getCaseDataByUuid(fourthCaze.getUuid()); assertEquals("COU-REG-DIS-" + year + "-005", fourthCaze.getEpidNumber()); @@ -1296,7 +1294,7 @@ public void testMergeCase() throws IOException { }); leadCase.setClinicianEmail("mail"); leadCase.getEpiData().setActivityAsCaseDetailsKnown(YesNoUnknown.NO); - getCaseFacade().saveCase(leadCase); + getCaseFacade().save(leadCase); VisitDto leadVisit = creator.createVisit(leadCase.getDisease(), leadCase.getPerson(), leadCase.getReportDate()); leadVisit.getSymptoms().setAnorexiaAppetiteLoss(SymptomState.YES); getVisitFacade().saveVisit(leadVisit); @@ -1351,7 +1349,7 @@ public void testMergeCase() throws IOException { otherActivitiesAsCase.add(activityAsCaseDto); otherCase.getEpiData().setActivitiesAsCase(otherActivitiesAsCase); - getCaseFacade().saveCase(otherCase); + getCaseFacade().save(otherCase); VisitDto otherVisit = creator.createVisit(otherCase.getDisease(), otherCase.getPerson(), otherCase.getReportDate()); otherVisit.getSymptoms().setAbdominalPain(SymptomState.YES); getVisitFacade().saveVisit(otherVisit); @@ -1522,7 +1520,7 @@ public void testCloneCaseActivityAsCaseIsCloned() { otherActivitiesAsCase.add(activityAsCaseDto); aCase.getEpiData().setActivitiesAsCase(otherActivitiesAsCase); - CaseDataDto caseDataDto = getCaseFacade().saveCase(aCase); + CaseDataDto caseDataDto = getCaseFacade().save(aCase); // 2. Clone CaseDataDto clonedCase = getCaseFacade().cloneCase(caseDataDto); @@ -1574,7 +1572,7 @@ public void testSymptomsUpdatedByVisit() { visit.getSymptoms().setAbdominalPain(SymptomState.YES); visit.getSymptoms().setChestPain(SymptomState.NO); - getCaseFacade().saveCase(caze); + getCaseFacade().save(caze); getVisitFacade().saveVisit(visit); CaseDataDto updatedCase = getCaseFacade().getCaseDataByUuid(caze.getUuid()); @@ -1613,7 +1611,7 @@ public void testArchiveAllArchivableCases() { // One archived case CaseDataDto case1 = creator.createCase(user, person, rdcf); CaseFacadeEjbLocal cut = getBean(CaseFacadeEjbLocal.class); - cut.archiveOrDearchiveCase(case1.getUuid(), true); + cut.archive(case1.getUuid()); // One other case CaseDataDto case2 = creator.createCase(user, person, rdcf); @@ -1667,7 +1665,7 @@ public void testSetResponsibleSurveillanceOfficer() { caze.setResponsibleDistrict(new DistrictReferenceDto(rdcf3.district.getUuid(), null, null)); caze.setResponsibleCommunity(new CommunityReferenceDto(rdcf3.community.getUuid(), null, null)); caze.setHealthFacility(new FacilityReferenceDto(rdcf3.facility.getUuid(), null, null)); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertNull(caze.getSurveillanceOfficer()); // Surveillance officer is set to the associated officer of an informant if available @@ -1675,7 +1673,7 @@ public void testSetResponsibleSurveillanceOfficer() { caze.setDistrict(new DistrictReferenceDto(rdcf2.district.getUuid(), null, null)); caze.setCommunity(new CommunityReferenceDto(rdcf2.community.getUuid(), null, null)); caze.setHealthFacility(new FacilityReferenceDto(rdcf2.facility.getUuid(), null, null)); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertThat(caze.getSurveillanceOfficer(), is(survOff3)); } @@ -1687,12 +1685,12 @@ public void testSearchCasesFreetext() { caze.setInternalToken("internalToken"); caze.setExternalToken("externalToken"); caze.setExternalID("externalID"); - getCaseFacade().saveCase(caze); + getCaseFacade().save(caze); CaseDataDto secondCaze = creator.createCase(creator.createUser(rdcf, UserRole.SURVEILLANCE_OFFICER).toReference(), creator.createPerson().toReference(), rdcf); secondCaze.setInternalToken("internalToken2"); - getCaseFacade().saveCase(secondCaze); + getCaseFacade().save(secondCaze); List indexList = getCaseFacade().getIndexList(new CaseCriteria(), 0, 100, Collections.emptyList()); @@ -1735,7 +1733,7 @@ public void testSearchCasesWithExtendedQuarantine() { CaseDataDto caze = creator.createCase(creator.createUser(rdcf, UserRole.SURVEILLANCE_OFFICER).toReference(), creator.createPerson().toReference(), rdcf); caze.setQuarantineExtended(true); - getCaseFacade().saveCase(caze); + getCaseFacade().save(caze); List indexList = getCaseFacade().getIndexList(new CaseCriteria(), 0, 100, Collections.emptyList()); assertThat(indexList.get(0).getUuid(), is(caze.getUuid())); @@ -1753,7 +1751,7 @@ public void testSearchCasesWithReducedQuarantine() { CaseDataDto caze = creator.createCase(creator.createUser(rdcf, UserRole.SURVEILLANCE_OFFICER).toReference(), creator.createPerson().toReference(), rdcf); caze.setQuarantineReduced(true); - getCaseFacade().saveCase(caze); + getCaseFacade().save(caze); List indexList = getCaseFacade().getIndexList(new CaseCriteria(), 0, 100, Collections.emptyList()); assertThat(indexList.get(0).getUuid(), is(caze.getUuid())); @@ -1896,7 +1894,7 @@ public void testCreateCaseWithoutUuid() { epiData.setExposures(Collections.singletonList(exposure)); caze.setEpiData(epiData); - CaseDataDto savedCaze = getCaseFacade().saveCase(caze); + CaseDataDto savedCaze = getCaseFacade().save(caze); MatcherAssert.assertThat(savedCaze.getUuid(), not(isEmptyOrNullString())); MatcherAssert.assertThat(savedCaze.getTherapy().getUuid(), not(isEmptyOrNullString())); @@ -1957,7 +1955,7 @@ private CaseDataDto createCaseOfFacilityType(RDCF rdcf, PersonReferenceDto perso epiData.setExposures(Collections.singletonList(exposure)); caze1.setEpiData(epiData); - return getCaseFacade().saveCase(caze1); + return getCaseFacade().save(caze1); } @Test @@ -2013,10 +2011,10 @@ public void testGetCasesByPersonUuids() { RDCF rdcf = creator.createRDCF(); PersonReferenceDto person1 = creator.createPerson().toReference(); - CaseDataDto case1 = getCaseFacade().saveCase(creator.createCase(user, person1, rdcf)); + CaseDataDto case1 = getCaseFacade().save(creator.createCase(user, person1, rdcf)); PersonReferenceDto person2 = creator.createPerson().toReference(); - CaseDataDto case2 = getCaseFacade().saveCase(creator.createCase(user, person2, rdcf)); + CaseDataDto case2 = getCaseFacade().save(creator.createCase(user, person2, rdcf)); List casesByPerson = getCaseFacade().getByPersonUuids(Collections.singletonList(person1.getUuid())); @@ -2069,7 +2067,7 @@ public void testUpdateFollowUpUntilAndStatus() { // Manually overwrite and increase the follow-up until date caze.setFollowUpUntil(DateUtils.addDays(new Date(), 23)); caze.setOverwriteFollowUpUntil(true); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(FollowUpStatus.FOLLOW_UP, caze.getFollowUpStatus()); // Add a cooperative visit AFTER the follow-up until date; should set follow-up to completed @@ -2085,7 +2083,7 @@ public void testUpdateFollowUpUntilAndStatus() { // Increasing the onset date should extend follow-up caze.getSymptoms().setOnsetDate(DateHelper.addDays(caze.getSymptoms().getOnsetDate(), 10)); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); assertEquals(FollowUpStatus.FOLLOW_UP, caze.getFollowUpStatus()); assertEquals(LocalDate.now().plusDays(21 + 10), DateHelper8.toLocalDate(caze.getFollowUpUntil())); } @@ -2133,7 +2131,7 @@ public void testCaseCriteriaChangedSinceLastShareWithReportingTool() { getExternalShareInfoService().ensurePersisted(shareInfo); sharedCase.setReInfection(YesNoUnknown.YES); - getCaseFacade().saveCase(sharedCase); + getCaseFacade().save(sharedCase); creator.createCase(user.toReference(), creator.createPerson().toReference(), rdcf); creator.createCase(user.toReference(), creator.createPerson().toReference(), rdcf); @@ -2167,7 +2165,7 @@ public void testCaseCriteriaLastShareWithReportingToolBetweenDates() { getExternalShareInfoService().ensurePersisted(shareInfoApril); sharedCase.setReInfection(YesNoUnknown.YES); - getCaseFacade().saveCase(sharedCase); + getCaseFacade().save(sharedCase); creator.createCase(user.toReference(), creator.createPerson().toReference(), rdcf); creator.createCase(user.toReference(), creator.createPerson().toReference(), rdcf); @@ -2293,7 +2291,7 @@ public void testGetCaseMeasurePerDistrict() { assertEquals(2, districtCaseCount.getElement1().intValue()); caze.setDistrict(rdcf2.district); - getCaseFacade().saveCase(caze); + getCaseFacade().save(caze); creator.createCase(user.toReference(), creator.createPerson("Person", "Three").toReference(), rdcf2); caseMeasurePerDistrict = getCaseFacade().getCaseMeasurePerDistrict(null, null, Disease.EVD, CaseMeasure.CASE_COUNT); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CasePartialUpdateTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CasePartialUpdateTest.java index 7c4c5dd71cf..740fcb4657b 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CasePartialUpdateTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CasePartialUpdateTest.java @@ -201,7 +201,7 @@ public void testResetValue() { rdcf); caze.setCaseOrigin(CaseOrigin.IN_COUNTRY); caze.setAdditionalDetails("additional details"); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); ObjectMapper mapper = new ObjectMapper(); JsonNode caseJson = mapper.convertValue(caze, JsonNode.class); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseStatisticsFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseStatisticsFacadeEjbTest.java index 05a99a7eaff..25e92990a0d 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseStatisticsFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseStatisticsFacadeEjbTest.java @@ -55,7 +55,7 @@ public void testQueryCaseCount() { new Date(), rdcf); caze.setOutcomeDate(DateHelper.addWeeks(caze.getReportDate(), 2)); - caze = getCaseFacade().saveCase(caze); + caze = getCaseFacade().save(caze); StatisticsCaseCriteria criteria = new StatisticsCaseCriteria(); int year = DateHelper8.toLocalDate(caze.getSymptoms().getOnsetDate()).getYear(); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java index 3f001329191..a5fd96e8b75 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java @@ -1285,7 +1285,7 @@ public void testArchiveOrDearchiveContact() { assertEquals(1, getVisitFacade().getAllActiveVisitsAfter(null).size()); assertEquals(1, getVisitFacade().getAllActiveUuids().size()); - getCaseFacade().archiveOrDearchiveCase(caze.getUuid(), true); + getCaseFacade().archive(caze.getUuid()); // getAllActiveContacts and getAllUuids should return length 0 assertEquals(0, getContactFacade().getAllAfter(null).size()); @@ -1293,7 +1293,7 @@ public void testArchiveOrDearchiveContact() { assertEquals(0, getVisitFacade().getAllActiveVisitsAfter(null).size()); assertEquals(0, getVisitFacade().getAllActiveUuids().size()); - getCaseFacade().archiveOrDearchiveCase(caze.getUuid(), false); + getCaseFacade().dearchive(caze.getUuid()); // getAllActiveContacts and getAllUuids should return length 1 assertEquals(1, getContactFacade().getAllAfter(null).size()); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/dashboard/DashboardFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/dashboard/DashboardFacadeEjbTest.java index 29cd679b915..a7e5c4d0e99 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/dashboard/DashboardFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/dashboard/DashboardFacadeEjbTest.java @@ -55,7 +55,7 @@ public void testGetCasesForDashboard() { new Date(), rdcf2); caze2.setSharedToCountry(true); - getCaseFacade().saveCase(caze2); + getCaseFacade().save(caze2); DashboardCriteria dashboardCriteria = new DashboardCriteria().region(caze.getResponsibleRegion()) .district(caze.getDistrict()) diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java index 46fbd5e9e59..2fa8d03ff04 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java @@ -313,7 +313,7 @@ public void testGetMatchingNameDtos() { EventDto inactiveEvent = creator.createEvent(user.toReference()); creator.createEventParticipant(inactiveEvent.toReference(), person7, user.toReference()); - getCaseFacade().archiveOrDearchiveCase(inactiveCase.getUuid(), true); + getCaseFacade().archive(inactiveCase.getUuid()); getEventFacade().archive(inactiveEvent.getUuid()); // Only persons that have active case, contact or event participant associations should be retrieved @@ -327,7 +327,7 @@ public void testGetMatchingNameDtos() { containsInAnyOrder(person1.getUuid(), person2.getUuid(), person3.getUuid(), person5.getUuid(), person6.getUuid(), person7.getUuid())); creator.createCase(user.toReference(), person4.toReference(), rdcf); - getCaseFacade().archiveOrDearchiveCase(inactiveCase.getUuid(), false); + getCaseFacade().dearchive(inactiveCase.getUuid()); getEventFacade().archive(inactiveEvent.getUuid()); PersonSimilarityCriteria criteria = new PersonSimilarityCriteria().sex(Sex.MALE).birthdateYYYY(1980).birthdateMM(1).birthdateDD(1); @@ -541,9 +541,9 @@ public void testGetFollowUpEndDatesCasesOnly() { case12.setFollowUpUntil(DateHelper.subtractDays(now, 8)); case2.setFollowUpUntil(now); - getCaseFacade().saveCase(case11); - getCaseFacade().saveCase(case12); - getCaseFacade().saveCase(case2); + getCaseFacade().save(case11); + getCaseFacade().save(case12); + getCaseFacade().save(case2); List followUpEndDtos = getPersonFacade().getLatestFollowUpEndDates(null, false); @@ -610,11 +610,11 @@ public void testGetFollowUpEndDatesContactsAndCases() { getContactFacade().save(contact2); getContactFacade().save(contact3); getContactFacade().save(contact4); - getCaseFacade().saveCase(case1); - getCaseFacade().saveCase(case2); - getCaseFacade().saveCase(case3); - getCaseFacade().saveCase(case4); - getCaseFacade().saveCase(case5); + getCaseFacade().save(case1); + getCaseFacade().save(case2); + getCaseFacade().save(case3); + getCaseFacade().save(case4); + getCaseFacade().save(case5); List followUpEndDtos = getPersonFacade().getLatestFollowUpEndDates(null, false); @@ -813,7 +813,7 @@ private void updateFollowUpStatus(ContactDto contact, FollowUpStatus status) { private void updateFollowUpStatus(CaseDataDto caze, FollowUpStatus status) { caze = getCaseFacade().getCaseDataByUuid(caze.getUuid()); caze.setFollowUpStatus(status); - getCaseFacade().saveCase(caze); + getCaseFacade().save(caze); } @Test diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjbTest.java index 03fff24437a..3b00a7d07e9 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjbTest.java @@ -105,7 +105,7 @@ public void testSaveAndUpdatePathogenTestAssociatedToBothCaseAndContact() { caseDataDto.setFacilityType(rdcf.facility.getType()); caseDataDto.setHealthFacility(new FacilityReferenceDto(rdcf.facility.getUuid(), null, null)); caseDataDto.setReportingUser(user.toReference()); - final CaseDataDto caseConvertedFromContact = getCaseFacade().saveCase(caseDataDto); + final CaseDataDto caseConvertedFromContact = getCaseFacade().save(caseDataDto); getCaseFacade().setSampleAssociations(contact.toReference(), caseConvertedFromContact.toReference()); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/SampleFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/SampleFacadeEjbTest.java index f3956ee397a..1c4ec4ebb3a 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/SampleFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/SampleFacadeEjbTest.java @@ -295,7 +295,7 @@ public void testGetIndexListForCaseConvertedFromContact() { caseDataDto.setFacilityType(rdcf.facility.getType()); caseDataDto.setHealthFacility(new FacilityReferenceDto(rdcf.facility.getUuid(), null, null)); caseDataDto.setReportingUser(user.toReference()); - CaseDataDto caseConvertedFromContact = getCaseFacade().saveCase(caseDataDto); + CaseDataDto caseConvertedFromContact = getCaseFacade().save(caseDataDto); getCaseFacade().setSampleAssociations(contact.toReference(), caseConvertedFromContact.toReference()); @@ -507,7 +507,7 @@ public void testArchivedSampleNotGettingTransfered() { assertEquals(1, getSampleTestFacade().getAllActivePathogenTestsAfter(null).size()); assertEquals(1, getSampleTestFacade().getAllActiveUuids().size()); - getCaseFacade().archiveOrDearchiveCase(caze.getUuid(), true); + getCaseFacade().archive(caze.getUuid()); // getAllActiveSamples/getAllActiveSampleTests and getAllUuids should return length 0 assertEquals(0, getSampleFacade().getAllActiveSamplesAfter(null).size()); @@ -515,7 +515,7 @@ public void testArchivedSampleNotGettingTransfered() { assertEquals(0, getSampleTestFacade().getAllActivePathogenTestsAfter(null).size()); assertEquals(0, getSampleTestFacade().getAllActiveUuids().size()); - getCaseFacade().archiveOrDearchiveCase(caze.getUuid(), false); + getCaseFacade().dearchive(caze.getUuid()); // getAllActiveSamples/getAllActiveSampleTests and getAllUuids should return length 1 assertEquals(1, getSampleFacade().getAllActiveSamplesAfter(null).size()); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/task/TaskFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/task/TaskFacadeEjbTest.java index 401a0aedfdf..bb3ddc4c7b8 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/task/TaskFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/task/TaskFacadeEjbTest.java @@ -173,14 +173,14 @@ public void testArchivedTaskNotGettingTransfered() { assertEquals(6, getTaskFacade().getAllActiveTasksAfter(null).size()); assertEquals(6, getTaskFacade().getAllActiveUuids().size()); - getCaseFacade().archiveOrDearchiveCase(caze.getUuid(), true); + getCaseFacade().archive(caze.getUuid()); getEventFacade().archive(event.getUuid()); // getAllActiveTasks and getAllUuids should return length 1 assertEquals(1, getTaskFacade().getAllActiveTasksAfter(null).size()); assertEquals(1, getTaskFacade().getAllActiveUuids().size()); - getCaseFacade().archiveOrDearchiveCase(caze.getUuid(), false); + getCaseFacade().dearchive(caze.getUuid()); getEventFacade().dearchive(event.getUuid()); // getAllActiveTasks and getAllUuids should return length 5 + 1 (contact investigation) diff --git a/sormas-rest/src/main/java/de/symeda/sormas/rest/CaseResource.java b/sormas-rest/src/main/java/de/symeda/sormas/rest/CaseResource.java index 3fc70c2d312..ef40d953d88 100644 --- a/sormas-rest/src/main/java/de/symeda/sormas/rest/CaseResource.java +++ b/sormas-rest/src/main/java/de/symeda/sormas/rest/CaseResource.java @@ -86,7 +86,7 @@ public List getByPersonUuids(List uuids) { @POST @Path("/push") public List postCases(@Valid List dtos) { - return savePushedDto(dtos, FacadeProvider.getCaseFacade()::saveCase); + return savePushedDto(dtos, FacadeProvider.getCaseFacade()::save); } @GET diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java index 5a3f118ad3a..90004cd29cd 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java @@ -244,7 +244,7 @@ public void createFromContact(ContactDto contact) { } else { CaseDataDto selectedCase = FacadeProvider.getCaseFacade().getCaseDataByUuid(uuid); selectedCase.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); - FacadeProvider.getCaseFacade().saveCase(selectedCase); + FacadeProvider.getCaseFacade().save(selectedCase); ContactDto updatedContact = FacadeProvider.getContactFacade().getByUuid(contact.getUuid()); updatedContact.setContactStatus(ContactStatus.CONVERTED); @@ -474,7 +474,7 @@ protected CaseDataDto saveCase(CaseDataDto cazeDto) { CaseDataDto existingDto = FacadeProvider.getCaseFacade().getCaseDataByUuid(cazeDto.getUuid()); onCaseChanged(existingDto, cazeDto); - CaseDataDto resultDto = FacadeProvider.getCaseFacade().saveCase(cazeDto); + CaseDataDto resultDto = FacadeProvider.getCaseFacade().save(cazeDto); if (resultDto.getPlagueType() != cazeDto.getPlagueType()) { // TODO would be much better to have a notification for this triggered in the backend @@ -1157,7 +1157,7 @@ public CommitDiscardWrapperComponent getHospitalizationComp cazeDtoInner.setFacilityType(FacilityType.HOSPITAL); cazeDtoInner.setHealthFacility(dto.getHealthFacility()); cazeDtoInner.setHealthFacilityDetails(dto.getHealthFacilityDetails()); - FacadeProvider.getCaseFacade().saveCase(cazeDtoInner); + FacadeProvider.getCaseFacade().save(cazeDtoInner); ControllerProvider.getCaseController().navigateToView(HospitalizationView.VIEW_NAME, caze.getUuid(), null); }); VaadinUiUtil.showModalPopupWindow(wrapperComponent, I18nProperties.getString(Strings.headingPlaceOfStayInHospital)); @@ -1361,7 +1361,7 @@ public void referFromPointOfEntry(CaseDataDto caze) { if (!form.getFieldGroup().isModified()) { CaseDataDto dto = form.getValue(); dto.getHospitalization().setAdmissionDate(new Date()); - FacadeProvider.getCaseFacade().saveCase(dto); + FacadeProvider.getCaseFacade().save(dto); window.close(); Notification.show(I18nProperties.getString(Strings.messageCaseReferredFromPoe), Type.ASSISTIVE_NOTIFICATION); SormasUI.refreshView(); @@ -1391,7 +1391,7 @@ private void archiveOrDearchiveCase(String caseUuid, boolean archive) { 640, e -> { if (e.booleanValue() == true) { - FacadeProvider.getCaseFacade().archiveOrDearchiveCase(caseUuid, true); + FacadeProvider.getCaseFacade().archive(caseUuid); Notification.show( String.format(I18nProperties.getString(Strings.messageCaseArchived), I18nProperties.getString(Strings.entityCase)), Type.ASSISTIVE_NOTIFICATION); @@ -1412,7 +1412,7 @@ private void archiveOrDearchiveCase(String caseUuid, boolean archive) { 640, e -> { if (e.booleanValue()) { - FacadeProvider.getCaseFacade().archiveOrDearchiveCase(caseUuid, false); + FacadeProvider.getCaseFacade().dearchive(caseUuid); Notification.show( String.format(I18nProperties.getString(Strings.messageCaseDearchived), I18nProperties.getString(Strings.entityCase)), Type.ASSISTIVE_NOTIFICATION); @@ -1688,7 +1688,7 @@ private void saveCasesFromLineListing(LineListingLayout lineListingForm, List

  • { if (uuid == null) { - FacadeProvider.getCaseFacade().saveCase(newCase); + FacadeProvider.getCaseFacade().save(newCase); Notification.show(I18nProperties.getString(Strings.messageCaseCreated), Type.ASSISTIVE_NOTIFICATION); } }); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/ClinicalCourseView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/ClinicalCourseView.java index f6ec45c428b..f424d0cd310 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/ClinicalCourseView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/ClinicalCourseView.java @@ -131,7 +131,7 @@ protected void initView(String params) { if (caze.getClinicalCourse() == null) { ClinicalCourseDto clinicalCourse = ClinicalCourseDto.build(); caze.setClinicalCourse(clinicalCourse); - caze = FacadeProvider.getCaseFacade().saveCase(caze); + caze = FacadeProvider.getCaseFacade().save(caze); } DetailSubComponentWrapper container = new DetailSubComponentWrapper(() -> editComponent); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/DevModeView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/DevModeView.java index 3d189cd5e5d..7749820ffc8 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/DevModeView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/DevModeView.java @@ -955,7 +955,7 @@ private void generateCases() { } FacadeProvider.getPersonFacade().savePerson(person); - FacadeProvider.getCaseFacade().saveCase(caze); + FacadeProvider.getCaseFacade().save(caze); } dt = System.nanoTime() - dt; @@ -1351,7 +1351,7 @@ private void generateEvents() { caze.setHealthFacility(facility.toReference()); caze.setFacilityType(facility.getType()); caze.setAdditionalDetails("Case generated using DevMode on " + LocalDate.now()); - FacadeProvider.getCaseFacade().saveCase(caze); + FacadeProvider.getCaseFacade().save(caze); eventParticipant.setResultingCase(caze.toReference()); generatedCases++; } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactController.java index c52be4f9277..a2c822ed549 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactController.java @@ -387,7 +387,7 @@ public CommitDiscardWrapperComponent getContactCreateComponen if (asSourceContact && caze != null) { CaseDataDto caseDto = FacadeProvider.getCaseFacade().getByUuid(caze.getUuid()); caseDto.getEpiData().setContactWithSourceCaseKnown(YesNoUnknown.YES); - FacadeProvider.getCaseFacade().saveCase(caseDto); + FacadeProvider.getCaseFacade().save(caseDto); } if (asSourceContact && alternativeCallback != null && casePerson != null) { selectOrCreateContact(dto, casePerson, selectedContactUuid -> { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java index b8ffbbc9c93..0ca5f6d8031 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java @@ -227,7 +227,7 @@ private void archiveOrDearchiveImmunization(String uuid, boolean archive) { 640, e -> { if (e) { - FacadeProvider.getImmunizationFacade().archiveOrDearchiveImmunization(uuid, true); + FacadeProvider.getImmunizationFacade().archive(uuid); Notification.show( String.format( I18nProperties.getString(Strings.messageImmunizationArchived), @@ -250,7 +250,7 @@ private void archiveOrDearchiveImmunization(String uuid, boolean archive) { 640, e -> { if (e) { - FacadeProvider.getImmunizationFacade().archiveOrDearchiveImmunization(uuid, false); + FacadeProvider.getImmunizationFacade().dearchive(uuid); Notification.show( String.format( I18nProperties.getString(Strings.messageImmunizationDearchived), diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java index b255df72fb4..780a48f5257 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java @@ -169,7 +169,7 @@ public static void showCaseUpdateWithNewDiseaseVariantDialog( CaseDataDto caseDataByUuid = FacadeProvider.getCaseFacade().getCaseDataByUuid(existingCaseDto.getUuid()); caseDataByUuid.setDiseaseVariant(diseaseVariant); caseDataByUuid.setDiseaseVariantDetails(diseaseVariantDetails); - FacadeProvider.getCaseFacade().saveCase(caseDataByUuid); + FacadeProvider.getCaseFacade().save(caseDataByUuid); } if (callback != null) { callback.accept(yes); @@ -469,7 +469,7 @@ public static void showCaseCloningWithNewDiseaseDialog( clonedCase.setDiseaseVariantDetails(diseaseVariantDetails); clonedCase.setEpidNumber(null); clonedCase.setReportDate(new Date()); - FacadeProvider.getCaseFacade().saveCase(clonedCase); + FacadeProvider.getCaseFacade().save(clonedCase); ControllerProvider.getCaseController().navigateToCase(clonedCase.getUuid()); } }); @@ -495,7 +495,7 @@ public void showConfirmCaseDialog(CaseDataDto caze) { if (confirmed) { CaseDataDto caseDataByUuid = FacadeProvider.getCaseFacade().getCaseDataByUuid(caze.getUuid()); caseDataByUuid.setCaseClassification(CaseClassification.CONFIRMED); - FacadeProvider.getCaseFacade().saveCase(caseDataByUuid); + FacadeProvider.getCaseFacade().save(caseDataByUuid); ControllerProvider.getCaseController().navigateToCase(caseDataByUuid.getUuid()); } }); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/TherapyView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/TherapyView.java index 084108a2276..4ad2a47e8c0 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/TherapyView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/TherapyView.java @@ -224,7 +224,7 @@ private void update(CaseDataDto caze) { if (caze.getTherapy() == null) { TherapyDto therapy = TherapyDto.build(); caze.setTherapy(therapy); - caze = FacadeProvider.getCaseFacade().saveCase(caze); + caze = FacadeProvider.getCaseFacade().save(caze); } prescriptionCriteria.therapy(caze.getTherapy().toReference()); diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/TestDataCreator.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/TestDataCreator.java index 32c0f16463d..15bed315431 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/TestDataCreator.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/TestDataCreator.java @@ -299,7 +299,7 @@ public CaseDataDto createCase( caze.setFacilityType(facility.getType()); caze.setHealthFacility(facility.toReference()); - caze = FacadeProvider.getCaseFacade().saveCase(caze); + caze = FacadeProvider.getCaseFacade().save(caze); return caze; } diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/caze/GermanCaseClassificationValidatorTest.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/caze/GermanCaseClassificationValidatorTest.java index 2ed3c05a5ee..4c6383934af 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/caze/GermanCaseClassificationValidatorTest.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/caze/GermanCaseClassificationValidatorTest.java @@ -110,7 +110,7 @@ public void testCaseClassificationValidator() { // assert classifications when other symptoms & positive lab result caze.getSymptoms().setFever(SymptomState.YES); - CaseDataDto savedCase1 = getCaseFacade().saveCase(caze); + CaseDataDto savedCase1 = getCaseFacade().save(caze); valid(CaseClassification.NOT_CLASSIFIED, validator); invalid(CaseClassification.SUSPECT, validator); @@ -122,7 +122,7 @@ public void testCaseClassificationValidator() { // assert classifications when other & covid symptoms & positive lab result savedCase1.getSymptoms().setPneumoniaClinicalOrRadiologic(SymptomState.YES); - CaseDataDto savedCase2 = getCaseFacade().saveCase(savedCase1); + CaseDataDto savedCase2 = getCaseFacade().save(savedCase1); valid(CaseClassification.NOT_CLASSIFIED, validator); valid(CaseClassification.SUSPECT, validator); diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/caze/importer/CaseImporterTest.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/caze/importer/CaseImporterTest.java index 0c7af62730a..752efb8ed6b 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/caze/importer/CaseImporterTest.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/caze/importer/CaseImporterTest.java @@ -227,7 +227,7 @@ protected void handleCaseSimilarity(CaseImportSimilarityInput input, Consumer pass diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/importexport/ImportExportTest.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/importexport/ImportExportTest.java index ed1dcf55119..9f283b06e4a 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/importexport/ImportExportTest.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/importexport/ImportExportTest.java @@ -106,7 +106,7 @@ public void testImportExportedCase() throws IOException, CsvException, InvalidCo caze.getSymptoms().setTremor(SymptomState.YES); caze.getSymptoms().setVomiting(SymptomState.YES); - getCaseFacade().saveCase(caze); + getCaseFacade().save(caze); person.setSex(Sex.MALE); person.setBirthdateDD(11); From bcbce1c878025fa542b0e04db28aad2b0e8cfe76 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Thu, 3 Feb 2022 13:48:28 +0200 Subject: [PATCH 014/253] #7246 - fix pseudonymization of API methods --- .../resources/doc/SORMAS_Data_Dictionary.xlsx | Bin 253758 -> 253756 bytes .../resources/doc/SORMAS_User_Rights.xlsx | Bin 19069 -> 19067 bytes .../backend/common/AbstractCoreEjb.java | 6 +++--- .../backend/contact/ContactFacadeEjb.java | 5 ----- .../sormas/backend/AbstractBeanTest.java | 4 ++++ .../CaseFacadeEjbPseudonymizationTest.java | 8 ++++---- .../ContactFacadeEjbPseudonymizationTest.java | 12 ++++++------ .../ImmunizationFacadeEjbTest.java | 4 ++-- .../travelentry/TravelEntryFacadeEjbTest.java | 4 ++-- 9 files changed, 21 insertions(+), 22 deletions(-) diff --git a/sormas-api/src/main/resources/doc/SORMAS_Data_Dictionary.xlsx b/sormas-api/src/main/resources/doc/SORMAS_Data_Dictionary.xlsx index fa8aa7e1dff6a09fd4f41e03ba2e5d0aad14351b..b3b0099e184e30a87e91b6a213d0b7266635aa79 100644 GIT binary patch delta 11776 zcmZvC30RG5_x^tOOQljdC`xKKAf9?L??_KTAb-8-)_1x=T!?T`ePbV|eI3v^8&~vERsD(sNPfzkP z=#*g_LHaUC(NQ?k2>;6OHZCB4l6CAu9}l_O*<_%f{qxL(Lyco^FK#xykEiea0oBfS zQ+?*F_SpY;)rvdmW9M)5wfmURW7wgJHvf3^E)L6y-*h@-Z==XFvpY}fm-MOZ?Y3fU{BCrh~htk5T{w^1vP|Lx2^7&Ox=`I)58ry~P$oBMlz3A|+L`sXU$ z5xGl>LuK0sgb3!zo;LbBH}3L@{O7>v1!K~U-JGTN!l1h|10-=>zD&1WZux8O_-#9S zZSX&MXx6R6vnxyb8%}=zp)FJ@a`HpLqwL#(mnF%Yk9ho6we+u9_HH*9E?T8{QgY7e z*6)rbM?XbWhlgCB9Q5Umn?crx`^s^%WPfgZeC1t!>I-vO;r;T}g6B|Oy=!`Qd5r~$ z0epo zboE+FRA2S8Nz7*Tb4Dx+NW^9Gfol8K?Q8h6OyL~&ANBJVpfTh*TV-GcqK@M2PPIWX zIG$C7i;82r*QuR66Ep(H5>*MyVBSs?Fy6~rMVw~t(+J$!uMuv4z+EjCeo&RAO!4uM zsvWYpc+{G3MB{VrsH$R_!s1wOwg1ZFY9B>;s;YXK!u_NsMsgbC`)ArH8lPr-@*Jqp zJl{A&w^fdINZNy2;c$*sNr)SjEI4_7bDjy4=aK3CXd>kK+(nJu{L%noSNLZhRVUgh zThol_98EF*TxJ@iVH2-L{&)bVV)z7+jMyQ{c-d(GDhAI0o5u5wJs|<=I57>m0jPF0xw7*;FdNrrK zOkFLUOh$qJk2S;t6`ITpo(@qvEv?+Des1?{nCcmR9YBHI&sV7oik>gkQ>WPVN+bOB z|7$kg_cd!p$a@>b^*5|_WmW>+ z8Rl%9hRzk%yi)4i!=|?LV_V_>Q7QjUm{50n?o1F^okHh5?Rce>@U=Z_K2YTA!1jfq ziyc`PC<2$$=-l3kIV+KVL=(o@g;zsWqC4|06uSy^5}{c)%w=L1VK8-}D7P!yA0;BD zM9eVq3`Tj@od>4OAw76~6utk0r%2K8UP5=ZCitC2=M#VO`Y6G`jrWqGS?+vlnhnH+ zjQXmi5JB)cbY9SpcaIYC`?HZ#BBHNQK+U@c@tzR`p-S`<2djb-;VDD-oKX7pp{yOu z*>O0ZJ-QY>LZBB06#JszmytYKipF~Jsi7#_n~y(1kaPiqb{fs4C?R%?Ku;%=`ZZP< zP8&nl=8qTXl|k3wWI8%OogmQj$mn4{%vp)_ebmp@9}|MfJRyQ0>mvGn^J5)SqG^(b zsR-b`q<+6m6E>*VpeO_VvZwQ%qJ%axcnc{Coyq$}(TiDp_X&b0m(bZONOSgWl;`JY zj-idxavrY@&#H|wESN{8$R&hlMN#B}+A9AntgSL(5f4h4S&P{%L=L)*(t2ra&D>>t zJ404thdQlbeo90$Y01?5Yn8B;Am!Rn;gH5WY^|_bgFdX|gH2uJ8<-1F)MFE$REjFX zY9VmBf-Tv+MRVKPDE}K?yHNKCVG|8Q(|;YQx$SJA_f=6xIVxIMsv&%c;X_a99^3ey zQ*=;X3&DtM=&ZLxbM@LNkH^(+W3!!nX3<%uT(*mkBtbCgx~Qvs6R**eDF^N0Q%dQ| z1kFy$l-5a_B4jZ420Gu~tJxNrvh#ixOSvRj_$(#Oo_|RAOv~D5C$(2b9TB=)l9z}o zXQ?CH$`$pMKduQ@8baS2LOS_W!3Yld!gB(sZ`T6hiJ^MQy;S&Dz2sXa7<5uEMc+c% zL_O(bjjXM{)WbkUQ0{Cg)zPe7GnGzitXhMSZKRrz6D_6AI_jmfw$j%Kl$gzMee!@s zm}+!7b(V(M5c6JdsWmnG_ZRJzuSQ8aNlvXSnD2E)CTB>tXMx{t2ny3kbOHljeLeUuf z&qzzuDihC21DdKx%D*p5b=3mkd8aKr$K|MG?6Ta~}E>MwDCiCVgM1-j1ND1K3|M{W|Es0P&u zu11P4)Jw%tVi#JpPK?-{SlwboH}ZE)jM%Hm%b4$N+79(~e=ASWQ8=(x$V?|ra zjz!oXeDM!~%L)7ez*jQ}+yjp|{6*luV6lz)x^F`#uTXh#sHvmpP(j*4qWX@c-{?H$ zhOXB5>A#Oug4Wvqr9cw;TanD#Nv2P;L{c{`k|9*8NGYLZOKp(krbP+@TRF?bLyn0R z!E_G85lUS*$wzK7g-p3fZ_RvSiwT2$zX{FZr(C4%Hr|fL>doNV3XSgDMHAYvGz0yw z7T|hVY$+WR4k4X{=AE6F&Ye@g#6|x)uO`{|!o*tEu27=bDlgt@2Di4e&<{zJ=8CDJL!%G@nL9)~+B8X#*Ms&LcC1#| zY7pW$X?A;)ZvIFbBG%8%2l^w4?Dgz8j8?NlZW(6=NpUQ#RI~{b;TES<5vYWwz-1j; zr{18?DT^Y?fwx+_8tNJ1;^#>#=`znEjN&RQAmhW~OUyuJN3dU>!cCEs}oMBE5ybkVHz3k4NF*pyco| zfvNC~L+jnxkY*?4E+@^j&eGC-mE}ZTyT-p@&2FATYD~~aLeiebdvFCwB!#~*h|mpm z_AuzQ2O+><4uc8&2O<#ChFfmG{{!FbZWmh$W1tAFv>(2s9v+o780RAVmcU&TvxaxG zgW^OyL00MVKhw=%ZUWon6$uz*6YNAL$taV+*HFfxkceFvl_?L&G;^wd+|KtNokM2N zTdT*vvLGN)w6!Kz%9t((ZOC>F)M8D^k+04%gN#I$$Sn*dT!UAMERm*32pyqg5`&%u z#=%^KdPMeI`OJwR+aa0?5=cWMZH3#9tIO>$))1{&f$)(Fwcd+D1<-9T)Ac2ADJ?xSp1{Fiu%D4#_al4N^Z~xzabH zqzh)rO!&`agsCu*!!-mNLjppoIPiQQbJ9!geOm-iRivt{wjmvnG+wLW5z_J=6&ZxFt6ne!mxJ88SdnXL$*!8&us~&9;?(w{HEYE! zIEz*?z-0$fuoHaYup-OM?^b%d@ko6 z%A1WOU#+3b`6Pex$qa&yuwcuMp!z(BLr2nv3<68x5r;JhrE9;-lfG-8;`ym&8Y9EB*4qj0WAL#+G|0s)}dlciRzzYryQp7f*ryxMEAee%C3d?x}T7?r3 zl)`*s2{eHd2x)_^toWoe3lsCxsyzg%RV3Y*J59*u4A9En61pB^!V{07@CI0NOtdGx zNhHt#E+V9H{tdmL*8wFapoD3i_YGU1Mn$^PtMn*2VcoSz|3bgxOnCNj6dns<9G)OB z9r6&;+0N|~aoiSSPvFsQ1IDS`8j+W3)D~pt(YhW+p_Qb#JQZDE0C1Q|;7}-2`TQte z+FJ&v($MDwSe@WX*7l!ctzc~`TARaEv=XK86X?1a4s%$DP<(1GK#jSey|Y6VQB9|i zW@5+dc48p7oaAAe?n-bohw3vJ<~1xtD+v>S62o|alEVrDkHB|?w8a7IGj)jYAT41% za7*K)(b-8wc%MtGv|4-|)+33;Nl8Ot9k{{adjbQ&;1tiT|AG*i6~ty?Zn-cLtu(sc z-lo154ep&I$dN>Z(@&vNI6UC+7ecYxQ2-OC2Kux&@s?#E3Xah#XB7CI=22Z1diEz1 z(@CqGpOB0sIur9u#;s#JDNgPzz^cxIS)78M4kHC-bOjt0T<_f1eEf}5A{nQp=K#Sf z(%z~8XUQ!4XpsOENFt?{5@8WObJ+F_!c^#ahR4~{WK=fUEAn=+?hv$wP!(xZr~O5w zrLJ0WF2NNfkvOl3a2wD)%b@dFgiB#4Lb@v-?oS;_-YL3hNt8mgiZpIlGfVQmS$iV? z19y-_n>fm?MS%tEJBhpg7|hPGaJ|oAxL)9ckdn;Ib#m<3>DvuSXr)OE?sxqpc>x%t zm4pb-xRSmSm1aYGB@-S&U;zXnq;Ex$N@LF&*7LYC#-6U#hXQDx z&hq^u9nXZ@cmXDlNB#NfOn)_6@uuI6B&u}XYwk%0RMH;PvG7Di%BT?R{YcxjX6y>s zUS#2hTtwkOn89Hbf%vfiA?<+Yr4``K<_l4)p&sa5l)YkA(Tj2977J!A>wiKp_p!M?4g52(c~#(&&2^hre$umME!_zV(MojVvr+d4 zC^@Vka4LL9NZSPQzQqBU@Gz};DFC+|PAZ<+t7;mOytPORVLg&aoRl0CwtyQPz9%pf z3@&qt^~YxGlQ`sKdfn{^fRQSa!$KP$awlmgqX%*%kvQp>Q8*PIaQF+M=)FaNkSz`L z>D&6jw&rY(b}l7kkh6)2EIgiDF=BKXW<+iO@&$#wy% zw>L0c@a4k-GSb@blvYCMHGYEp?m1qtM-usXQMb{R_@&8CEVcX^FZEHcMb_=v#XSUc zud|GtuVY4MVJJd6AjkSn?COMi+P6+Ch(;1^+6+aD4)&~Ro8b;u`i4qkbt1mfCt=ji zH`uZ5eFOF5!RH2d9e-n3Q#*DT1V}=wFS%_loAi8_ffclBB9R!^dFMDQS&%H9a+cnt-eTGblw>lGi(oCG~5`{M+S;ro`Ag z4~^SQDYJFAhB~{!HEkL=-^ABQQ`na${!XL*>HG7!v5rKtz^Z=K_LeNFUOtOzk&gjZ z+Onvl^I6n6#3;98%p_z|(T&+|(i>Q977jt(s{iZE{NJEI-5u+RKeD}TB$C~4>c{^E z)&*>L1{aXhyqRa7w^Sb@3fMfxla({0z^hO+g~9@sXeBXbk0bOpV1X+%P>=K7PR+xw zcndd5B(3Z0L_T;HiXBJ~mlvYv+PTd0;#>@rS;zwAla=CmG*DcT*o;bc%}cs)0i{xL zgYD`_dPCO|ZeAt?S2~w3y|+3-w6!DBLt&QT`feiVCp5&5Lvn?%Vcg(*d+ zNE;i~eWe7G5+oR%VXi|;co7cXcisCo#dG3azlio{nO0m0Yv@tppLUt~zrKv2-<7b? z-^t4JD~#@PhmWmA;)r_>aUUPx%Us<~29_|9y(K8}`krV=_y6#arvvqHYmaJeZ48{c z!$zv?4n}(Nh`3uoi@Ty3sl3x&G`=Zirv`r|`;E#yN^5es7{d?O3cmzm@A7eS4{LNc z2j|z~SpDkbUogF|s7Hb{y@x^e*RaU=3-W(YMfZ{+itk zD(~Pf4{i)O5Ap0gy~nov3*nE^VSK0ithsLY(RkXBG2a^EPeG(FBycQQx!07@uOXej z%9vRHk^2nN@WPg!lQFL<8G5yOz`Qy>K(9A8%*)DF)S8A6LNIq^uE#KS+O)+#U#+ab z%k{ZW{eJX?rw`a3=wmU`89kY2|A(w7Ut-+Qi^Yq1$d7d7=Jt1=$bz z9^`*6Had$}TRZ*wF-N;IJ%>lENxdFn5YK)ra(F*1cg-VKZWLJ=)t}H?{@$g*A8tJR z>MU$Hm*hc2(E^N0MKgNx+U>Nx?}lSD5zj^4%k7W{4FMBN*;LFc#kfwxnEzq)Cp(r+ zj4s0&^CL2;s70gJEgO!%*^~LZmofhdW$3@vi}`1Ii8}R9@?JuCIhuJ{jlo|{$*|BU zNy#%dmt!N(^{t=!-(#4deK||LM>&cZ`ZJLQ7=>(2@Kt=79qmy+9zdVRY+!;Oqv-yH%(HAErhD=++qO$&CF3s^uIe#Ax#0#M z!zyrU{2SGu8V8V7@TobKoayo!Z;Q$8>Ia^%iRo>rV1*`BV36=g7XE$(EA#^~Cg3k| WI52QKO4NZ4Pec=)PtmyTlK%toQsIsO delta 11271 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 diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java index d4dd45b8b8c..3f7cf91a491 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java @@ -49,13 +49,13 @@ public AbstractCoreEjb(Class adoClass, Class dtoClass, SRV service, Us @Override public DTO getByUuid(String uuid) { - Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithInaccessibleValuePlaceHolder(userService::hasRight); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); return convertToDto(service.getByUuid(uuid), pseudonymizer); } @Override public List getByUuids(List uuids) { - Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithInaccessibleValuePlaceHolder(userService::hasRight); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); return service.getByUuids(uuids).stream().map(c -> convertToDto(c, pseudonymizer)).collect(Collectors.toList()); } @@ -65,7 +65,7 @@ public List getAllAfter(Date date) { } public List getAllAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { - Pseudonymizer pseudonymizer = Pseudonymizer.getDefaultWithInaccessibleValuePlaceHolder(userService::hasRight); + Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); return service.getAllAfter(date, batchSize, lastSynchronizedUuid) .stream() .map(c -> convertToDto(c, pseudonymizer)) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java index 2716d898719..b1503c84544 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java @@ -1808,11 +1808,6 @@ public List getMatchingContacts(ContactSimilarityCriteria cri return contacts; } - @Override - public boolean exists(String uuid) { - return this.service.exists(uuid); - } - @Override public boolean doesExternalTokenExist(String externalToken, String contactUuid) { return service.exists( diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java index 3aad79a656b..040d91f2110 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java @@ -281,6 +281,10 @@ public ConfigFacade getConfigFacade() { return getBean(ConfigFacadeEjbLocal.class); } + /** + * Using local bean here to avoid multiple transactions in test. + * @return + */ public CaseFacadeEjbLocal getCaseFacade() { return getBean(CaseFacadeEjbLocal.class); } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbPseudonymizationTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbPseudonymizationTest.java index b6fe1e38475..bf028e2ec76 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbPseudonymizationTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbPseudonymizationTest.java @@ -414,11 +414,11 @@ private void assertPseudonymized(CaseDataDto caze) { assertThat(caze.getDistrict(), is(rdcf1.district)); assertThat(caze.getCommunity(), is(nullValue())); assertThat(caze.getHealthFacility(), is(nullValue())); - assertThat(caze.getHealthFacilityDetails(), equalTo(CONFIDENTIAL)); + assertThat(caze.getHealthFacilityDetails(), is(isEmptyString())); assertThat(caze.getPointOfEntry(), is(nullValue())); - assertThat(caze.getPointOfEntryDetails(), equalTo(CONFIDENTIAL)); - assertThat(caze.getPerson().getFirstName(), equalTo(CONFIDENTIAL)); - assertThat(caze.getPerson().getLastName(), equalTo(CONFIDENTIAL)); + assertThat(caze.getPointOfEntryDetails(), is(isEmptyString())); + assertThat(caze.getPerson().getFirstName(), is(isEmptyString())); + assertThat(caze.getPerson().getLastName(), is(isEmptyString())); //sensitive data assertThat(caze.getReportingUser(), is(nullValue())); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbPseudonymizationTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbPseudonymizationTest.java index f8009ff9917..ae2603aedf2 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbPseudonymizationTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbPseudonymizationTest.java @@ -343,8 +343,8 @@ private void assertNotPseudonymized(ContactDto contact, boolean caseInJurisdicti assertThat(contact.getPerson().getFirstName(), is("James")); assertThat(contact.getPerson().getLastName(), is("Smith")); - assertThat(contact.getCaze().getFirstName(), caseInJurisdiction ? is("James") : equalTo(CONFIDENTIAL)); - assertThat(contact.getCaze().getLastName(), caseInJurisdiction ? is("Smith") : equalTo(CONFIDENTIAL)); + assertThat(contact.getCaze().getFirstName(), caseInJurisdiction ? is("James") : isEmptyString()); + assertThat(contact.getCaze().getLastName(), caseInJurisdiction ? is("Smith") : isEmptyString()); // sensitive data assertThat(contact.getReportingUser().getUuid(), is(user2.getUuid())); @@ -358,11 +358,11 @@ private void assertNotPseudonymized(ContactDto contact, boolean caseInJurisdicti private void assertPseudonymized(ContactDto contact) { - Assert.assertEquals(contact.getPerson().getFirstName(), CONFIDENTIAL); - Assert.assertEquals(contact.getPerson().getLastName(), CONFIDENTIAL); + assertThat(contact.getPerson().getFirstName(), isEmptyString()); + assertThat(contact.getPerson().getLastName(), isEmptyString()); - Assert.assertEquals(contact.getCaze().getLastName(), CONFIDENTIAL); - Assert.assertEquals(contact.getCaze().getLastName(), CONFIDENTIAL); + assertThat(contact.getCaze().getFirstName(), isEmptyString()); + assertThat(contact.getCaze().getLastName(), isEmptyString()); // sensitive data assertThat(contact.getReportingUser(), is(nullValue())); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjbTest.java index 9a0bcbea04c..63fca1b0b8a 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjbTest.java @@ -216,8 +216,8 @@ public void testJurisdictionFiltering() { // assert getting non seen immunization in grid is pseudonymized ImmunizationDto byUuid = getImmunizationFacade().getByUuid(nonSeenImmunization.getUuid()); assertEquals(nonSeenImmunization.getUuid(), byUuid.getUuid()); - assertEquals("Confidential", byUuid.getPerson().getLastName()); - assertEquals("Confidential", byUuid.getPerson().getFirstName()); + assertEquals("", byUuid.getPerson().getLastName()); + assertEquals("", byUuid.getPerson().getFirstName()); List allPersonsAfter = getPersonFacade().getPersonsAfter(new DateTime(new Date()).minusDays(1).toDate()); assertEquals(1, allPersonsAfter.size()); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjbTest.java index 297fcdbf62f..5bfd89c5586 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjbTest.java @@ -130,8 +130,8 @@ public void testCanSeeByResponsibleJurisdiction() { TravelEntryDto notInJurisdictionTravelEntry = getTravelEntryFacade().getByUuid(notSeenTravelEntry.getUuid()); assertEquals(notInJurisdictionTravelEntry.getUuid(), notSeenTravelEntry.getUuid()); - assertThat(notInJurisdictionTravelEntry.getPerson().getLastName(), is(CONFIDENTIAL)); - assertThat(notInJurisdictionTravelEntry.getPerson().getFirstName(), is(CONFIDENTIAL)); + assertThat(notInJurisdictionTravelEntry.getPerson().getLastName(), is(isEmptyString())); + assertThat(notInJurisdictionTravelEntry.getPerson().getFirstName(), is(isEmptyString())); assertEquals(notInJurisdictionTravelEntry.getDisease(), notSeenTravelEntry.getDisease()); } From da569fa13d516ba79ecb63c0bccedba61a9ffd99 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Thu, 3 Feb 2022 13:57:37 +0200 Subject: [PATCH 015/253] #7246 - standardize abstract facade names --- .../api/{CoreBaseFacade.java => CoreFacade.java} | 2 +- .../de/symeda/sormas/api/campaign/CampaignFacade.java | 7 ++----- .../java/de/symeda/sormas/api/caze/CaseFacade.java | 4 ++-- .../de/symeda/sormas/api/contact/ContactFacade.java | 4 ++-- .../java/de/symeda/sormas/api/event/EventFacade.java | 4 ++-- .../sormas/api/event/EventParticipantFacade.java | 4 ++-- .../sormas/api/immunization/ImmunizationFacade.java | 4 ++-- .../sormas/api/infrastructure/GeoLocationFacade.java | 2 +- ...uctureBaseFacade.java => InfrastructureFacade.java} | 2 +- .../api/infrastructure/facility/FacilityFacade.java | 4 ++-- .../pointofentry/PointOfEntryFacade.java | 4 ++-- .../sormas/api/travelentry/TravelEntryFacade.java | 5 ++--- .../sormas/backend/campaign/CampaignFacadeEjb.java | 8 ++------ .../de/symeda/sormas/backend/caze/CaseFacadeEjb.java | 4 ++-- ...AbstractCoreEjb.java => AbstractCoreFacadeEjb.java} | 10 ++++++---- .../sormas/backend/contact/ContactFacadeEjb.java | 4 ++-- .../CoreEntityDeletionService.java | 8 ++++---- .../de/symeda/sormas/backend/event/EventFacadeEjb.java | 4 ++-- .../backend/event/EventParticipantFacadeEjb.java | 4 ++-- .../backend/immunization/ImmunizationFacadeEjb.java | 4 ++-- ...reEjb.java => AbstractInfrastructureFacadeEjb.java} | 10 +++++----- .../backend/infrastructure/area/AreaFacadeEjb.java | 4 ++-- .../infrastructure/central/CentralInfraSyncFacade.java | 4 ++-- .../infrastructure/community/CommunityFacadeEjb.java | 4 ++-- .../infrastructure/continent/ContinentFacadeEjb.java | 4 ++-- .../infrastructure/country/CountryFacadeEjb.java | 4 ++-- .../infrastructure/district/DistrictFacadeEjb.java | 5 ++--- .../infrastructure/facility/FacilityFacadeEjb.java | 4 ++-- .../pointofentry/PointOfEntryFacadeEjb.java | 4 ++-- .../backend/infrastructure/region/RegionFacadeEjb.java | 5 ++--- .../subcontinent/SubcontinentFacadeEjb.java | 4 ++-- .../data/infra/InfrastructureValidator.java | 4 ++-- .../backend/travelentry/TravelEntryFacadeEjb.java | 4 ++-- 33 files changed, 72 insertions(+), 80 deletions(-) rename sormas-api/src/main/java/de/symeda/sormas/api/{CoreBaseFacade.java => CoreFacade.java} (89%) rename sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/{InfrastructureBaseFacade.java => InfrastructureFacade.java} (82%) rename sormas-backend/src/main/java/de/symeda/sormas/backend/common/{AbstractCoreEjb.java => AbstractCoreFacadeEjb.java} (91%) rename sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/{AbstractInfrastructureEjb.java => AbstractInfrastructureFacadeEjb.java} (91%) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/CoreBaseFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/CoreFacade.java similarity index 89% rename from sormas-api/src/main/java/de/symeda/sormas/api/CoreBaseFacade.java rename to sormas-api/src/main/java/de/symeda/sormas/api/CoreFacade.java index 83ec3c7989d..75abb792b67 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/CoreBaseFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/CoreFacade.java @@ -22,7 +22,7 @@ import de.symeda.sormas.api.utils.criteria.BaseCriteria; -public interface CoreBaseFacade +public interface CoreFacade extends BaseFacade { void archive(String uuid); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/campaign/CampaignFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/campaign/CampaignFacade.java index 7228556d5df..f4429bce30c 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/campaign/CampaignFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/campaign/CampaignFacade.java @@ -1,17 +1,14 @@ package de.symeda.sormas.api.campaign; -import java.util.Date; import java.util.List; import javax.ejb.Remote; -import javax.validation.Valid; -import de.symeda.sormas.api.CoreBaseFacade; +import de.symeda.sormas.api.CoreFacade; import de.symeda.sormas.api.campaign.diagram.CampaignDashboardElement; -import de.symeda.sormas.api.utils.SortProperty; @Remote -public interface CampaignFacade extends CoreBaseFacade { +public interface CampaignFacade extends CoreFacade { List getAllActiveCampaignsAsReference(); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java index 369a0ad7cd6..1ff5075b251 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java @@ -31,7 +31,7 @@ import com.fasterxml.jackson.databind.JsonNode; import de.symeda.sormas.api.CaseMeasure; -import de.symeda.sormas.api.CoreBaseFacade; +import de.symeda.sormas.api.CoreFacade; import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.Language; import de.symeda.sormas.api.common.Page; @@ -53,7 +53,7 @@ import de.symeda.sormas.api.utils.ValidationRuntimeException; @Remote -public interface CaseFacade extends CoreBaseFacade { +public interface CaseFacade extends CoreFacade { List getAllActiveCasesAfter(Date date); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java index 42b3fdba865..292d4338491 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java @@ -25,7 +25,7 @@ import javax.ejb.Remote; import javax.validation.Valid; -import de.symeda.sormas.api.CoreBaseFacade; +import de.symeda.sormas.api.CoreFacade; import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.Language; import de.symeda.sormas.api.common.Page; @@ -40,7 +40,7 @@ import de.symeda.sormas.api.visit.VisitSummaryExportDto; @Remote -public interface ContactFacade extends CoreBaseFacade { +public interface ContactFacade extends CoreFacade { ContactDto save(@Valid ContactDto dto, boolean handleChanges, boolean handleCaseChanges); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java index 0595e49e093..9c6c13db1fe 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java @@ -27,7 +27,7 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; -import de.symeda.sormas.api.CoreBaseFacade; +import de.symeda.sormas.api.CoreFacade; import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.common.Page; import de.symeda.sormas.api.externaldata.ExternalDataDto; @@ -38,7 +38,7 @@ import de.symeda.sormas.api.utils.ValidationRuntimeException; @Remote -public interface EventFacade extends CoreBaseFacade { +public interface EventFacade extends CoreFacade { Map getEventCountByDisease(EventCriteria eventCriteria); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventParticipantFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventParticipantFacade.java index a0280b60915..b838b90f97b 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventParticipantFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventParticipantFacade.java @@ -25,14 +25,14 @@ import javax.ejb.Remote; import javax.validation.Valid; -import de.symeda.sormas.api.CoreBaseFacade; +import de.symeda.sormas.api.CoreFacade; import de.symeda.sormas.api.Language; import de.symeda.sormas.api.common.Page; import de.symeda.sormas.api.importexport.ExportConfigurationDto; import de.symeda.sormas.api.utils.SortProperty; @Remote -public interface EventParticipantFacade extends CoreBaseFacade { +public interface EventParticipantFacade extends CoreFacade { List getAllEventParticipantsByEventAfter(Date date, String eventUuid); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/immunization/ImmunizationFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/immunization/ImmunizationFacade.java index 66b2d315660..4a733deb543 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/immunization/ImmunizationFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/immunization/ImmunizationFacade.java @@ -20,12 +20,12 @@ import javax.ejb.Remote; -import de.symeda.sormas.api.CoreBaseFacade; +import de.symeda.sormas.api.CoreFacade; import de.symeda.sormas.api.common.Page; import de.symeda.sormas.api.utils.SortProperty; @Remote -public interface ImmunizationFacade extends CoreBaseFacade { +public interface ImmunizationFacade extends CoreFacade { void validate(ImmunizationDto immunizationDto); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/GeoLocationFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/GeoLocationFacade.java index 72757cbb86e..ed2a704df9d 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/GeoLocationFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/GeoLocationFacade.java @@ -18,7 +18,7 @@ */ @Remote public interface GeoLocationFacade - extends InfrastructureBaseFacade { + extends InfrastructureFacade { List getReferencesByName(String name, boolean includeArchived); } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/InfrastructureBaseFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/InfrastructureFacade.java similarity index 82% rename from sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/InfrastructureBaseFacade.java rename to sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/InfrastructureFacade.java index 5def294ef77..926adce9d37 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/InfrastructureBaseFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/InfrastructureFacade.java @@ -10,7 +10,7 @@ import de.symeda.sormas.api.InfrastructureDataReferenceDto; import de.symeda.sormas.api.utils.criteria.BaseCriteria; -public interface InfrastructureBaseFacade +public interface InfrastructureFacade extends BaseFacade { diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/facility/FacilityFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/facility/FacilityFacade.java index fe4cf5271b4..77980ffa31a 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/facility/FacilityFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/facility/FacilityFacade.java @@ -25,13 +25,13 @@ import javax.ejb.Remote; import de.symeda.sormas.api.common.Page; -import de.symeda.sormas.api.infrastructure.InfrastructureBaseFacade; +import de.symeda.sormas.api.infrastructure.InfrastructureFacade; import de.symeda.sormas.api.infrastructure.community.CommunityReferenceDto; import de.symeda.sormas.api.infrastructure.district.DistrictReferenceDto; import de.symeda.sormas.api.utils.SortProperty; @Remote -public interface FacilityFacade extends InfrastructureBaseFacade { +public interface FacilityFacade extends InfrastructureFacade { List getActiveFacilitiesByCommunityAndType( CommunityReferenceDto community, diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/pointofentry/PointOfEntryFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/pointofentry/PointOfEntryFacade.java index 4e7640d21b6..e08491d393d 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/pointofentry/PointOfEntryFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/infrastructure/pointofentry/PointOfEntryFacade.java @@ -6,14 +6,14 @@ import javax.ejb.Remote; import de.symeda.sormas.api.common.Page; -import de.symeda.sormas.api.infrastructure.InfrastructureBaseFacade; +import de.symeda.sormas.api.infrastructure.InfrastructureFacade; import de.symeda.sormas.api.infrastructure.district.DistrictReferenceDto; import de.symeda.sormas.api.utils.SortProperty; import de.symeda.sormas.api.utils.ValidationRuntimeException; @Remote public interface PointOfEntryFacade - extends InfrastructureBaseFacade { + extends InfrastructureFacade { /** * @param includeOthers diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/travelentry/TravelEntryFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/travelentry/TravelEntryFacade.java index f4a3cb8ed78..7a6814d0040 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/travelentry/TravelEntryFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/travelentry/TravelEntryFacade.java @@ -4,13 +4,12 @@ import javax.ejb.Remote; -import de.symeda.sormas.api.BaseFacade; -import de.symeda.sormas.api.CoreBaseFacade; +import de.symeda.sormas.api.CoreFacade; import de.symeda.sormas.api.common.Page; import de.symeda.sormas.api.utils.SortProperty; @Remote -public interface TravelEntryFacade extends CoreBaseFacade { +public interface TravelEntryFacade extends CoreFacade { void validate(TravelEntryDto travelEntryDto); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java index 1c566bdc4cd..4ee8d3bf124 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java @@ -14,8 +14,6 @@ import javax.ejb.LocalBean; import javax.ejb.Stateless; import javax.inject.Inject; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; @@ -26,7 +24,7 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; -import de.symeda.sormas.backend.common.AbstractCoreEjb; +import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; import de.symeda.sormas.backend.util.Pseudonymizer; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -47,18 +45,16 @@ import de.symeda.sormas.api.utils.ValidationRuntimeException; import de.symeda.sormas.backend.campaign.diagram.CampaignDiagramDefinitionFacadeEjb; import de.symeda.sormas.backend.campaign.form.CampaignFormMetaService; -import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.user.User; import de.symeda.sormas.backend.user.UserFacadeEjb; import de.symeda.sormas.backend.user.UserRoleConfigFacadeEjb.UserRoleConfigFacadeEjbLocal; import de.symeda.sormas.backend.user.UserService; import de.symeda.sormas.backend.util.DtoHelper; -import de.symeda.sormas.backend.util.ModelConstants; import de.symeda.sormas.backend.util.QueryHelper; @Stateless(name = "CampaignFacade") -public class CampaignFacadeEjb extends AbstractCoreEjb implements CampaignFacade { +public class CampaignFacadeEjb extends AbstractCoreFacadeEjb implements CampaignFacade { @EJB private CampaignFormMetaService campaignFormMetaService; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java index f7c3219d175..eb33c63e904 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java @@ -209,7 +209,7 @@ import de.symeda.sormas.backend.clinicalcourse.ClinicalVisitFacadeEjb.ClinicalVisitFacadeEjbLocal; import de.symeda.sormas.backend.clinicalcourse.ClinicalVisitService; import de.symeda.sormas.backend.clinicalcourse.HealthConditions; -import de.symeda.sormas.backend.common.AbstractCoreEjb; +import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; @@ -325,7 +325,7 @@ import de.symeda.sormas.utils.CaseJoins; @Stateless(name = "CaseFacade") -public class CaseFacadeEjb extends AbstractCoreEjb +public class CaseFacadeEjb extends AbstractCoreFacadeEjb implements CaseFacade { private static final int ARCHIVE_BATCH_SIZE = 1000; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreFacadeEjb.java similarity index 91% rename from sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java rename to sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreFacadeEjb.java index 3f7cf91a491..9b5a0b075e0 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreFacadeEjb.java @@ -26,6 +26,7 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; +import de.symeda.sormas.api.CoreFacade; import de.symeda.sormas.api.EntityDto; import de.symeda.sormas.api.ReferenceDto; import de.symeda.sormas.api.deletionconfiguration.DeletionReference; @@ -37,13 +38,14 @@ import de.symeda.sormas.backend.util.Pseudonymizer; import de.symeda.sormas.backend.util.QueryHelper; -public abstract class AbstractCoreEjb, CRITERIA extends BaseCriteria> - extends AbstractBaseEjb { +public abstract class AbstractCoreFacadeEjb, CRITERIA extends BaseCriteria> + extends AbstractBaseEjb + implements CoreFacade { - public AbstractCoreEjb() { + public AbstractCoreFacadeEjb() { } - public AbstractCoreEjb(Class adoClass, Class dtoClass, SRV service, UserService userService) { + public AbstractCoreFacadeEjb(Class adoClass, Class dtoClass, SRV service, UserService userService) { super(adoClass, dtoClass, service, userService); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java index b1503c84544..538f7eb514a 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java @@ -138,7 +138,7 @@ import de.symeda.sormas.backend.caze.CaseFacadeEjb.CaseFacadeEjbLocal; import de.symeda.sormas.backend.caze.CaseService; import de.symeda.sormas.backend.clinicalcourse.ClinicalCourseFacadeEjb; -import de.symeda.sormas.backend.common.AbstractCoreEjb; +import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; @@ -202,7 +202,7 @@ import de.symeda.sormas.backend.visit.VisitService; @Stateless(name = "ContactFacade") -public class ContactFacadeEjb extends AbstractCoreEjb +public class ContactFacadeEjb extends AbstractCoreFacadeEjb implements ContactFacade { private static final long SECONDS_30_DAYS = TimeUnit.DAYS.toSeconds(30L); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/CoreEntityDeletionService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/CoreEntityDeletionService.java index 7ba51d4688e..4284c1dfa59 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/CoreEntityDeletionService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/CoreEntityDeletionService.java @@ -9,7 +9,7 @@ import javax.inject.Inject; import de.symeda.sormas.backend.caze.CaseFacadeEjb; -import de.symeda.sormas.backend.common.AbstractCoreEjb; +import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; import de.symeda.sormas.backend.contact.ContactFacadeEjb; import de.symeda.sormas.backend.event.EventFacadeEjb; import de.symeda.sormas.backend.event.EventParticipantFacadeEjb; @@ -59,14 +59,14 @@ public void executeAutomaticDeletion() { private static final class EntityTypeFacadePair { private final CoreEntityType coreEntityType; - private final AbstractCoreEjb entityFacade; + private final AbstractCoreFacadeEjb entityFacade; - private EntityTypeFacadePair(CoreEntityType coreEntityType, AbstractCoreEjb entityFacade) { + private EntityTypeFacadePair(CoreEntityType coreEntityType, AbstractCoreFacadeEjb entityFacade) { this.coreEntityType = coreEntityType; this.entityFacade = entityFacade; } - public static EntityTypeFacadePair of(CoreEntityType coreEntityType, AbstractCoreEjb entityFacade) { + public static EntityTypeFacadePair of(CoreEntityType coreEntityType, AbstractCoreFacadeEjb entityFacade) { return new EntityTypeFacadePair(coreEntityType, entityFacade); } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java index 42f280e80a4..62ed065f1fb 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java @@ -91,7 +91,7 @@ import de.symeda.sormas.api.utils.SortProperty; import de.symeda.sormas.api.utils.ValidationRuntimeException; import de.symeda.sormas.backend.caze.Case; -import de.symeda.sormas.backend.common.AbstractCoreEjb; +import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.contact.Contact; @@ -125,7 +125,7 @@ import de.symeda.sormas.utils.EventJoins; @Stateless(name = "EventFacade") -public class EventFacadeEjb extends AbstractCoreEjb +public class EventFacadeEjb extends AbstractCoreFacadeEjb implements EventFacade { private final Logger logger = LoggerFactory.getLogger(getClass()); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java index 1d1c559aa1f..134c5d9475b 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java @@ -88,7 +88,7 @@ import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.caze.CaseFacadeEjb; import de.symeda.sormas.backend.caze.CaseService; -import de.symeda.sormas.backend.common.AbstractCoreEjb; +import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.common.DeletableAdo; @@ -133,7 +133,7 @@ @Stateless(name = "EventParticipantFacade") public class EventParticipantFacadeEjb extends - AbstractCoreEjb + AbstractCoreFacadeEjb implements EventParticipantFacade { private final Logger logger = LoggerFactory.getLogger(getClass()); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java index 73f64c0282d..f0afc296f81 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java @@ -75,7 +75,7 @@ import de.symeda.sormas.api.vaccination.VaccinationDto; import de.symeda.sormas.backend.caze.CaseFacadeEjb; import de.symeda.sormas.backend.caze.CaseService; -import de.symeda.sormas.backend.common.AbstractCoreEjb; +import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; import de.symeda.sormas.backend.immunization.entity.Immunization; import de.symeda.sormas.backend.infrastructure.community.CommunityFacadeEjb; import de.symeda.sormas.backend.infrastructure.community.CommunityService; @@ -108,7 +108,7 @@ @Stateless(name = "ImmunizationFacade") public class ImmunizationFacadeEjb - extends AbstractCoreEjb + extends AbstractCoreFacadeEjb implements ImmunizationFacade { private final Logger logger = LoggerFactory.getLogger(ImmunizationFacadeEjb.class); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/AbstractInfrastructureEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/AbstractInfrastructureFacadeEjb.java similarity index 91% rename from sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/AbstractInfrastructureEjb.java rename to sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/AbstractInfrastructureFacadeEjb.java index 65690b68f38..5473c7f0c97 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/AbstractInfrastructureEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/AbstractInfrastructureFacadeEjb.java @@ -7,7 +7,7 @@ import de.symeda.sormas.api.feature.FeatureType; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Validations; -import de.symeda.sormas.api.infrastructure.InfrastructureBaseFacade; +import de.symeda.sormas.api.infrastructure.InfrastructureFacade; import de.symeda.sormas.api.infrastructure.InfrastructureDto; import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.utils.ValidationRuntimeException; @@ -20,18 +20,18 @@ import de.symeda.sormas.backend.user.UserService; import de.symeda.sormas.backend.util.DtoHelper; -public abstract class AbstractInfrastructureEjb, CRITERIA extends BaseCriteria> +public abstract class AbstractInfrastructureFacadeEjb, CRITERIA extends BaseCriteria> extends AbstractBaseEjb - implements InfrastructureBaseFacade { + implements InfrastructureFacade { protected FeatureConfigurationFacadeEjb featureConfiguration; private String duplicateErrorMessageProperty; - protected AbstractInfrastructureEjb() { + protected AbstractInfrastructureFacadeEjb() { super(); } - protected AbstractInfrastructureEjb( + protected AbstractInfrastructureFacadeEjb( Class adoClass, Class dtoClass, SRV service, diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/area/AreaFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/area/AreaFacadeEjb.java index 83cf1b010b7..42b7452d3eb 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/area/AreaFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/area/AreaFacadeEjb.java @@ -25,14 +25,14 @@ import de.symeda.sormas.api.infrastructure.area.AreaReferenceDto; import de.symeda.sormas.api.utils.SortProperty; import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal; -import de.symeda.sormas.backend.infrastructure.AbstractInfrastructureEjb; +import de.symeda.sormas.backend.infrastructure.AbstractInfrastructureFacadeEjb; import de.symeda.sormas.backend.infrastructure.region.Region; import de.symeda.sormas.backend.user.UserService; import de.symeda.sormas.backend.util.DtoHelper; import de.symeda.sormas.backend.util.QueryHelper; @Stateless(name = "AreaFacade") -public class AreaFacadeEjb extends AbstractInfrastructureEjb +public class AreaFacadeEjb extends AbstractInfrastructureFacadeEjb implements AreaFacade { public AreaFacadeEjb() { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/central/CentralInfraSyncFacade.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/central/CentralInfraSyncFacade.java index 88ff6c05ac5..67728b1ae13 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/central/CentralInfraSyncFacade.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/central/CentralInfraSyncFacade.java @@ -18,7 +18,7 @@ import de.symeda.sormas.api.InfrastructureDataReferenceDto; import de.symeda.sormas.api.feature.FeatureType; import de.symeda.sormas.api.infrastructure.InfrastructureDto; -import de.symeda.sormas.api.infrastructure.InfrastructureBaseFacade; +import de.symeda.sormas.api.infrastructure.InfrastructureFacade; import de.symeda.sormas.api.infrastructure.area.AreaDto; import de.symeda.sormas.api.infrastructure.community.CommunityDto; import de.symeda.sormas.api.infrastructure.continent.ContinentDto; @@ -81,7 +81,7 @@ public class CentralInfraSyncFacade { private Date loadAndStore( String type, Class clazz, - InfrastructureBaseFacade facade, + InfrastructureFacade facade, Date lastSync) { List dtos; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/community/CommunityFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/community/CommunityFacadeEjb.java index d7de3c6af62..aec9ef41213 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/community/CommunityFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/community/CommunityFacadeEjb.java @@ -47,7 +47,7 @@ import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.InfrastructureAdo; import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal; -import de.symeda.sormas.backend.infrastructure.AbstractInfrastructureEjb; +import de.symeda.sormas.backend.infrastructure.AbstractInfrastructureFacadeEjb; import de.symeda.sormas.backend.infrastructure.district.District; import de.symeda.sormas.backend.infrastructure.district.DistrictFacadeEjb; import de.symeda.sormas.backend.infrastructure.district.DistrictService; @@ -61,7 +61,7 @@ @Stateless(name = "CommunityFacade") public class CommunityFacadeEjb - extends AbstractInfrastructureEjb + extends AbstractInfrastructureFacadeEjb implements CommunityFacade { @EJB diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/continent/ContinentFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/continent/ContinentFacadeEjb.java index cef6bc3a109..96626274d8b 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/continent/ContinentFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/continent/ContinentFacadeEjb.java @@ -47,7 +47,7 @@ import de.symeda.sormas.api.infrastructure.subcontinent.SubcontinentReferenceDto; import de.symeda.sormas.api.utils.SortProperty; import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal; -import de.symeda.sormas.backend.infrastructure.AbstractInfrastructureEjb; +import de.symeda.sormas.backend.infrastructure.AbstractInfrastructureFacadeEjb; import de.symeda.sormas.backend.infrastructure.country.Country; import de.symeda.sormas.backend.infrastructure.country.CountryService; import de.symeda.sormas.backend.infrastructure.subcontinent.Subcontinent; @@ -58,7 +58,7 @@ @Stateless(name = "ContinentFacade") public class ContinentFacadeEjb - extends AbstractInfrastructureEjb + extends AbstractInfrastructureFacadeEjb implements ContinentFacade { @EJB diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/country/CountryFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/country/CountryFacadeEjb.java index c656a91403b..5b3d9e88b35 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/country/CountryFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/country/CountryFacadeEjb.java @@ -54,7 +54,7 @@ import de.symeda.sormas.backend.common.ConfigFacadeEjb; import de.symeda.sormas.backend.common.InfrastructureAdo; import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal; -import de.symeda.sormas.backend.infrastructure.AbstractInfrastructureEjb; +import de.symeda.sormas.backend.infrastructure.AbstractInfrastructureFacadeEjb; import de.symeda.sormas.backend.infrastructure.continent.Continent; import de.symeda.sormas.backend.infrastructure.continent.ContinentService; import de.symeda.sormas.backend.infrastructure.subcontinent.Subcontinent; @@ -67,7 +67,7 @@ @Stateless(name = "CountryFacade") public class CountryFacadeEjb - extends AbstractInfrastructureEjb + extends AbstractInfrastructureFacadeEjb implements CountryFacade { @EJB diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/district/DistrictFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/district/DistrictFacadeEjb.java index 8bd3662325d..d29ea8da9eb 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/district/DistrictFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/district/DistrictFacadeEjb.java @@ -49,9 +49,8 @@ import de.symeda.sormas.api.infrastructure.district.DistrictReferenceDto; import de.symeda.sormas.api.infrastructure.region.RegionReferenceDto; import de.symeda.sormas.api.utils.SortProperty; -import de.symeda.sormas.api.utils.ValidationRuntimeException; import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal; -import de.symeda.sormas.backend.infrastructure.AbstractInfrastructureEjb; +import de.symeda.sormas.backend.infrastructure.AbstractInfrastructureFacadeEjb; import de.symeda.sormas.backend.infrastructure.PopulationDataFacadeEjb.PopulationDataFacadeEjbLocal; import de.symeda.sormas.backend.infrastructure.area.Area; import de.symeda.sormas.backend.infrastructure.area.AreaService; @@ -67,7 +66,7 @@ @Stateless(name = "DistrictFacade") public class DistrictFacadeEjb - extends AbstractInfrastructureEjb + extends AbstractInfrastructureFacadeEjb implements DistrictFacade { @EJB diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/facility/FacilityFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/facility/FacilityFacadeEjb.java index 0df927e5d57..1be33ef8e9a 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/facility/FacilityFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/facility/FacilityFacadeEjb.java @@ -37,7 +37,7 @@ import javax.validation.constraints.NotNull; import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal; -import de.symeda.sormas.backend.infrastructure.AbstractInfrastructureEjb; +import de.symeda.sormas.backend.infrastructure.AbstractInfrastructureFacadeEjb; import de.symeda.sormas.backend.user.UserService; import org.apache.commons.collections.CollectionUtils; @@ -71,7 +71,7 @@ @Stateless(name = "FacilityFacade") public class FacilityFacadeEjb - extends AbstractInfrastructureEjb + extends AbstractInfrastructureFacadeEjb implements FacilityFacade { @EJB diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/pointofentry/PointOfEntryFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/pointofentry/PointOfEntryFacadeEjb.java index ab0bc08f17a..d09c30e0710 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/pointofentry/PointOfEntryFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/pointofentry/PointOfEntryFacadeEjb.java @@ -20,7 +20,7 @@ import javax.validation.constraints.NotNull; import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal; -import de.symeda.sormas.backend.infrastructure.AbstractInfrastructureEjb; +import de.symeda.sormas.backend.infrastructure.AbstractInfrastructureFacadeEjb; import org.apache.commons.collections.CollectionUtils; import de.symeda.sormas.backend.user.UserService; import org.apache.commons.lang3.StringUtils; @@ -50,7 +50,7 @@ @Stateless(name = "PointOfEntryFacade") public class PointOfEntryFacadeEjb extends - AbstractInfrastructureEjb + AbstractInfrastructureFacadeEjb implements PointOfEntryFacade { @EJB diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/region/RegionFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/region/RegionFacadeEjb.java index f80d0fde7c2..b34c52abf12 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/region/RegionFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/region/RegionFacadeEjb.java @@ -48,10 +48,9 @@ import de.symeda.sormas.api.infrastructure.region.RegionIndexDto; import de.symeda.sormas.api.infrastructure.region.RegionReferenceDto; import de.symeda.sormas.api.utils.SortProperty; -import de.symeda.sormas.api.utils.ValidationRuntimeException; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal; -import de.symeda.sormas.backend.infrastructure.AbstractInfrastructureEjb; +import de.symeda.sormas.backend.infrastructure.AbstractInfrastructureFacadeEjb; import de.symeda.sormas.backend.infrastructure.PopulationDataFacadeEjb.PopulationDataFacadeEjbLocal; import de.symeda.sormas.backend.infrastructure.area.Area; import de.symeda.sormas.backend.infrastructure.area.AreaFacadeEjb; @@ -68,7 +67,7 @@ import de.symeda.sormas.backend.util.QueryHelper; @Stateless(name = "RegionFacade") -public class RegionFacadeEjb extends AbstractInfrastructureEjb +public class RegionFacadeEjb extends AbstractInfrastructureFacadeEjb implements RegionFacade { @EJB diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/subcontinent/SubcontinentFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/subcontinent/SubcontinentFacadeEjb.java index bfa0732bc6d..f5732480f56 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/subcontinent/SubcontinentFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/subcontinent/SubcontinentFacadeEjb.java @@ -50,7 +50,7 @@ import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.InfrastructureAdo; import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal; -import de.symeda.sormas.backend.infrastructure.AbstractInfrastructureEjb; +import de.symeda.sormas.backend.infrastructure.AbstractInfrastructureFacadeEjb; import de.symeda.sormas.backend.infrastructure.continent.Continent; import de.symeda.sormas.backend.infrastructure.continent.ContinentFacadeEjb; import de.symeda.sormas.backend.infrastructure.continent.ContinentService; @@ -63,7 +63,7 @@ @Stateless(name = "SubcontinentFacade") public class SubcontinentFacadeEjb extends - AbstractInfrastructureEjb + AbstractInfrastructureFacadeEjb implements SubcontinentFacade { @EJB diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/data/infra/InfrastructureValidator.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/data/infra/InfrastructureValidator.java index 1a24a297a96..02bb40bdb4a 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/data/infra/InfrastructureValidator.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/data/infra/InfrastructureValidator.java @@ -24,7 +24,7 @@ import de.symeda.sormas.api.InfrastructureDataReferenceDto; import de.symeda.sormas.api.i18n.Validations; -import de.symeda.sormas.api.infrastructure.InfrastructureBaseFacade; +import de.symeda.sormas.api.infrastructure.InfrastructureFacade; import de.symeda.sormas.api.infrastructure.InfrastructureDto; import de.symeda.sormas.api.infrastructure.community.CommunityReferenceDto; import de.symeda.sormas.api.infrastructure.continent.ContinentReferenceDto; @@ -155,7 +155,7 @@ private facade, + InfrastructureFacade facade, String i18property, Consumer onNoErrors, ValidationDirection validationDirection) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java index 37c04d08037..f41baa34371 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java @@ -28,7 +28,7 @@ import de.symeda.sormas.api.utils.ValidationRuntimeException; import de.symeda.sormas.backend.caze.CaseFacadeEjb; import de.symeda.sormas.backend.caze.CaseService; -import de.symeda.sormas.backend.common.AbstractCoreEjb; +import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; import de.symeda.sormas.backend.infrastructure.community.CommunityFacadeEjb; import de.symeda.sormas.backend.infrastructure.community.CommunityService; import de.symeda.sormas.backend.infrastructure.district.DistrictFacadeEjb; @@ -48,7 +48,7 @@ @Stateless(name = "TravelEntryFacade") public class TravelEntryFacadeEjb - extends AbstractCoreEjb + extends AbstractCoreFacadeEjb implements TravelEntryFacade { @EJB From e9e6b9c9ba8550d64326fb2b827d255e74d39dbe Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Thu, 3 Feb 2022 14:32:30 +0200 Subject: [PATCH 016/253] #7246 - fix compilation issue after merge --- .../src/main/java/de/symeda/sormas/rest/CaseResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sormas-rest/src/main/java/de/symeda/sormas/rest/CaseResource.java b/sormas-rest/src/main/java/de/symeda/sormas/rest/CaseResource.java index 302a697befa..4e96c9a04d7 100644 --- a/sormas-rest/src/main/java/de/symeda/sormas/rest/CaseResource.java +++ b/sormas-rest/src/main/java/de/symeda/sormas/rest/CaseResource.java @@ -93,7 +93,7 @@ public List postCases(@Valid List dtos) { @POST @Path("/push-detailed") public Map> postCasesDetailed(@Valid List dtos) { - return savePushedDetailedDto(dtos, FacadeProvider.getCaseFacade()::saveCase); + return savePushedDetailedDto(dtos, FacadeProvider.getCaseFacade()::save); } @GET From 732a61aac8021c8117eb23adaf789494a5f4756c Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Thu, 3 Feb 2022 14:46:45 +0200 Subject: [PATCH 017/253] #7246 - fix compilation issue after merge --- .../symeda/sormas/ui/contact/importer/ContactImporterTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/contact/importer/ContactImporterTest.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/contact/importer/ContactImporterTest.java index 7146775b31d..5b4d0adf6c6 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/contact/importer/ContactImporterTest.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/contact/importer/ContactImporterTest.java @@ -287,7 +287,7 @@ public void testImportContactsWithVaccinations() throws IOException, Interrupted assertEquals(contactImporter.stringBuilder.toString(), ImportResultStatus.COMPLETED, importResult); - List contacts = getContactFacade().getAllActiveContactsAfter(null); + List contacts = getContactFacade().getAllAfter(null); assertEquals(3, contacts.size()); ContactDto contact1 = contacts.stream().filter(c -> c.getCaseIdExternalSystem().equals("case1")).findFirst().get(); From e9975e3259ade1ccf87f5dcac93a0fa3ff0d7a5e Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Thu, 3 Feb 2022 17:47:39 +0200 Subject: [PATCH 018/253] #7246 - fix tests + deployment issues due to annotations --- .../java/de/symeda/sormas/api/BaseFacade.java | 1 + .../de/symeda/sormas/api/caze/CaseFacade.java | 2 +- .../backend/campaign/CampaignFacadeEjb.java | 14 +++++------ .../sormas/backend/caze/CaseFacadeEjb.java | 4 +-- .../backend/contact/ContactFacadeEjb.java | 2 +- .../immunization/ImmunizationFacadeEjb.java | 4 +-- .../AbstractInfrastructureFacadeEjb.java | 5 +++- .../de/symeda/sormas/ui/AbstractBeanTest.java | 4 +-- .../symeda/sormas/ui/FacadeProviderMock.java | 25 +++++++++++++++++++ .../de/symeda/sormas/ui/TestDataCreator.java | 12 ++++----- 10 files changed, 50 insertions(+), 23 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/BaseFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/BaseFacade.java index d22b601fc0d..3769808194e 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/BaseFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/BaseFacade.java @@ -4,6 +4,7 @@ import java.util.Date; import java.util.List; +import javax.ejb.Remote; import javax.validation.Valid; import javax.validation.constraints.NotNull; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java index 1ff5075b251..c145fbca59b 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java @@ -91,7 +91,7 @@ List getExportList( CaseDataDto getCaseDataByUuid(String uuid); - CaseDataDto save(@Valid CaseDataDto dto, Boolean systemSave) throws ValidationRuntimeException; + CaseDataDto save(@Valid @NotNull CaseDataDto dto, Boolean systemSave) throws ValidationRuntimeException; void setSampleAssociations(ContactReferenceDto sourceContact, CaseReferenceDto cazeRef); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java index 4ee8d3bf124..f7cade9a84e 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java @@ -24,8 +24,6 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; -import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; -import de.symeda.sormas.backend.util.Pseudonymizer; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -45,12 +43,14 @@ import de.symeda.sormas.api.utils.ValidationRuntimeException; import de.symeda.sormas.backend.campaign.diagram.CampaignDiagramDefinitionFacadeEjb; import de.symeda.sormas.backend.campaign.form.CampaignFormMetaService; +import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.user.User; import de.symeda.sormas.backend.user.UserFacadeEjb; import de.symeda.sormas.backend.user.UserRoleConfigFacadeEjb.UserRoleConfigFacadeEjbLocal; import de.symeda.sormas.backend.user.UserService; import de.symeda.sormas.backend.util.DtoHelper; +import de.symeda.sormas.backend.util.Pseudonymizer; import de.symeda.sormas.backend.util.QueryHelper; @Stateless(name = "CampaignFacade") @@ -67,7 +67,7 @@ public CampaignFacadeEjb() { } @Inject - public CampaignFacadeEjb( CampaignService service, UserService userService) { + public CampaignFacadeEjb(CampaignService service, UserService userService) { super(Campaign.class, CampaignDto.class, service, userService); } @@ -158,7 +158,7 @@ public long count(CampaignCriteria campaignCriteria) { } @Override - public CampaignDto save(@Valid CampaignDto dto) { + public CampaignDto save(@Valid @NotNull CampaignDto dto) { validate(dto); Campaign campaign = fillOrBuildEntity(dto, service.getByUuid(dto.getUuid()), true); service.ensurePersisted(campaign); @@ -360,10 +360,7 @@ protected void restorePseudonymizedDto(CampaignDto dto, CampaignDto existingDto, @Override public List getAllAfter(Date date) { - return service.getAllAfter(date) - .stream() - .map(campaignFormMeta -> toDto(campaignFormMeta)) - .collect(Collectors.toList()); + return service.getAllAfter(date).stream().map(campaignFormMeta -> toDto(campaignFormMeta)).collect(Collectors.toList()); } @Override @@ -396,6 +393,7 @@ public static CampaignReferenceDto toReferenceDto(Campaign entity) { @LocalBean @Stateless public static class CampaignFacadeEjbLocal extends CampaignFacadeEjb { + public CampaignFacadeEjbLocal() { } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java index eb33c63e904..0f5e5f4574d 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java @@ -1344,12 +1344,12 @@ public CaseReferenceDto getReferenceByUuid(String uuid) { } @Override - public CaseDataDto save(@Valid CaseDataDto dto) throws ValidationRuntimeException { + public CaseDataDto save(@Valid @NotNull CaseDataDto dto) throws ValidationRuntimeException { return save(dto, true, true, true, false); } @Override - public CaseDataDto save(@Valid CaseDataDto dto, Boolean systemSave) throws ValidationRuntimeException { + public CaseDataDto save(@Valid @NotNull CaseDataDto dto, Boolean systemSave) throws ValidationRuntimeException { return save(dto, true, true, true, systemSave); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java index e27ae0cdfd0..71a354ec73c 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java @@ -304,7 +304,7 @@ private ContactDto getContactWithoutPseudonyimizationByUuid(String uuid) { } @Override - public ContactDto save(@Valid ContactDto dto) { + public ContactDto save(@Valid @NotNull ContactDto dto) { return save(dto, true, true); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java index f0afc296f81..9923efe9f37 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java @@ -279,11 +279,11 @@ public List getSimilarImmunizations(ImmunizationSimilarityCrite } @Override - public ImmunizationDto save(ImmunizationDto dto) { + public ImmunizationDto save(@Valid @NotNull ImmunizationDto dto) { return save(dto, true, true); } - public ImmunizationDto save(@Valid ImmunizationDto dto, boolean checkChangeDate, boolean internal) { + public ImmunizationDto save(@Valid @NotNull ImmunizationDto dto, boolean checkChangeDate, boolean internal) { Immunization existingImmunization = service.getByUuid(dto.getUuid()); if (internal && existingImmunization != null && !service.isImmunizationEditAllowed(existingImmunization)) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/AbstractInfrastructureFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/AbstractInfrastructureFacadeEjb.java index 5473c7f0c97..b892bbeec3a 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/AbstractInfrastructureFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/infrastructure/AbstractInfrastructureFacadeEjb.java @@ -20,6 +20,9 @@ import de.symeda.sormas.backend.user.UserService; import de.symeda.sormas.backend.util.DtoHelper; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + public abstract class AbstractInfrastructureFacadeEjb, CRITERIA extends BaseCriteria> extends AbstractBaseEjb implements InfrastructureFacade { @@ -44,7 +47,7 @@ protected AbstractInfrastructureFacadeEjb( } @Override - public DTO save(DTO dtoToSave) { + public DTO save(@Valid @NotNull DTO dtoToSave) { return save(dtoToSave, false); } diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/AbstractBeanTest.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/AbstractBeanTest.java index 7d911cac350..9f3a0f8c153 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/AbstractBeanTest.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/AbstractBeanTest.java @@ -139,7 +139,7 @@ public PersonFacade getPersonFacade() { return getBean(PersonFacadeEjbLocal.class); } - public CaseFacade getCaseFacade() { + public CaseFacadeEjbLocal getCaseFacade() { return getBean(CaseFacadeEjbLocal.class); } @@ -151,7 +151,7 @@ public TravelEntryFacade getTravelEntryFacade() { return getBean(TravelEntryFacadeEjb.TravelEntryFacadeEjbLocal.class); } - public ContactFacade getContactFacade() { + public ContactFacadeEjbLocal getContactFacade() { return getBean(ContactFacadeEjbLocal.class); } diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/FacadeProviderMock.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/FacadeProviderMock.java index 1e997be1404..37dd06e9611 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/FacadeProviderMock.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/FacadeProviderMock.java @@ -179,4 +179,29 @@ public

    P lookupEjbRemote(Class

    clazz) { return null; } + + public static CaseFacadeEjbLocal getCaseFacade() { + BeanProviderHelper bm = BeanProviderHelper.getInstance(); + return bm.getBean(CaseFacadeEjbLocal.class); + } + + public static ContactFacadeEjbLocal getContactFacade() { + BeanProviderHelper bm = BeanProviderHelper.getInstance(); + return bm.getBean(ContactFacadeEjbLocal.class); + } + + public static EventFacadeEjbLocal getEventFacade() { + BeanProviderHelper bm = BeanProviderHelper.getInstance(); + return bm.getBean(EventFacadeEjbLocal.class); + } + + public static EventParticipantFacadeEjbLocal getEventParticipantFacade() { + BeanProviderHelper bm = BeanProviderHelper.getInstance(); + return bm.getBean(EventParticipantFacadeEjbLocal.class); + } + + public static SampleFacadeEjbLocal getSampleFacade() { + BeanProviderHelper bm = BeanProviderHelper.getInstance(); + return bm.getBean(SampleFacadeEjbLocal.class); + } } diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/TestDataCreator.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/TestDataCreator.java index e84451e6514..4c39fd6c265 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/TestDataCreator.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/TestDataCreator.java @@ -158,7 +158,7 @@ public EventParticipantDto createEventParticipant( eventParticipant.setPerson(eventPerson); eventParticipant.setInvolvementDescription(involvementDescription); - eventParticipant = FacadeProvider.getEventParticipantFacade().saveEventParticipant(eventParticipant); + eventParticipant = FacadeProviderMock.getEventParticipantFacade().saveEventParticipant(eventParticipant); return eventParticipant; } @@ -211,7 +211,7 @@ public ContactDto createContact( customConfig.accept(contact); } - contact = FacadeProvider.getContactFacade().save(contact); + contact = FacadeProviderMock.getContactFacade().save(contact); return contact; } @@ -233,7 +233,7 @@ public SampleDto createSample( customSettings.accept(sample); } - sample = FacadeProvider.getSampleFacade().saveSample(sample); + sample = FacadeProviderMock.getSampleFacade().saveSample(sample); return sample; } @@ -253,7 +253,7 @@ public ContactDto createContact( contact.setReportDateTime(reportDateTime); contact.setLastContactDate(lastContactDate); - contact = FacadeProvider.getContactFacade().save(contact); + contact = FacadeProviderMock.getContactFacade().save(contact); return contact; } @@ -299,7 +299,7 @@ public CaseDataDto createCase( caze.setFacilityType(facility.getType()); caze.setHealthFacility(facility.toReference()); - caze = FacadeProvider.getCaseFacade().save(caze); + caze = FacadeProviderMock.getCaseFacade().save(caze); return caze; } @@ -454,7 +454,7 @@ public EventDto createEvent( customSettings.accept(event); } - event = FacadeProvider.getEventFacade().save(event); + event = FacadeProviderMock.getEventFacade().save(event); return event; } From dd6805b8b5c6b3d7a4efe8a5d16b92f32c921984 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Fri, 4 Feb 2022 07:19:29 +0200 Subject: [PATCH 019/253] #7868 Update sormas-api/src/main/java/de/symeda/sormas/api/CoreFacade.java Co-authored-by: Jonas Cirotzki --- sormas-api/src/main/java/de/symeda/sormas/api/CoreFacade.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/CoreFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/CoreFacade.java index 75abb792b67..56ec6899eef 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/CoreFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/CoreFacade.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or From 44663ec80240275aaaf087e0628b4fb109762120 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Fri, 4 Feb 2022 07:27:50 +0200 Subject: [PATCH 020/253] #7868 Update sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractDeletableAdoService.java Co-authored-by: Jonas Cirotzki --- .../sormas/backend/common/AbstractDeletableAdoService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractDeletableAdoService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractDeletableAdoService.java index 2cca34d98db..5ffc482c29f 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractDeletableAdoService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractDeletableAdoService.java @@ -23,7 +23,7 @@ public void delete(ADO deleteme) { protected Predicate changeDateFilter(CriteriaBuilder cb, Timestamp date, From path, String... joinFields) { From parent = path; - for (int i = 0; i < joinFields.length; i++) { + for (String joinField : joinFields) { parent = parent.join(joinFields[i], JoinType.LEFT); } return CriteriaBuilderHelper.greaterThanAndNotNull(cb, parent.get(AbstractDomainObject.CHANGE_DATE), date); From 63bede87ecf3d7870110913c9e13181168067fc5 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Fri, 4 Feb 2022 07:29:52 +0200 Subject: [PATCH 021/253] #7246 - CR suggestions --- .../sormas/backend/common/AbstractBaseEjb.java | 4 ---- .../backend/common/AbstractCoreAdoService.java | 4 +--- .../backend/common/AbstractCoreFacadeEjb.java | 4 ++-- .../backend/common/AbstractDeletableAdoService.java | 4 ++-- .../backend/common/AdoServiceWithUserFilter.java | 1 - .../backend/event/EventParticipantFacadeEjb.java | 13 ------------- 6 files changed, 5 insertions(+), 25 deletions(-) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractBaseEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractBaseEjb.java index 8dfc49c4d1d..506d5ee487d 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractBaseEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractBaseEjb.java @@ -42,10 +42,6 @@ protected AbstractBaseEjb(Class adoClass, Class dtoClass, SRV service, this.userService = userService; } - public abstract void archive(String uuid); - - public abstract void dearchive(String uuid); - @Override public DTO getByUuid(String uuid) { return toDto(service.getByUuid(uuid)); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java index b6e118dfe32..25c92ed00d3 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java @@ -15,15 +15,13 @@ package de.symeda.sormas.backend.common; -import de.symeda.sormas.backend.travelentry.TravelEntry; - import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; public abstract class AbstractCoreAdoService extends AbstractDeletableAdoService { - public AbstractCoreAdoService(Class elementClass) { + protected AbstractCoreAdoService(Class elementClass) { super(elementClass); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreFacadeEjb.java index 9b5a0b075e0..f1c7da2c5c5 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreFacadeEjb.java @@ -42,10 +42,10 @@ public abstract class AbstractCoreFacadeEjb implements CoreFacade { - public AbstractCoreFacadeEjb() { + protected AbstractCoreFacadeEjb() { } - public AbstractCoreFacadeEjb(Class adoClass, Class dtoClass, SRV service, UserService userService) { + protected AbstractCoreFacadeEjb(Class adoClass, Class dtoClass, SRV service, UserService userService) { super(adoClass, dtoClass, service, userService); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractDeletableAdoService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractDeletableAdoService.java index 5ffc482c29f..40b16cef85b 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractDeletableAdoService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractDeletableAdoService.java @@ -9,7 +9,7 @@ public abstract class AbstractDeletableAdoService extends AdoServiceWithUserFilter { - public AbstractDeletableAdoService(Class elementClass) { + protected AbstractDeletableAdoService(Class elementClass) { super(elementClass); } @@ -24,7 +24,7 @@ public void delete(ADO deleteme) { protected Predicate changeDateFilter(CriteriaBuilder cb, Timestamp date, From path, String... joinFields) { From parent = path; for (String joinField : joinFields) { - parent = parent.join(joinFields[i], JoinType.LEFT); + parent = parent.join(joinField, JoinType.LEFT); } return CriteriaBuilderHelper.greaterThanAndNotNull(cb, parent.get(AbstractDomainObject.CHANGE_DATE), date); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AdoServiceWithUserFilter.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AdoServiceWithUserFilter.java index dfaa0d346c8..49746af4cce 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AdoServiceWithUserFilter.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AdoServiceWithUserFilter.java @@ -1,6 +1,5 @@ package de.symeda.sormas.backend.common; -import java.util.Collections; import java.util.Date; import java.util.List; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java index 134c5d9475b..21a8787691f 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java @@ -241,12 +241,6 @@ public List getDeletedUuidsSince(Date since) { return deletedEventParticipants; } - @Override - public List getByUuids(List uuids) { - Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); - return service.getByUuids(uuids).stream().map(c -> convertToDto(c, pseudonymizer)).collect(Collectors.toList()); - } - @Override protected void selectDtoFields(CriteriaQuery cq, Root root) { @@ -399,13 +393,6 @@ public void deleteEventParticipant(EventParticipantReferenceDto eventParticipant service.delete(eventParticipant); } - @Override - public EventParticipantDto getByUuid(String uuid) { - return convertToDto( - service.getByUuid(uuid), - Pseudonymizer.getDefault(userService::hasRight, I18nProperties.getCaption(Captions.inaccessibleValue))); - } - @Override public List getIndexList( EventParticipantCriteria eventParticipantCriteria, From 44e9988b7276fe3ce255bb2b4cb55c2a34c7fb59 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Fri, 4 Feb 2022 07:46:57 +0200 Subject: [PATCH 022/253] #7246 - CR suggestions --- .../sormas/backend/task/TaskFacadeEjb.java | 4 +++- .../travelentry/TravelEntryFacadeEjb.java | 23 ++++++++----------- .../services/BaseTravelEntryService.java | 7 +++--- 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/task/TaskFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/task/TaskFacadeEjb.java index 6dbf9f0b7f2..761990afa75 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/task/TaskFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/task/TaskFacadeEjb.java @@ -145,6 +145,8 @@ public class TaskFacadeEjb implements TaskFacade { private ConfigFacadeEjbLocal configFacade; @EJB private TravelEntryService travelEntryService; + @EJB + private TravelEntryFacadeEjb.TravelEntryFacadeEjbLocal travelEntryFacade; public Task fromDto(TaskDto source, boolean checkChangeDate) { @@ -252,7 +254,7 @@ public TaskDto toDto(Task source, Pseudonymizer pseudonymizer) { target.setCaze(CaseFacadeEjb.toReferenceDto(source.getCaze())); target.setContact(ContactFacadeEjb.toReferenceDto(source.getContact())); target.setEvent(EventFacadeEjb.toReferenceDto(source.getEvent())); - target.setTravelEntry(TravelEntryFacadeEjb.toReferenceDto(source.getTravelEntry())); + target.setTravelEntry(travelEntryFacade.toRefDto(source.getTravelEntry())); target.setClosedLat(source.getClosedLat()); target.setClosedLon(source.getClosedLon()); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java index f41baa34371..93c2c6b2a14 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java @@ -76,18 +76,6 @@ public TravelEntryFacadeEjb(TravelEntryService service, UserService userService) super(TravelEntry.class, TravelEntryDto.class, service, userService); } - public static TravelEntryReferenceDto toReferenceDto(TravelEntry entity) { - - if (entity == null) { - return null; - } - return new TravelEntryReferenceDto( - entity.getUuid(), - entity.getExternalId(), - entity.getPerson().getFirstName(), - entity.getPerson().getLastName()); - } - @Override public boolean isDeleted(String travelEntryUuid) { return service.isDeleted(travelEntryUuid); @@ -277,8 +265,15 @@ public TravelEntryDto toDto(TravelEntry entity) { } @Override - public TravelEntryReferenceDto toRefDto(TravelEntry travelEntry) { - return null; + public TravelEntryReferenceDto toRefDto(TravelEntry entity) { + if (entity == null) { + return null; + } + return new TravelEntryReferenceDto( + entity.getUuid(), + entity.getExternalId(), + entity.getPerson().getFirstName(), + entity.getPerson().getLastName()); } @Override diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java index 7fd96a466b1..212fbb9ff65 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java @@ -1,5 +1,8 @@ package de.symeda.sormas.backend.travelentry.services; +import java.util.Date; +import java.util.List; + import javax.ejb.EJB; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; @@ -9,16 +12,12 @@ import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.backend.common.AbstractCoreAdoService; -import de.symeda.sormas.backend.common.AbstractDeletableAdoService; import de.symeda.sormas.backend.travelentry.TravelEntry; import de.symeda.sormas.backend.travelentry.TravelEntryJurisdictionPredicateValidator; import de.symeda.sormas.backend.travelentry.TravelEntryQueryContext; import de.symeda.sormas.backend.user.User; import de.symeda.sormas.backend.user.UserService; -import java.util.Date; -import java.util.List; - public class BaseTravelEntryService extends AbstractCoreAdoService { @EJB From 6e0e9e5f8f6ea6a9431cc10159c7ee066345cd5b Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Fri, 4 Feb 2022 07:53:08 +0200 Subject: [PATCH 023/253] #7246 - add archived column to contacts and evPart --- .../immunization/ReceivedImmunizationProcessor.java | 8 ++++---- sormas-backend/src/main/resources/sql/sormas_schema.sql | 9 +++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/immunization/ReceivedImmunizationProcessor.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/immunization/ReceivedImmunizationProcessor.java index 148598d0efd..e9172cbf888 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/immunization/ReceivedImmunizationProcessor.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/entities/immunization/ReceivedImmunizationProcessor.java @@ -15,6 +15,7 @@ package de.symeda.sormas.backend.sormastosormas.entities.immunization; +import javax.ejb.EJB; import javax.ejb.LocalBean; import javax.ejb.Stateless; import javax.inject.Inject; @@ -40,20 +41,19 @@ public class ReceivedImmunizationProcessor extends ReceivedDataProcessor { + @EJB + private ImmunizationFacadeEjb.ImmunizationFacadeEjbLocal immunizationFacadeEjb; + public ReceivedImmunizationProcessor() { } - private ImmunizationFacadeEjb.ImmunizationFacadeEjbLocal immunizationFacadeEjb; - @Inject protected ReceivedImmunizationProcessor( - ImmunizationFacadeEjb.ImmunizationFacadeEjbLocal facadeEjb, ImmunizationService service, UserService userService, ConfigFacadeEjb.ConfigFacadeEjbLocal configFacade, SormasToSormasImmunizationDtoValidator validator) { super(service, userService, configFacade, validator); - this.immunizationFacadeEjb = facadeEjb; } @Override diff --git a/sormas-backend/src/main/resources/sql/sormas_schema.sql b/sormas-backend/src/main/resources/sql/sormas_schema.sql index 266d6c49ab1..c86e7e890a8 100644 --- a/sormas-backend/src/main/resources/sql/sormas_schema.sql +++ b/sormas-backend/src/main/resources/sql/sormas_schema.sql @@ -9821,4 +9821,13 @@ ALTER TABLE deletionconfiguration_history OWNER TO sormas_user; INSERT INTO schema_version (version_number, comment) VALUES (437, 'Add configurations for each entity to trigger automated deletion #7008'); +-- 2022-02-02 Refactor CoreAdo to include archiving #7246 + +ALTER TABLE contact ADD COLUMN archived BOOLEAN; +ALTER TABLE contact_history ADD COLUMN archived BOOLEAN; +ALTER TABLE eventparticipant ADD COLUMN archived BOOLEAN; +ALTER TABLE eventparticipant_history ADD COLUMN archived BOOLEAN; + +INSERT INTO schema_version (version_number, comment) VALUES (438, 'Refactor CoreAdo to include archiving #7246'); + -- *** Insert new sql commands BEFORE this line. Remember to always consider _history tables. *** From a337a2f09b547a1e26c5b7cdfb624a6e4dc37b13 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Fri, 4 Feb 2022 08:06:25 +0200 Subject: [PATCH 024/253] #7246 - add archived column to contacts and evPart --- .../main/java/de/symeda/sormas/backend/contact/Contact.java | 5 ----- .../de/symeda/sormas/backend/event/EventParticipant.java | 5 ----- 2 files changed, 10 deletions(-) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/Contact.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/Contact.java index 69cfe6f77c7..561e8ff893b 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/Contact.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/Contact.java @@ -1087,9 +1087,4 @@ public String getQuarantineChangeComment() { public void setQuarantineChangeComment(String quarantineChangeComment) { this.quarantineChangeComment = quarantineChangeComment; } - - @Transient - public boolean isArchived() { - return false; - } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipant.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipant.java index e7a32baec29..db31c2307eb 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipant.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipant.java @@ -188,9 +188,4 @@ public VaccinationStatus getVaccinationStatus() { public void setVaccinationStatus(VaccinationStatus vaccinationStatus) { this.vaccinationStatus = vaccinationStatus; } - - @Transient - public boolean isArchived() { - return false; - } } From 2d0d636e975b1b02fcf8e83fe64ca8317875b2aa Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Fri, 4 Feb 2022 13:52:10 +0100 Subject: [PATCH 025/253] Added scenario "Check all filters are work properly in Samples directory" to SampleFilters.feature --- .../e2etests/enums/SpecimenConditions.java | 10 +++++ .../samples/SamplesDirectoryPage.java | 2 + .../services/api/SampleApiService.java | 1 + .../cases/EditCasePersonSteps.java | 1 - .../samples/SamplesDirectorySteps.java | 45 +++++++++++++++++++ .../features/sanity/web/SampleFilters.feature | 23 ++++++++++ 6 files changed, 81 insertions(+), 1 deletion(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java index a04009d088b..d91d1cf23d0 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java @@ -20,6 +20,7 @@ import java.util.Random; import lombok.Getter; +import lombok.SneakyThrows; @Getter public enum SpecimenConditions { @@ -32,6 +33,15 @@ public enum SpecimenConditions { condition = aSpecimen; } + @SneakyThrows + public static String getForName(String option) { + SpecimenConditions[] specimenConditionOptions = SpecimenConditions.values(); + for (SpecimenConditions value : specimenConditionOptions) { + if (value.condition.equalsIgnoreCase(option)) return value.condition; + } + throw new Exception("Unable to find " + option + " value in RiskLevelValues Enum"); + } + public static String getRandomCondition() { Random random = new Random(); return String.valueOf(SpecimenConditions.values()[random.nextInt(values().length)]); diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java index 3d361320743..920a2eecc75 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java @@ -41,4 +41,6 @@ public class SamplesDirectoryPage { By.cssSelector(("tbody>tr:first-child>td:last-child")); public static final By EDIT_TEST_RESULTS_BUTTON = By.cssSelector("[location='pathogenTests'] [class='v-slot v-slot-s-list'] [role='button']"); + public static final By CASE_CLASIFICATION_SEARCH_COMBOBOX = + By.cssSelector("[id='caseClassification'] [class='v-filterselect-button']"); } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/SampleApiService.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/SampleApiService.java index 36baf030633..48a763db8bc 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/SampleApiService.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/SampleApiService.java @@ -37,6 +37,7 @@ public Sample buildGeneratedSample(Case caze) { .associatedCase(AssociatedCase.builder().uuid(caze.getUuid()).build()) .sampleMaterial("BLOOD") .samplePurpose("EXTERNAL") + .specimenCondition("ADEQUATE") .pathogenTestResult("PENDING") .lab( Lab.builder() diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCasePersonSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCasePersonSteps.java index d6c82151c36..c02414abf51 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCasePersonSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCasePersonSteps.java @@ -139,7 +139,6 @@ public EditCasePersonSteps(final WebDriverHelpers webDriverHelpers, CaseService () -> { collectedCase = collectSpecificCasePersonData(); // TODO: Get and check GPS coordinates for DE - // specific version ComparisonHelper.compareEqualFieldsOfEntities( addressData, collectedCase, diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java index 1e8d421faa4..39c266eda38 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java @@ -23,8 +23,10 @@ import com.google.common.truth.Truth; import cucumber.api.java8.En; import java.util.Arrays; +import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.inject.Named; +import org.sormas.e2etests.enums.CaseClassification; import org.sormas.e2etests.enums.LaboratoryValues; import org.sormas.e2etests.enums.PathogenTestResults; import org.sormas.e2etests.enums.SpecimenConditions; @@ -43,6 +45,49 @@ public SamplesDirectorySteps( ApiState apiState, AssertHelpers assertHelpers) { + When( + "I click a apply button in Sample", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.clickOnWebElementBySelector(APPLY_FILTER_BUTTON); + TimeUnit.SECONDS.sleep(3); + }); + When( + "fill a Full name of person from API", + () -> { + webDriverHelpers.fillAndSubmitInWebElement( + SAMPLE_SEARCH_INPUT, + apiState.getLastCreatedPerson().getFirstName() + + " " + + apiState.getLastCreatedPerson().getLastName()); + }); + When( + "I select Test result filter among the filter options from API", + () -> { + String testResult = apiState.getCreatedSample().getPathogenTestResult(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + TEST_RESULTS_SEARCH_COMBOBOX, + testResult.substring(0, 1).toUpperCase() + testResult.substring(1).toLowerCase()); + }); + When( + "I select Specimen condition filter among the filter options from API", + () -> { + String specimenCondition = apiState.getCreatedSample().getSpecimenCondition(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + SPECIMEN_CONDITION_SEARCH_COMBOBOX, SpecimenConditions.getForName(specimenCondition)); + }); + When( + "I select Case clasification filter among the filter options from API", + () -> { + String caseSpecification = apiState.getCreatedCase().getCaseClassification(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + SPECIMEN_CONDITION_SEARCH_COMBOBOX, + CaseClassification.getUIValueFor(caseSpecification)); + }); + When( "^I search last created Sample by Case ID$", () -> { diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature index ad658b66fca..800aae17699 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature @@ -13,3 +13,26 @@ Feature: Sample filter functionality Then I check the displayed specimen condition filter dropdown When I search for samples created with the API Then I check the displayed Laboratory filter dropdown + + @issue=SORDEV-5981 + Scenario: Check all filters are work properly in Samples directory + Given API: I create a new person + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given API: I create a new case + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given API: I create a new sample + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in with National User + When I click on the Sample button from navbar + Then fill a Full name of person from API + And I select Test result filter among the filter options from API + And I select Specimen condition filter among the filter options from API + And I select Case clasification filter among the filter options from API + And I click a apply button in Sample + And I check that number of displayed sample results is 1 + + + And I fill all fields for a new case created for event participant From 81a57d072d1d809f52f4d329c1c7d140807adf60 Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Fri, 28 Jan 2022 14:22:58 +0100 Subject: [PATCH 026/253] Improvement Persons.feature after review --- .../e2etests/enums/CommunityValues.java | 10 +++ .../e2etests/enums/DistrictsValues.java | 10 +++ .../sormas/e2etests/enums/RegionsValues.java | 10 +++ .../persons/PersonDirectoryPage.java | 16 ++++- .../features/sanity/web/Persons.feature | 65 ++++++++++++++++++- 5 files changed, 109 insertions(+), 2 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CommunityValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CommunityValues.java index 170e61942d4..77d11478f9e 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CommunityValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CommunityValues.java @@ -18,6 +18,7 @@ package org.sormas.e2etests.enums; import lombok.Getter; +import lombok.SneakyThrows; @Getter public enum CommunityValues { @@ -30,4 +31,13 @@ public enum CommunityValues { this.name = name; this.uuid = uuid; } + + @SneakyThrows + public static String getValueFor(String option) { + CommunityValues[] communityValuesOptions = CommunityValues.values(); + for (CommunityValues value : communityValuesOptions) { + if (value.uuid.equalsIgnoreCase(option)) return value.name; + } + throw new Exception("Unable to find " + option + " value in Community Enum"); + } } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java index 4e319b51219..ae68e2bb24f 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java @@ -18,6 +18,7 @@ package org.sormas.e2etests.enums; import lombok.Getter; +import lombok.SneakyThrows; @Getter public enum DistrictsValues { @@ -30,4 +31,13 @@ public enum DistrictsValues { this.name = name; this.uuid = uuid; } + + @SneakyThrows + public static String getValueFor(String option) { + DistrictsValues[] districtValuesOptions = DistrictsValues.values(); + for (DistrictsValues value : districtValuesOptions) { + if (value.uuid.equalsIgnoreCase(option)) return value.name; + } + throw new Exception("Unable to find " + option + " value in District Enum"); + } } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RegionsValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RegionsValues.java index a70fcc5bf0b..51206d98035 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RegionsValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RegionsValues.java @@ -18,6 +18,7 @@ package org.sormas.e2etests.enums; import lombok.Getter; +import lombok.SneakyThrows; @Getter public enum RegionsValues { @@ -30,4 +31,13 @@ public enum RegionsValues { this.name = name; this.uuid = uuid; } + + @SneakyThrows + public static String getValueFor(String option) { + RegionsValues[] regionValuesOptions = RegionsValues.values(); + for (RegionsValues value : regionValuesOptions) { + if (value.uuid.equalsIgnoreCase(option)) return value.name; + } + throw new Exception("Unable to find " + option + " value in Region Enum"); + } } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/PersonDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/PersonDirectoryPage.java index dc7ecb6d02e..a14fde0f816 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/PersonDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/PersonDirectoryPage.java @@ -24,11 +24,25 @@ public class PersonDirectoryPage { public static final By MULTIPLE_OPTIONS_SEARCH_INPUT = By.cssSelector("#nameAddressPhoneEmailLike"); - public static final By APPLY_FILTERS_BUTTON = By.cssSelector("[id='actionApplyFilters']"); + public static final By APPLY_FILTERS_BUTTON = By.cssSelector("#actionApplyFilters"); public static final By RESET_FILTERS_BUTTON = By.cssSelector("[id='actionResetFilters']"); public static final String PERSON_RESULTS_UUID_LOCATOR = "[title = '%s']"; public static final By SEARCH_PERSON_BY_FREE_TEXT = By.id("nameAddressPhoneEmailLike"); public static final By ALL_BUTTON = By.id("All"); + public static final By BIRTH_YEAR_COMBOBOX = + By.cssSelector("[id='birthdateYYYY'] [class='v-filterselect-button']"); + public static final By BIRTH_MONTH_COMBOBOX = + By.cssSelector("[id='birthdateMM'] [class='v-filterselect-button']"); + public static final By BIRTH_DAY_COMBOBOX = + By.cssSelector("[id='birthdateDD'] [class='v-filterselect-button']"); + public static final By PRESENT_CONDITION = + By.cssSelector("[id='presentCondition'] [class='v-filterselect-button']"); + public static final By REGIONS_COMBOBOX = + By.cssSelector("[id='region'] [class='v-filterselect-button']"); + public static final By DISTRICTS_COMBOBOX = + By.cssSelector("[id='district'] [class='v-filterselect-button']"); + public static final By COMMUNITY_PERSON_COMBOBOX = + By.cssSelector("[id='community'] [class='v-filterselect-button']"); public static final By CASE_PERSON_ID_COLUMN_HEADERS = By.cssSelector("v-grid-column-header-content v-grid-column-default-header-content"); } diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature index 92b87f79931..2800895c990 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature @@ -16,4 +16,67 @@ Feature: Edit Persons And While on Person edit page, I will edit all fields with new values And I edit all Person primary contact details and save Then I click on save button from Edit Person page - And I check that previous edited person is correctly displayed in Edit Person page \ No newline at end of file + And I check that previous edited person is correctly displayed in Edit Person page + + Scenario: Check Filters on Person page work as expected + Given API: I create a new person + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Then API: I create a new case + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + When I log in with National User + When I click on the Persons button from navbar + Then I choose random value for Year of birth filter in Persons for the last created person by API + And I choose random value for Month of birth filter in Persons for the last created person by API + And I choose random value for Day of birth filter in Persons for the last created person by API + Then I search after last created person from API by factor "uuid" + And I choose present condition field from specific range for the last created person by API + And I choose random value of Region in Persons for the last created person by API + And I choose random value of District in Persons for the last created person by API + And I choose random value of Community in Persons for the last created person by API + Then I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 1 + And I change Year of birth filter to "1955" for Person + Then I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 0 + Then I choose random value for Year of birth filter in Persons for the last created person by API + Then I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 1 + And I change Month of birth filter to "4" for Person + Then I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 0 + And I choose random value for Month of birth filter in Persons for the last created person by API + Then I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 1 + And I change Day of birth filter to "13" for Person + Then I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 0 + And I choose random value for Day of birth filter in Persons for the last created person by API + Then I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 1 + Then I change "uuid" information data field for Person + And I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 0 + And I search after last created person from API by factor "uuid" + And I change present condition filter to "Unknown" for Person + And I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 0 + And I choose present condition field from specific range for the last created person by API + Then I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 1 + And I change REGION filter to "Berlin" for Person + And I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 0 + And I choose random value of Region in Persons for the last created person by API + And I choose random value of District in Persons for the last created person by API + Then I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 1 + Then I change Community filter to "Community2" for Person + And I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 0 + And I choose random value of Community in Persons for the last created person by API + Then I click on the APPLY FILTERS button for Person + And I check that number of displayed Person results is 1 + And I click on the APPLY FILTERS button for Person + And I click on the RESET FILTERS button for Person \ No newline at end of file From 45c9f81c43c586238fd063bda04f12e81fb2e5f5 Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Wed, 2 Feb 2022 17:32:15 +0100 Subject: [PATCH 027/253] I changed a methods in PersonDirectorySteps and maked a change in scenario PersonDirectorySteps. Also I modified PresentCondition enum --- .../e2etests/enums/PresentCondition.java | 2 +- .../persons/PersonDirectorySteps.java | 259 +++++++++++++++--- .../features/sanity/web/Persons.feature | 18 +- 3 files changed, 234 insertions(+), 45 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PresentCondition.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PresentCondition.java index dfaa6b87608..add9c5a3fb3 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PresentCondition.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PresentCondition.java @@ -37,7 +37,7 @@ public enum PresentCondition { public static String getRandomPresentCondition() { Random random = new Random(); - return String.valueOf(PresentCondition.values()[random.nextInt(values().length)]); + return String.valueOf(PresentCondition.values()[random.nextInt(values().length)].condition); } @SneakyThrows diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java index 00f3aba5e3a..a8df387af56 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java @@ -22,15 +22,21 @@ import static org.sormas.e2etests.pages.application.persons.EditPersonPage.*; import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.*; -import com.google.common.truth.Truth; +import com.github.javafaker.Faker; import cucumber.api.java8.En; +import java.util.UUID; import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.inject.Named; import org.openqa.selenium.By; import org.sormas.e2etests.common.DataOperations; +import org.sormas.e2etests.enums.CommunityValues; +import org.sormas.e2etests.enums.DistrictsValues; +import org.sormas.e2etests.enums.PresentCondition; +import org.sormas.e2etests.enums.RegionsValues; import org.sormas.e2etests.helpers.AssertHelpers; import org.sormas.e2etests.helpers.WebDriverHelpers; +import org.sormas.e2etests.pojo.web.Person; import org.sormas.e2etests.state.ApiState; import org.sormas.e2etests.steps.web.application.contacts.EditContactPersonSteps; import org.sormas.e2etests.steps.web.application.events.EditEventSteps; @@ -44,8 +50,9 @@ public PersonDirectorySteps( WebDriverHelpers webDriverHelpers, @Named("ENVIRONMENT_URL") String environmentUrl, ApiState apiState, - AssertHelpers assertHelpers, - DataOperations dataOperations) { + DataOperations dataOperations, + Faker faker, + AssertHelpers assertHelpers) { this.webDriverHelpers = webDriverHelpers; // TODO refactor all BDD methods naming to be more explicit regarding where data comes from @@ -70,31 +77,143 @@ public PersonDirectorySteps( }); Then( - "I check the result for UID for second person in grid PERSON ID column", + "I choose random value for Year of birth filter in Persons for the last created person by API", () -> { - webDriverHelpers.waitUntilAListOfElementsHasText( - CASE_GRID_RESULTS_ROWS, apiState.getLastCreatedPerson().getUuid()); + String yearOfBirth = apiState.getLastCreatedPerson().getBirthdateYYYY().toString(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(BIRTH_YEAR_COMBOBOX, yearOfBirth); + }); + + Then( + "I choose random value for Month of birth filter in Persons for the last created person by API", + () -> { + String monthOfBirth = apiState.getLastCreatedPerson().getBirthdateMM().toString(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(BIRTH_MONTH_COMBOBOX, monthOfBirth); + }); + + Then( + "I choose random value for Day of birth filter in Persons for the last created person by API", + () -> { + String dayOfBirth = apiState.getLastCreatedPerson().getBirthdateDD().toString(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(BIRTH_DAY_COMBOBOX, dayOfBirth); + }); + + Then( + "I fill Persons UUID for the last created person by API", + () -> { + String personUUID = + dataOperations.getPartialUuidFromAssociatedLink( + apiState.getLastCreatedPerson().getUuid()); + System.out.println(personUUID); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.fillInWebElement(MULTIPLE_OPTIONS_SEARCH_INPUT, personUUID); + }); + + Then( + "I choose present condition field from specific range for the last created person by API", + () -> { + String presentCondition = apiState.getLastCreatedPerson().getPresentCondition(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + PRESENT_CONDITION, PresentCondition.getValueFor(presentCondition)); + }); + + Then( + "I choose random value of Region in Persons for the last created person by API", + () -> { + String regionName = apiState.getLastCreatedPerson().getAddress().getRegion(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + REGIONS_COMBOBOX, RegionsValues.getValueFor(regionName)); + }); + + Then( + "I choose random value of District in Persons for the last created person by API", + () -> { + String districtName = apiState.getLastCreatedPerson().getAddress().getDistrict(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + DISTRICTS_COMBOBOX, DistrictsValues.getValueFor(districtName)); + }); + + Then( + "I choose random value of Community in Persons for the last created person by API", + () -> { + String communityName = apiState.getLastCreatedPerson().getAddress().getCommunity(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + COMMUNITY_PERSON_COMBOBOX, CommunityValues.getValueFor(communityName)); + }); + + Then( + "I check that number of displayed Person results is {int}", + (Integer number) -> { + webDriverHelpers.waitForPageLoaded(); assertHelpers.assertWithPoll20Second( () -> - Truth.assertWithMessage( - apiState.getLastCreatedPerson().getUuid() - + " value is not displayed in grid Disease column") - .that(apiState.getLastCreatedPerson().getUuid()) - .isEqualTo( - String.valueOf( - webDriverHelpers.getTextFromPresentWebElement( - CASE_PERSON_ID_COLUMN_HEADERS)))); - }); - - Then( - "I check that number of displayed Persons results is {int}", - (Integer number) -> - assertHelpers.assertWithPoll20Second( - () -> - Assert.assertEquals( - webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), - number.intValue(), - "Number of displayed cases is not correct"))); + Assert.assertEquals( + webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), + number.intValue(), + "Number of displayed persons is not correct")); + }); + + When( + "I click on the APPLY FILTERS button for Person", + () -> { + webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable( + APPLY_FILTERS_BUTTON, 30); + webDriverHelpers.clickOnWebElementBySelector(APPLY_FILTERS_BUTTON); + TimeUnit.SECONDS.sleep(10); + }); + + Then( + "I change Year of birth filter by random value for Person", + () -> { + Integer yearOfBirth = faker.number().numberBetween(1900, 2022); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(BIRTH_YEAR_COMBOBOX, yearOfBirth.toString()); + }); + + Then( + "I change Month of birth filter by random value for Person", + () -> { + Integer monthOfBirth = faker.number().numberBetween(1, 12); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(BIRTH_MONTH_COMBOBOX, monthOfBirth.toString()); + }); + + Then( + "I change Day of birth filter by random value for Person", + () -> { + Integer dayOfBirth = faker.number().numberBetween(1, 29); + webDriverHelpers.selectFromCombobox(BIRTH_DAY_COMBOBOX, dayOfBirth.toString()); + }); + + Then( + "I change present condition filter to random for Person", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + PRESENT_CONDITION, PresentCondition.getRandomPresentCondition()); + }); + + Then( + "I change REGION filter to {string} for Person", + (String region) -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(REGIONS_COMBOBOX, region); + }); + + Then( + "I change DISTRICT filter to {string} for Person", + (String district) -> webDriverHelpers.selectFromCombobox(DISTRICTS_COMBOBOX, district)); + + Then( + "I change Community filter to {string} for Person", + (String community) -> + webDriverHelpers.selectFromCombobox(COMMUNITY_PERSON_COMBOBOX, community)); When( "I navigate to the last created Person page via URL", @@ -124,22 +243,90 @@ public PersonDirectorySteps( }); When( - "I apply on the APPLY FILTERS button", - () -> { - webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable( - APPLY_FILTERS_BUTTON, 30); - webDriverHelpers.clickOnWebElementBySelector(APPLY_FILTERS_BUTTON); - TimeUnit.SECONDS.sleep(10); - }); - - When( - "I click on the RESET FILTERS button", + "I click on the RESET FILTERS button for Person", () -> { webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable( RESET_FILTERS_BUTTON, 30); - TimeUnit.SECONDS.sleep(10); webDriverHelpers.clickOnWebElementBySelector(RESET_FILTERS_BUTTON); TimeUnit.SECONDS.sleep(10); }); + + Then( + "I search after last created person from API by {string}", + (String searchCriteria) -> { + String searchText = ""; + String personUUID = apiState.getLastCreatedPerson().getUuid(); + switch (searchCriteria) { + case "uuid": + searchText = personUUID; + break; + case "full name": + searchText = + apiState.getLastCreatedPerson().getLastName() + + " " + + apiState.getLastCreatedPerson().getFirstName(); + break; + // etc + } + webDriverHelpers.waitUntilElementIsVisibleAndClickable(APPLY_FILTERS_BUTTON); + webDriverHelpers.clickOnWebElementBySelector(ALL_BUTTON); + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(150); + webDriverHelpers.fillInWebElement(MULTIPLE_OPTIONS_SEARCH_INPUT, searchText); + webDriverHelpers.clickOnWebElementBySelector(APPLY_FILTERS_BUTTON); + By uuidLocator = By.cssSelector(String.format(PERSON_RESULTS_UUID_LOCATOR, personUUID)); + webDriverHelpers.isElementVisibleWithTimeout(uuidLocator, 150); + webDriverHelpers.clickOnWebElementBySelector(uuidLocator); + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(120); + webDriverHelpers.isElementVisibleWithTimeout(UUID_INPUT, 20); + }); + + Then( + "I search after last created person from API by factor {string}", + (String searchCriteria) -> { + String searchText = ""; + String personUUID = apiState.getLastCreatedPerson().getUuid(); + switch (searchCriteria) { + case "uuid": + searchText = dataOperations.getPartialUuidFromAssociatedLink((personUUID)); + break; + case "full name": + searchText = + apiState.getLastCreatedPerson().getLastName() + + " " + + apiState.getLastCreatedPerson().getFirstName(); + break; + case "phone number": + searchText = apiState.getLastCreatedPerson().getPhone(); + break; + case "email": + searchText = apiState.getLastCreatedPerson().getEmailAddress(); + break; + } + + webDriverHelpers.fillInWebElement(MULTIPLE_OPTIONS_SEARCH_INPUT, searchText); + }); + + Then( + "I change {string} information data field for Person", + (String searchCriteria) -> { + String searchText = ""; + String personUUID = + dataOperations.getPartialUuidFromAssociatedLink(UUID.randomUUID().toString()); + switch (searchCriteria) { + case "uuid": + searchText = personUUID; + break; + case "full name": + searchText = faker.name().fullName(); + break; + case "phone number": + searchText = faker.phoneNumber().phoneNumber(); + break; + case "email": + searchText = faker.name().fullName() + "@PERSON.com"; + break; + } + webDriverHelpers.fillInWebElement(MULTIPLE_OPTIONS_SEARCH_INPUT, searchText); + }); } } diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature index 2800895c990..1737609ce61 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature @@ -30,36 +30,38 @@ Feature: Edit Persons Then I choose random value for Year of birth filter in Persons for the last created person by API And I choose random value for Month of birth filter in Persons for the last created person by API And I choose random value for Day of birth filter in Persons for the last created person by API - Then I search after last created person from API by factor "uuid" + Then I fill Persons UUID for the last created person by API And I choose present condition field from specific range for the last created person by API And I choose random value of Region in Persons for the last created person by API And I choose random value of District in Persons for the last created person by API And I choose random value of Community in Persons for the last created person by API Then I click on the APPLY FILTERS button for Person And I check that number of displayed Person results is 1 - And I change Year of birth filter to "1955" for Person + And I change Year of birth filter by random value for Person Then I click on the APPLY FILTERS button for Person And I check that number of displayed Person results is 0 Then I choose random value for Year of birth filter in Persons for the last created person by API Then I click on the APPLY FILTERS button for Person And I check that number of displayed Person results is 1 - And I change Month of birth filter to "4" for Person + And I change Month of birth filter by random value for Person Then I click on the APPLY FILTERS button for Person And I check that number of displayed Person results is 0 And I choose random value for Month of birth filter in Persons for the last created person by API Then I click on the APPLY FILTERS button for Person And I check that number of displayed Person results is 1 - And I change Day of birth filter to "13" for Person + And I change Day of birth filter by random value for Person Then I click on the APPLY FILTERS button for Person And I check that number of displayed Person results is 0 And I choose random value for Day of birth filter in Persons for the last created person by API Then I click on the APPLY FILTERS button for Person + And I search after last created person from API by factor "full name" + And I click on the APPLY FILTERS button for Person And I check that number of displayed Person results is 1 - Then I change "uuid" information data field for Person + Then I change "full name" information data field for Person And I click on the APPLY FILTERS button for Person And I check that number of displayed Person results is 0 - And I search after last created person from API by factor "uuid" - And I change present condition filter to "Unknown" for Person + Then I fill Persons UUID for the last created person by API + And I change present condition filter to random for Person And I click on the APPLY FILTERS button for Person And I check that number of displayed Person results is 0 And I choose present condition field from specific range for the last created person by API @@ -79,4 +81,4 @@ Feature: Edit Persons Then I click on the APPLY FILTERS button for Person And I check that number of displayed Person results is 1 And I click on the APPLY FILTERS button for Person - And I click on the RESET FILTERS button for Person \ No newline at end of file + And I click on the RESET FILTERS button for Person From e691893473bf496c035d37dfc57f2dd9af678f5c Mon Sep 17 00:00:00 2001 From: Pawel Kujawa Date: Sat, 5 Feb 2022 14:12:49 +0100 Subject: [PATCH 028/253] WebDriverHelpers getCheckedDisabledOptionFromHorizontalOptionGroup, slow down tests, fix create and edit new event --- .../pages/application/events/EditEventPage.java | 5 ----- .../application/tasks/CreateNewTaskPage.java | 5 ++--- .../sormas/e2etests/helpers/WebDriverHelpers.java | 14 ++++++++++++++ .../steps/web/application/NavBarSteps.java | 1 + .../web/application/cases/CaseDirectorySteps.java | 15 +++++++++++---- .../web/application/cases/EditCaseSteps.java | 3 +++ .../web/application/events/EditEventSteps.java | 6 +++--- .../application/events/EventDirectorySteps.java | 2 +- .../web/application/tasks/CreateNewTaskSteps.java | 10 +++++++--- .../application/tasks/TaskManagementSteps.java | 2 ++ 10 files changed, 44 insertions(+), 19 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EditEventPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EditEventPage.java index b9adf74157d..ce4de169589 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EditEventPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EditEventPage.java @@ -30,13 +30,8 @@ public class EditEventPage { public static final By SAVE_BUTTON_FOR_POPUP_WINDOWS = By.cssSelector(".popupContent #commit"); public static final By EVENT_STATUS_OPTIONS = By.cssSelector("#eventStatus .v-select-option label"); - public static final By SELECTED_EVENT_STATUS = By.cssSelector("#eventStatus input:checked"); public static final By RISK_LEVEL_INPUT = By.cssSelector(" #riskLevel input"); - public static final By SELECTED_EVENT_MANAGEMENT_STATUS = - By.cssSelector("#eventManagementStatus input:checked"); public static final By START_DATA_INPUT = By.cssSelector(" #startDate input"); - public static final By SELECTED_EVENT_INVESTIGATION_STATUS = - By.cssSelector("#eventInvestigationStatus input:checked"); public static final By DISEASE_INPUT = By.cssSelector("#disease input"); public static final By SOURCE_TYPE_INPUT = By.cssSelector(" #srcType input"); public static final By TYPE_OF_PLACE_INPUT = By.cssSelector("#typeOfPlace input"); diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/tasks/CreateNewTaskPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/tasks/CreateNewTaskPage.java index 3f96e3df197..e215a2930e4 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/tasks/CreateNewTaskPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/tasks/CreateNewTaskPage.java @@ -23,7 +23,7 @@ public class CreateNewTaskPage { public static final By TASK_POPUP = By.xpath("(//div[@class='popupContent'])[2]"); public static final By TASK_TYPE_COMBOBOX = By.cssSelector(".v-window #taskType input+div"); - public static final By TASK_TYPE_INPUT = By.cssSelector(".v-window #taskType input"); + public static final By TASK_TYPE_INPUT = By.cssSelector(".v-window #taskType div"); public static final By SUGGESTED_START_DATE_INPUT = By.cssSelector(".v-window #suggestedStart_date input"); public static final By DUE_DATE_DATE_INPUT = By.cssSelector(".v-window #dueDate_date input"); @@ -44,6 +44,5 @@ public class CreateNewTaskPage { public static final By TASK_STATUS_OPTIONS = By.cssSelector(".v-window #taskStatus .v-radiobutton label"); public static final By SAVE_BUTTON = By.cssSelector(".v-window #commit"); - public static final By SELECTED_TASK_CONTEXT = - By.cssSelector(".v-window #taskContext input:checked"); + public static final By SELECTED_TASK_CONTEXT = By.cssSelector(".v-window [id='taskContext']"); } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java index edcbfbe1a5d..bd4fad0c7de 100755 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java @@ -49,6 +49,10 @@ public class WebDriverHelpers { public static final By SELECTED_RADIO_BUTTON = By.xpath("ancestor::div[contains(@role,'group')]//input[@checked]/following-sibling::label"); + public static final By SELECTED_RADIO_DISABLED_AND_CHECKED_BUTTON = + By.xpath( + "//div[contains(@class,'v-select-optiongroup')]//input[@checked and @disabled]/following-sibling::label"); + public static final int FLUENT_WAIT_TIMEOUT_SECONDS = 20; public static final By CHECKBOX_TEXT_LABEL = By.xpath("ancestor::span//label"); public static final By TABLE_SCROLLER = @@ -658,6 +662,16 @@ public String getCheckedOptionFromHorizontalOptionGroup(By options) { return baseSteps.getDriver().findElement(options).findElement(SELECTED_RADIO_BUTTON).getText(); } + public String getCheckedDisabledOptionFromHorizontalOptionGroup(By options) { + waitUntilIdentifiedElementIsPresent(options); + scrollToElement(options); + return baseSteps + .getDriver() + .findElement(options) + .findElement(SELECTED_RADIO_DISABLED_AND_CHECKED_BUTTON) + .getText(); + } + public void clearWebElement(By selector) { Instant start = Instant.now(); waitUntilElementIsVisibleAndClickable(selector); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/NavBarSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/NavBarSteps.java index fd9a703b807..692ccffc5f5 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/NavBarSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/NavBarSteps.java @@ -89,6 +89,7 @@ public NavBarSteps(WebDriverHelpers webDriverHelpers) { webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(NavBarPage.TASKS_BUTTON); webDriverHelpers.clickOnWebElementBySelector(NavBarPage.TASKS_BUTTON); startTime = ZonedDateTime.now().toInstant().toEpochMilli(); + TimeUnit.SECONDS.sleep(2); }); When( diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java index 8fb2ca69ddf..7599402f8f4 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java @@ -55,13 +55,20 @@ public CaseDirectorySteps( When( "^I open last created case", - () -> webDriverHelpers.clickOnWebElementBySelector(FIRST_CASE_ID_BUTTON)); + () -> { + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(40); + webDriverHelpers.waitUntilElementIsVisibleAndClickable(FIRST_CASE_ID_BUTTON); + webDriverHelpers.clickOnWebElementBySelector(FIRST_CASE_ID_BUTTON); + }); When( "^Search for Case using Case UUID from the created Task", - () -> - webDriverHelpers.fillAndSubmitInWebElement( - NAME_UUID_EPID_NUMBER_LIKE_INPUT, EditCaseSteps.aCase.getUuid())); + () -> { + webDriverHelpers.fillAndSubmitInWebElement( + NAME_UUID_EPID_NUMBER_LIKE_INPUT, EditCaseSteps.aCase.getUuid()); + TimeUnit.SECONDS.sleep(2); + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(40); + }); When( "I click on the DETAILED button from Case directory", () -> { diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java index ac80efbc494..987f3eb626e 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java @@ -125,6 +125,7 @@ public EditCaseSteps( Case.builder() .investigationStatus("Investigation " + investigationStatus) .build(); // TODO: Create POJO updater class + TimeUnit.SECONDS.sleep(1); }); When( @@ -137,6 +138,7 @@ public EditCaseSteps( webDriverHelpers.clickWebElementByText( OUTCOME_OF_CASE_OPTIONS, CaseOutcome.getValueFor(caseStatus).toUpperCase()); editedCase = editedCase.toBuilder().outcomeOfCase(caseStatus).build(); + TimeUnit.SECONDS.sleep(1); }); When( @@ -149,6 +151,7 @@ public EditCaseSteps( webDriverHelpers.clickWebElementByText( SEQUELAE_OPTIONS, CaseOutcome.getValueFor(option).toUpperCase()); editedCase = editedCase.toBuilder().sequelae(option).build(); + TimeUnit.SECONDS.sleep(1); }); When( diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java index 07173bdfbf1..010fc6313ac 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java @@ -360,13 +360,13 @@ private Event collectEventData() { .eventDate(eventDate) .uuid(webDriverHelpers.getValueFromWebElement(UUID_INPUT)) .eventStatus( - webDriverHelpers.getCheckedOptionFromHorizontalOptionGroup(SELECTED_EVENT_STATUS)) + webDriverHelpers.getCheckedOptionFromHorizontalOptionGroup(EVENT_STATUS_OPTIONS)) .investigationStatus( webDriverHelpers.getCheckedOptionFromHorizontalOptionGroup( - SELECTED_EVENT_INVESTIGATION_STATUS)) + EVENT_INVESTIGATION_STATUS_OPTIONS)) .eventManagementStatus( webDriverHelpers.getCheckedOptionFromHorizontalOptionGroup( - SELECTED_EVENT_MANAGEMENT_STATUS)) + EVENT_MANAGEMENT_STATUS_OPTIONS)) .riskLevel(webDriverHelpers.getValueFromWebElement(RISK_LEVEL_INPUT)) .disease(webDriverHelpers.getValueFromWebElement(DISEASE_INPUT)) .title(webDriverHelpers.getValueFromWebElement(TITLE_INPUT)) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index cc66e48be37..25447b6b24a 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -196,7 +196,7 @@ public EventDirectorySteps( webDriverHelpers.clickOnWebElementBySelector(RESET_FILTER); final String eventUuid = CreateNewEventSteps.newEvent.getUuid(); webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable( - SEARCH_EVENT_BY_FREE_TEXT_INPUT, 15); + SEARCH_EVENT_BY_FREE_TEXT_INPUT, 20); webDriverHelpers.fillAndSubmitInWebElement(SEARCH_EVENT_BY_FREE_TEXT_INPUT, eventUuid); webDriverHelpers.clickOnWebElementBySelector(APPLY_FILTER); }); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/tasks/CreateNewTaskSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/tasks/CreateNewTaskSteps.java index 44c4e6d72b2..d80857fda08 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/tasks/CreateNewTaskSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/tasks/CreateNewTaskSteps.java @@ -24,6 +24,7 @@ import java.time.LocalDate; import java.time.LocalTime; import java.time.format.DateTimeFormatter; +import java.util.concurrent.TimeUnit; import javax.inject.Inject; import org.sormas.e2etests.helpers.WebDriverHelpers; import org.sormas.e2etests.pojo.helpers.ComparisonHelper; @@ -60,6 +61,8 @@ public CreateNewTaskSteps(WebDriverHelpers webDriverHelpers, TaskService taskSer When( "^I check the created task is correctly displayed on Edit task page", () -> { + TimeUnit.SECONDS.sleep(2); + webDriverHelpers.waitForPageLoaded(); final Task actualTask = collectTaskData(); ComparisonHelper.compareEqualEntities(task, actualTask); }); @@ -129,7 +132,7 @@ private void selectTaskStatus(String taskStatus) { private Task collectTaskData() { return Task.builder() - .taskContext(getTaskContext()) + .taskContext(getDisabledTaskContext()) .taskType(webDriverHelpers.getValueFromWebElement(TASK_TYPE_INPUT)) .suggestedStartDate(getSuggestedStartDate()) .suggestedStartTime(getSuggestedStartTime()) @@ -185,7 +188,8 @@ private String getStatus() { return webDriverHelpers.getCheckedOptionFromHorizontalOptionGroup(TASK_STATUS_OPTIONS); } - private String getTaskContext() { - return webDriverHelpers.getCheckedOptionFromHorizontalOptionGroup(SELECTED_TASK_CONTEXT); + private String getDisabledTaskContext() { + return webDriverHelpers.getCheckedDisabledOptionFromHorizontalOptionGroup( + SELECTED_TASK_CONTEXT); } } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/tasks/TaskManagementSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/tasks/TaskManagementSteps.java index 8918fdffb34..c60a8e4fdf5 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/tasks/TaskManagementSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/tasks/TaskManagementSteps.java @@ -75,6 +75,7 @@ public TaskManagementSteps( do { webDriverHelpers.scrollInTable(10); } while (!webDriverHelpers.isElementVisibleWithTimeout(lastTaskEditButton, 2)); + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(40); webDriverHelpers.clickOnWebElementBySelector(lastTaskEditButton); webDriverHelpers.isElementVisibleWithTimeout(TASK_POPUP, 5); }); @@ -91,6 +92,7 @@ public TaskManagementSteps( When( "^I am checking if the associated linked event appears in task management and click on it$", () -> { + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(40); String eventUuid = apiState.getCreatedEvent().getUuid(); webDriverHelpers.fillAndSubmitInWebElement(GENERAL_SEARCH_INPUT, eventUuid); webDriverHelpers.waitForPageLoadingSpinnerToDisappear(15); From e6071684ac2c44121dc5e724664e6888a59145ce Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Sat, 5 Feb 2022 14:15:05 +0100 Subject: [PATCH 029/253] Added the next steps to scenario [SORDEV-5981] to SampleFilters.feature,Modyfied CaseApiService.java and Enums: CaseClassification, DiseasesValues, DistrictsValues, PathogenTestResults, RegionsValues, --- .../e2etests/enums/CaseClassification.java | 2 +- .../sormas/e2etests/enums/DiseasesValues.java | 2 +- .../e2etests/enums/DistrictsValues.java | 10 ++ .../e2etests/enums/PathogenTestResults.java | 6 + .../sormas/e2etests/enums/RegionsValues.java | 10 ++ .../e2etests/enums/SpecimenConditions.java | 2 +- .../samples/SamplesDirectoryPage.java | 12 +- .../e2etests/services/api/CaseApiService.java | 4 +- .../samples/SamplesDirectorySteps.java | 128 +++++++++++++++++- .../features/sanity/web/SampleFilters.feature | 42 +++++- 10 files changed, 202 insertions(+), 16 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CaseClassification.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CaseClassification.java index 459569f04ac..6e445fb7cb5 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CaseClassification.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CaseClassification.java @@ -44,7 +44,7 @@ public enum CaseClassification { public static String getUIValueFor(String option) { CaseClassification[] classifications = CaseClassification.values(); for (CaseClassification value : classifications) { - if (value.getClassificationUIvalue().equalsIgnoreCase(option)) + if (value.getClassificationAPIvalue().equalsIgnoreCase(option)) return value.getClassificationUIvalue(); } throw new Exception("Unable to find " + option + " value in CaseClassification Enum"); diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DiseasesValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DiseasesValues.java index 44a6298e7be..bfb24366169 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DiseasesValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DiseasesValues.java @@ -71,7 +71,7 @@ public static String getCaptionForName(String option) { for (DiseasesValues value : diseasesOptions) { if (value.getDiseaseName().equalsIgnoreCase(option)) return value.getDiseaseCaption(); } - throw new Exception("Unable to find " + option + " value in SourceTypeValues Enum"); + throw new Exception("Unable to find " + option + " value in DiseasesValues Enum"); } /** Returns values used for API tests */ diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java index 4e319b51219..ae68e2bb24f 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java @@ -18,6 +18,7 @@ package org.sormas.e2etests.enums; import lombok.Getter; +import lombok.SneakyThrows; @Getter public enum DistrictsValues { @@ -30,4 +31,13 @@ public enum DistrictsValues { this.name = name; this.uuid = uuid; } + + @SneakyThrows + public static String getValueFor(String option) { + DistrictsValues[] districtValuesOptions = DistrictsValues.values(); + for (DistrictsValues value : districtValuesOptions) { + if (value.uuid.equalsIgnoreCase(option)) return value.name; + } + throw new Exception("Unable to find " + option + " value in District Enum"); + } } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PathogenTestResults.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PathogenTestResults.java index 9fd68be42e9..8eda3830839 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PathogenTestResults.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PathogenTestResults.java @@ -39,4 +39,10 @@ public static String getRandomResult() { Random random = new Random(); return String.valueOf(PathogenTestResults.values()[random.nextInt(values().length)]); } + + public static String geRandomResultName() { + Random random = new Random(); + return String.valueOf( + PathogenTestResults.values()[random.nextInt(values().length)].pathogenResults); + } } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RegionsValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RegionsValues.java index a70fcc5bf0b..51206d98035 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RegionsValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RegionsValues.java @@ -18,6 +18,7 @@ package org.sormas.e2etests.enums; import lombok.Getter; +import lombok.SneakyThrows; @Getter public enum RegionsValues { @@ -30,4 +31,13 @@ public enum RegionsValues { this.name = name; this.uuid = uuid; } + + @SneakyThrows + public static String getValueFor(String option) { + RegionsValues[] regionValuesOptions = RegionsValues.values(); + for (RegionsValues value : regionValuesOptions) { + if (value.uuid.equalsIgnoreCase(option)) return value.name; + } + throw new Exception("Unable to find " + option + " value in Region Enum"); + } } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java index d91d1cf23d0..4c436588fbc 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java @@ -39,7 +39,7 @@ public static String getForName(String option) { for (SpecimenConditions value : specimenConditionOptions) { if (value.condition.equalsIgnoreCase(option)) return value.condition; } - throw new Exception("Unable to find " + option + " value in RiskLevelValues Enum"); + throw new Exception("Unable to find " + option + " value in SpecimenConditions Enum"); } public static String getRandomCondition() { diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java index 920a2eecc75..8c084b171b4 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java @@ -41,6 +41,16 @@ public class SamplesDirectoryPage { By.cssSelector(("tbody>tr:first-child>td:last-child")); public static final By EDIT_TEST_RESULTS_BUTTON = By.cssSelector("[location='pathogenTests'] [class='v-slot v-slot-s-list'] [role='button']"); - public static final By CASE_CLASIFICATION_SEARCH_COMBOBOX = + public static final By SAMPLE_CLASIFICATION_SEARCH_COMBOBOX = By.cssSelector("[id='caseClassification'] [class='v-filterselect-button']"); + public static final By SAMPLE_DISEASE_SEARCH_COMBOBOX = + By.cssSelector("[id='disease'] [class='v-filterselect-button']"); + public static final By SAMPLE_REGION_SEARCH_COMBOBOX = + By.cssSelector("[id='region'] [class='v-filterselect-button']"); + public static final By SAMPLE_DISTRICT_SEARCH_COMBOBOX = + By.cssSelector("[id='district'] [class='v-filterselect-button']"); + public static final By SAMPLE_NOT_SHIPPED = By.id("sampleNotShipped"); + public static final By SAMPLE_SHIPPED = By.id("sampleShipped"); + public static final By SAMPLE_RECEIVED = By.id("sampleReceived"); + public static final By SAMPLE_REFFERED_TO_OTHER_LAB = By.id("sampleReferred"); } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/CaseApiService.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/CaseApiService.java index 75be123cacf..ccd82469b2e 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/CaseApiService.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/CaseApiService.java @@ -36,7 +36,7 @@ public CaseApiService() {} public Case buildGeneratedCase(Person person) { return Case.builder() - .disease(DiseasesValues.CORONAVIRUS.getDiseaseName()) + .disease(DiseasesValues.getRandomDiseaseName()) .diseaseDetails("Test Disease") .pseudonymized(false) .uuid(UUID.randomUUID().toString()) @@ -58,7 +58,7 @@ public Case buildGeneratedCase(Person person) { .firstName(person.getFirstName()) .lastName(person.getLastName()) .build()) - .caseClassification("NOT_CLASSIFIED") + .caseClassification(CaseClassification.getRandomAPIClassification()) .investigationStatus("PENDING") .outcome("NO_OUTCOME") .epiData(EpiData.builder().uuid(UUID.randomUUID().toString()).build()) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java index 39c266eda38..0fa6682e8e8 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java @@ -23,13 +23,9 @@ import com.google.common.truth.Truth; import cucumber.api.java8.En; import java.util.Arrays; -import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.inject.Named; -import org.sormas.e2etests.enums.CaseClassification; -import org.sormas.e2etests.enums.LaboratoryValues; -import org.sormas.e2etests.enums.PathogenTestResults; -import org.sormas.e2etests.enums.SpecimenConditions; +import org.sormas.e2etests.enums.*; import org.sormas.e2etests.helpers.AssertHelpers; import org.sormas.e2etests.helpers.WebDriverHelpers; import org.sormas.e2etests.state.ApiState; @@ -50,8 +46,15 @@ public SamplesDirectorySteps( () -> { webDriverHelpers.waitForPageLoaded(); webDriverHelpers.clickOnWebElementBySelector(APPLY_FILTER_BUTTON); - TimeUnit.SECONDS.sleep(3); }); + + When( + "I click a Reset button in Sample", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.clickOnWebElementBySelector(RESET_FILTER_BUTTON); + }); + When( "fill a Full name of person from API", () -> { @@ -61,6 +64,7 @@ public SamplesDirectorySteps( + " " + apiState.getLastCreatedPerson().getLastName()); }); + When( "I select Test result filter among the filter options from API", () -> { @@ -70,6 +74,15 @@ public SamplesDirectorySteps( TEST_RESULTS_SEARCH_COMBOBOX, testResult.substring(0, 1).toUpperCase() + testResult.substring(1).toLowerCase()); }); + + When( + "I select random Test result filter among the filter options", + () -> { + String testResult = PathogenTestResults.geRandomResultName(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(TEST_RESULTS_SEARCH_COMBOBOX, testResult); + }); + When( "I select Specimen condition filter among the filter options from API", () -> { @@ -78,16 +91,98 @@ public SamplesDirectorySteps( webDriverHelpers.selectFromCombobox( SPECIMEN_CONDITION_SEARCH_COMBOBOX, SpecimenConditions.getForName(specimenCondition)); }); + + When( + "I select {string} Specimen condition option among the filter options", + (String specimenCondition) -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + SPECIMEN_CONDITION_SEARCH_COMBOBOX, specimenCondition); + }); + When( "I select Case clasification filter among the filter options from API", () -> { String caseSpecification = apiState.getCreatedCase().getCaseClassification(); webDriverHelpers.waitForPageLoaded(); webDriverHelpers.selectFromCombobox( - SPECIMEN_CONDITION_SEARCH_COMBOBOX, + SAMPLE_CLASIFICATION_SEARCH_COMBOBOX, CaseClassification.getUIValueFor(caseSpecification)); }); + When( + "I select random Case clasification filter among the filter options", + () -> { + String caseSpecification = CaseClassification.getRandomUIClassification(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + SAMPLE_CLASIFICATION_SEARCH_COMBOBOX, caseSpecification); + }); + + When( + "I select Disease filter among the filter options from API", + () -> { + String disease = apiState.getCreatedCase().getDisease(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + SAMPLE_DISEASE_SEARCH_COMBOBOX, DiseasesValues.getCaptionForName(disease)); + }); + + When( + "I select random Disease filter among the filter options in Sample directory", + () -> { + String disease = DiseasesValues.getRandomDiseaseCaption(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(SAMPLE_DISEASE_SEARCH_COMBOBOX, disease); + }); + + When( + "I select Region filter among the filter options from API", + () -> { + String region = apiState.getCreatedCase().getRegion().getUuid(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + SAMPLE_REGION_SEARCH_COMBOBOX, RegionsValues.getValueFor(region)); + }); + + When( + "I change Region filter to {string} option in Sample directory", + (String region) -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(SAMPLE_REGION_SEARCH_COMBOBOX, region); + }); + + When( + "I select District filter among the filter options from API", + () -> { + String district = apiState.getCreatedCase().getDistrict().getUuid(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + SAMPLE_DISTRICT_SEARCH_COMBOBOX, DistrictsValues.getValueFor(district)); + }); + + When( + "I change District filter to {string} option in Sample directory", + (String district) -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(SAMPLE_DISTRICT_SEARCH_COMBOBOX, district); + }); + + When( + "I select Laboratory filter among the filter options from API", + () -> { + String laboratory = apiState.getCreatedSample().getLab().getCaption(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(LABORATORY_SEARCH_COMBOBOX, laboratory); + }); + + When( + "I change Labolatory filter to {string} option in Sample directory", + (String laboratory) -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(LABORATORY_SEARCH_COMBOBOX, laboratory); + }); + When( "^I search last created Sample by Case ID$", () -> { @@ -143,6 +238,25 @@ public SamplesDirectorySteps( "Number of created samples is wrong"); }); + Then( + "I select {string} filter from quick filter", + (String searchCriteria) -> { + switch (searchCriteria) { + case "Not shipped": + webDriverHelpers.clickOnWebElementBySelector(SAMPLE_NOT_SHIPPED); + break; + case "Shipped": + webDriverHelpers.clickOnWebElementBySelector(SAMPLE_SHIPPED); + break; + case "Received": + webDriverHelpers.clickOnWebElementBySelector(SAMPLE_RECEIVED); + break; + case "Referred to other lab": + webDriverHelpers.clickOnWebElementBySelector(SAMPLE_REFFERED_TO_OTHER_LAB); + break; + } + }); + Then( "^I check the displayed test results filter dropdown", () -> diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature index 800aae17699..db469520245 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature @@ -31,8 +31,44 @@ Feature: Sample filter functionality And I select Test result filter among the filter options from API And I select Specimen condition filter among the filter options from API And I select Case clasification filter among the filter options from API + And I select Disease filter among the filter options from API + And I select Region filter among the filter options from API + And I select District filter among the filter options from API + And I select Laboratory filter among the filter options from API And I click a apply button in Sample And I check that number of displayed sample results is 1 - - - And I fill all fields for a new case created for event participant + Then I select random Test result filter among the filter options + And I click a apply button in Sample + And I check that number of displayed sample results is 0 + And I select Test result filter among the filter options from API + Then I select "Not adequate" Specimen condition option among the filter options + And I click a apply button in Sample + And I check that number of displayed sample results is 0 + And I select Specimen condition filter among the filter options from API + Then I select random Case clasification filter among the filter options + And I click a apply button in Sample + And I check that number of displayed sample results is 0 + And I select Case clasification filter among the filter options from API + Then I select random Disease filter among the filter options in Sample directory + And I click a apply button in Sample + And I check that number of displayed sample results is 0 + And I select Disease filter among the filter options from API + Then I change Region filter to "Berlin" option in Sample directory + And I click a apply button in Sample + And I check that number of displayed sample results is 0 + And I select Region filter among the filter options from API + Then I change Region filter to "Region1" option in Sample directory + And I change District filter to "District11" option in Sample directory + And I click a apply button in Sample + And I check that number of displayed sample results is 0 + And I select Region filter among the filter options from API + And I select District filter among the filter options from API + Then I change Labolatory filter to "Other facility" option in Sample directory + And I click a apply button in Sample + And I check that number of displayed sample results is 0 + And I click a Reset button in Sample + Then I select "Not shipped" filter from quick filter + And I select "Shipped" filter from quick filter + And I select "Received" filter from quick filter + And I select "Referred to other lab" filter from quick filter + And I click a Reset button in Sample \ No newline at end of file From fcb210c61369294693abd92527e41ba7a6e22c98 Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Mon, 7 Feb 2022 08:42:25 +0100 Subject: [PATCH 030/253] Added method to SpecimenConditions --- .../java/org/sormas/e2etests/enums/SpecimenConditions.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java index 4c436588fbc..60e9f8cab45 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java @@ -46,4 +46,9 @@ public static String getRandomCondition() { Random random = new Random(); return String.valueOf(SpecimenConditions.values()[random.nextInt(values().length)]); } + + public static String getRandomConditionName() { + Random random = new Random(); + return String.valueOf(SpecimenConditions.values()[random.nextInt(values().length)].condition); + } } From ffbfdb3c6975ca454afeb2aaae3da3166304652a Mon Sep 17 00:00:00 2001 From: marius Date: Mon, 7 Feb 2022 14:34:44 +0200 Subject: [PATCH 031/253] #7674 getSimilarPersons --- .../sormas/api/person/PersonFacade.java | 2 +- .../backend/person/PersonFacadeEjb.java | 8 +-- .../backend/person/PersonFacadeEjbTest.java | 47 ++++------------ .../de/symeda/sormas/rest/PersonResource.java | 8 +++ .../sormas/ui/person/PersonSelectionGrid.java | 4 +- .../ui/caze/importer/CaseImporterTest.java | 48 +++++++++-------- .../contact/importer/ContactImporterTest.java | 22 ++++---- .../EventParticipantImporterTest.java | 54 +++++++++---------- .../ui/event/importer/EventImporterTest.java | 2 +- 9 files changed, 88 insertions(+), 107 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonFacade.java index b62525eb871..9bd5a985646 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonFacade.java @@ -67,7 +67,7 @@ public interface PersonFacade { * * @return */ - List getSimilarPersonDtos(UserReferenceDto user, PersonSimilarityCriteria criteria); + List getSimilarPersonDtos(PersonSimilarityCriteria criteria); boolean checkMatchingNameInDatabase(UserReferenceDto userRef, PersonSimilarityCriteria criteria); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java index 2e9ff956320..2ff54cd93a6 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java @@ -103,7 +103,6 @@ import de.symeda.sormas.api.person.PersonReferenceDto; import de.symeda.sormas.api.person.PersonSimilarityCriteria; import de.symeda.sormas.api.person.PresentCondition; -import de.symeda.sormas.api.person.Sex; import de.symeda.sormas.api.person.SimilarPersonDto; import de.symeda.sormas.api.person.SymptomJournalStatus; import de.symeda.sormas.api.user.UserReferenceDto; @@ -224,12 +223,7 @@ public List getAllUuids() { } @Override - public List getSimilarPersonDtos(UserReferenceDto userRef, PersonSimilarityCriteria criteria) { - - User user = userService.getByReferenceDto(userRef); - if (user == null) { - return Collections.emptyList(); - } + public List getSimilarPersonDtos(PersonSimilarityCriteria criteria) { return personService.getSimilarPersonDtos(criteria, null); } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java index 379e8fd3fb7..c93b9a91b42 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java @@ -317,10 +317,8 @@ public void testGetMatchingNameDtos() { getEventFacade().archiveOrDearchiveEvent(inactiveEvent.getUuid(), true); // Only persons that have active case, contact or event participant associations should be retrieved - List relevantNameUuids = getPersonFacade().getSimilarPersonDtos(user.toReference(), new PersonSimilarityCriteria()) - .stream() - .map(dto -> dto.getUuid()) - .collect(Collectors.toList()); + List relevantNameUuids = + getPersonFacade().getSimilarPersonDtos(new PersonSimilarityCriteria()).stream().map(dto -> dto.getUuid()).collect(Collectors.toList()); assertThat(relevantNameUuids, hasSize(6)); assertThat( relevantNameUuids, @@ -331,34 +329,23 @@ public void testGetMatchingNameDtos() { getEventFacade().archiveOrDearchiveEvent(inactiveEvent.getUuid(), false); PersonSimilarityCriteria criteria = new PersonSimilarityCriteria().sex(Sex.MALE).birthdateYYYY(1980).birthdateMM(1).birthdateDD(1); - List matchingUuids = getPersonFacade().getSimilarPersonDtos(user.toReference(), criteria) - .stream() - .map(person -> person.getUuid()) - .collect(Collectors.toList()); + List matchingUuids = + getPersonFacade().getSimilarPersonDtos(criteria).stream().map(person -> person.getUuid()).collect(Collectors.toList()); assertThat(matchingUuids, hasSize(2)); assertThat(matchingUuids, containsInAnyOrder(person1.getUuid(), person7.getUuid())); criteria.birthdateMM(null).birthdateDD(null); - matchingUuids = getPersonFacade().getSimilarPersonDtos(user.toReference(), criteria) - .stream() - .map(person -> person.getUuid()) - .collect(Collectors.toList()); + matchingUuids = getPersonFacade().getSimilarPersonDtos(criteria).stream().map(person -> person.getUuid()).collect(Collectors.toList()); assertThat(matchingUuids, hasSize(3)); assertThat(matchingUuids, containsInAnyOrder(person1.getUuid(), person3.getUuid(), person7.getUuid())); criteria.sex(Sex.FEMALE).birthdateYYYY(1984); - matchingUuids = getPersonFacade().getSimilarPersonDtos(user.toReference(), criteria) - .stream() - .map(person -> person.getUuid()) - .collect(Collectors.toList()); + matchingUuids = getPersonFacade().getSimilarPersonDtos(criteria).stream().map(person -> person.getUuid()).collect(Collectors.toList()); assertThat(matchingUuids, hasSize(3)); assertThat(matchingUuids, containsInAnyOrder(person4.getUuid(), person5.getUuid(), person6.getUuid())); criteria.sex(null); - matchingUuids = getPersonFacade().getSimilarPersonDtos(user.toReference(), criteria) - .stream() - .map(person -> person.getUuid()) - .collect(Collectors.toList()); + matchingUuids = getPersonFacade().getSimilarPersonDtos(criteria).stream().map(person -> person.getUuid()).collect(Collectors.toList()); assertThat(matchingUuids, hasSize(4)); assertThat(matchingUuids, containsInAnyOrder(person4.getUuid(), person5.getUuid(), person6.getUuid(), person7.getUuid())); @@ -377,36 +364,24 @@ public void testGetMatchingNameDtos() { criteria.sex(Sex.MALE).birthdateYYYY(1980); criteria.passportNumber(passportNr); - matchingUuids = getPersonFacade().getSimilarPersonDtos(user.toReference(), criteria) - .stream() - .map(person -> person.getUuid()) - .collect(Collectors.toList()); + matchingUuids = getPersonFacade().getSimilarPersonDtos(criteria).stream().map(person -> person.getUuid()).collect(Collectors.toList()); assertThat(matchingUuids, hasSize(6)); assertThat( matchingUuids, containsInAnyOrder(person1.getUuid(), person3.getUuid(), person7.getUuid(), person8.getUuid(), person9.getUuid(), person10.getUuid())); criteria.nationalHealthId(healthId).passportNumber(null); - matchingUuids = getPersonFacade().getSimilarPersonDtos(user.toReference(), criteria) - .stream() - .map(person -> person.getUuid()) - .collect(Collectors.toList()); + matchingUuids = getPersonFacade().getSimilarPersonDtos(criteria).stream().map(person -> person.getUuid()).collect(Collectors.toList()); assertThat(matchingUuids, hasSize(4)); assertThat(matchingUuids, containsInAnyOrder(person1.getUuid(), person3.getUuid(), person7.getUuid(), person8.getUuid())); criteria.nationalHealthId(otherHealthId); - matchingUuids = getPersonFacade().getSimilarPersonDtos(user.toReference(), criteria) - .stream() - .map(person -> person.getUuid()) - .collect(Collectors.toList()); + matchingUuids = getPersonFacade().getSimilarPersonDtos(criteria).stream().map(person -> person.getUuid()).collect(Collectors.toList()); assertThat(matchingUuids, hasSize(4)); assertThat(matchingUuids, containsInAnyOrder(person1.getUuid(), person3.getUuid(), person7.getUuid(), person9.getUuid())); criteria.passportNumber(otherPassportNr); - matchingUuids = getPersonFacade().getSimilarPersonDtos(user.toReference(), criteria) - .stream() - .map(person -> person.getUuid()) - .collect(Collectors.toList()); + matchingUuids = getPersonFacade().getSimilarPersonDtos(criteria).stream().map(person -> person.getUuid()).collect(Collectors.toList()); assertThat(matchingUuids, hasSize(5)); assertThat(matchingUuids, containsInAnyOrder(person1.getUuid(), person3.getUuid(), person7.getUuid(), person9.getUuid(), person11.getUuid())); } diff --git a/sormas-rest/src/main/java/de/symeda/sormas/rest/PersonResource.java b/sormas-rest/src/main/java/de/symeda/sormas/rest/PersonResource.java index 62e6fe855de..527338ab750 100644 --- a/sormas-rest/src/main/java/de/symeda/sormas/rest/PersonResource.java +++ b/sormas-rest/src/main/java/de/symeda/sormas/rest/PersonResource.java @@ -41,6 +41,8 @@ import de.symeda.sormas.api.person.PersonCriteria; import de.symeda.sormas.api.person.PersonDto; import de.symeda.sormas.api.person.PersonIndexDto; +import de.symeda.sormas.api.person.PersonSimilarityCriteria; +import de.symeda.sormas.api.person.SimilarPersonDto; import io.swagger.v3.oas.annotations.parameters.RequestBody; /** @@ -124,4 +126,10 @@ public Response updateExternalData(@Valid List externalData) { return Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build(); } } + + @POST + @Path("/similarPersons") + public List getSimilarPersons(@RequestBody PersonSimilarityCriteria criteria) { + return FacadeProvider.getPersonFacade().getSimilarPersonDtos(criteria); + } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonSelectionGrid.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonSelectionGrid.java index 38620da25ad..dabc3436e8a 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonSelectionGrid.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonSelectionGrid.java @@ -28,7 +28,6 @@ import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.person.PersonSimilarityCriteria; import de.symeda.sormas.api.person.SimilarPersonDto; -import de.symeda.sormas.ui.UserProvider; @SuppressWarnings("serial") public class PersonSelectionGrid extends Grid { @@ -89,8 +88,7 @@ private BeanItemContainer getContainer() { * The person criteria. */ public void loadData(PersonSimilarityCriteria criteria) { - List similarPersons = - FacadeProvider.getPersonFacade().getSimilarPersonDtos(UserProvider.getCurrent().getUserReference(), criteria); + List similarPersons = FacadeProvider.getPersonFacade().getSimilarPersonDtos(criteria); getContainer().removeAllItems(); getContainer().addAll(similarPersons); diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/caze/importer/CaseImporterTest.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/caze/importer/CaseImporterTest.java index b5910f3524d..82e928aef83 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/caze/importer/CaseImporterTest.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/caze/importer/CaseImporterTest.java @@ -19,18 +19,6 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import de.symeda.sormas.api.Disease; -import de.symeda.sormas.api.caze.Vaccine; -import de.symeda.sormas.api.feature.FeatureConfigurationIndexDto; -import de.symeda.sormas.api.feature.FeatureType; -import de.symeda.sormas.api.infrastructure.facility.FacilityType; -import de.symeda.sormas.api.sample.PathogenTestDto; -import de.symeda.sormas.api.sample.PathogenTestResultType; -import de.symeda.sormas.api.sample.PathogenTestType; -import de.symeda.sormas.api.sample.SampleDto; -import de.symeda.sormas.api.sample.SampleMaterial; -import de.symeda.sormas.api.utils.YesNoUnknown; -import de.symeda.sormas.api.vaccination.VaccinationDto; import java.io.File; import java.io.IOException; import java.io.Writer; @@ -39,7 +27,6 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; -import java.util.Date; import java.util.List; import java.util.function.BiFunction; import java.util.function.Consumer; @@ -54,16 +41,26 @@ import com.opencsv.exceptions.CsvValidationException; import com.vaadin.ui.UI; +import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.caze.CaseDataDto; +import de.symeda.sormas.api.caze.Vaccine; import de.symeda.sormas.api.importexport.InvalidColumnException; import de.symeda.sormas.api.importexport.ValueSeparator; +import de.symeda.sormas.api.infrastructure.facility.FacilityType; import de.symeda.sormas.api.person.PersonDto; import de.symeda.sormas.api.person.PersonHelper; import de.symeda.sormas.api.person.PersonSimilarityCriteria; import de.symeda.sormas.api.person.SimilarPersonDto; +import de.symeda.sormas.api.sample.PathogenTestDto; +import de.symeda.sormas.api.sample.PathogenTestResultType; +import de.symeda.sormas.api.sample.PathogenTestType; +import de.symeda.sormas.api.sample.SampleDto; +import de.symeda.sormas.api.sample.SampleMaterial; import de.symeda.sormas.api.user.UserDto; import de.symeda.sormas.api.user.UserRole; +import de.symeda.sormas.api.utils.YesNoUnknown; +import de.symeda.sormas.api.vaccination.VaccinationDto; import de.symeda.sormas.ui.AbstractBeanTest; import de.symeda.sormas.ui.TestDataCreator; import de.symeda.sormas.ui.importer.CaseImportSimilarityInput; @@ -121,7 +118,7 @@ protected void handlePersonSimilarity( assertEquals("ABC-DEF-GHI-19-5", getCaseFacade().getAllActiveCasesAfter(null).get(4).getEpidNumber()); // Similarity: pick - List persons = FacadeProvider.getPersonFacade().getSimilarPersonDtos(user.toReference(), new PersonSimilarityCriteria()); + List persons = FacadeProvider.getPersonFacade().getSimilarPersonDtos(new PersonSimilarityCriteria()); csvFile = new File(getClass().getClassLoader().getResource("sormas_import_test_similarities.csv").toURI()); caseImporter = new CaseImporterExtension(csvFile, true, user) { @@ -359,7 +356,7 @@ public void testImportWithSamples() throws IOException, InterruptedException, Cs TestDataCreator.RDCF rdcf = creator.createRDCF(); creator.createFacility("Lab", FacilityType.LABORATORY, rdcf.region.toReference(), rdcf.district.toReference(), rdcf.community.toReference()); UserDto user = creator - .createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); + .createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); // import of 3 cases with different number of samples File csvFile = new File(getClass().getClassLoader().getResource("sormas_case_import_test_samples.csv").toURI()); @@ -380,19 +377,20 @@ public void testImportWithSamples() throws IOException, InterruptedException, Cs List case3Samples = getSampleFacade().getByCaseUuids(Collections.singletonList(case3.getUuid())); assertEquals(2, case3Samples.size()); - assertEquals("Should have one blood sample",1, case3Samples.stream().filter(s -> s.getSampleMaterial() == SampleMaterial.BLOOD).count()); + assertEquals("Should have one blood sample", 1, case3Samples.stream().filter(s -> s.getSampleMaterial() == SampleMaterial.BLOOD).count()); assertEquals("Should have one stool sample", 1, case3Samples.stream().filter(s -> s.getSampleMaterial() == SampleMaterial.STOOL).count()); } @Test - public void testImportWithPathogenTests() throws IOException, InterruptedException, CsvValidationException, InvalidColumnException, URISyntaxException { + public void testImportWithPathogenTests() + throws IOException, InterruptedException, CsvValidationException, InvalidColumnException, URISyntaxException { TestDataCreator creator = new TestDataCreator(); TestDataCreator.RDCF rdcf = creator.createRDCF(); creator.createFacility("Lab", FacilityType.LABORATORY, rdcf.region.toReference(), rdcf.district.toReference(), rdcf.community.toReference()); UserDto user = creator - .createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); + .createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); // import of 3 cases with different number of samples and pathogen tests File csvFile = new File(getClass().getClassLoader().getResource("sormas_case_import_test_pathogen_tests.csv").toURI()); @@ -431,13 +429,14 @@ public void testImportWithPathogenTests() throws IOException, InterruptedExcepti @Test @Ignore("Remove ignore once we have replaced H2, and feature properties can be changed by code") - public void testImportWithVaccinations() throws IOException, InterruptedException, CsvValidationException, InvalidColumnException, URISyntaxException { + public void testImportWithVaccinations() + throws IOException, InterruptedException, CsvValidationException, InvalidColumnException, URISyntaxException { TestDataCreator creator = new TestDataCreator(); TestDataCreator.RDCF rdcf = creator.createRDCF(); creator.createFacility("Lab", FacilityType.LABORATORY, rdcf.region.toReference(), rdcf.district.toReference(), rdcf.community.toReference()); UserDto user = creator - .createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); + .createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); // import of 3 cases with different number of vaccinations File csvFile = new File(getClass().getClassLoader().getResource("sormas_case_import_test_vaccinations.csv").toURI()); @@ -450,15 +449,18 @@ public void testImportWithVaccinations() throws IOException, InterruptedExceptio CaseDataDto case2 = getCaseFacade().getByExternalId("case2").get(0); CaseDataDto case3 = getCaseFacade().getByExternalId("case3").get(0); - List case1Vaccinations = FacadeProvider.getVaccinationFacade().getAllVaccinations(case1.getPerson().getUuid(), Disease.CORONAVIRUS); + List case1Vaccinations = + FacadeProvider.getVaccinationFacade().getAllVaccinations(case1.getPerson().getUuid(), Disease.CORONAVIRUS); assertEquals(0, case1Vaccinations.size()); - List case2Vaccinations = FacadeProvider.getVaccinationFacade().getAllVaccinations(case2.getPerson().getUuid(), Disease.CORONAVIRUS); + List case2Vaccinations = + FacadeProvider.getVaccinationFacade().getAllVaccinations(case2.getPerson().getUuid(), Disease.CORONAVIRUS); assertEquals(1, case2Vaccinations.size()); assertEquals(Vaccine.COMIRNATY, case2Vaccinations.get(0).getVaccineName()); assertNull(case2Vaccinations.get(0).getHealthConditions().getChronicPulmonaryDisease()); - List case3Vaccinations = FacadeProvider.getVaccinationFacade().getAllVaccinations(case3.getPerson().getUuid(), Disease.CORONAVIRUS); + List case3Vaccinations = + FacadeProvider.getVaccinationFacade().getAllVaccinations(case3.getPerson().getUuid(), Disease.CORONAVIRUS); assertEquals(2, case3Vaccinations.size()); assertEquals(Vaccine.MRNA_1273, case3Vaccinations.get(0).getVaccineName()); assertEquals(YesNoUnknown.YES, case3Vaccinations.get(0).getHealthConditions().getChronicPulmonaryDisease()); diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/contact/importer/ContactImporterTest.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/contact/importer/ContactImporterTest.java index 83c0555f6e2..0209a1e74b1 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/contact/importer/ContactImporterTest.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/contact/importer/ContactImporterTest.java @@ -6,9 +6,6 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import de.symeda.sormas.api.caze.Vaccine; -import de.symeda.sormas.api.utils.YesNoUnknown; -import de.symeda.sormas.api.vaccination.VaccinationDto; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; @@ -39,6 +36,7 @@ import de.symeda.sormas.api.caze.CaseClassification; import de.symeda.sormas.api.caze.CaseDataDto; import de.symeda.sormas.api.caze.InvestigationStatus; +import de.symeda.sormas.api.caze.Vaccine; import de.symeda.sormas.api.contact.ContactCriteria; import de.symeda.sormas.api.contact.ContactDto; import de.symeda.sormas.api.importexport.InvalidColumnException; @@ -49,6 +47,8 @@ import de.symeda.sormas.api.person.SimilarPersonDto; import de.symeda.sormas.api.user.UserDto; import de.symeda.sormas.api.user.UserRole; +import de.symeda.sormas.api.utils.YesNoUnknown; +import de.symeda.sormas.api.vaccination.VaccinationDto; import de.symeda.sormas.backend.contact.ContactFacadeEjb; import de.symeda.sormas.backend.contact.ContactFacadeEjb.ContactFacadeEjbLocal; import de.symeda.sormas.ui.AbstractBeanTest; @@ -88,7 +88,7 @@ public void testImportCaseContacts() assertEquals(5, contactFacade.count(null)); // Person Similarity: pick - List persons = FacadeProvider.getPersonFacade().getSimilarPersonDtos(user.toReference(), new PersonSimilarityCriteria()); + List persons = FacadeProvider.getPersonFacade().getSimilarPersonDtos(new PersonSimilarityCriteria()); csvFile = new File(getClass().getClassLoader().getResource("sormas_case_contact_import_test_similarities.csv").toURI()); contactImporter = new ContactImporterExtension(csvFile, user, caze) { @@ -276,10 +276,11 @@ public void testImportCaseContactsDifferentAddressTypes() @Test @Ignore("Remove ignore once we have replaced H2, and feature properties can be changed by code") - public void testImportContactsWithVaccinations() throws IOException, InterruptedException, CsvValidationException, InvalidColumnException, URISyntaxException { + public void testImportContactsWithVaccinations() + throws IOException, InterruptedException, CsvValidationException, InvalidColumnException, URISyntaxException { RDCF rdcf = creator.createRDCF("Abia", "Umuahia North", "Urban Ward 2", "Anelechi Hospital"); UserDto user = creator - .createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); + .createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); File csvFile = new File(getClass().getClassLoader().getResource("sormas_contact_import_test_vaccinations.csv").toURI()); ContactImporterExtension contactImporter = new ContactImporterExtension(csvFile, user, null); @@ -294,15 +295,18 @@ public void testImportContactsWithVaccinations() throws IOException, Interrupted ContactDto contact2 = contacts.stream().filter(c -> c.getCaseIdExternalSystem().equals("case2")).findFirst().get(); ContactDto contact3 = contacts.stream().filter(c -> c.getCaseIdExternalSystem().equals("case3")).findFirst().get(); - List case1Vaccinations = FacadeProvider.getVaccinationFacade().getAllVaccinations(contact1.getPerson().getUuid(), Disease.CORONAVIRUS); + List case1Vaccinations = + FacadeProvider.getVaccinationFacade().getAllVaccinations(contact1.getPerson().getUuid(), Disease.CORONAVIRUS); assertEquals(0, case1Vaccinations.size()); - List case2Vaccinations = FacadeProvider.getVaccinationFacade().getAllVaccinations(contact2.getPerson().getUuid(), Disease.CORONAVIRUS); + List case2Vaccinations = + FacadeProvider.getVaccinationFacade().getAllVaccinations(contact2.getPerson().getUuid(), Disease.CORONAVIRUS); assertEquals(1, case2Vaccinations.size()); assertEquals(Vaccine.COMIRNATY, case2Vaccinations.get(0).getVaccineName()); assertNull(case2Vaccinations.get(0).getHealthConditions().getChronicPulmonaryDisease()); - List case3Vaccinations = FacadeProvider.getVaccinationFacade().getAllVaccinations(contact3.getPerson().getUuid(), Disease.CORONAVIRUS); + List case3Vaccinations = + FacadeProvider.getVaccinationFacade().getAllVaccinations(contact3.getPerson().getUuid(), Disease.CORONAVIRUS); assertEquals(2, case3Vaccinations.size()); assertEquals(Vaccine.MRNA_1273, case3Vaccinations.get(0).getVaccineName()); assertEquals(YesNoUnknown.YES, case3Vaccinations.get(0).getHealthConditions().getChronicPulmonaryDisease()); diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/event/eventparticipantimporter/EventParticipantImporterTest.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/event/eventparticipantimporter/EventParticipantImporterTest.java index 853769def3f..6ed60e29be3 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/event/eventparticipantimporter/EventParticipantImporterTest.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/event/eventparticipantimporter/EventParticipantImporterTest.java @@ -21,14 +21,8 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import de.symeda.sormas.api.caze.Vaccine; -import de.symeda.sormas.api.contact.ContactDto; -import de.symeda.sormas.api.utils.YesNoUnknown; -import de.symeda.sormas.api.vaccination.VaccinationDto; import java.io.File; import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; import java.io.Writer; import java.net.URISyntaxException; import java.nio.file.Path; @@ -52,6 +46,7 @@ import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.caze.CaseClassification; import de.symeda.sormas.api.caze.InvestigationStatus; +import de.symeda.sormas.api.caze.Vaccine; import de.symeda.sormas.api.event.EventDto; import de.symeda.sormas.api.event.EventParticipantCriteria; import de.symeda.sormas.api.event.EventParticipantDto; @@ -68,6 +63,8 @@ import de.symeda.sormas.api.user.UserDto; import de.symeda.sormas.api.user.UserRole; import de.symeda.sormas.api.utils.DateHelper; +import de.symeda.sormas.api.utils.YesNoUnknown; +import de.symeda.sormas.api.vaccination.VaccinationDto; import de.symeda.sormas.backend.event.EventParticipantFacadeEjb.EventParticipantFacadeEjbLocal; import de.symeda.sormas.ui.AbstractBeanTest; import de.symeda.sormas.ui.TestDataCreator.RDCF; @@ -151,7 +148,7 @@ public void testImportEventParticipantSimilarityPick() rdcf); // Person Similarity: pick - List persons = FacadeProvider.getPersonFacade().getSimilarPersonDtos(user.toReference(), new PersonSimilarityCriteria()); + List persons = FacadeProvider.getPersonFacade().getSimilarPersonDtos(new PersonSimilarityCriteria()); File csvFile = new File(getClass().getClassLoader().getResource("sormas_eventparticipant_import_test_similarities.csv").toURI()); EventParticipantImporterExtension eventParticipantImporter = new EventParticipantImporterExtension(csvFile, user, event) { @@ -215,7 +212,7 @@ public void testImportEventParticipantSimilarityPickEventParticipant() EventParticipantDto eventParticipant = creator.createEventParticipant(eventRef, person, "old desc", user.toReference()); // Person Similarity: pick event participant - List persons = FacadeProvider.getPersonFacade().getSimilarPersonDtos(user.toReference(), new PersonSimilarityCriteria()); + List persons = FacadeProvider.getPersonFacade().getSimilarPersonDtos(new PersonSimilarityCriteria()); File csvFile = new File(getClass().getClassLoader().getResource("sormas_eventparticipant_import_test_similarities.csv").toURI()); EventParticipantImporterExtension eventParticipantImporter = new EventParticipantImporterExtension(csvFile, user, event) { @@ -437,23 +434,24 @@ public void testImportEventParticipantDifferentAddressTypes() @Test @Ignore("Remove ignore once we have replaced H2, and feature properties can be changed by code") - public void testImportWithVaccinations() throws URISyntaxException, IOException, InterruptedException, CsvValidationException, InvalidColumnException { + public void testImportWithVaccinations() + throws URISyntaxException, IOException, InterruptedException, CsvValidationException, InvalidColumnException { RDCF rdcf = creator.createRDCF("Region", "District", "Community", "Facility"); UserDto user = creator - .createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); + .createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); EventDto event = creator.createEvent( - EventStatus.SIGNAL, - "Title", - "Description", - "First", - "Name", - "12345", - TypeOfPlace.PUBLIC_PLACE, - DateHelper.subtractDays(new Date(), 2), - new Date(), - user.toReference(), - user.toReference(), - Disease.CORONAVIRUS); + EventStatus.SIGNAL, + "Title", + "Description", + "First", + "Name", + "12345", + TypeOfPlace.PUBLIC_PLACE, + DateHelper.subtractDays(new Date(), 2), + new Date(), + user.toReference(), + user.toReference(), + Disease.CORONAVIRUS); // Successful import of 5 event participant File csvFile = new File(getClass().getClassLoader().getResource("sormas_eventparticipant_import_test_vaccinations.csv").toURI()); @@ -470,15 +468,18 @@ public void testImportWithVaccinations() throws URISyntaxException, IOException, EventParticipantDto ep2 = eventParticipants.stream().filter(e -> e.getPerson().getFirstName().equals("Peter")).findFirst().get(); EventParticipantDto ep3 = eventParticipants.stream().filter(e -> e.getPerson().getFirstName().equals("Hans")).findFirst().get(); - List case1Vaccinations = FacadeProvider.getVaccinationFacade().getAllVaccinations(ep1.getPerson().getUuid(), Disease.CORONAVIRUS); + List case1Vaccinations = + FacadeProvider.getVaccinationFacade().getAllVaccinations(ep1.getPerson().getUuid(), Disease.CORONAVIRUS); assertEquals(0, case1Vaccinations.size()); - List case2Vaccinations = FacadeProvider.getVaccinationFacade().getAllVaccinations(ep2.getPerson().getUuid(), Disease.CORONAVIRUS); + List case2Vaccinations = + FacadeProvider.getVaccinationFacade().getAllVaccinations(ep2.getPerson().getUuid(), Disease.CORONAVIRUS); assertEquals(1, case2Vaccinations.size()); assertEquals(Vaccine.COMIRNATY, case2Vaccinations.get(0).getVaccineName()); assertNull(case2Vaccinations.get(0).getHealthConditions().getChronicPulmonaryDisease()); - List case3Vaccinations = FacadeProvider.getVaccinationFacade().getAllVaccinations(ep3.getPerson().getUuid(), Disease.CORONAVIRUS); + List case3Vaccinations = + FacadeProvider.getVaccinationFacade().getAllVaccinations(ep3.getPerson().getUuid(), Disease.CORONAVIRUS); assertEquals(2, case3Vaccinations.size()); assertEquals(Vaccine.MRNA_1273, case3Vaccinations.get(0).getVaccineName()); assertEquals(YesNoUnknown.YES, case3Vaccinations.get(0).getHealthConditions().getChronicPulmonaryDisease()); @@ -492,8 +493,7 @@ private static class EventParticipantImporterExtension extends EventParticipantI public StringBuilder stringBuilder = new StringBuilder(); private StringBuilderWriter writer = new StringBuilderWriter(stringBuilder); - private EventParticipantImporterExtension(File inputFile, UserDto currentUser, EventDto event) - throws IOException { + private EventParticipantImporterExtension(File inputFile, UserDto currentUser, EventDto event) throws IOException { super(inputFile, currentUser, event, ValueSeparator.DEFAULT); } diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/event/importer/EventImporterTest.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/event/importer/EventImporterTest.java index 3262b12f6d4..750feff2b29 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/event/importer/EventImporterTest.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/event/importer/EventImporterTest.java @@ -85,7 +85,7 @@ protected void handlePersonSimilarity(PersonDto newPerson, Consumer persons = FacadeProvider.getPersonFacade().getSimilarPersonDtos(user.toReference(), new PersonSimilarityCriteria()); + List persons = FacadeProvider.getPersonFacade().getSimilarPersonDtos(new PersonSimilarityCriteria()); csvFile = new File(getClass().getClassLoader().getResource("sormas_event_import_test_similarities.csv").toURI()); eventImporter = new EventImporterExtension(csvFile, true, user) { From 8b5f67e88f31df5e37d6c465d3bb07026d5c9c8c Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Tue, 8 Feb 2022 12:54:20 +0100 Subject: [PATCH 032/253] Added scenario [SORDEV 5570] to Event.feature --- .../application/events/EditEventPage.java | 7 +++ .../events/EventDirectoryPage.java | 3 +- .../application/events/EditEventSteps.java | 49 +++++++++++++++++++ .../events/EventDirectorySteps.java | 12 +++-- .../features/sanity/web/Event.feature | 21 +++++++- 5 files changed, 86 insertions(+), 6 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EditEventPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EditEventPage.java index b9adf74157d..1df703bf043 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EditEventPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EditEventPage.java @@ -56,6 +56,8 @@ public class EditEventPage { public static final By LINK_EVENT_GROUP_BUTTON = By.cssSelector("div#Link\\ event\\ group"); public static final By NEW_EVENT_GROUP_RADIOBUTTON = By.xpath("//*[contains(text(),'New event group')]/.."); + public static final By SELECT_EVENT_GROUP_RADIOBUTTON = + By.xpath("//*[contains(text(),'Select event group')]/.."); public static final By GROUP_EVENT_NAME_POPUP_INPUT = By.cssSelector(".popupContent #name"); public static final By GROUP_EVENT_UUID = By.xpath("//*[contains(text(),'Group id')]/../following-sibling::input[1]"); @@ -69,6 +71,11 @@ public class EditEventPage { By.cssSelector(".popupContent [id='Create']"); public static final By CANCEL_EVENT_HANDOUT_BUTTON = By.cssSelector(".popupContent [id='Cancel']"); + public static final By UNLINK_EVENT_BUTTON = By.id("unlink-event-1"); + public static final By EDIT_EVENT_GROUP_BUTTON = By.id("add-event-0"); + public static final By NAVIGATE_TO_EVENT_DIRECTORY_EVENT_GROUP_BUTTON = By.id("list-events-0"); + public static final By SAVE_BUTTON_FOR_EDIT_EVENT_GROUP = By.id("commit"); + public static final By FIRST_GROUP_ID = By.xpath("//table/tbody/tr[1]/td[2]"); public static By getGroupEventName(String groupEventName) { return By.xpath("//*[contains(text(),'" + groupEventName + "')]"); diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java index 9a6ae95bc19..6371681dacc 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java @@ -59,8 +59,9 @@ public class EventDirectoryPage { public static final By FIRST_EVENT_ID_BUTTON = By.cssSelector(".v-grid-row-has-data a[title]"); public static final By CREATE_CASE_BUTTON = By.xpath("//td//span[contains(@class, 'v-icon-edit')]"); + public static final By TOTAL_EVENTS_COUNTER = By.cssSelector(".badge"); public static By getByEventUuid(String eventUuid) { return By.xpath(String.format("//a[@title='%s']", eventUuid)); } -} \ No newline at end of file +} diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java index 07173bdfbf1..8a187ffe6fb 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java @@ -37,6 +37,7 @@ import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.List; +import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.inject.Named; import org.sormas.e2etests.enums.DistrictsValues; @@ -241,6 +242,54 @@ public EditEventSteps( webDriverHelpers.clickOnWebElementBySelector(LINK_EVENT_GROUP_BUTTON); }); + When( + "I choose select event group Radiobutton", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.clickOnWebElementBySelector(SELECT_EVENT_GROUP_RADIOBUTTON); + }); + + When( + "I select the first row from table and I click on save button", + () -> { + webDriverHelpers.clickOnWebElementBySelector(FIRST_GROUP_ID); + TimeUnit.SECONDS.sleep(3); + webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON_FOR_POPUP_WINDOWS); + }); + + When( + "I unlinked the first chosen group by click on Unlink event group button", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.scrollToElement(UNLINK_EVENT_BUTTON); + webDriverHelpers.clickOnWebElementBySelector(UNLINK_EVENT_BUTTON); + }); + + When( + "I click on edit event group button from event groups box", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.scrollToElement(EDIT_EVENT_GROUP_BUTTON); + webDriverHelpers.clickOnWebElementBySelector(EDIT_EVENT_GROUP_BUTTON); + webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON_FOR_EDIT_EVENT_GROUP); + }); + + When( + "I click on Edit event button to back Event form", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.clickOnWebElementBySelector(EDIT_EVENT_GROUP_BUTTON); + }); + + When( + "I click on the Navigate to event directory filtered on this event group", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.scrollToElement(NAVIGATE_TO_EVENT_DIRECTORY_EVENT_GROUP_BUTTON); + webDriverHelpers.clickOnWebElementBySelector( + NAVIGATE_TO_EVENT_DIRECTORY_EVENT_GROUP_BUTTON); + }); + When( "^I create a new event group$", () -> { diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index cc66e48be37..c33d0fcac0e 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -92,9 +92,9 @@ public EventDirectorySteps( When( "I select random Disease filter among the filter options", () -> { + String disease = DiseasesValues.getRandomDiseaseCaption(); webDriverHelpers.waitForPageLoaded(); - webDriverHelpers.selectFromCombobox( - FILTER_BY_DISEASE, DiseasesValues.getRandomDiseaseCaption()); + webDriverHelpers.selectFromCombobox(FILTER_BY_DISEASE, disease); }); When( @@ -168,6 +168,7 @@ public EventDirectorySteps( webDriverHelpers.selectFromCombobox( FILTER_BY_TYPE_OF_PLACE, TypeOfPlace.getValueFor(sourceTypeOfPlace)); }); + When( "I select random Type of Place field among the filter options", () -> { @@ -254,17 +255,20 @@ public EventDirectorySteps( When( "I open the first event from events list", () -> webDriverHelpers.clickOnWebElementBySelector(FIRST_EVENT_ID_BUTTON)); + And( "I click Create Case for Event Participant", () -> webDriverHelpers.clickOnWebElementBySelector(CREATE_CASE_BUTTON)); + Then( "I check that number of displayed Event results is {int}", (Integer number) -> assertHelpers.assertWithPoll20Second( () -> Assert.assertEquals( - webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), + Integer.parseInt( + webDriverHelpers.getTextFromPresentWebElement(TOTAL_EVENTS_COUNTER)), number.intValue(), "Number of displayed cases is not correct"))); } -} \ No newline at end of file +} diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature index af875bb0fca..b2d42969c2b 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature @@ -230,4 +230,23 @@ Feature: Create events And I select Screening filter from quick filter And I select Cluster filter from quick filter And I select Dropped filter from quick filter - And I click on the RESET FILTERS button \ No newline at end of file + And I click on the RESET FILTERS button + + @issue=SORDEV-5570 + Scenario: Testing Event screen Impact + Given API: I create a new event + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in with National User + And I click on the Events button from navbar + Then I open the last created event via api + And I click on link event group + And I choose select event group Radiobutton + And I select the first row from table and I click on save button + And I click on link event group + And I create a new event group + Then I unlinked the first chosen group by click on Unlink event group button + And I click on edit event group button from event groups box + And I click on Edit event button to back Event form + And I click on the Navigate to event directory filtered on this event group + And I check that number of displayed Event results is 1 \ No newline at end of file From 543da05b92829807595b4c79723c2c5297309e24 Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Fri, 4 Feb 2022 13:52:10 +0100 Subject: [PATCH 033/253] Added scenario "Check all filters are work properly in Samples directory" to SampleFilters.feature --- .../e2etests/enums/SpecimenConditions.java | 10 +++++ .../samples/SamplesDirectoryPage.java | 2 + .../services/api/SampleApiService.java | 1 + .../samples/SamplesDirectorySteps.java | 45 +++++++++++++++++++ .../features/sanity/web/SampleFilters.feature | 23 ++++++++++ 5 files changed, 81 insertions(+) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java index a04009d088b..d91d1cf23d0 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java @@ -20,6 +20,7 @@ import java.util.Random; import lombok.Getter; +import lombok.SneakyThrows; @Getter public enum SpecimenConditions { @@ -32,6 +33,15 @@ public enum SpecimenConditions { condition = aSpecimen; } + @SneakyThrows + public static String getForName(String option) { + SpecimenConditions[] specimenConditionOptions = SpecimenConditions.values(); + for (SpecimenConditions value : specimenConditionOptions) { + if (value.condition.equalsIgnoreCase(option)) return value.condition; + } + throw new Exception("Unable to find " + option + " value in RiskLevelValues Enum"); + } + public static String getRandomCondition() { Random random = new Random(); return String.valueOf(SpecimenConditions.values()[random.nextInt(values().length)]); diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java index 3d361320743..920a2eecc75 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java @@ -41,4 +41,6 @@ public class SamplesDirectoryPage { By.cssSelector(("tbody>tr:first-child>td:last-child")); public static final By EDIT_TEST_RESULTS_BUTTON = By.cssSelector("[location='pathogenTests'] [class='v-slot v-slot-s-list'] [role='button']"); + public static final By CASE_CLASIFICATION_SEARCH_COMBOBOX = + By.cssSelector("[id='caseClassification'] [class='v-filterselect-button']"); } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/SampleApiService.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/SampleApiService.java index 36baf030633..48a763db8bc 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/SampleApiService.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/SampleApiService.java @@ -37,6 +37,7 @@ public Sample buildGeneratedSample(Case caze) { .associatedCase(AssociatedCase.builder().uuid(caze.getUuid()).build()) .sampleMaterial("BLOOD") .samplePurpose("EXTERNAL") + .specimenCondition("ADEQUATE") .pathogenTestResult("PENDING") .lab( Lab.builder() diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java index 1e8d421faa4..39c266eda38 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java @@ -23,8 +23,10 @@ import com.google.common.truth.Truth; import cucumber.api.java8.En; import java.util.Arrays; +import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.inject.Named; +import org.sormas.e2etests.enums.CaseClassification; import org.sormas.e2etests.enums.LaboratoryValues; import org.sormas.e2etests.enums.PathogenTestResults; import org.sormas.e2etests.enums.SpecimenConditions; @@ -43,6 +45,49 @@ public SamplesDirectorySteps( ApiState apiState, AssertHelpers assertHelpers) { + When( + "I click a apply button in Sample", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.clickOnWebElementBySelector(APPLY_FILTER_BUTTON); + TimeUnit.SECONDS.sleep(3); + }); + When( + "fill a Full name of person from API", + () -> { + webDriverHelpers.fillAndSubmitInWebElement( + SAMPLE_SEARCH_INPUT, + apiState.getLastCreatedPerson().getFirstName() + + " " + + apiState.getLastCreatedPerson().getLastName()); + }); + When( + "I select Test result filter among the filter options from API", + () -> { + String testResult = apiState.getCreatedSample().getPathogenTestResult(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + TEST_RESULTS_SEARCH_COMBOBOX, + testResult.substring(0, 1).toUpperCase() + testResult.substring(1).toLowerCase()); + }); + When( + "I select Specimen condition filter among the filter options from API", + () -> { + String specimenCondition = apiState.getCreatedSample().getSpecimenCondition(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + SPECIMEN_CONDITION_SEARCH_COMBOBOX, SpecimenConditions.getForName(specimenCondition)); + }); + When( + "I select Case clasification filter among the filter options from API", + () -> { + String caseSpecification = apiState.getCreatedCase().getCaseClassification(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + SPECIMEN_CONDITION_SEARCH_COMBOBOX, + CaseClassification.getUIValueFor(caseSpecification)); + }); + When( "^I search last created Sample by Case ID$", () -> { diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature index ad658b66fca..800aae17699 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature @@ -13,3 +13,26 @@ Feature: Sample filter functionality Then I check the displayed specimen condition filter dropdown When I search for samples created with the API Then I check the displayed Laboratory filter dropdown + + @issue=SORDEV-5981 + Scenario: Check all filters are work properly in Samples directory + Given API: I create a new person + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given API: I create a new case + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given API: I create a new sample + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in with National User + When I click on the Sample button from navbar + Then fill a Full name of person from API + And I select Test result filter among the filter options from API + And I select Specimen condition filter among the filter options from API + And I select Case clasification filter among the filter options from API + And I click a apply button in Sample + And I check that number of displayed sample results is 1 + + + And I fill all fields for a new case created for event participant From d69ddd8b87ab8402bdb95bc73177de982aa1b883 Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Sat, 5 Feb 2022 14:15:05 +0100 Subject: [PATCH 034/253] Added the next steps to scenario [SORDEV-5981] to SampleFilters.feature,Modyfied CaseApiService.java and Enums: CaseClassification, DiseasesValues, DistrictsValues, PathogenTestResults, RegionsValues, --- .../e2etests/enums/CaseClassification.java | 2 +- .../sormas/e2etests/enums/DiseasesValues.java | 2 +- .../e2etests/enums/DistrictsValues.java | 8 +- .../e2etests/enums/PathogenTestResults.java | 6 + .../sormas/e2etests/enums/RegionsValues.java | 10 ++ .../e2etests/enums/SpecimenConditions.java | 2 +- .../samples/SamplesDirectoryPage.java | 12 +- .../e2etests/services/api/CaseApiService.java | 4 +- .../samples/SamplesDirectorySteps.java | 128 +++++++++++++++++- .../features/sanity/web/SampleFilters.feature | 42 +++++- 10 files changed, 196 insertions(+), 20 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CaseClassification.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CaseClassification.java index 459569f04ac..6e445fb7cb5 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CaseClassification.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CaseClassification.java @@ -44,7 +44,7 @@ public enum CaseClassification { public static String getUIValueFor(String option) { CaseClassification[] classifications = CaseClassification.values(); for (CaseClassification value : classifications) { - if (value.getClassificationUIvalue().equalsIgnoreCase(option)) + if (value.getClassificationAPIvalue().equalsIgnoreCase(option)) return value.getClassificationUIvalue(); } throw new Exception("Unable to find " + option + " value in CaseClassification Enum"); diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DiseasesValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DiseasesValues.java index 44a6298e7be..bfb24366169 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DiseasesValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DiseasesValues.java @@ -71,7 +71,7 @@ public static String getCaptionForName(String option) { for (DiseasesValues value : diseasesOptions) { if (value.getDiseaseName().equalsIgnoreCase(option)) return value.getDiseaseCaption(); } - throw new Exception("Unable to find " + option + " value in SourceTypeValues Enum"); + throw new Exception("Unable to find " + option + " value in DiseasesValues Enum"); } /** Returns values used for API tests */ diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java index 29719d59e97..ae68e2bb24f 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java @@ -34,10 +34,10 @@ public enum DistrictsValues { @SneakyThrows public static String getValueFor(String option) { - DistrictsValues[] districtsValues = DistrictsValues.values(); - for (DistrictsValues value : districtsValues) { - if (value.getName().equalsIgnoreCase(option)) return value.getName(); + DistrictsValues[] districtValuesOptions = DistrictsValues.values(); + for (DistrictsValues value : districtValuesOptions) { + if (value.uuid.equalsIgnoreCase(option)) return value.name; } - throw new Exception("Unable to find " + option + " value in DistrictsValues Enum"); + throw new Exception("Unable to find " + option + " value in District Enum"); } } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PathogenTestResults.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PathogenTestResults.java index 9fd68be42e9..8eda3830839 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PathogenTestResults.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PathogenTestResults.java @@ -39,4 +39,10 @@ public static String getRandomResult() { Random random = new Random(); return String.valueOf(PathogenTestResults.values()[random.nextInt(values().length)]); } + + public static String geRandomResultName() { + Random random = new Random(); + return String.valueOf( + PathogenTestResults.values()[random.nextInt(values().length)].pathogenResults); + } } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RegionsValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RegionsValues.java index a70fcc5bf0b..51206d98035 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RegionsValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RegionsValues.java @@ -18,6 +18,7 @@ package org.sormas.e2etests.enums; import lombok.Getter; +import lombok.SneakyThrows; @Getter public enum RegionsValues { @@ -30,4 +31,13 @@ public enum RegionsValues { this.name = name; this.uuid = uuid; } + + @SneakyThrows + public static String getValueFor(String option) { + RegionsValues[] regionValuesOptions = RegionsValues.values(); + for (RegionsValues value : regionValuesOptions) { + if (value.uuid.equalsIgnoreCase(option)) return value.name; + } + throw new Exception("Unable to find " + option + " value in Region Enum"); + } } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java index d91d1cf23d0..4c436588fbc 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java @@ -39,7 +39,7 @@ public static String getForName(String option) { for (SpecimenConditions value : specimenConditionOptions) { if (value.condition.equalsIgnoreCase(option)) return value.condition; } - throw new Exception("Unable to find " + option + " value in RiskLevelValues Enum"); + throw new Exception("Unable to find " + option + " value in SpecimenConditions Enum"); } public static String getRandomCondition() { diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java index 920a2eecc75..8c084b171b4 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java @@ -41,6 +41,16 @@ public class SamplesDirectoryPage { By.cssSelector(("tbody>tr:first-child>td:last-child")); public static final By EDIT_TEST_RESULTS_BUTTON = By.cssSelector("[location='pathogenTests'] [class='v-slot v-slot-s-list'] [role='button']"); - public static final By CASE_CLASIFICATION_SEARCH_COMBOBOX = + public static final By SAMPLE_CLASIFICATION_SEARCH_COMBOBOX = By.cssSelector("[id='caseClassification'] [class='v-filterselect-button']"); + public static final By SAMPLE_DISEASE_SEARCH_COMBOBOX = + By.cssSelector("[id='disease'] [class='v-filterselect-button']"); + public static final By SAMPLE_REGION_SEARCH_COMBOBOX = + By.cssSelector("[id='region'] [class='v-filterselect-button']"); + public static final By SAMPLE_DISTRICT_SEARCH_COMBOBOX = + By.cssSelector("[id='district'] [class='v-filterselect-button']"); + public static final By SAMPLE_NOT_SHIPPED = By.id("sampleNotShipped"); + public static final By SAMPLE_SHIPPED = By.id("sampleShipped"); + public static final By SAMPLE_RECEIVED = By.id("sampleReceived"); + public static final By SAMPLE_REFFERED_TO_OTHER_LAB = By.id("sampleReferred"); } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/CaseApiService.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/CaseApiService.java index fd25f041405..ae17b538ef9 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/CaseApiService.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/CaseApiService.java @@ -37,7 +37,7 @@ public CaseApiService() {} public Case buildGeneratedCase(Person person) { return Case.builder() - .disease(DiseasesValues.CORONAVIRUS.getDiseaseName()) + .disease(DiseasesValues.getRandomDiseaseName()) .diseaseDetails("Test Disease") .pseudonymized(false) .uuid(UUID.randomUUID().toString()) @@ -59,7 +59,7 @@ public Case buildGeneratedCase(Person person) { .firstName(person.getFirstName()) .lastName(person.getLastName()) .build()) - .caseClassification("NOT_CLASSIFIED") + .caseClassification(CaseClassification.getRandomAPIClassification()) .investigationStatus("PENDING") .outcome("NO_OUTCOME") .epiData(EpiData.builder().uuid(UUID.randomUUID().toString()).build()) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java index 39c266eda38..0fa6682e8e8 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java @@ -23,13 +23,9 @@ import com.google.common.truth.Truth; import cucumber.api.java8.En; import java.util.Arrays; -import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.inject.Named; -import org.sormas.e2etests.enums.CaseClassification; -import org.sormas.e2etests.enums.LaboratoryValues; -import org.sormas.e2etests.enums.PathogenTestResults; -import org.sormas.e2etests.enums.SpecimenConditions; +import org.sormas.e2etests.enums.*; import org.sormas.e2etests.helpers.AssertHelpers; import org.sormas.e2etests.helpers.WebDriverHelpers; import org.sormas.e2etests.state.ApiState; @@ -50,8 +46,15 @@ public SamplesDirectorySteps( () -> { webDriverHelpers.waitForPageLoaded(); webDriverHelpers.clickOnWebElementBySelector(APPLY_FILTER_BUTTON); - TimeUnit.SECONDS.sleep(3); }); + + When( + "I click a Reset button in Sample", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.clickOnWebElementBySelector(RESET_FILTER_BUTTON); + }); + When( "fill a Full name of person from API", () -> { @@ -61,6 +64,7 @@ public SamplesDirectorySteps( + " " + apiState.getLastCreatedPerson().getLastName()); }); + When( "I select Test result filter among the filter options from API", () -> { @@ -70,6 +74,15 @@ public SamplesDirectorySteps( TEST_RESULTS_SEARCH_COMBOBOX, testResult.substring(0, 1).toUpperCase() + testResult.substring(1).toLowerCase()); }); + + When( + "I select random Test result filter among the filter options", + () -> { + String testResult = PathogenTestResults.geRandomResultName(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(TEST_RESULTS_SEARCH_COMBOBOX, testResult); + }); + When( "I select Specimen condition filter among the filter options from API", () -> { @@ -78,16 +91,98 @@ public SamplesDirectorySteps( webDriverHelpers.selectFromCombobox( SPECIMEN_CONDITION_SEARCH_COMBOBOX, SpecimenConditions.getForName(specimenCondition)); }); + + When( + "I select {string} Specimen condition option among the filter options", + (String specimenCondition) -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + SPECIMEN_CONDITION_SEARCH_COMBOBOX, specimenCondition); + }); + When( "I select Case clasification filter among the filter options from API", () -> { String caseSpecification = apiState.getCreatedCase().getCaseClassification(); webDriverHelpers.waitForPageLoaded(); webDriverHelpers.selectFromCombobox( - SPECIMEN_CONDITION_SEARCH_COMBOBOX, + SAMPLE_CLASIFICATION_SEARCH_COMBOBOX, CaseClassification.getUIValueFor(caseSpecification)); }); + When( + "I select random Case clasification filter among the filter options", + () -> { + String caseSpecification = CaseClassification.getRandomUIClassification(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + SAMPLE_CLASIFICATION_SEARCH_COMBOBOX, caseSpecification); + }); + + When( + "I select Disease filter among the filter options from API", + () -> { + String disease = apiState.getCreatedCase().getDisease(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + SAMPLE_DISEASE_SEARCH_COMBOBOX, DiseasesValues.getCaptionForName(disease)); + }); + + When( + "I select random Disease filter among the filter options in Sample directory", + () -> { + String disease = DiseasesValues.getRandomDiseaseCaption(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(SAMPLE_DISEASE_SEARCH_COMBOBOX, disease); + }); + + When( + "I select Region filter among the filter options from API", + () -> { + String region = apiState.getCreatedCase().getRegion().getUuid(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + SAMPLE_REGION_SEARCH_COMBOBOX, RegionsValues.getValueFor(region)); + }); + + When( + "I change Region filter to {string} option in Sample directory", + (String region) -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(SAMPLE_REGION_SEARCH_COMBOBOX, region); + }); + + When( + "I select District filter among the filter options from API", + () -> { + String district = apiState.getCreatedCase().getDistrict().getUuid(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + SAMPLE_DISTRICT_SEARCH_COMBOBOX, DistrictsValues.getValueFor(district)); + }); + + When( + "I change District filter to {string} option in Sample directory", + (String district) -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(SAMPLE_DISTRICT_SEARCH_COMBOBOX, district); + }); + + When( + "I select Laboratory filter among the filter options from API", + () -> { + String laboratory = apiState.getCreatedSample().getLab().getCaption(); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(LABORATORY_SEARCH_COMBOBOX, laboratory); + }); + + When( + "I change Labolatory filter to {string} option in Sample directory", + (String laboratory) -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(LABORATORY_SEARCH_COMBOBOX, laboratory); + }); + When( "^I search last created Sample by Case ID$", () -> { @@ -143,6 +238,25 @@ public SamplesDirectorySteps( "Number of created samples is wrong"); }); + Then( + "I select {string} filter from quick filter", + (String searchCriteria) -> { + switch (searchCriteria) { + case "Not shipped": + webDriverHelpers.clickOnWebElementBySelector(SAMPLE_NOT_SHIPPED); + break; + case "Shipped": + webDriverHelpers.clickOnWebElementBySelector(SAMPLE_SHIPPED); + break; + case "Received": + webDriverHelpers.clickOnWebElementBySelector(SAMPLE_RECEIVED); + break; + case "Referred to other lab": + webDriverHelpers.clickOnWebElementBySelector(SAMPLE_REFFERED_TO_OTHER_LAB); + break; + } + }); + Then( "^I check the displayed test results filter dropdown", () -> diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature index 800aae17699..db469520245 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature @@ -31,8 +31,44 @@ Feature: Sample filter functionality And I select Test result filter among the filter options from API And I select Specimen condition filter among the filter options from API And I select Case clasification filter among the filter options from API + And I select Disease filter among the filter options from API + And I select Region filter among the filter options from API + And I select District filter among the filter options from API + And I select Laboratory filter among the filter options from API And I click a apply button in Sample And I check that number of displayed sample results is 1 - - - And I fill all fields for a new case created for event participant + Then I select random Test result filter among the filter options + And I click a apply button in Sample + And I check that number of displayed sample results is 0 + And I select Test result filter among the filter options from API + Then I select "Not adequate" Specimen condition option among the filter options + And I click a apply button in Sample + And I check that number of displayed sample results is 0 + And I select Specimen condition filter among the filter options from API + Then I select random Case clasification filter among the filter options + And I click a apply button in Sample + And I check that number of displayed sample results is 0 + And I select Case clasification filter among the filter options from API + Then I select random Disease filter among the filter options in Sample directory + And I click a apply button in Sample + And I check that number of displayed sample results is 0 + And I select Disease filter among the filter options from API + Then I change Region filter to "Berlin" option in Sample directory + And I click a apply button in Sample + And I check that number of displayed sample results is 0 + And I select Region filter among the filter options from API + Then I change Region filter to "Region1" option in Sample directory + And I change District filter to "District11" option in Sample directory + And I click a apply button in Sample + And I check that number of displayed sample results is 0 + And I select Region filter among the filter options from API + And I select District filter among the filter options from API + Then I change Labolatory filter to "Other facility" option in Sample directory + And I click a apply button in Sample + And I check that number of displayed sample results is 0 + And I click a Reset button in Sample + Then I select "Not shipped" filter from quick filter + And I select "Shipped" filter from quick filter + And I select "Received" filter from quick filter + And I select "Referred to other lab" filter from quick filter + And I click a Reset button in Sample \ No newline at end of file From 79dfdb98406632f4c70ab03ff2b681b99f5d60a4 Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Mon, 7 Feb 2022 08:42:25 +0100 Subject: [PATCH 035/253] Added method to SpecimenConditions --- .../java/org/sormas/e2etests/enums/SpecimenConditions.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java index 4c436588fbc..60e9f8cab45 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java @@ -46,4 +46,9 @@ public static String getRandomCondition() { Random random = new Random(); return String.valueOf(SpecimenConditions.values()[random.nextInt(values().length)]); } + + public static String getRandomConditionName() { + Random random = new Random(); + return String.valueOf(SpecimenConditions.values()[random.nextInt(values().length)].condition); + } } From a097b9921018af1a3279e286a40f5ab259c1e398 Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Tue, 8 Feb 2022 13:25:46 +0100 Subject: [PATCH 036/253] Corrected SampleFilters.feature scenario and DistrictsValues enum --- .../e2etests/enums/DistrictsValues.java | 15 +++++++++++--- .../samples/SamplesDirectorySteps.java | 6 +++--- .../features/sanity/web/SampleFilters.feature | 20 +++++++++---------- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java index ae68e2bb24f..5d92f51d423 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java @@ -34,10 +34,19 @@ public enum DistrictsValues { @SneakyThrows public static String getValueFor(String option) { - DistrictsValues[] districtValuesOptions = DistrictsValues.values(); - for (DistrictsValues value : districtValuesOptions) { + DistrictsValues[] districtsValues = DistrictsValues.values(); + for (DistrictsValues value : districtsValues) { + if (value.getName().equalsIgnoreCase(option)) return value.getName(); + } + throw new Exception("Unable to find " + option + " value in DistrictsValues Enum"); + } + + @SneakyThrows + public static String getNameFor(String option) { + DistrictsValues[] districtsValues = DistrictsValues.values(); + for (DistrictsValues value : districtsValues) { if (value.uuid.equalsIgnoreCase(option)) return value.name; } - throw new Exception("Unable to find " + option + " value in District Enum"); + throw new Exception("Unable to find " + option + " value in DistrictsValues Enum"); } } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java index 0fa6682e8e8..8bb8fe65fe0 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java @@ -42,14 +42,14 @@ public SamplesDirectorySteps( AssertHelpers assertHelpers) { When( - "I click a apply button in Sample", + "I click a apply button on Sample", () -> { webDriverHelpers.waitForPageLoaded(); webDriverHelpers.clickOnWebElementBySelector(APPLY_FILTER_BUTTON); }); When( - "I click a Reset button in Sample", + "I click a Reset button on Sample", () -> { webDriverHelpers.waitForPageLoaded(); webDriverHelpers.clickOnWebElementBySelector(RESET_FILTER_BUTTON); @@ -158,7 +158,7 @@ public SamplesDirectorySteps( String district = apiState.getCreatedCase().getDistrict().getUuid(); webDriverHelpers.waitForPageLoaded(); webDriverHelpers.selectFromCombobox( - SAMPLE_DISTRICT_SEARCH_COMBOBOX, DistrictsValues.getValueFor(district)); + SAMPLE_DISTRICT_SEARCH_COMBOBOX, DistrictsValues.getNameFor(district)); }); When( diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature index db469520245..aeea8741880 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature @@ -35,40 +35,40 @@ Feature: Sample filter functionality And I select Region filter among the filter options from API And I select District filter among the filter options from API And I select Laboratory filter among the filter options from API - And I click a apply button in Sample + And I click a apply button on Sample And I check that number of displayed sample results is 1 Then I select random Test result filter among the filter options - And I click a apply button in Sample + And I click a apply button on Sample And I check that number of displayed sample results is 0 And I select Test result filter among the filter options from API Then I select "Not adequate" Specimen condition option among the filter options - And I click a apply button in Sample + And I click a apply button on Sample And I check that number of displayed sample results is 0 And I select Specimen condition filter among the filter options from API Then I select random Case clasification filter among the filter options - And I click a apply button in Sample + And I click a apply button on Sample And I check that number of displayed sample results is 0 And I select Case clasification filter among the filter options from API Then I select random Disease filter among the filter options in Sample directory - And I click a apply button in Sample + And I click a apply button on Sample And I check that number of displayed sample results is 0 And I select Disease filter among the filter options from API Then I change Region filter to "Berlin" option in Sample directory - And I click a apply button in Sample + And I click a apply button on Sample And I check that number of displayed sample results is 0 And I select Region filter among the filter options from API Then I change Region filter to "Region1" option in Sample directory And I change District filter to "District11" option in Sample directory - And I click a apply button in Sample + And I click a apply button on Sample And I check that number of displayed sample results is 0 And I select Region filter among the filter options from API And I select District filter among the filter options from API Then I change Labolatory filter to "Other facility" option in Sample directory - And I click a apply button in Sample + And I click a apply button on Sample And I check that number of displayed sample results is 0 - And I click a Reset button in Sample + And I click a Reset button on Sample Then I select "Not shipped" filter from quick filter And I select "Shipped" filter from quick filter And I select "Received" filter from quick filter And I select "Referred to other lab" filter from quick filter - And I click a Reset button in Sample \ No newline at end of file + And I click a Reset button on Sample \ No newline at end of file From d8c8e286d26bf1f555260c620818b551e2ebf008 Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Tue, 8 Feb 2022 14:37:37 +0100 Subject: [PATCH 037/253] Corrected Persons.feature scenario after review --- .../application/persons/PersonDirectorySteps.java | 12 ++++++++---- .../resources/features/sanity/web/Persons.feature | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java index b7389749d7c..5d27adc5b01 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java @@ -107,7 +107,6 @@ public PersonDirectorySteps( String personUUID = dataOperations.getPartialUuidFromAssociatedLink( apiState.getLastCreatedPerson().getUuid()); - System.out.println(personUUID); webDriverHelpers.waitForPageLoaded(); webDriverHelpers.fillInWebElement(MULTIPLE_OPTIONS_SEARCH_INPUT, personUUID); }); @@ -253,7 +252,7 @@ public PersonDirectorySteps( }); Then( - "I search after last created person from API by {string}", + "I search after last created person from API by {string} in Person directory", (String searchCriteria) -> { String searchText = ""; String personUUID = apiState.getLastCreatedPerson().getUuid(); @@ -267,7 +266,12 @@ public PersonDirectorySteps( + " " + apiState.getLastCreatedPerson().getFirstName(); break; - // etc + case "phone number": + searchText = apiState.getLastCreatedPerson().getPhone(); + break; + case "email": + searchText = apiState.getLastCreatedPerson().getEmailAddress(); + break; } webDriverHelpers.waitUntilElementIsVisibleAndClickable(APPLY_FILTERS_BUTTON); webDriverHelpers.clickOnWebElementBySelector(ALL_BUTTON); @@ -282,7 +286,7 @@ public PersonDirectorySteps( }); Then( - "I search after last created person from API by factor {string}", + "I search after last created person from API by factor {string} in Person directory", (String searchCriteria) -> { String searchText = ""; String personUUID = apiState.getLastCreatedPerson().getUuid(); diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature index 1737609ce61..22ff155bed2 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature @@ -18,6 +18,7 @@ Feature: Edit Persons Then I click on save button from Edit Person page And I check that previous edited person is correctly displayed in Edit Person page + @issue=SORDEV-8466 Scenario: Check Filters on Person page work as expected Given API: I create a new person Then API: I check that POST call body is "OK" @@ -54,7 +55,7 @@ Feature: Edit Persons And I check that number of displayed Person results is 0 And I choose random value for Day of birth filter in Persons for the last created person by API Then I click on the APPLY FILTERS button for Person - And I search after last created person from API by factor "full name" + And I search after last created person from API by factor "full name" in Person directory And I click on the APPLY FILTERS button for Person And I check that number of displayed Person results is 1 Then I change "full name" information data field for Person @@ -81,4 +82,4 @@ Feature: Edit Persons Then I click on the APPLY FILTERS button for Person And I check that number of displayed Person results is 1 And I click on the APPLY FILTERS button for Person - And I click on the RESET FILTERS button for Person + And I click on the RESET FILTERS button for Person \ No newline at end of file From bb43f28a8b7425eccbf526b3be21180514e2a44f Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Tue, 8 Feb 2022 12:54:20 +0100 Subject: [PATCH 038/253] Added scenario [SORDEV 5570] to Event.feature --- .../application/events/EditEventPage.java | 7 +++ .../events/EventDirectoryPage.java | 3 +- .../application/events/EditEventSteps.java | 49 +++++++++++++++++++ .../events/EventDirectorySteps.java | 10 ++-- .../features/sanity/web/Event.feature | 21 +++++++- 5 files changed, 85 insertions(+), 5 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EditEventPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EditEventPage.java index b20e6fd57fb..0ad3300fbfa 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EditEventPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EditEventPage.java @@ -56,6 +56,8 @@ public class EditEventPage { public static final By LINK_EVENT_GROUP_BUTTON = By.cssSelector("div#Link\\ event\\ group"); public static final By NEW_EVENT_GROUP_RADIOBUTTON = By.xpath("//*[contains(text(),'New event group')]/.."); + public static final By SELECT_EVENT_GROUP_RADIOBUTTON = + By.xpath("//*[contains(text(),'Select event group')]/.."); public static final By GROUP_EVENT_NAME_POPUP_INPUT = By.cssSelector(".popupContent #name"); public static final By GROUP_EVENT_UUID = By.xpath("//*[contains(text(),'Group id')]/../following-sibling::input[1]"); @@ -69,6 +71,11 @@ public class EditEventPage { By.cssSelector(".popupContent [id='Create']"); public static final By CANCEL_EVENT_HANDOUT_BUTTON = By.cssSelector(".popupContent [id='Cancel']"); + public static final By UNLINK_EVENT_BUTTON = By.id("unlink-event-1"); + public static final By EDIT_EVENT_GROUP_BUTTON = By.id("add-event-0"); + public static final By NAVIGATE_TO_EVENT_DIRECTORY_EVENT_GROUP_BUTTON = By.id("list-events-0"); + public static final By SAVE_BUTTON_FOR_EDIT_EVENT_GROUP = By.id("commit"); + public static final By FIRST_GROUP_ID = By.xpath("//table/tbody/tr[1]/td[2]"); public static final By TOTAL_ACTIONS_COUNTER = By.cssSelector(".badge"); public static By getGroupEventName(String groupEventName) { diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java index 1014497c46b..5b4c5530647 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java @@ -60,8 +60,9 @@ public class EventDirectoryPage { public static final By FIRST_EVENT_ID_BUTTON = By.cssSelector(".v-grid-row-has-data a[title]"); public static final By CREATE_CASE_BUTTON = By.xpath("//td//span[contains(@class, 'v-icon-edit')]"); + public static final By TOTAL_EVENTS_COUNTER = By.cssSelector(".badge"); public static By getByEventUuid(String eventUuid) { return By.xpath(String.format("//a[@title='%s']", eventUuid)); } -} \ No newline at end of file +} diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java index cb8d2e6426e..008eca253fa 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java @@ -37,6 +37,7 @@ import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.List; +import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.inject.Named; import org.sormas.e2etests.enums.DistrictsValues; @@ -244,6 +245,54 @@ public EditEventSteps( webDriverHelpers.clickOnWebElementBySelector(LINK_EVENT_GROUP_BUTTON); }); + When( + "I choose select event group Radiobutton", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.clickOnWebElementBySelector(SELECT_EVENT_GROUP_RADIOBUTTON); + }); + + When( + "I select the first row from table and I click on save button", + () -> { + webDriverHelpers.clickOnWebElementBySelector(FIRST_GROUP_ID); + TimeUnit.SECONDS.sleep(3); + webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON_FOR_POPUP_WINDOWS); + }); + + When( + "I unlinked the first chosen group by click on Unlink event group button", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.scrollToElement(UNLINK_EVENT_BUTTON); + webDriverHelpers.clickOnWebElementBySelector(UNLINK_EVENT_BUTTON); + }); + + When( + "I click on edit event group button from event groups box", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.scrollToElement(EDIT_EVENT_GROUP_BUTTON); + webDriverHelpers.clickOnWebElementBySelector(EDIT_EVENT_GROUP_BUTTON); + webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON_FOR_EDIT_EVENT_GROUP); + }); + + When( + "I click on Edit event button to back Event form", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.clickOnWebElementBySelector(EDIT_EVENT_GROUP_BUTTON); + }); + + When( + "I click on the Navigate to event directory filtered on this event group", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.scrollToElement(NAVIGATE_TO_EVENT_DIRECTORY_EVENT_GROUP_BUTTON); + webDriverHelpers.clickOnWebElementBySelector( + NAVIGATE_TO_EVENT_DIRECTORY_EVENT_GROUP_BUTTON); + }); + When( "^I create a new event group$", () -> { diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index 80144fc6aa6..ce53fdb8a6e 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -92,9 +92,9 @@ public EventDirectorySteps( When( "I select random Disease filter among the filter options", () -> { + String disease = DiseasesValues.getRandomDiseaseCaption(); webDriverHelpers.waitForPageLoaded(); - webDriverHelpers.selectFromCombobox( - FILTER_BY_DISEASE, DiseasesValues.getRandomDiseaseCaption()); + webDriverHelpers.selectFromCombobox(FILTER_BY_DISEASE, disease); }); When( @@ -168,6 +168,7 @@ public EventDirectorySteps( webDriverHelpers.selectFromCombobox( FILTER_BY_TYPE_OF_PLACE, TypeOfPlace.getValueFor(sourceTypeOfPlace)); }); + When( "I select random Type of Place field among the filter options", () -> { @@ -260,16 +261,19 @@ public EventDirectorySteps( When( "I open the first event from events list", () -> webDriverHelpers.clickOnWebElementBySelector(FIRST_EVENT_ID_BUTTON)); + And( "I click Create Case for Event Participant", () -> webDriverHelpers.clickOnWebElementBySelector(CREATE_CASE_BUTTON)); + Then( "I check that number of displayed Event results is {int}", (Integer number) -> assertHelpers.assertWithPoll20Second( () -> Assert.assertEquals( - webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), + Integer.parseInt( + webDriverHelpers.getTextFromPresentWebElement(TOTAL_EVENTS_COUNTER)), number.intValue(), "Number of displayed cases is not correct"))); } diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature index 760368ae29a..31797c6e178 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature @@ -233,4 +233,23 @@ Feature: Create events And I select Screening filter from quick filter And I select Cluster filter from quick filter And I select Dropped filter from quick filter - And I click on the RESET FILTERS button \ No newline at end of file + And I click on the RESET FILTERS button + + @issue=SORDEV-5570 + Scenario: Testing Event screen Impact + Given API: I create a new event + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in with National User + And I click on the Events button from navbar + Then I open the last created event via api + And I click on link event group + And I choose select event group Radiobutton + And I select the first row from table and I click on save button + And I click on link event group + And I create a new event group + Then I unlinked the first chosen group by click on Unlink event group button + And I click on edit event group button from event groups box + And I click on Edit event button to back Event form + And I click on the Navigate to event directory filtered on this event group + And I check that number of displayed Event results is 1 \ No newline at end of file From 9b79c4dc3cea5ba7f4ac430a55ffc04a8b90f54f Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Tue, 8 Feb 2022 17:09:26 +0100 Subject: [PATCH 039/253] Fixied scenario [SORDEV 5570] after review --- .../steps/web/application/events/EditEventSteps.java | 7 +++---- .../src/test/resources/features/sanity/web/Event.feature | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java index 008eca253fa..ff2182de1aa 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java @@ -37,7 +37,6 @@ import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.List; -import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.inject.Named; import org.sormas.e2etests.enums.DistrictsValues; @@ -255,8 +254,8 @@ public EditEventSteps( When( "I select the first row from table and I click on save button", () -> { + webDriverHelpers.waitForPageLoaded(); webDriverHelpers.clickOnWebElementBySelector(FIRST_GROUP_ID); - TimeUnit.SECONDS.sleep(3); webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON_FOR_POPUP_WINDOWS); }); @@ -269,7 +268,7 @@ public EditEventSteps( }); When( - "I click on edit event group button from event groups box", + "I click on Edit event group button from event groups box", () -> { webDriverHelpers.waitForPageLoaded(); webDriverHelpers.scrollToElement(EDIT_EVENT_GROUP_BUTTON); @@ -278,7 +277,7 @@ public EditEventSteps( }); When( - "I click on Edit event button to back Event form", + "I click on Edit event button for the first event in Events section", () -> { webDriverHelpers.waitForPageLoaded(); webDriverHelpers.clickOnWebElementBySelector(EDIT_EVENT_GROUP_BUTTON); diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature index 31797c6e178..33fc9d10bb3 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature @@ -249,7 +249,7 @@ Feature: Create events And I click on link event group And I create a new event group Then I unlinked the first chosen group by click on Unlink event group button - And I click on edit event group button from event groups box - And I click on Edit event button to back Event form + And I click on Edit event group button from event groups box + And I click on Edit event button for the first event in Events section And I click on the Navigate to event directory filtered on this event group And I check that number of displayed Event results is 1 \ No newline at end of file From 6a47e5cd29e8058deef0304a37d4a8e167b271fc Mon Sep 17 00:00:00 2001 From: jparzuch Date: Wed, 9 Feb 2022 04:33:58 +0100 Subject: [PATCH 040/253] Added a test for error messages when editing a Person --- .../application/persons/EditPersonPage.java | 4 ++ .../contacts/PersonContactDetailsSteps.java | 16 ++++++++ .../application/persons/EditPersonSteps.java | 41 +++++++++++++++++++ .../persons/PersonDirectorySteps.java | 6 +++ .../features/sanity/web/Persons.feature | 18 +++++++- 5 files changed, 84 insertions(+), 1 deletion(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java index 8193c5fd0a6..d284684128d 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java @@ -103,6 +103,10 @@ public class EditPersonPage { "//*[contains(text(),'The case person was added as an event participant to the selected event.')]"); public static final By SEE_EVENTS_FOR_PERSON = By.cssSelector("div#See\\ events\\ for\\ this\\ person"); + public static final By INVALID_DATA_ERROR = + By.cssSelector(".v-Notification.error.v-Notification-error"); + public static final By ERROR_INDICATOR = + By.cssSelector(".v-errorindicator.v-errorindicator-info"); public static By getByPersonUuid(String personUuid) { return By.cssSelector("a[title='" + personUuid + "']"); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/PersonContactDetailsSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/PersonContactDetailsSteps.java index 634902c8d1f..aa0a49497c9 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/PersonContactDetailsSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/PersonContactDetailsSteps.java @@ -44,6 +44,22 @@ public PersonContactDetailsSteps(WebDriverHelpers webDriverHelpers) { newGeneratedPerson.getPersonContactDetailsContactInformation()); webDriverHelpers.clickOnWebElementBySelector(DONE_BUTTON); }); + + Then( + "I enter an incorrect phone number and confirm", + () -> { + selectTypeOfContactDetails("Phone"); + fillContactInformationInput("ABCdef!@#."); + webDriverHelpers.clickOnWebElementBySelector(DONE_BUTTON); + }); + + Then( + "I enter an incorrect email and confirm", + () -> { + selectTypeOfContactDetails("Email"); + fillContactInformationInput("1234567890"); + webDriverHelpers.clickOnWebElementBySelector(DONE_BUTTON); + }); } private void selectTypeOfContactDetails(String type) { diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java index 76e6fcb36f4..357dd37b36e 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java @@ -18,6 +18,10 @@ package org.sormas.e2etests.steps.web.application.persons; +import static org.sormas.e2etests.pages.application.contacts.CreateNewContactPage.SAVE_BUTTON; +import static org.sormas.e2etests.pages.application.contacts.EditContactPersonPage.CONTACT_PERSON_FIRST_NAME_INPUT; +import static org.sormas.e2etests.pages.application.contacts.EditContactPersonPage.CONTACT_PERSON_LAST_NAME_INPUT; +import static org.sormas.e2etests.pages.application.contacts.EditContactPersonPage.SEX_COMBOBOX; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.getByEventUuid; import static org.sormas.e2etests.pages.application.persons.EditPersonPage.*; @@ -143,6 +147,43 @@ public EditPersonSteps( webDriverHelpers.accessWebSite( environmentUrl + "/sormas-webdriver/#!persons/data/" + personUuid); }); + + When( + "I clear the mandatory Person fields", + () -> { + webDriverHelpers.clearWebElement(FIRST_NAME_INPUT); + webDriverHelpers.clearWebElement(LAST_NAME_INPUT); + webDriverHelpers.selectFromCombobox(SEX_COMBOBOX, ""); + }); + + When( + "^I check that an invalid data error message appears$", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.waitUntilIdentifiedElementIsPresent(INVALID_DATA_ERROR); + webDriverHelpers.clickOnWebElementBySelector(INVALID_DATA_ERROR); + }); + + Then( + "I fill in the home address, facility category and type", + () -> { + newGeneratedPerson = personService.buildGeneratedPerson(); + selectFacilityCategory(newGeneratedPerson.getFacilityCategory()); + selectFacilityType(newGeneratedPerson.getFacilityType()); + fillStreet(newGeneratedPerson.getStreet()); + fillHouseNumber(newGeneratedPerson.getHouseNumber()); + fillAdditionalInformation(newGeneratedPerson.getAdditionalInformation()); + fillPostalCode(newGeneratedPerson.getPostalCode()); + fillCity(newGeneratedPerson.getCity()); + selectAreaType(newGeneratedPerson.getAreaType()); + }); + + When( + "^I check that the empty district highlight appears$", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.waitUntilIdentifiedElementIsPresent(ERROR_INDICATOR); + }); } private void fillFirstName(String firstName) { diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java index 00f3aba5e3a..393b533910e 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java @@ -123,6 +123,12 @@ public PersonDirectorySteps( webDriverHelpers.clickOnWebElementBySelector(getByPersonUuid(personUuid)); }); + When( + "I click on first person in person directory", + () -> { + webDriverHelpers.clickOnWebElementBySelector(By.cssSelector("[role='gridcell'] a")); + }); + When( "I apply on the APPLY FILTERS button", () -> { diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature index 92b87f79931..6ff71ae640b 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature @@ -16,4 +16,20 @@ Feature: Edit Persons And While on Person edit page, I will edit all fields with new values And I edit all Person primary contact details and save Then I click on save button from Edit Person page - And I check that previous edited person is correctly displayed in Edit Person page \ No newline at end of file + And I check that previous edited person is correctly displayed in Edit Person page + +@issue=SORDEV-8468 + Scenario: Edit existent person and provoke errors + Given I log in with National User + When I click on the Persons button from navbar + And I click on first person in person directory + And I clear the mandatory Person fields + And I click on save button from Edit Person page + Then I check that an invalid data error message appears + When I fill in the home address, facility category and type + Then I check that the empty district highlight appears + When I click on new entry button from Contact Information section + And I enter an incorrect phone number and confirm + Then I check that an invalid data error message appears + When I enter an incorrect email and confirm + Then I check that an invalid data error message appears From d1bb1f0cea5c841f0822f31542b20b00e7e24248 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Wed, 9 Feb 2022 12:05:12 +0200 Subject: [PATCH 041/253] #7246 - merge development --- .../java/de/symeda/sormas/api/CoreFacade.java | 3 ++ .../de/symeda/sormas/api/caze/CaseFacade.java | 2 - .../sormas/api/contact/ContactFacade.java | 2 - .../symeda/sormas/api/event/EventFacade.java | 2 - .../api/event/EventParticipantFacade.java | 2 - .../api/immunization/ImmunizationFacade.java | 2 - .../api/travelentry/TravelEntryFacade.java | 2 - .../resources/doc/SORMAS_Data_Dictionary.xlsx | Bin 257611 -> 257041 bytes .../resources/doc/SORMAS_User_Rights.xlsx | Bin 19067 -> 19173 bytes .../backend/campaign/CampaignFacadeEjb.java | 12 +++++ .../sormas/backend/caze/CaseFacadeEjb.java | 5 +-- .../backend/common/AbstractCoreFacadeEjb.java | 41 ++++++++++++++++-- .../backend/contact/ContactFacadeEjb.java | 6 +-- .../deletionconfiguration/CoreEntityType.java | 3 +- .../sormas/backend/event/EventFacadeEjb.java | 5 +-- .../event/EventParticipantFacadeEjb.java | 5 +-- .../immunization/ImmunizationFacadeEjb.java | 8 +--- .../travelentry/TravelEntryFacadeEjb.java | 5 +-- 18 files changed, 67 insertions(+), 38 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/CoreFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/CoreFacade.java index 56ec6899eef..98646d2e38e 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/CoreFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/CoreFacade.java @@ -20,6 +20,7 @@ import java.util.Date; import java.util.List; +import de.symeda.sormas.api.deletionconfiguration.AutomaticDeletionInfoDto; import de.symeda.sormas.api.utils.criteria.BaseCriteria; public interface CoreFacade @@ -34,4 +35,6 @@ public interface CoreFacade getAllAfter(Date date, Integer batchSize, String lastSynchronizedUuid); + + AutomaticDeletionInfoDto getAutomaticDeletionInfo(String uuid); } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java index 5bcc09cdfb4..b7521ea8a9a 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java @@ -230,6 +230,4 @@ void saveBulkEditWithFacilities( PreviousCaseDto getMostRecentPreviousCase(PersonReferenceDto person, Disease disease, Date startDate); Map cleanUpReinfectionDetails(Map reinfectionDetails); - - AutomaticDeletionInfoDto getAutomaticDeletionInfo(String uuid); } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java index 502a8d98669..e774aae41a7 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java @@ -141,6 +141,4 @@ List getContactFollowUpList( void updateCompleteness(String uuid); void updateExternalData(@Valid List externalData) throws ExternalDataUpdateException; - - AutomaticDeletionInfoDto getAutomaticDeletionInfo(String uuid); } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java index 88c382e3088..2c2c01fe63f 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java @@ -90,6 +90,4 @@ public interface EventFacade extends CoreFacade getExportList( List getByPersonUuids(List personUuids); List getByEventAndPersons(String eventUuid, List personUuids); - - AutomaticDeletionInfoDto getAutomaticDeletionInfo(String uuid); } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/immunization/ImmunizationFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/immunization/ImmunizationFacade.java index e1d84213675..5aa0ed6d5f6 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/immunization/ImmunizationFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/immunization/ImmunizationFacade.java @@ -55,6 +55,4 @@ Page getIndexPage( boolean linkRecoveryImmunizationToSearchedCase(String specificCaseSearchValue, ImmunizationDto immunization); List getByPersonUuids(List uuids); - - AutomaticDeletionInfoDto getAutomaticDeletionInfo(String uuid); } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/travelentry/TravelEntryFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/travelentry/TravelEntryFacade.java index 0f05816b194..25feb20135a 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/travelentry/TravelEntryFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/travelentry/TravelEntryFacade.java @@ -29,6 +29,4 @@ public interface TravelEntryFacade extends CoreFacade getEntriesList(TravelEntryListCriteria criteria, Integer first, Integer max); Page getIndexPage(TravelEntryCriteria criteria, Integer first, Integer max, List sortProperties); - - AutomaticDeletionInfoDto getAutomaticDeletionInfo(String uuid); } diff --git a/sormas-api/src/main/resources/doc/SORMAS_Data_Dictionary.xlsx b/sormas-api/src/main/resources/doc/SORMAS_Data_Dictionary.xlsx index ba355095f2b50f79b621ca8499c1e135acf87518..34253040e7479d495f6c45134224274a9e11ba08 100644 GIT binary patch delta 205529 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 z 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

    W47F(ZBexL#``(6bSKYq8-W8NFx7`X_=3hY8=s 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 b;r+6UNiIZUu?vSHXZne&=!+h~{z>yclK*}g diff --git a/sormas-api/src/main/resources/doc/SORMAS_User_Rights.xlsx b/sormas-api/src/main/resources/doc/SORMAS_User_Rights.xlsx index d5a1737045b441bdd6bdfb0ec13b1d9fddfe602e..1b720fab85d2435178df547750bc5036e54c452f 100644 GIT binary patch delta 11625 zcmb7q2|QI@7q{W!$~@0wX1T5@nO#yYLWankr%V|_65*OkB_)Skv&uYHhKwOoO6H*u zm8b|2nfdm))YJ34@B4kf@BV(yzV_LB?X~`Et^Znwvl&l3l|W2mtWSzyCPE^SL~v;R)ypsU$A@)3da49dGSXop>^gchk*}wz_SVZ?1`r@>rtAFGm?02htuO#U-j< zz+cU`jro)n?`S^auZSWMCpvDH7ZIiU>O&OGm-yYMXRxQ1-bW=Q=ZL4gyc*3k^*zXc z^AU9hZQxF=W}lg;0uyb3X3|k&s^eT1OKGYJ7Q=J5<;kRO#IMu%hpWB zReS%*(1h-13N|4>j-0ReF~&bXND*_F%i*Y@beGkpaz5}&e}Icmo;R< z9s<)bhv|MY40IUJlt#_tbp)Ou5YHu}jx*@I0IH z(}oZY<}NBvvHX{J6gBFv;3nV8mR4qs1=pRbX`*taL6j+ZVUf7k-#kX&GN2@x)a`?FSxQe$lZ*Z; z`_m}Lr4QSi_97HVU#8Sr>&<(P)+)5dFhTF0)u)yFKV|w^ZlC0steEBbp=elt{-rhoiB>bq*%Xd7Y1;iwd50$l}Q1Bai-CUur$y`$MjyHTW|Nt{6)dbwCf5 zVB*kUNJ|mxwOJ5;q&~AvOc(1Dj!3$EUE~x2^>wR9eM) ziyU$HS7uCI=Qh?!Ut)=QGcVHISTUz@D?Dboh|}Lba*^%r^ZGlEiZLHWF;`fKYspzL zK7yg2MM9=qpQUU(XN;_2RT18q{`CIxa^N;Li20PsR(s>FPyKgYA~qZajsa73&#TdO z+coxpjTiR3c1oKkUUhA8#c?DvPF*`|I;-=U@#%^ymwPVg7*n==_v|YZYJgFl^QT##6kUSn6-*kG~AuFh?2s5K{VP}#>1Ftf3DR$53Us=5r_FD-ASs2)fx6k~OFzwW9=?LzBl%q;!x zsApC~2mjWBGyRqj=k>GmZ6wkiyb1>;Cv5;~kj{4uiL?~BU<{5D!fFu^$_LlVxB@?U~OWu3Md<_~>lb9wmDGIusQ zqJwnv<%!R|opfc)eKn`I72H+_X%h{pDDBD{sL)jQS4fk`)li`ZH!tK~kVWbmLq0BL zgAb%qYrRle$Lo*Dzg#R1bvpfw<)mcydGud*Wm|Bvz6s+LXqgH+q7AKfP4|<{T=bR- z%2Z^%7_u4_a{GC_`NUDlutQcP%_o-=CNDEv*SpMq6Ueu@H=>t^R3 z#Q>`koQX@by3YBZ)|Yt_kUigzL}!*p)sS7oMMXUKYAT8ldUW9_n|g07Q_2am(rbtC>i?j=4LOl9QnL^_!X5&2#*K3W3F&q%wqD%LuPOP z!pE<*(ywYrr#oi28cP54V#i6@ML`h< z9?-&GsP?1H`>h zrmH*hbEi^04|&~=n2~bpJ+`FeFx5`?$mmjoT~L?cTI*}Q)cfzR1(#nuY`Zv^?>0tV zcG5(d>@LmWPmeh6hwKzx+(z_GfR4o{>0h5|2>1U>P*&(pg4| zvVi2X^>Sj=>Df%VXNDaS=T5vk8^Tw;D6c=X_>k`qtLK;Xjh^-d?-1LoybGvCrLQ5T z_i;{z<6n-%%FfBqdWBG@zqQqfwIlC|ePZW1Pwp5wS$V{B@Cjxm%=l7nN5|^*WzScJ zf0Ze;kg{3XYtOuB+GRMaSkU%OgTf~b6~OhN{Vxm|-8-R2aoRT{>Yi(yUTP(M8WHhn z>6mg@_mDP1JT*qMSF3A|alw_^)@Z4D)GQ1x#ip0fP$7c_%l{Z5}Y| zSfmTHqNTc1wNyR9lG+-%dE)X$z^ZWkB9&yJ&-Ale-On6n<8_OL(i4BOv(S_Ary%_! z5JFVAC^@Z?q3CBCy&_pP1+@RlIcjZ563tA+eQw z(r%HhF1aiH#%X3FkD3MzWyDt^b_x~u%DCI^O^vKYLv+r$p2y#PWTr0oa?Uj>;cB1O zDcTNMb0s_GLz#iB$7bi`iaL#j6lGa*6(N0^Rx_K9)r^x2$JO?w#L($hevZfHH8msau)`L(^?qO1EFvvp>S zk6R8W^u@vNVRl*Z>;MtbH~D|{bY?{0Q^rKcLqh0@-?JX1KGy3|Gl#GIN>ro9hbs%U zGI4T~+#T!0=iAr6WHhJy-o;cAvbC_gy`53I^JBibePVofvH$$6v{9*j{pO_C0&aco z4sL6?W+8m{%9ZU2jol2s-JsnMIQ5;4`FFV%8QXk(xWH}PY_8GnMk!y&+S*h5iS3=A zllJ4gv+wva_|`W!=^7fgm)8^db{3o4alw~YekAg$7Q3^XtGhq8qSq2L>~QLz za-ZTnCbn@u-c6|2Z*I*R@$GESufNrBF`|3MowxCQCea^<+g!kfxQ*{})Nju5HH2(z zS#@XFfBP)DJ-4l)5wf098nQdL&RQ3;vN^iDz0|O~HJ51Au(Lc8aIJLb=fa(g@m=+h zZ4EWl+R~xT(Xwxe&S@E)-9FFMUIhf)^OMz>U7kCQ%UuW@S|2Uznpi1%_0-w++3e|I zukMrU)+IiTS_$sHQinOTxtYFtIofh!mG?2P z7vt>axbV=Vhhy->W=mk*$)bfTxt4dH-dqV@V3}QXdi-qRouk?~YG}3I{#*NI>&~;) z=4IR$MgQHQqhVv7tVf|{U{Wz z$>w}IvZm^VU|*{_>tmGX6Wxp6i8?jD?eQtebM#Xs(<(=+i(6?=&Y!Q=j_0xlQ@E}n zFjw&!%z4ym$ES>fx%r^%h4-v?)yFzOD3<$KUUxnE%+Qz)K!nnRdL&JlJ}h!ijO7eo9ezMBt^D zUY&OQ1k_?+^1~Y^_ru%wNBncuYWjqR@Dd42igaR3!n%vxNXl}GOTv1JTuq91GD*S)%SMF;=$#iyOImi4 z#do-fKuMj`n@{jJ=o_mVFGn3a5cUH|T%kAKahgqkN}A9By=OCU&;D#zNt%GO2w?j| zyzQ;0GKY<@ou(!~;yYD^e=B$xYBR8s``VeMIPtDY^_)D^Vc;Zpy7MT~!N#FZ`{32a z6=6h)6*6@&tuwKt< zBLZF$>~;Fn+)aJt7%-PDV$}ng7u{5=^b38Q+>Lpl*nb+>Ui{jWQ_l5umK-!5H1^*t z3|(1{Bk3m7Q6L`}d>_5Olvl$Q6f(e!Xk2SVG)7Kz_SWAFy%B~D#Wp3$p+zZjh;k4) zBst_c#5rU+q&XC;0YtvX9B?8IP7bUNk^C=&U#J}OIqEKPRpo@5pSO#L*XHSW-0B)` zw~%FvVU(eiVK<&7O;gz1%B9c{%u`gGm0@aDa7^SV4q?0M@`b$KdSs&bYv zf{s$Y_a#Z7Nq#|GQz}rz<~;E+WVlUu-Csh-TddBOFN;j-SX+1&-eU8xrL4KN2h_dl zc@|ktG@NV3aNT@-0bWyRCtdGW+}0;Xdb ze}Wp;*T)ra;bB`{Y;0HIC;Y`2Y7pm?x6V9CX+UK_VL;cVN+d@jM=Td1C*Al9wgpG4 z(S*wJlDdLfy(^=Hfva3Hj+;}>qo)M17Zc9Bp&VgJp-D|iY=4JD(VU*OmxbM+Uv_;x zi-n)9Ys4jC^fQn7C^82_sxs;g6@-4-wAj? z7=9Eh!-pb<`%fjkW@?sNg96OJ%1m3zTTlomyMhOhi0|LSdSCI)vOl2quowxfUCJqu zobw5+IsxGQw_ZHgE%!`zoqY-KESAL7GO|yQ&*`B>5x!85 z0E+AAo^|6Dep8jU0mDNH({{sLTtTme@JtXduk_(-cM3od*Y*vKCinxqJuJXVVHXRM zNm3>vCK9H-z#)N%q0#rFVqxM<6%r0^7mA@B4jyQh_aJnelhM>6Lb@2?MB+s5^g9}N zFV|Mse*H4{vbLt=V&&eT2~^|56XEIcNIW|pWEq|sKSn%ZOKCt^Voq#I+8_F(yzye= z@_SWMJfz9XEUgSMDJhXmoAYQWoYkW!m*nwXeMR9*;-Gb*_-_&1coID0So48S2rbVo z$ndyQlE*q4Ig8y?svf;R1pS13Jm?vnCUJ66RQmgFS$kM@h@9*oNGxekT>!BoDG<{?(-04E(z zw}?mo_=2UC(a6x!p{tRVl?W+)had-FqJtns`Jtv%L?^Z>mAbPdOgvP)DF9&azk_TsQ*p8L1o|I-9?PJ{bK4XW==pPg zm}_GNq$j|IyClU^f8O=<$j2oVK~)d^_A#;_`~0$p)^U9$7aY z744})_%fnJ$$Vu&QS&7j4^nQLywf%8Yv|W7j>e?p&>3kav3|qJz9H5`6T&sqoAMTp zWa2!f0nz|rKy5%`aKM1vfOh^2@ibH_Dum8WYs)T{LS+-K7+~9;hrWP=9SljPvl`Df zetNG;h8C_mMK(R)U_!)KSy=kur&vp_L}zQd8xX+GE6PgL&wG9Ak&KZ0q&}eC#tJR8D5TCK z1;resIApRtP%Zsswiz7cJ|9@G6tPf+5Frvlh>$qnCS*|<97+KIO+a4Xr3F!+)7qx6 z;Oy+Z0fuDP9k{zOvhiqR%ll4BJOr~|#1D}CpqecT2}%a!dI$8ufG=f9p$HpboBro| z*8j3T@OhQ!k_aak$g`-uqECqjQClsoBEeP zsFQ~iWH-I=I;_)vh0ThsDvEja%5ZY22!)acFu(&Gc%a5{9`z-T(RWaG2)vNKU(r(o zewTx&mXWHuZ}O;a;2uY;!2SJwbOuBqk}iUcXi;Kc6X4DsVJ_$=Cp{k{2p`8;0q>J+ ziHUQ@vky?H48FtHBHyk}bbi?NC*3C>9`-IyMwOUX(KS^;7<;}`Y>8~&c?gLFl9pYX z4P+AB2!7`H&!VrpZwZhLTLKTzf`m4`^vFjOHygY1R$&(#yUt)V)WyRNfZ&JpBS$uL0J@hfs9hKjg(``oInYW+jDYtX49TXUTf#h?RV6X6W&!dAC{!uX7alUb z1IRSYxuI?zHlQJcd=QEieSE(gBmh1yk17R#yAc2f%PDWcfL~Vd?-q1$bYOHaxiAe$ zi%Uxt7Ds``#>Vccc5waa$}56o41cB$ zLVzF{2de^iypWolEUKozsxCkJRp9_(kaV&6)lS%gwE3^-QI!HerVwaE5n7iLK;)1Q zyFtBD0*w2U9^RBNfmi?s!;Fj@2Kj4iZKD_Ssuq+v5PEx6^8q+4TxmafNll4N!-vho zltAT1OQCttYG_h4p>9`oQ{jJgy4sE&Hg^7;iT)nm;tHsRk&ldj6H&=~71W>ffzCzv zN}zMebD#s#ypS4-o%w$l#3hIo@V4ekdv@O?TjJ9><4r(X`}L_?2{mQNWl?8Sbd-YLG`Pdfo^ef0V1bzhNCcLysA6{@a~+@Rq$7Xy0G7I z$gsB@{gy@^7*EnE9+n>pm+d6$y`a7@{qLtBI9+oTQFEdm-U0WtwBVqgg3pC$WK`&l zK!x9HM!=cXbkq9}Jsf+cFSliTxJJM7nCz=0B;EKQNyh5JS(<`HSu=<%lUVM z)|Tb)_szlo`S?PBbzgQZGvmHfy{5Y?p-@gyxR?nCwCf(Yu?dK2Hb#FGAh#+?C`0eY zRsue0agfJ2YrwffilFYRRE~9#Zi&P zDAdB}{Yo(Glh)qjs<$rw1a(OQNN+q8rlf>74OJ3Gvs9g;nU)9jR+WnbM@#8Ua|15a zD3pEAa1>}9cwpzj?C^o`O{VG;sMY`9b9_;~o;a z5O5__P+GWP5gxK++5dHS$#Xv9*P|qwo#0TArTeW0ob#`0|A;0Yt>=MOl8N2B#qE(b zH8z98?St>865CH;7B!==80dqJ3@-cV^@sE#S{S z`ofh-K*hEjs*$yYO-%a=A4oEjPIvY?z402vaP*LXYJ`d4r#fJ$$QP`AuAX@h^vsaV zwueG?OA1krp*%nd5o4sFs>5!$hO42{3qoRoVj>hqFS6n@Z)K*Y=JV$XB^DA4Pa^2) zlM|MCH}ghjQsz~DfmolrOVoNdVn;=^E-B|Y2d7CS7<6wavy>Z9F7dsf7jR-`WM*Jy zil>ifjAw|4QclNWg)uA`1q_YSWde#_^7QhI@(l7!<@7>F5GE*-bc{HI&&1IehNLS+ zrKZ^jW=`AZhSN%5U|utHabB{MWLHuHKWJ~J{iek>PQWm5vI$`f=h=*YU3c`x&JW;!?It;EGRG?af& zSm$~rylYU_|5H#nl&Yk}CIws?4JIpn=fDsgGR7@%_y)Zkw0q<*d&^s(tIEoQVpIEp z;r0r@0-ce3R@Yn-s9#xL1NbK=&26sSRC+{tFm5ED%_Gh2?xlir^DovBWQeN>9YiZa z7?J%+{oGj-Lt~6F)>y~*gt4|U0h;+Wh(?){<^e$A(u|IMZrr5;9mrEfmBmVBZXo)Z zVFHjBoTdkkTN5;e6;-1*2mYNKD12rpJZDC=C4(9_j3QA3}DuX2U;d&7L z5jGkIGo}Ih0mcD_0VqWYvQ`!)Db!F+B%|U=b@(M34R~%s_+_7UReh@^hQXlQ;c7X5KCeLV#2H9 z2O$vh|BQH_b_!WnAs0ax5f=enWR^`99I5+w=KRL<1jMDyjf3O)M;5_VnfviKmitEl zo=_Pacg-Cy_bZU9Fa=t`%7q4nlZ0!9KY$~>MO9n?+E2WHYO!=haW4d+2x$amSbTK6 zv$0;J`$+yz;MN=h_$TbiVf0UoK#w$!F#b9J_p~%TT|!uHYoD7u>*dA!;yWFO+yUf) zjwHcwN1y6Q1HFzc5PX^8nQ`28P^uQEumPW=u-4%@vn#o2fx`qh0SQwOyOdU{s7Kn2`)6gNeb?dd8X0REuW4RG${5}3$O0*2 zg96Tz%?Ca29$)!<|Cb*`|8@kuGm}7|%3wg>P`)%EEZ_*4;fZn8SOG1NhtProt9%{R zKH-IvFU=ea7YTRr$+>F47=DWpm3(f4UXtO7Yp(LXh%W3+dY~O1qSe%9NniGxIen8p zIL)o3p+11Wc>)eGi2f+6@N5WIPN+|Un}pz}+D zzzb2rc2SuCe$&XzOA<+cp8gmttxTJ-+)z#k@|V#3n|&h7O`D))%pvYr5OTev`M0x6 zO}$Jazs#ET8T!5O&n01|XJ&+wb!0hUBVaMM@QENziPqsD?lUBVqP3(r;tqZ)cg;;- zzEtp+>+C>31ZULB(UE*ns6NfmlZ!KCYnbexzZAmJb^snyn}h7F8nS+tFD5OQ~19NjH!o5+Qx%t z>LuW?Pqn7RfV>I8OL-G{^N$h;(P8+Y9wjnXBb7NbYwO(ftV;#Ods|=~;hN-5;Jm;Q z*W8f}Wpg+9`Wr#GrbfbWQewoFE*}$_I%|RvNkEt*1`!H~3WOhG1wn&|`E=XpY@b2T z-$fO0=s)F^0|hBTV!@S50+*jix40{MFai0t+!WU9I81`@6;6?VIxZ{T;CC&5QCJ9y z`4pk1g_HYy|IgBUcy6HI5I7l5O!zvzF`7aldlb1oZ+4;jcR_*H6%Mk>24DZr^OGS? z4SwjYHm9ObWUAuazzxVj*31 zZrn^jE@6Ecp)jdIzl~zR$Y21F7!HgQh71Fj)fIqmi)#LFU&GY8>iUn2R~rqCOfC1D z2~ZhU0&(|e^!#^uGA+0E%KrC#+T{-VTi_m9n+NyK7Z75nn-Hk)b=Wnx0e=Vp3I>gh z&wtwq$VY7f_zT4Np$fuaK**4bbs#^qWW}LdTC&XW0zwdh#FYTa@|s5}BThk%2hM^z zAmHn)S$xRhhKNUt_mM%q?ZcVkYq;yOcIQn!*=Wi~V~-kQ!A7l_HLb6E9V zj%K2%obg4L%Bww?-)J-~hAvj`V#v%{Zi{@VdS06U@Xa}X{PH)WLANy4r4|7NJ`pxm z`|n$H>D$dyr~C4hgHDz74@Hw+)x36G*K?TP>Om-~hUI#?e+8a+6m7~s){QKqmEZZ< zMk92{-Xxe5#w#e-NRI)$2-`|{8J3uYndtY6#L&X=!-V&S#dOsPqpPk8C3uh6jPL?2 zRIGcLAO7vnS1*|1w=I5u$`DW&f)(PxQd_|b`Bgm_X23BxBoPtK??vzz9y%hT%kI*? z7X#eS`Jyg+xEt&LLld*v7pHY*!NNOWJ6QY2M+?GXc?sHOV!4RjpgOELL90LGfc=m4 jL`1ilpxaEG5T713AFS1%0Q_^|4@gf>l3Y(0-u-_7cHaEf delta 11777 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 diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java index f7cade9a84e..9ff5316b6df 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java @@ -24,6 +24,8 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; +import de.symeda.sormas.api.deletionconfiguration.AutomaticDeletionInfoDto; +import de.symeda.sormas.backend.deletionconfiguration.CoreEntityType; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -390,6 +392,16 @@ public static CampaignReferenceDto toReferenceDto(Campaign entity) { return dto; } + @Override + protected CoreEntityType getCoreEntityType() { + return CoreEntityType.CAMPAIGN; + } + + @Override + public AutomaticDeletionInfoDto getAutomaticDeletionInfo(String uuid) { + return null; // campaigns do not support automatic deletion yet + } + @LocalBean @Stateless public static class CampaignFacadeEjbLocal extends CampaignFacadeEjb { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java index 6f22fd64fb8..a27efbe60dd 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java @@ -223,7 +223,6 @@ import de.symeda.sormas.backend.contact.ContactFacadeEjb.ContactFacadeEjbLocal; import de.symeda.sormas.backend.contact.ContactService; import de.symeda.sormas.backend.contact.VisitSummaryExportDetails; -import de.symeda.sormas.backend.deletionconfiguration.AbstractCoreEntityFacade; import de.symeda.sormas.backend.deletionconfiguration.CoreEntityType; import de.symeda.sormas.backend.disease.DiseaseConfigurationFacadeEjb.DiseaseConfigurationFacadeEjbLocal; import de.symeda.sormas.backend.document.Document; @@ -2793,8 +2792,8 @@ public Map cleanUpReinfectionDetails(Map implements CoreFacade { + @Inject + private DeletionConfigurationService deletionConfigurationService; + protected AbstractCoreFacadeEjb() { } @@ -133,9 +140,19 @@ public void executeAutomaticDeletion(DeletionConfiguration entityConfig) { List toDeleteEntities = QueryHelper.getResultList(em, cq, null, null); - toDeleteEntities.forEach(entity -> { - delete(entity); - }); + toDeleteEntities.forEach(this::delete); + } + + @Override + public AutomaticDeletionInfoDto getAutomaticDeletionInfo(String uuid) { + DeletionConfiguration deletionConfiguration = deletionConfigurationService.getCoreEntityTypeConfig(getCoreEntityType()); + if (deletionConfiguration.getDeletionPeriod() == null || deletionConfiguration.getDeletionReference() == null) { + return null; + } + Object[] deletionData = getDeletionData(uuid, deletionConfiguration); + Date referenceDate = (Date) deletionData[0]; + Date deletiondate = DateHelper.addDays(referenceDate, deletionConfiguration.getDeletionPeriod()); + return new AutomaticDeletionInfoDto(deletiondate, (Date) deletionData[1], deletionConfiguration.getDeletionPeriod()); } protected void delete(ADO entity) { @@ -153,6 +170,24 @@ protected String getDeleteReferenceField(DeletionReference deletionReference) { } } + private Object[] getDeletionData(String uuid, DeletionConfiguration entityConfig) { + + if (entityConfig.getDeletionReference() == null) { + return null; + } + + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(Object[].class); + Root from = cq.from(adoClass); + + cq.multiselect(from.get(getDeleteReferenceField(entityConfig.getDeletionReference())), from.get(AbstractDomainObject.CHANGE_DATE)); + cq.where(cb.equal(from.get(AbstractDomainObject.UUID), uuid)); + + return em.createQuery(cq).getSingleResult(); + } + + protected abstract CoreEntityType getCoreEntityType(); + protected abstract void pseudonymizeDto(ADO source, DTO dto, Pseudonymizer pseudonymizer); protected abstract void restorePseudonymizedDto(DTO dto, DTO existingDto, ADO entity, Pseudonymizer pseudonymizer); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java index 1e712182d47..f0399ac8e78 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java @@ -89,7 +89,6 @@ import de.symeda.sormas.api.contact.MergeContactIndexDto; import de.symeda.sormas.api.contact.SimilarContactDto; import de.symeda.sormas.api.dashboard.DashboardContactDto; -import de.symeda.sormas.api.deletionconfiguration.AutomaticDeletionInfoDto; import de.symeda.sormas.api.document.DocumentRelatedEntityType; import de.symeda.sormas.api.epidata.EpiDataDto; import de.symeda.sormas.api.epidata.EpiDataHelper; @@ -144,7 +143,6 @@ import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.common.TaskCreationException; -import de.symeda.sormas.backend.deletionconfiguration.AbstractCoreEntityFacade; import de.symeda.sormas.backend.deletionconfiguration.CoreEntityType; import de.symeda.sormas.backend.disease.DiseaseConfigurationFacadeEjb.DiseaseConfigurationFacadeEjbLocal; import de.symeda.sormas.backend.document.Document; @@ -2069,8 +2067,8 @@ public void updateExternalData(@Valid List externalData) throws } @Override - public AutomaticDeletionInfoDto getAutomaticDeletionInfo(String uuid) { - return getAutomaticDeletionInfo(uuid, CoreEntityType.CONTACT); + protected CoreEntityType getCoreEntityType() { + return CoreEntityType.CONTACT; } @Override diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/CoreEntityType.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/CoreEntityType.java index 7b8ffeaee53..590c8403bf0 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/CoreEntityType.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/CoreEntityType.java @@ -8,5 +8,6 @@ public enum CoreEntityType { EVENT, EVENT_PARTICIPANT, IMMUNIZATION, - TRAVEL_ENTRY; + TRAVEL_ENTRY, + CAMPAIGN; } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java index 78c699e9567..5cc851e3127 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java @@ -96,7 +96,6 @@ import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.contact.Contact; -import de.symeda.sormas.backend.deletionconfiguration.AbstractCoreEntityFacade; import de.symeda.sormas.backend.deletionconfiguration.CoreEntityType; import de.symeda.sormas.backend.externalsurveillancetool.ExternalSurveillanceToolGatewayFacadeEjb.ExternalSurveillanceToolGatewayFacadeEjbLocal; import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal; @@ -1288,8 +1287,8 @@ public Boolean isEventEditAllowed(String eventUuid) { } @Override - public AutomaticDeletionInfoDto getAutomaticDeletionInfo(String uuid) { - return getAutomaticDeletionInfo(uuid, CoreEntityType.EVENT); + protected CoreEntityType getCoreEntityType() { + return CoreEntityType.EVENT; } @LocalBean diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java index 4c378887a00..4abaad61ffc 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java @@ -99,7 +99,6 @@ import de.symeda.sormas.backend.common.messaging.NotificationDeliveryFailedException; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.contact.ContactService; -import de.symeda.sormas.backend.deletionconfiguration.AbstractCoreEntityFacade; import de.symeda.sormas.backend.deletionconfiguration.CoreEntityType; import de.symeda.sormas.backend.event.EventFacadeEjb.EventFacadeEjbLocal; import de.symeda.sormas.backend.immunization.ImmunizationEntityHelper; @@ -1070,8 +1069,8 @@ public EventParticipantFacadeEjbLocal(EventParticipantService service, UserServi } @Override - public AutomaticDeletionInfoDto getAutomaticDeletionInfo(String uuid) { - return getAutomaticDeletionInfo(uuid, CoreEntityType.EVENT_PARTICIPANT); + protected CoreEntityType getCoreEntityType() { + return CoreEntityType.EVENT_PARTICIPANT; } @Override diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java index f608528ade0..55ad3abee1c 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java @@ -77,11 +77,7 @@ import de.symeda.sormas.backend.caze.CaseFacadeEjb; import de.symeda.sormas.backend.caze.CaseService; import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; -import de.symeda.sormas.backend.contact.ContactService; -import de.symeda.sormas.backend.deletionconfiguration.AbstractCoreEntityFacade; import de.symeda.sormas.backend.deletionconfiguration.CoreEntityType; -import de.symeda.sormas.backend.event.EventParticipantService; -import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb; import de.symeda.sormas.backend.immunization.entity.Immunization; import de.symeda.sormas.backend.infrastructure.community.CommunityFacadeEjb; import de.symeda.sormas.backend.infrastructure.community.CommunityService; @@ -230,8 +226,8 @@ public ImmunizationDto toDto(Immunization entity) { } @Override - public AutomaticDeletionInfoDto getAutomaticDeletionInfo(String uuid) { - return getAutomaticDeletionInfo(uuid, CoreEntityType.IMMUNIZATION); + protected CoreEntityType getCoreEntityType() { + return CoreEntityType.IMMUNIZATION; } @Override diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java index a493ffa76a5..80d594c8942 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java @@ -29,7 +29,6 @@ import de.symeda.sormas.api.utils.ValidationRuntimeException; import de.symeda.sormas.backend.caze.CaseFacadeEjb; import de.symeda.sormas.backend.caze.CaseService; -import de.symeda.sormas.backend.deletionconfiguration.AbstractCoreEntityFacade; import de.symeda.sormas.backend.deletionconfiguration.CoreEntityType; import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; import de.symeda.sormas.backend.infrastructure.community.CommunityFacadeEjb; @@ -194,8 +193,8 @@ public List getEntriesList(TravelEntryListCriteria crit } @Override - public AutomaticDeletionInfoDto getAutomaticDeletionInfo(String uuid) { - return getAutomaticDeletionInfo(uuid, CoreEntityType.TRAVEL_ENTRY); + protected CoreEntityType getCoreEntityType() { + return CoreEntityType.TRAVEL_ENTRY; } @Override From ea98fc67537f1febd7c1d075e11733bba1a92e1d Mon Sep 17 00:00:00 2001 From: jenkins Date: Wed, 9 Feb 2022 14:54:33 +0100 Subject: [PATCH 042/253] [GITFLOW]updating poms for 1.69.0-SNAPSHOT development --- sormas-api/pom.xml | 2 +- sormas-app/pom.xml | 2 +- sormas-backend/pom.xml | 2 +- sormas-base/dependencies/serverlibs.pom | 2 +- sormas-base/pom.xml | 5 ++--- sormas-cargoserver/pom.xml | 2 +- sormas-ear/pom.xml | 2 +- sormas-keycloak-service-provider/pom.xml | 5 ++--- sormas-rest/pom.xml | 2 +- sormas-ui/pom.xml | 2 +- sormas-widgetset/pom.xml | 2 +- 11 files changed, 13 insertions(+), 15 deletions(-) diff --git a/sormas-api/pom.xml b/sormas-api/pom.xml index 9cf1cb0b29c..34ab0c6f590 100644 --- a/sormas-api/pom.xml +++ b/sormas-api/pom.xml @@ -2,7 +2,7 @@ de.symeda.sormas sormas-base - 1.68.0-SNAPSHOT + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-app/pom.xml b/sormas-app/pom.xml index ab6390a8bb1..3bb68392128 100644 --- a/sormas-app/pom.xml +++ b/sormas-app/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.0-SNAPSHOT + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-backend/pom.xml b/sormas-backend/pom.xml index e58c9d5c917..65f2c404621 100644 --- a/sormas-backend/pom.xml +++ b/sormas-backend/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.0-SNAPSHOT + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-base/dependencies/serverlibs.pom b/sormas-base/dependencies/serverlibs.pom index 42fee73b573..7fa1fd8c18e 100644 --- a/sormas-base/dependencies/serverlibs.pom +++ b/sormas-base/dependencies/serverlibs.pom @@ -8,7 +8,7 @@ sormas-base de.symeda.sormas - 1.68.0-SNAPSHOT + 1.69.0-SNAPSHOT ../ diff --git a/sormas-base/pom.xml b/sormas-base/pom.xml index 6488ec52d93..76e183d75a7 100644 --- a/sormas-base/pom.xml +++ b/sormas-base/pom.xml @@ -1,12 +1,11 @@ - + 4.0.0 de.symeda.sormas sormas-base pom - 1.68.0-SNAPSHOT + 1.69.0-SNAPSHOT 1.8 diff --git a/sormas-cargoserver/pom.xml b/sormas-cargoserver/pom.xml index 0e2a5e98930..8c6009ec75f 100644 --- a/sormas-cargoserver/pom.xml +++ b/sormas-cargoserver/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.68.0-SNAPSHOT + 1.69.0-SNAPSHOT ../sormas-base diff --git a/sormas-ear/pom.xml b/sormas-ear/pom.xml index 37022bac398..eb67f26b2b0 100644 --- a/sormas-ear/pom.xml +++ b/sormas-ear/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.68.0-SNAPSHOT + 1.69.0-SNAPSHOT ../sormas-base diff --git a/sormas-keycloak-service-provider/pom.xml b/sormas-keycloak-service-provider/pom.xml index 9fa4c3acbd6..142c2f5858e 100644 --- a/sormas-keycloak-service-provider/pom.xml +++ b/sormas-keycloak-service-provider/pom.xml @@ -1,10 +1,9 @@ - + sormas-base de.symeda.sormas - 1.68.0-SNAPSHOT + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-rest/pom.xml b/sormas-rest/pom.xml index 8daaf03a056..85e9fe6b41d 100644 --- a/sormas-rest/pom.xml +++ b/sormas-rest/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.68.0-SNAPSHOT + 1.69.0-SNAPSHOT ../sormas-base diff --git a/sormas-ui/pom.xml b/sormas-ui/pom.xml index 672a44bbd4b..2245a5f673d 100644 --- a/sormas-ui/pom.xml +++ b/sormas-ui/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.0-SNAPSHOT + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-widgetset/pom.xml b/sormas-widgetset/pom.xml index 63aea166184..f8d6a25f29d 100644 --- a/sormas-widgetset/pom.xml +++ b/sormas-widgetset/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.0-SNAPSHOT + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 From 2f27f16ca32de11c529676fa85bf4800c6e230b3 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Wed, 9 Feb 2022 14:59:22 +0100 Subject: [PATCH 043/253] Added test scenario for Persons Form Card navigtion --- .../application/persons/EditPersonPage.java | 8 +++++ .../application/persons/EditPersonSteps.java | 34 +++++++++++++++++++ .../persons/PersonDirectorySteps.java | 10 ++++++ .../features/sanity/web/Persons.feature | 34 ++++++++++++++++++- 4 files changed, 85 insertions(+), 1 deletion(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java index 8193c5fd0a6..61c26009c5d 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java @@ -103,8 +103,16 @@ public class EditPersonPage { "//*[contains(text(),'The case person was added as an event participant to the selected event.')]"); public static final By SEE_EVENTS_FOR_PERSON = By.cssSelector("div#See\\ events\\ for\\ this\\ person"); + public static final By SEE_CASES_FOR_PERSON = By.id("See cases for this person"); + public static final By SEE_CONTACTS_FOR_PERSON = By.id("See contacts for this person"); + public static final By EDIT_CASES = By.id("edit-case-0"); + public static final By EDIT_CONTACTS = By.id("edit-contact-0"); public static By getByPersonUuid(String personUuid) { return By.cssSelector("a[title='" + personUuid + "']"); } + + public static By getByImmunizationUuid(String immunizationUuid) { + return By.id("edit-immunization-" + immunizationUuid); + } } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java index c3cad360fa4..c0edb27dac5 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java @@ -35,6 +35,7 @@ import org.sormas.e2etests.pojo.helpers.ComparisonHelper; import org.sormas.e2etests.pojo.web.Person; import org.sormas.e2etests.services.PersonService; +import org.sormas.e2etests.state.ApiState; import org.sormas.e2etests.steps.BaseSteps; import org.sormas.e2etests.steps.web.application.contacts.EditContactPersonSteps; import org.sormas.e2etests.steps.web.application.events.EditEventSteps; @@ -51,6 +52,7 @@ public EditPersonSteps( WebDriverHelpers webDriverHelpers, PersonService personService, BaseSteps baseSteps, + ApiState apiState, @Named("ENVIRONMENT_URL") String environmentUrl) { this.webDriverHelpers = webDriverHelpers; @@ -120,6 +122,38 @@ public EditPersonSteps( fillBirthName(newGeneratedPerson.getBirthName()); fillNamesOfGuardians(newGeneratedPerson.getNameOfGuardians()); }); + Then( + "I click on See Cases for this Person button from Edit Person page", + () -> { + webDriverHelpers.clickOnWebElementBySelector(SEE_CASES_FOR_PERSON); + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(150); + }); + Then( + "I click on See CONTACTS for this Person button from Edit Person page", + () -> { + webDriverHelpers.clickOnWebElementBySelector(SEE_CONTACTS_FOR_PERSON); + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(150); + }); + + Then( + "I click on Edit Case button from Cases card on Edit Person page", + () -> { + webDriverHelpers.clickOnWebElementBySelector(EDIT_CASES); + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(150); + }); + Then( + "I click on Edit Contact button from Contacts card on Edit Person page", + () -> { + webDriverHelpers.clickOnWebElementBySelector(EDIT_CONTACTS); + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(150); + }); + Then( + "I click on Edit Immunization button from Immunization card on Edit Person page", + () -> { + webDriverHelpers.clickOnWebElementBySelector( + getByImmunizationUuid(apiState.getCreatedImmunization().getUuid())); + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(150); + }); Then( "I click on save button from Edit Person page", diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java index 00f3aba5e3a..254cd9a34d7 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java @@ -106,6 +106,16 @@ public PersonDirectorySteps( webDriverHelpers.waitForPageLoaded(); webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(UUID_INPUT, 50); }); + When( + "I navigate to the last created via api Person page via URL", + () -> { + String createdPersonUUID = apiState.getLastCreatedPerson().getUuid(); + String LAST_CREATED_PERSON_PAGE_URL = + environmentUrl + "/sormas-webdriver/#!persons/data/" + createdPersonUUID; + webDriverHelpers.accessWebSite(LAST_CREATED_PERSON_PAGE_URL); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(UUID_INPUT, 50); + }); When( "I search for specific person in person directory", diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature index 92b87f79931..9cec1040b19 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature @@ -16,4 +16,36 @@ Feature: Edit Persons And While on Person edit page, I will edit all fields with new values And I edit all Person primary contact details and save Then I click on save button from Edit Person page - And I check that previous edited person is correctly displayed in Edit Person page \ No newline at end of file + And I check that previous edited person is correctly displayed in Edit Person page + + Scenario: Form card navigation in Edit Person Directory + Given API: I create a new person + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + And API: I create a new case + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given API: I create a new contact linked to the previous created case + Then API: I check that POST call body is "OK" + Given API: I create a new event + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given API: I create 1 new immunizations for last created person + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in with National User + When I click on the Contacts button from navbar + Then I navigate to the last created via api Person page via URL + And I click on See Cases for this Person button from Edit Person page + And I check that number of displayed cases results is 1 + Then I navigate to the last created via api Person page via URL + And I click on See CONTACTS for this Person button from Edit Person page + And I check that number of displayed contact results is 1 + Then I navigate to the last created via api Person page via URL + And I click on Edit Case button from Cases card on Edit Person page + Then I navigate to the last created via api Person page via URL + And I click on Edit Contact button from Contacts card on Edit Person page + Then I navigate to the last created via api Person page via URL + And I click on Edit Immunization button from Immunization card on Edit Person page + Then I navigate to the last created via api Person page via URL + From d1e312fd70cda29233894433093193d8bd39e63d Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Wed, 9 Feb 2022 14:59:22 +0100 Subject: [PATCH 044/253] Added test scenario for Persons Form Card navigtion --- .../application/persons/EditPersonPage.java | 8 +++++ .../application/persons/EditPersonSteps.java | 34 +++++++++++++++++++ .../persons/PersonDirectorySteps.java | 10 ++++++ .../features/sanity/web/Persons.feature | 34 ++++++++++++++++++- 4 files changed, 85 insertions(+), 1 deletion(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java index 8193c5fd0a6..61c26009c5d 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java @@ -103,8 +103,16 @@ public class EditPersonPage { "//*[contains(text(),'The case person was added as an event participant to the selected event.')]"); public static final By SEE_EVENTS_FOR_PERSON = By.cssSelector("div#See\\ events\\ for\\ this\\ person"); + public static final By SEE_CASES_FOR_PERSON = By.id("See cases for this person"); + public static final By SEE_CONTACTS_FOR_PERSON = By.id("See contacts for this person"); + public static final By EDIT_CASES = By.id("edit-case-0"); + public static final By EDIT_CONTACTS = By.id("edit-contact-0"); public static By getByPersonUuid(String personUuid) { return By.cssSelector("a[title='" + personUuid + "']"); } + + public static By getByImmunizationUuid(String immunizationUuid) { + return By.id("edit-immunization-" + immunizationUuid); + } } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java index c3cad360fa4..c0edb27dac5 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java @@ -35,6 +35,7 @@ import org.sormas.e2etests.pojo.helpers.ComparisonHelper; import org.sormas.e2etests.pojo.web.Person; import org.sormas.e2etests.services.PersonService; +import org.sormas.e2etests.state.ApiState; import org.sormas.e2etests.steps.BaseSteps; import org.sormas.e2etests.steps.web.application.contacts.EditContactPersonSteps; import org.sormas.e2etests.steps.web.application.events.EditEventSteps; @@ -51,6 +52,7 @@ public EditPersonSteps( WebDriverHelpers webDriverHelpers, PersonService personService, BaseSteps baseSteps, + ApiState apiState, @Named("ENVIRONMENT_URL") String environmentUrl) { this.webDriverHelpers = webDriverHelpers; @@ -120,6 +122,38 @@ public EditPersonSteps( fillBirthName(newGeneratedPerson.getBirthName()); fillNamesOfGuardians(newGeneratedPerson.getNameOfGuardians()); }); + Then( + "I click on See Cases for this Person button from Edit Person page", + () -> { + webDriverHelpers.clickOnWebElementBySelector(SEE_CASES_FOR_PERSON); + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(150); + }); + Then( + "I click on See CONTACTS for this Person button from Edit Person page", + () -> { + webDriverHelpers.clickOnWebElementBySelector(SEE_CONTACTS_FOR_PERSON); + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(150); + }); + + Then( + "I click on Edit Case button from Cases card on Edit Person page", + () -> { + webDriverHelpers.clickOnWebElementBySelector(EDIT_CASES); + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(150); + }); + Then( + "I click on Edit Contact button from Contacts card on Edit Person page", + () -> { + webDriverHelpers.clickOnWebElementBySelector(EDIT_CONTACTS); + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(150); + }); + Then( + "I click on Edit Immunization button from Immunization card on Edit Person page", + () -> { + webDriverHelpers.clickOnWebElementBySelector( + getByImmunizationUuid(apiState.getCreatedImmunization().getUuid())); + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(150); + }); Then( "I click on save button from Edit Person page", diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java index 00f3aba5e3a..254cd9a34d7 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java @@ -106,6 +106,16 @@ public PersonDirectorySteps( webDriverHelpers.waitForPageLoaded(); webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(UUID_INPUT, 50); }); + When( + "I navigate to the last created via api Person page via URL", + () -> { + String createdPersonUUID = apiState.getLastCreatedPerson().getUuid(); + String LAST_CREATED_PERSON_PAGE_URL = + environmentUrl + "/sormas-webdriver/#!persons/data/" + createdPersonUUID; + webDriverHelpers.accessWebSite(LAST_CREATED_PERSON_PAGE_URL); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(UUID_INPUT, 50); + }); When( "I search for specific person in person directory", diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature index 92b87f79931..9cec1040b19 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature @@ -16,4 +16,36 @@ Feature: Edit Persons And While on Person edit page, I will edit all fields with new values And I edit all Person primary contact details and save Then I click on save button from Edit Person page - And I check that previous edited person is correctly displayed in Edit Person page \ No newline at end of file + And I check that previous edited person is correctly displayed in Edit Person page + + Scenario: Form card navigation in Edit Person Directory + Given API: I create a new person + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + And API: I create a new case + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given API: I create a new contact linked to the previous created case + Then API: I check that POST call body is "OK" + Given API: I create a new event + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given API: I create 1 new immunizations for last created person + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in with National User + When I click on the Contacts button from navbar + Then I navigate to the last created via api Person page via URL + And I click on See Cases for this Person button from Edit Person page + And I check that number of displayed cases results is 1 + Then I navigate to the last created via api Person page via URL + And I click on See CONTACTS for this Person button from Edit Person page + And I check that number of displayed contact results is 1 + Then I navigate to the last created via api Person page via URL + And I click on Edit Case button from Cases card on Edit Person page + Then I navigate to the last created via api Person page via URL + And I click on Edit Contact button from Contacts card on Edit Person page + Then I navigate to the last created via api Person page via URL + And I click on Edit Immunization button from Immunization card on Edit Person page + Then I navigate to the last created via api Person page via URL + From f5facbc827f7dcb4ea5019b41092f05313caca0a Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Wed, 9 Feb 2022 15:12:50 +0100 Subject: [PATCH 045/253] Issue tag added --- .../src/test/resources/features/sanity/web/Persons.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature index 9cec1040b19..96d4ccc5f8e 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature @@ -18,6 +18,7 @@ Feature: Edit Persons Then I click on save button from Edit Person page And I check that previous edited person is correctly displayed in Edit Person page + @issue=SORDEV-8469 Scenario: Form card navigation in Edit Person Directory Given API: I create a new person Then API: I check that POST call body is "OK" From 26c3955b06005ba2335862936c72168d51f9c299 Mon Sep 17 00:00:00 2001 From: jenkins Date: Wed, 9 Feb 2022 15:28:23 +0100 Subject: [PATCH 046/253] [GITFLOW]updating develop poms to master versions to avoid merge conflicts --- sormas-api/pom.xml | 2 +- sormas-app/pom.xml | 2 +- sormas-backend/pom.xml | 2 +- sormas-base/dependencies/serverlibs.pom | 2 +- sormas-base/pom.xml | 2 +- sormas-cargoserver/pom.xml | 2 +- sormas-ear/pom.xml | 2 +- sormas-keycloak-service-provider/pom.xml | 2 +- sormas-rest/pom.xml | 2 +- sormas-ui/pom.xml | 2 +- sormas-widgetset/pom.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sormas-api/pom.xml b/sormas-api/pom.xml index 34ab0c6f590..69d7b0c097e 100644 --- a/sormas-api/pom.xml +++ b/sormas-api/pom.xml @@ -2,7 +2,7 @@ de.symeda.sormas sormas-base - 1.69.0-SNAPSHOT + 1.68.0 ../sormas-base 4.0.0 diff --git a/sormas-app/pom.xml b/sormas-app/pom.xml index 3bb68392128..666d36c94ae 100644 --- a/sormas-app/pom.xml +++ b/sormas-app/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.0 ../sormas-base 4.0.0 diff --git a/sormas-backend/pom.xml b/sormas-backend/pom.xml index 65f2c404621..f621e32c8b1 100644 --- a/sormas-backend/pom.xml +++ b/sormas-backend/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.0 ../sormas-base 4.0.0 diff --git a/sormas-base/dependencies/serverlibs.pom b/sormas-base/dependencies/serverlibs.pom index 7fa1fd8c18e..760c24ffa6b 100644 --- a/sormas-base/dependencies/serverlibs.pom +++ b/sormas-base/dependencies/serverlibs.pom @@ -8,7 +8,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.0 ../ diff --git a/sormas-base/pom.xml b/sormas-base/pom.xml index 76e183d75a7..9f9cb76d280 100644 --- a/sormas-base/pom.xml +++ b/sormas-base/pom.xml @@ -5,7 +5,7 @@ de.symeda.sormas sormas-base pom - 1.69.0-SNAPSHOT + 1.68.0 1.8 diff --git a/sormas-cargoserver/pom.xml b/sormas-cargoserver/pom.xml index 8c6009ec75f..4fc4743f3c9 100644 --- a/sormas-cargoserver/pom.xml +++ b/sormas-cargoserver/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.69.0-SNAPSHOT + 1.68.0 ../sormas-base diff --git a/sormas-ear/pom.xml b/sormas-ear/pom.xml index eb67f26b2b0..64dd2a9168f 100644 --- a/sormas-ear/pom.xml +++ b/sormas-ear/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.69.0-SNAPSHOT + 1.68.0 ../sormas-base diff --git a/sormas-keycloak-service-provider/pom.xml b/sormas-keycloak-service-provider/pom.xml index 142c2f5858e..03f1769132e 100644 --- a/sormas-keycloak-service-provider/pom.xml +++ b/sormas-keycloak-service-provider/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.0 ../sormas-base 4.0.0 diff --git a/sormas-rest/pom.xml b/sormas-rest/pom.xml index 85e9fe6b41d..5c4879bee2a 100644 --- a/sormas-rest/pom.xml +++ b/sormas-rest/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.69.0-SNAPSHOT + 1.68.0 ../sormas-base diff --git a/sormas-ui/pom.xml b/sormas-ui/pom.xml index 2245a5f673d..04ddceff812 100644 --- a/sormas-ui/pom.xml +++ b/sormas-ui/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.0 ../sormas-base 4.0.0 diff --git a/sormas-widgetset/pom.xml b/sormas-widgetset/pom.xml index f8d6a25f29d..a1c4df38387 100644 --- a/sormas-widgetset/pom.xml +++ b/sormas-widgetset/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.0 ../sormas-base 4.0.0 From 0a8da447d49bf021dd77ce4300374f2ea85dfc96 Mon Sep 17 00:00:00 2001 From: jenkins Date: Wed, 9 Feb 2022 15:28:26 +0100 Subject: [PATCH 047/253] [GITFLOW]Updating develop poms back to pre merge state --- sormas-api/pom.xml | 2 +- sormas-app/pom.xml | 2 +- sormas-backend/pom.xml | 2 +- sormas-base/dependencies/serverlibs.pom | 2 +- sormas-base/pom.xml | 2 +- sormas-cargoserver/pom.xml | 2 +- sormas-ear/pom.xml | 2 +- sormas-keycloak-service-provider/pom.xml | 2 +- sormas-rest/pom.xml | 2 +- sormas-ui/pom.xml | 2 +- sormas-widgetset/pom.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sormas-api/pom.xml b/sormas-api/pom.xml index 69d7b0c097e..34ab0c6f590 100644 --- a/sormas-api/pom.xml +++ b/sormas-api/pom.xml @@ -2,7 +2,7 @@ de.symeda.sormas sormas-base - 1.68.0 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-app/pom.xml b/sormas-app/pom.xml index 666d36c94ae..3bb68392128 100644 --- a/sormas-app/pom.xml +++ b/sormas-app/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.0 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-backend/pom.xml b/sormas-backend/pom.xml index f621e32c8b1..65f2c404621 100644 --- a/sormas-backend/pom.xml +++ b/sormas-backend/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.0 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-base/dependencies/serverlibs.pom b/sormas-base/dependencies/serverlibs.pom index 760c24ffa6b..7fa1fd8c18e 100644 --- a/sormas-base/dependencies/serverlibs.pom +++ b/sormas-base/dependencies/serverlibs.pom @@ -8,7 +8,7 @@ sormas-base de.symeda.sormas - 1.68.0 + 1.69.0-SNAPSHOT ../ diff --git a/sormas-base/pom.xml b/sormas-base/pom.xml index 9f9cb76d280..76e183d75a7 100644 --- a/sormas-base/pom.xml +++ b/sormas-base/pom.xml @@ -5,7 +5,7 @@ de.symeda.sormas sormas-base pom - 1.68.0 + 1.69.0-SNAPSHOT 1.8 diff --git a/sormas-cargoserver/pom.xml b/sormas-cargoserver/pom.xml index 4fc4743f3c9..8c6009ec75f 100644 --- a/sormas-cargoserver/pom.xml +++ b/sormas-cargoserver/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.68.0 + 1.69.0-SNAPSHOT ../sormas-base diff --git a/sormas-ear/pom.xml b/sormas-ear/pom.xml index 64dd2a9168f..eb67f26b2b0 100644 --- a/sormas-ear/pom.xml +++ b/sormas-ear/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.68.0 + 1.69.0-SNAPSHOT ../sormas-base diff --git a/sormas-keycloak-service-provider/pom.xml b/sormas-keycloak-service-provider/pom.xml index 03f1769132e..142c2f5858e 100644 --- a/sormas-keycloak-service-provider/pom.xml +++ b/sormas-keycloak-service-provider/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.0 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-rest/pom.xml b/sormas-rest/pom.xml index 5c4879bee2a..85e9fe6b41d 100644 --- a/sormas-rest/pom.xml +++ b/sormas-rest/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.68.0 + 1.69.0-SNAPSHOT ../sormas-base diff --git a/sormas-ui/pom.xml b/sormas-ui/pom.xml index 04ddceff812..2245a5f673d 100644 --- a/sormas-ui/pom.xml +++ b/sormas-ui/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.0 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-widgetset/pom.xml b/sormas-widgetset/pom.xml index a1c4df38387..f8d6a25f29d 100644 --- a/sormas-widgetset/pom.xml +++ b/sormas-widgetset/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.0 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 From 87cba9a19aafa6c2e183186b0f8fb8a0901a29e1 Mon Sep 17 00:00:00 2001 From: jparzuch Date: Wed, 9 Feb 2022 16:32:55 +0100 Subject: [PATCH 048/253] Amendments requested in the code review --- .../application/persons/PersonDirectoryPage.java | 2 ++ .../contacts/PersonContactDetailsSteps.java | 10 +++++++--- .../web/application/persons/EditPersonSteps.java | 4 ++-- .../application/persons/PersonDirectorySteps.java | 7 +++++++ .../resources/features/sanity/web/Persons.feature | 14 +++++++++----- 5 files changed, 27 insertions(+), 10 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/PersonDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/PersonDirectoryPage.java index dc7ecb6d02e..831a5976f91 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/PersonDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/PersonDirectoryPage.java @@ -31,4 +31,6 @@ public class PersonDirectoryPage { public static final By ALL_BUTTON = By.id("All"); public static final By CASE_PERSON_ID_COLUMN_HEADERS = By.cssSelector("v-grid-column-header-content v-grid-column-default-header-content"); + public static final By PRESENT_CONDITION_FILTER_COMBOBOX = + By.cssSelector("#presentCondition div"); } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/PersonContactDetailsSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/PersonContactDetailsSteps.java index aa0a49497c9..4b9d269818e 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/PersonContactDetailsSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/PersonContactDetailsSteps.java @@ -46,18 +46,22 @@ public PersonContactDetailsSteps(WebDriverHelpers webDriverHelpers) { }); Then( - "I enter an incorrect phone number and confirm", + "I enter an incorrect phone number in Person Contact Details popup", () -> { selectTypeOfContactDetails("Phone"); fillContactInformationInput("ABCdef!@#."); - webDriverHelpers.clickOnWebElementBySelector(DONE_BUTTON); }); Then( - "I enter an incorrect email and confirm", + "I enter an incorrect email in Person Contact Details popup", () -> { selectTypeOfContactDetails("Email"); fillContactInformationInput("1234567890"); + }); + + Then( + "I click the Done button in Person Contact Details popup", + () -> { webDriverHelpers.clickOnWebElementBySelector(DONE_BUTTON); }); } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java index 357dd37b36e..bc77ae40f5e 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java @@ -165,7 +165,7 @@ public EditPersonSteps( }); Then( - "I fill in the home address, facility category and type", + "I fill in the home address, facility category and type in the Home Address section of the Edit Person Page", () -> { newGeneratedPerson = personService.buildGeneratedPerson(); selectFacilityCategory(newGeneratedPerson.getFacilityCategory()); @@ -179,7 +179,7 @@ public EditPersonSteps( }); When( - "^I check that the empty district highlight appears$", + "^I check that an empty district highlight appears above the facility combobox$", () -> { webDriverHelpers.waitForPageLoaded(); webDriverHelpers.waitUntilIdentifiedElementIsPresent(ERROR_INDICATOR); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java index 393b533910e..647f5e5ae62 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java @@ -123,6 +123,13 @@ public PersonDirectorySteps( webDriverHelpers.clickOnWebElementBySelector(getByPersonUuid(personUuid)); }); + When( + "I filter for persons who are alive", + () -> { + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(40); + webDriverHelpers.selectFromCombobox(PRESENT_CONDITION_FILTER_COMBOBOX, "Alive"); + }); + When( "I click on first person in person directory", () -> { diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature index 6ff71ae640b..fefef268498 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature @@ -19,17 +19,21 @@ Feature: Edit Persons And I check that previous edited person is correctly displayed in Edit Person page @issue=SORDEV-8468 - Scenario: Edit existent person and provoke errors + Scenario: Edit existent person and provoke errors in the Edit Person page Given I log in with National User When I click on the Persons button from navbar + And I filter for persons who are alive + And I apply on the APPLY FILTERS button And I click on first person in person directory And I clear the mandatory Person fields And I click on save button from Edit Person page Then I check that an invalid data error message appears - When I fill in the home address, facility category and type - Then I check that the empty district highlight appears + When I fill in the home address, facility category and type in the Home Address section of the Edit Person Page + Then I check that an empty district highlight appears above the facility combobox When I click on new entry button from Contact Information section - And I enter an incorrect phone number and confirm + And I enter an incorrect phone number in Person Contact Details popup + And I click the Done button in Person Contact Details popup Then I check that an invalid data error message appears - When I enter an incorrect email and confirm + When I enter an incorrect email in Person Contact Details popup + And I click the Done button in Person Contact Details popup Then I check that an invalid data error message appears From 6640d45a65a2dbf2bfb951e329342794dfeef94c Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Wed, 9 Feb 2022 20:09:07 +0200 Subject: [PATCH 049/253] #7784 - discard override checkbox on immunization discard (#7939) --- .../ui/immunization/ImmunizationController.java | 11 +++++++++-- .../components/form/ImmunizationDataForm.java | 9 ++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java index 205a519265c..9b96a93451e 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java @@ -140,10 +140,17 @@ public CommitDiscardWrapperComponent getImmunizationDataEd immunizationDataForm.setValue(immunizationDto); UserProvider currentUserProvider = UserProvider.getCurrent(); - CommitDiscardWrapperComponent editComponent = new CommitDiscardWrapperComponent<>( + CommitDiscardWrapperComponent editComponent = new CommitDiscardWrapperComponent( immunizationDataForm, currentUserProvider != null && currentUserProvider.hasUserRight(UserRight.IMMUNIZATION_EDIT), - immunizationDataForm.getFieldGroup()); + immunizationDataForm.getFieldGroup()) { + + @Override + public void discard() { + super.discard(); + immunizationDataForm.discard(); + } + }; AutomaticDeletionInfoDto automaticDeletionInfoDto = FacadeProvider.getImmunizationFacade().getAutomaticDeletionInfo(immunizationDto.getUuid()); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/components/form/ImmunizationDataForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/components/form/ImmunizationDataForm.java index 871de477c1c..ea8b48b40cc 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/components/form/ImmunizationDataForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/components/form/ImmunizationDataForm.java @@ -118,6 +118,7 @@ public class ImmunizationDataForm extends AbstractEditForm { private final CaseReferenceDto relatedCase; private boolean ignoreMeansOfImmunizationChange = false; private MeansOfImmunization previousMeansOfImmunization; + private CheckBox overwriteImmunizationManagementStatus; public ImmunizationDataForm(boolean isPseudonymized, CaseReferenceDto relatedCase) { super( @@ -154,7 +155,7 @@ protected void addFields() { ComboBox meansOfImmunizationField = addField(ImmunizationDto.MEANS_OF_IMMUNIZATION, ComboBox.class); addField(ImmunizationDto.MEANS_OF_IMMUNIZATION_DETAILS, TextField.class); - CheckBox overwriteImmunizationManagementStatus = addCustomField(OVERWRITE_IMMUNIZATION_MANAGEMENT_STATUS, Boolean.class, CheckBox.class); + overwriteImmunizationManagementStatus = addCustomField(OVERWRITE_IMMUNIZATION_MANAGEMENT_STATUS, Boolean.class, CheckBox.class); overwriteImmunizationManagementStatus.addStyleName(VSPACE_3); ComboBox managementStatusField = addField(ImmunizationDto.IMMUNIZATION_MANAGEMENT_STATUS, ComboBox.class); @@ -547,4 +548,10 @@ public void setValue(ImmunizationDto newFieldValue) throws ReadOnlyException, Co ignoreMeansOfImmunizationChange = false; previousMeansOfImmunization = newFieldValue.getMeansOfImmunization(); } + + @Override + public void discard() throws SourceException { + super.discard(); + overwriteImmunizationManagementStatus.setValue(false); + } } From beef2cc11fce39482de79562fae428e5e4343f09 Mon Sep 17 00:00:00 2001 From: Jonas Cirotzki Date: Wed, 9 Feb 2022 12:48:11 +0100 Subject: [PATCH 050/253] [#7907] case insensitive comparison --- .../de/symeda/sormas/api/AuthProvider.java | 117 ++++++++---------- .../backend/user/CurrentUserService.java | 6 +- .../sormas/backend/user/UserFacadeEjb.java | 4 +- .../sormas/backend/user/UserService.java | 67 ++++------ .../backend/user/UserFacadeEjbTest.java | 3 - .../sormas/backend/user/UserServiceTest.java | 1 - 6 files changed, 79 insertions(+), 119 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/AuthProvider.java b/sormas-api/src/main/java/de/symeda/sormas/api/AuthProvider.java index 4949769fbac..305f546301d 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/AuthProvider.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/AuthProvider.java @@ -1,17 +1,14 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System * Copyright © 2016-2020 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) - * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -22,8 +19,8 @@ * Authentication provider which can be configured trough the {@link ConfigFacade#getAuthenticationProvider()} property. * Once initialized it provides Auth Provider specific authentication configs like: *

      - *
    • is user name case sensitive
    • - *
    • is email required
    • + *
    • is user name case sensitive
    • + *
    • is email required
    • *
    * * @author Alex Vidrean @@ -31,75 +28,61 @@ */ public class AuthProvider { - public static final String KEYCLOAK = "KEYCLOAK"; + public static final String KEYCLOAK = "KEYCLOAK"; - public static final String SORMAS = "SORMAS"; + public static final String SORMAS = "SORMAS"; - private static AuthProvider provider; + private static AuthProvider provider; - private final boolean isUsernameCaseSensitive; + private final boolean isDefaultProvider; - private final boolean isDefaultProvider; + private final boolean isUserSyncSupported; - private final boolean isUserSyncSupported; + private final boolean isUserSyncAtStartupEnabled; - private final boolean isUserSyncAtStartupEnabled; - - private final String name; + private final String name; private AuthProvider(ConfigFacade configFacade) { String configuredProvider = configFacade.getAuthenticationProvider(); - isUsernameCaseSensitive = SORMAS.equalsIgnoreCase(configuredProvider); - isDefaultProvider = SORMAS.equalsIgnoreCase(configuredProvider); - isUserSyncSupported = KEYCLOAK.equalsIgnoreCase(configuredProvider); - isUserSyncAtStartupEnabled = isUserSyncSupported && configFacade.isAuthenticationProviderUserSyncAtStartupEnabled(); - name = configuredProvider; - } - - public static AuthProvider getProvider(ConfigFacade configFacade) { - if (provider == null) { - synchronized (AuthProvider.class) { - if (provider == null) { - provider = new AuthProvider(configFacade); - } - } - } - return provider; - } - - /** - * Authentication Provider requires usernames to be case sensitive or insensitive - */ - public boolean isUsernameCaseSensitive() { - return isUsernameCaseSensitive; - } - - /** - * Current Authentication Provider is the SORMAS default one. - */ - public boolean isDefaultProvider() { - return isDefaultProvider; - } - - /** - * Authentication Provider enables users to be synced from the default provider. - */ - public boolean isUserSyncSupported() { - return isUserSyncSupported; - } - - /** - * Even if the Authentication Provider supports user sync, the user sync at startup might be disabled for startup performance reasons. - * If user sync is not supported, this will always return false. - */ - public boolean isUserSyncAtStartupEnabled() { - return isUserSyncAtStartupEnabled; - } - - /** - * Name of the active Authentication Provider. - */ - public String getName() { - return name; - } + isDefaultProvider = SORMAS.equalsIgnoreCase(configuredProvider); + isUserSyncSupported = KEYCLOAK.equalsIgnoreCase(configuredProvider); + isUserSyncAtStartupEnabled = isUserSyncSupported && configFacade.isAuthenticationProviderUserSyncAtStartupEnabled(); + name = configuredProvider; + } + + public static synchronized AuthProvider getProvider(ConfigFacade configFacade) { + if (provider == null) { + provider = new AuthProvider(configFacade); + } + return provider; + } + + /** + * Current Authentication Provider is the SORMAS default one. + */ + public boolean isDefaultProvider() { + return isDefaultProvider; + } + + /** + * Authentication Provider enables users to be synced from the default provider. + */ + public boolean isUserSyncSupported() { + return isUserSyncSupported; + } + + /** + * Even if the Authentication Provider supports user sync, the user sync at startup might be disabled for startup performance reasons. + * If user sync is not supported, this will always return false. + */ + public boolean isUserSyncAtStartupEnabled() { + return isUserSyncAtStartupEnabled; + } + + /** + * Name of the active Authentication Provider. + */ + public String getName() { + return name; + } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/CurrentUserService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/CurrentUserService.java index 82adde885d9..b968dfa37b1 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/CurrentUserService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/CurrentUserService.java @@ -51,16 +51,14 @@ public CurrentUser getCurrentUser() { final ParameterExpression userNameParam = cb.parameter(String.class, User.USER_NAME); final CriteriaQuery cq = cb.createQuery(User.class); final Root from = cq.from(User.class); - cq.where(cb.equal(cb.lower(from.get(User.USER_NAME)), userNameParam)); + // case-insensitive check + cq.where(cb.equal(cb.lower(from.get(User.USER_NAME)), userNameParam)); final TypedQuery q = em.createQuery(cq).setParameter(userNameParam, userName.toLowerCase()); final User user = q.getResultList().stream().findFirst().orElse(null); if (user != null) { - user.getUserRoles().size(); - // TODO - user.getAddress().getAddressType(); return new CurrentUser(user); } else { return new CurrentUser(null); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserFacadeEjb.java index 97419d78b09..b42b7f0e804 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserFacadeEjb.java @@ -671,7 +671,7 @@ private User fromDto(UserDto source, boolean checkChangeDate) { target.setHasConsentedToGdpr(source.isHasConsentedToGdpr()); final Set userRoles = source.getUserRoles(); - target.setUserRoles(new HashSet(userRoles)); + target.setUserRoles(new HashSet<>(userRoles)); target.updateJurisdictionLevel(); return target; @@ -705,7 +705,7 @@ public Set getValidLoginRoles(String userName, String password) { User user = userService.getByUserName(userName); if (user != null && user.isActive()) { if (DataHelper.equal(user.getPassword(), PasswordHelper.encodePassword(password, user.getSeed()))) { - return new HashSet(user.getUserRoles()); + return new HashSet<>(user.getUserRoles()); } } return null; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserService.java index 21a52a344b8..c4c980b8e05 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserService.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2018 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -91,26 +91,28 @@ public User getCurrentUser() { return super.getCurrentUser(); } + /** + * Fetches a use from the DB by its username. The check is done case-insensitive. + * + * @param userName + * The username in any casing. + * @return The corresponding User object from the DB. + */ public User getByUserName(String userName) { - CriteriaBuilder cb = em.getCriteriaBuilder(); ParameterExpression userNameParam = cb.parameter(String.class, User.USER_NAME); CriteriaQuery cq = cb.createQuery(getElementClass()); Root from = cq.from(getElementClass()); - Expression userNameExpression = from.get(User.USER_NAME); - String userNameParamValue = userName; - if (!AuthProvider.getProvider(configFacade).isUsernameCaseSensitive()) { - userNameExpression = cb.lower(userNameExpression); - userNameParamValue = userName.toLowerCase(); - } + // lowercase everything for case-insensitive check + Expression userNameExpression = cb.lower(from.get(User.USER_NAME)); + String userNameParamValue = userName.toLowerCase(); cq.where(cb.equal(userNameExpression, userNameParam)); TypedQuery q = em.createQuery(cq).setParameter(userNameParam, userNameParamValue); - User entity = q.getResultList().stream().findFirst().orElse(null); - return entity; + return q.getResultList().stream().findFirst().orElse(null); } public List getAllByRegionAndUserRoles(Region region, UserRole... userRoles) { @@ -225,12 +227,12 @@ public List getReferenceList( if (CollectionUtils.isNotEmpty(regionUuids)) { Join regionJoin = userRoot.join(User.REGION, JoinType.LEFT); - filter = CriteriaBuilderHelper.and(cb, filter, cb.in(regionJoin.get(Region.UUID)).value(regionUuids)); + filter = CriteriaBuilderHelper.and(cb, filter, cb.in(regionJoin.get(AbstractDomainObject.UUID)).value(regionUuids)); userEntityJoinUsed = true; } if (CollectionUtils.isNotEmpty(districtUuids)) { Join districtJoin = userRoot.join(User.DISTRICT, JoinType.LEFT); - filter = CriteriaBuilderHelper.and(cb, filter, cb.in(districtJoin.get(District.UUID)).value(districtUuids)); + filter = CriteriaBuilderHelper.and(cb, filter, cb.in(districtJoin.get(AbstractDomainObject.UUID)).value(districtUuids)); userEntityJoinUsed = true; } if (filterByJurisdiction) { @@ -241,7 +243,7 @@ public List getReferenceList( filter = CriteriaBuilderHelper.and(cb, filter, rolesJoin.in(userRoles)); } if (userEntityJoinUsed) { - filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(root.get(UserReference.ID), userRoot.get(User.ID))); + filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(root.get(UserReference.ID), userRoot.get(AbstractDomainObject.ID))); } // WHERE OR @@ -258,7 +260,7 @@ public List getReferenceList( if (CollectionUtils.isNotEmpty(communityUuids)) { Join communityJoin = userRoot.join(User.COMMUNITY, JoinType.LEFT); - filter = CriteriaBuilderHelper.and(cb, filter, cb.in(communityJoin.get(Community.UUID)).value(communityUuids)); + filter = CriteriaBuilderHelper.and(cb, filter, cb.in(communityJoin.get(AbstractDomainObject.UUID)).value(communityUuids)); } if (filter != null) { @@ -266,10 +268,9 @@ public List getReferenceList( } cq.distinct(true); - cq.orderBy(cb.asc(root.get(User.ID))); + cq.orderBy(cb.asc(root.get(AbstractDomainObject.ID))); - List resultList = em.createQuery(cq).setHint(ModelConstants.HINT_HIBERNATE_READ_ONLY, true).getResultList(); - return resultList; + return em.createQuery(cq).setHint(ModelConstants.HINT_HIBERNATE_READ_ONLY, true).getResultList(); } public List getUserReferencesByIds(Collection userIds) { @@ -383,33 +384,13 @@ public Map getResponsibleUsersByEventUuids(List eventUuids } public boolean isLoginUnique(String uuid, String userName) { - CriteriaBuilder cb = em.getCriteriaBuilder(); - ParameterExpression userNameParam = cb.parameter(String.class, User.USER_NAME); - CriteriaQuery cq = cb.createQuery(getElementClass()); - Root from = cq.from(getElementClass()); - - Expression userNameExpression = from.get(User.USER_NAME); - String userNameParamValue = userName; - if (!AuthProvider.getProvider(configFacade).isUsernameCaseSensitive()) { - userNameExpression = cb.lower(userNameExpression); - userNameParamValue = userName.toLowerCase(); - } - - cq.where(cb.equal(userNameExpression, userNameParam)); - - TypedQuery q = em.createQuery(cq).setParameter(userNameParam, userNameParamValue); - - User entity = q.getResultList().stream().findFirst().orElse(null); - - return entity == null || entity.getUuid().equals(uuid); + User user = getByUserName(userName); + return user == null || user.getUuid().equals(uuid); } public String resetPassword(String userUuid) { - User user = getByUuid(userUuid); - if (user == null) { -// logger.warn("resetPassword() for unknown user '{}'", realmUserUuid); return null; } @@ -433,11 +414,13 @@ public Predicate buildCriteriaFilter(UserCriteria userCriteria, CriteriaBuilder } if (userCriteria.getRegion() != null) { filter = CriteriaBuilderHelper - .and(cb, filter, cb.equal(from.join(Case.REGION, JoinType.LEFT).get(Region.UUID), userCriteria.getRegion().getUuid())); + .and(cb, filter, cb.equal(from.join(Case.REGION, JoinType.LEFT).get(AbstractDomainObject.UUID), userCriteria.getRegion().getUuid())); } if (userCriteria.getDistrict() != null) { - filter = CriteriaBuilderHelper - .and(cb, filter, cb.equal(from.join(Case.DISTRICT, JoinType.LEFT).get(District.UUID), userCriteria.getDistrict().getUuid())); + filter = CriteriaBuilderHelper.and( + cb, + filter, + cb.equal(from.join(Case.DISTRICT, JoinType.LEFT).get(AbstractDomainObject.UUID), userCriteria.getDistrict().getUuid())); } if (userCriteria.getFreeText() != null) { String[] textFilters = userCriteria.getFreeText().split("\\s+"); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/user/UserFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/user/UserFacadeEjbTest.java index 2d6d4227253..a2c94ef466e 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/user/UserFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/user/UserFacadeEjbTest.java @@ -245,7 +245,6 @@ public void testGetReferencesByRoleAndJurisdiction() { */ @Test public void testGetIndexListFilteredAndOrderedByAddress() { - List result = getUserFacade().getIndexList(new UserCriteria().freeText("min"), 0, 100, Collections.singletonList(new SortProperty(UserDto.ADDRESS))); @@ -255,12 +254,10 @@ public void testGetIndexListFilteredAndOrderedByAddress() { @Test public void testGetValidLoginRoles() { - AuthProvider authProvider = mock(AuthProvider.class); MockedStatic mockAuthProvider = mockStatic(AuthProvider.class); Mockito.when(AuthProvider.getProvider(any())).thenReturn(authProvider); - when(authProvider.isUsernameCaseSensitive()).thenReturn(true); RDCF rdcf = creator.createRDCF(); UserDto user = creator.createUser(rdcf, SURVEILLANCE_SUPERVISOR); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/user/UserServiceTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/user/UserServiceTest.java index ad631225225..4770fcdaf29 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/user/UserServiceTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/user/UserServiceTest.java @@ -44,7 +44,6 @@ public static void beforeClass() { mockAuthProvider = mockStatic(AuthProvider.class); assertNotNull(mockAuthProvider); Mockito.when(AuthProvider.getProvider(any())).thenReturn(authProvider); - when(authProvider.isUsernameCaseSensitive()).thenReturn(true); } @AfterClass From b8f3afef7e5afb2f91a22210dcec9d184d56b702 Mon Sep 17 00:00:00 2001 From: Jonas Cirotzki Date: Wed, 9 Feb 2022 12:59:30 +0100 Subject: [PATCH 051/253] [#7907] create lowercase index --- sormas-backend/src/main/resources/sql/sormas_schema.sql | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sormas-backend/src/main/resources/sql/sormas_schema.sql b/sormas-backend/src/main/resources/sql/sormas_schema.sql index 6148852d02e..fe83b33fc9b 100644 --- a/sormas-backend/src/main/resources/sql/sormas_schema.sql +++ b/sormas-backend/src/main/resources/sql/sormas_schema.sql @@ -9949,4 +9949,11 @@ ALTER TABLE eventparticipant_history ADD COLUMN archived BOOLEAN; INSERT INTO schema_version (version_number, comment) VALUES (440, 'Refactor CoreAdo to include archiving #7246'); +-- 2022-02-09 Create missing history tables for entities #7907 +DROP INDEX idx_users_username; +CREATE UNIQUE INDEX idx_users_username_lower ON users(LOWER(username)); +REINDEX INDEX idx_users_username_lower; + +INSERT INTO schema_version (version_number, comment) VALUES (441, ' Align username handling of Keycloak and legacy login #7907 '); + -- *** Insert new sql commands BEFORE this line. Remember to always consider _history tables. *** From 203fe710a7835fe9b5508e84876a35790f413779 Mon Sep 17 00:00:00 2001 From: Jonas Cirotzki Date: Wed, 9 Feb 2022 16:25:47 +0100 Subject: [PATCH 052/253] [#7907] fix comment --- sormas-backend/src/main/resources/sql/sormas_schema.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sormas-backend/src/main/resources/sql/sormas_schema.sql b/sormas-backend/src/main/resources/sql/sormas_schema.sql index fe83b33fc9b..80f6baea399 100644 --- a/sormas-backend/src/main/resources/sql/sormas_schema.sql +++ b/sormas-backend/src/main/resources/sql/sormas_schema.sql @@ -9949,7 +9949,7 @@ ALTER TABLE eventparticipant_history ADD COLUMN archived BOOLEAN; INSERT INTO schema_version (version_number, comment) VALUES (440, 'Refactor CoreAdo to include archiving #7246'); --- 2022-02-09 Create missing history tables for entities #7907 +-- 2022-02-09 Align username handling of Keycloak and legacy login #7907 DROP INDEX idx_users_username; CREATE UNIQUE INDEX idx_users_username_lower ON users(LOWER(username)); REINDEX INDEX idx_users_username_lower; From 9be49d985fb05d3055aec007df1f4a909c0bf2a3 Mon Sep 17 00:00:00 2001 From: Jonas Cirotzki Date: Wed, 9 Feb 2022 17:10:08 +0100 Subject: [PATCH 053/253] [#7907] add test + sonar lint --- sormas-backend/pom.xml | 5 ++ .../sormas/backend/user/UserFacadeEjb.java | 51 +++++++------- .../sormas/backend/TestDataCreator.java | 2 +- .../backend/user/UserFacadeEjbTest.java | 67 +++++++++++++++---- .../backend/visit/VisitFacadeEjbTest.java | 16 ++--- 5 files changed, 93 insertions(+), 48 deletions(-) diff --git a/sormas-backend/pom.xml b/sormas-backend/pom.xml index 65f2c404621..a32f8107f3b 100644 --- a/sormas-backend/pom.xml +++ b/sormas-backend/pom.xml @@ -232,6 +232,11 @@ com.google.http-client google-http-client-gson + + javax + javaee-web-api + test + diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserFacadeEjb.java index b42b7f0e804..084da585f75 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserFacadeEjb.java @@ -46,6 +46,8 @@ import javax.validation.Valid; import javax.validation.ValidationException; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Validations; import org.apache.commons.beanutils.BeanUtils; import de.symeda.sormas.api.HasUuid; @@ -185,28 +187,22 @@ public static UserDto toDto(User source) { target.setHasConsentedToGdpr(source.isHasConsentedToGdpr()); source.getUserRoles().size(); - target.setUserRoles(new HashSet(source.getUserRoles())); + target.setUserRoles(new HashSet<>(source.getUserRoles())); return target; } public static UserReferenceDto toReferenceDto(User entity) { - if (entity == null) { return null; } - - UserReferenceDto dto = new UserReferenceDto(entity.getUuid(), entity.getFirstName(), entity.getLastName(), entity.getUserRoles()); - return dto; + return new UserReferenceDto(entity.getUuid(), entity.getFirstName(), entity.getLastName(), entity.getUserRoles()); } public static UserReferenceDto toReferenceDto(UserReference entity) { - if (entity == null) { return null; } - - UserReferenceDto dto = new UserReferenceDto(entity.getUuid(), entity.getFirstName(), entity.getLastName(), entity.getUserRoles()); - return dto; + return new UserReferenceDto(entity.getUuid(), entity.getFirstName(), entity.getLastName(), entity.getUserRoles()); } private List toUuidList(HasUuid hasUuid) { @@ -215,7 +211,7 @@ private List toUuidList(HasUuid hasUuid) { * Supports conversion of a null object into a list with one "null" value in it. * Uncertain if that use case exists, but wasn't suppose to be broken when replacing the Dto to Entity lookup. */ - return Arrays.asList(hasUuid == null ? null : hasUuid.getUuid()); + return Collections.singletonList(hasUuid == null ? null : hasUuid.getUuid()); } @Override @@ -223,7 +219,7 @@ public List getUsersByRegionAndRoles(RegionReferenceDto region return userService.getReferenceList(toUuidList(regionRef), null, false, true, true, assignableRoles) .stream() - .map(f -> toReferenceDto(f)) + .map(UserFacadeEjb::toReferenceDto) .collect(Collectors.toList()); } @@ -234,7 +230,8 @@ public List getUsersByRegionAndRight(RegionReferenceDto region .filter(r -> userRoleConfigFacade.getEffectiveUserRights(r).contains(userRight)) .collect(Collectors.toList()); - return userService.getReferenceList(region == null ? null : Arrays.asList(region.getUuid()), null, null, false, true, true, userRoles) + return userService + .getReferenceList(region == null ? null : Collections.singletonList(region.getUuid()), null, null, false, true, true, userRoles) .stream() .map(UserFacadeEjb::toReferenceDto) .collect(Collectors.toList()); @@ -273,7 +270,7 @@ public List getUsersWithSuperiorJurisdiction(UserDto user) { break; case REGION: superiorUsersList = userService.getReferenceList( - Arrays.asList(user.getRegion().getUuid()), + Collections.singletonList(user.getRegion().getUuid()), null, null, false, @@ -298,12 +295,12 @@ public List getUsersWithSuperiorJurisdiction(UserDto user) { if (community == null) { superiorUsersList = - userService.getReferenceList(null, Arrays.asList(district.getUuid()), null, false, false, true, superordinateRoles); + userService.getReferenceList(null, Collections.singletonList(district.getUuid()), null, false, false, true, superordinateRoles); } else if (district != null) { superiorUsersList = userService.getReferenceList( null, - Arrays.asList(district.getUuid()), - Arrays.asList(community.getUuid()), + Collections.singletonList(district.getUuid()), + Collections.singletonList(community.getUuid()), false, false, true, @@ -313,7 +310,7 @@ public List getUsersWithSuperiorJurisdiction(UserDto user) { break; } - return superiorUsersList.stream().map(f -> toReferenceDto(f)).collect(Collectors.toList()); + return superiorUsersList.stream().map(UserFacadeEjb::toReferenceDto).collect(Collectors.toList()); } @Override @@ -321,7 +318,7 @@ public List getUserRefsByDistrict(DistrictReferenceDto distric return userService.getReferenceList(null, toUuidList(districtRef), includeSupervisors, true, true, userRoles) .stream() - .map(f -> toReferenceDto(f)) + .map(UserFacadeEjb::toReferenceDto) .collect(Collectors.toList()); } @@ -346,7 +343,7 @@ public List getAllUserRefs(boolean includeInactive) { return userService.getReferenceList(null, null, false, true, !includeInactive) .stream() - .map(c -> toReferenceDto(c)) + .map(UserFacadeEjb::toReferenceDto) .collect(Collectors.toList()); } @@ -391,7 +388,7 @@ public List getAssignableUsersWithTaskNumbers(T public List getUsersByAssociatedOfficer(UserReferenceDto associatedOfficerRef, UserRole... userRoles) { User associatedOfficer = userService.getByReferenceDto(associatedOfficerRef); - return userService.getAllByAssociatedOfficer(associatedOfficer, userRoles).stream().map(f -> toDto(f)).collect(Collectors.toList()); + return userService.getAllByAssociatedOfficer(associatedOfficer, userRoles).stream().map(UserFacadeEjb::toDto).collect(Collectors.toList()); } @Override @@ -482,7 +479,7 @@ public List getUsersHavingE cq.distinct(true); cq.orderBy(cb.asc(root.get(User.ID))); List resultList = em.createQuery(cq).setHint(ModelConstants.HINT_HIBERNATE_READ_ONLY, true).getResultList(); - return resultList.stream().map(c -> toReferenceDto(c)).collect(Collectors.toList()); + return resultList.stream().map(UserFacadeEjb::toReferenceDto).collect(Collectors.toList()); } public interface JurisdictionOverEntitySubqueryBuilder { @@ -499,12 +496,12 @@ public Page getIndexPage(UserCriteria userCriteria, int offset, int siz @Override public List getAllAfter(Date date) { - return userService.getAllAfter(date).stream().map(c -> toDto(c)).collect(Collectors.toList()); + return userService.getAllAfter(date).stream().map(UserFacadeEjb::toDto).collect(Collectors.toList()); } @Override public List getByUuids(List uuids) { - return userService.getByUuids(uuids).stream().map(c -> toDto(c)).collect(Collectors.toList()); + return userService.getByUuids(uuids).stream().map(UserFacadeEjb::toDto).collect(Collectors.toList()); } @Override @@ -547,6 +544,10 @@ public UserDto saveUser(@Valid UserDto dto) { throw new ValidationException(e); } + if (!isLoginUnique(oldUser == null ? null : oldUser.getUuid(), dto.getUserName())) { + throw new ValidationException(I18nProperties.getValidationError(Validations.userNameNotUnique)); + } + userService.ensurePersisted(user); if (oldUser == null) { @@ -585,8 +586,8 @@ public List getIndexList(UserCriteria userCriteria, Integer first, Inte cq.where(filter); } - if (sortProperties != null && sortProperties.size() > 0) { - List order = new ArrayList(sortProperties.size()); + if (sortProperties != null && !sortProperties.isEmpty()) { + List order = new ArrayList<>(sortProperties.size()); for (SortProperty sortProperty : sortProperties) { Expression expression; switch (sortProperty.propertyName) { diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java index 659aa95efe8..20e129318f5 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java @@ -166,7 +166,7 @@ public UserDto createUser(RDCF rdcf, UserRole... roles) { return createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "First", "Name", roles); } - public UserDto createUser(RDCFEntities rdcf, String firstName, String lastName, UserRole... roles) { + public UserDto createUser(RDCF rdcf, String firstName, String lastName, UserRole... roles) { return createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), firstName, lastName, roles); } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/user/UserFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/user/UserFacadeEjbTest.java index a2c94ef466e..f0b64325205 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/user/UserFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/user/UserFacadeEjbTest.java @@ -29,23 +29,27 @@ import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Set; +import java.util.UUID; import java.util.stream.Collectors; -import de.symeda.sormas.api.user.UserRight; -import de.symeda.sormas.backend.infrastructure.region.RegionFacadeEjb; +import javax.validation.ValidationException; + +import de.symeda.sormas.api.EntityDto; import org.junit.Before; import org.junit.Test; +import org.junit.function.ThrowingRunnable; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockedStatic; @@ -53,19 +57,21 @@ import org.mockito.MockitoAnnotations; import de.symeda.sormas.api.AuthProvider; -import de.symeda.sormas.api.infrastructure.facility.FacilityReferenceDto; import de.symeda.sormas.api.infrastructure.community.CommunityReferenceDto; import de.symeda.sormas.api.infrastructure.district.DistrictReferenceDto; +import de.symeda.sormas.api.infrastructure.facility.FacilityReferenceDto; import de.symeda.sormas.api.infrastructure.region.RegionReferenceDto; import de.symeda.sormas.api.user.UserCriteria; import de.symeda.sormas.api.user.UserDto; +import de.symeda.sormas.api.user.UserFacade; import de.symeda.sormas.api.user.UserReferenceDto; +import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.user.UserRole; import de.symeda.sormas.api.utils.SortProperty; import de.symeda.sormas.backend.AbstractBeanTest; import de.symeda.sormas.backend.TestDataCreator.RDCF; -import de.symeda.sormas.backend.TestDataCreator.RDCFEntities; import de.symeda.sormas.backend.infrastructure.region.Region; +import de.symeda.sormas.backend.infrastructure.region.RegionFacadeEjb; import de.symeda.sormas.backend.infrastructure.region.RegionService; public class UserFacadeEjbTest extends AbstractBeanTest { @@ -83,7 +89,6 @@ public void setUp() { @Test public void testGetUsersByRegionAndRoles() { - // 0. Call with no users and without region does not fail assertThat(getUserFacade().getUsersByRegionAndRoles(null, SURVEILLANCE_OFFICER), is(empty())); @@ -96,9 +101,9 @@ public void testGetUsersByRegionAndRoles() { @Test public void testGetUsersByRegionAndRight() { - RDCFEntities rdcf = creator.createRDCFEntities(); + RDCF rdcf = creator.createRDCF(); + RegionReferenceDto region = rdcf.region; RegionFacadeEjb.RegionFacadeEjbLocal regionFacade = (RegionFacadeEjb.RegionFacadeEjbLocal) getRegionFacade(); - RegionReferenceDto region = regionFacade.toRefDto(rdcf.region); List result = getUserFacade().getUsersByRegionAndRight(region, UserRight.LAB_MESSAGES); @@ -127,7 +132,7 @@ public void testGetUsersByRegionAndRight() { public void testGetIndexList() { // 1 region, 2 districts - RDCFEntities rdcf = creator.createRDCFEntities(); + RDCF rdcf = creator.createRDCF(); Region region = getBean(RegionService.class).getByUuid(rdcf.region.getUuid()); creator.createDistrict("district 2", region); @@ -143,7 +148,7 @@ public void testGetIndexList() { // 1. Check that query works without filter: All 3 distinct users are found (+ admin by default) result = getUserFacade().getIndexList(new UserCriteria(), 0, 100, null); assertThat(result, hasSize(4)); - assertThat(result.stream().map(e -> e.getUuid()).collect(Collectors.toSet()), hasSize(4)); + assertThat(result.stream().map(EntityDto::getUuid).collect(Collectors.toSet()), hasSize(4)); // 2. Check that only the expected user is found result = getUserFacade().getIndexList(new UserCriteria().freeText("myUser"), 0, 100, null); @@ -287,7 +292,7 @@ public void testGetExistentDefaultUsers() { for (User user : testUsers) { Mockito.when(userService.getCurrentUser()).thenReturn(user); - Mockito.when(userService.getAllDefaultUsers()).thenReturn(Arrays.asList(user)); + Mockito.when(userService.getAllDefaultUsers()).thenReturn(Collections.singletonList(user)); if (defaultUsers.contains(user)) { assertEquals(1, userFacadeEjb.getUsersWithDefaultPassword().size()); assertEquals(UserFacadeEjb.toDto(user), userFacadeEjb.getUsersWithDefaultPassword().get(0)); @@ -320,9 +325,47 @@ public void testGetExistentDefaultUsersUpperCase() { for (User user : defaultUsers) { user.setUserName(user.getUserName().toUpperCase()); Mockito.when(userService.getCurrentUser()).thenReturn(user); - Mockito.when(userService.getAllDefaultUsers()).thenReturn(Arrays.asList(user)); + Mockito.when(userService.getAllDefaultUsers()).thenReturn(Collections.singletonList(user)); assertEquals(0, userFacadeEjb.getUsersWithDefaultPassword().size()); } + } + + @Test + public void testGetByUserName() { + final UserFacade userFacade = getUserFacade(); + assertNull(userFacade.getByUserName("HansPeter")); + RDCF rdcf = creator.createRDCF(); + UserDto user = creator.createUser(rdcf, "Hans", "Peter", SURVEILLANCE_OFFICER); + + assertEquals(user, userFacade.getByUserName("HANSPETER")); + assertEquals(user, userFacade.getByUserName("hanspeter")); + assertEquals(user, userFacade.getByUserName("HansPeter")); + assertEquals(user, userFacade.getByUserName("hansPETER")); + } + + @Test + public void testLoginUnique() { + final UserFacade userFacade = getUserFacade(); + assertNull(userFacade.getByUserName("HansPeter")); + + RDCF rdcf = creator.createRDCF(); + creator.createUser(rdcf, "Hans", "Peter", SURVEILLANCE_OFFICER); + + assertTrue(userFacade.isLoginUnique(String.valueOf(UUID.randomUUID()), "MarieLisa")); + assertFalse(userFacade.isLoginUnique(String.valueOf(UUID.randomUUID()), "HansPeter")); + assertFalse(userFacade.isLoginUnique(String.valueOf(UUID.randomUUID()), "hanspeter")); + } + + @Test + public void testFailOnSavingDuplicateUser() { + final UserFacade userFacade = getUserFacade(); + assertNull(userFacade.getByUserName("HansPeter")); + + RDCF rdcf = creator.createRDCF(); + creator.createUser(rdcf, "Hans", "Peter", SURVEILLANCE_OFFICER); + assertThrows("User name is not unique!", ValidationException.class, () -> creator.createUser(rdcf, "Hans", "Peter", SURVEILLANCE_OFFICER)); + assertThrows("User name is not unique!", ValidationException.class, () -> creator.createUser(rdcf, "hans", "peter", SURVEILLANCE_OFFICER)); + assertThrows("User name is not unique!", ValidationException.class, () -> creator.createUser(rdcf, "HANS", "PETER", SURVEILLANCE_OFFICER)); } } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/visit/VisitFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/visit/VisitFacadeEjbTest.java index 500b907a808..e210637ea05 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/visit/VisitFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/visit/VisitFacadeEjbTest.java @@ -251,7 +251,7 @@ public void testGetAllActiveUuids() throws ExternalSurveillanceToolException { TestDataCreator.RDCF rdcf = creator.createRDCF(); - UserDto user = creator.createUser(creator.createRDCFEntities(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); + UserDto user = creator.createUser(rdcf, "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); PersonDto person = creator.createPerson(); PersonDto person2 = creator.createPerson(); @@ -287,9 +287,8 @@ public void testGetAllActiveUuids() throws ExternalSurveillanceToolException { @Test public void testGetAllActiveVisitsAfter() throws InterruptedException, ExternalSurveillanceToolException { - - UserDto user = creator.createUser(creator.createRDCFEntities(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); TestDataCreator.RDCF rdcf = creator.createRDCF(); + UserDto user = creator.createUser(rdcf, "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); Date date = new Date(); PersonDto person = creator.createPerson(); @@ -336,8 +335,7 @@ public void testGetAllActiveVisitsAfter() throws InterruptedException, ExternalS @Test public void testGetLastVisitByContact() { - - UserDto user = creator.createUser(creator.createRDCFEntities(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); + UserDto user = creator.createUser(creator.createRDCF(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); PersonDto person = creator.createPerson(); ContactDto contact = creator.createContact(user.toReference(), person.toReference()); @@ -351,7 +349,7 @@ public void testGetLastVisitByContact() { @Test public void testGetVisitsByContactAndPeriod() { - UserDto user = creator.createUser(creator.createRDCFEntities(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); + UserDto user = creator.createUser(creator.createRDCF(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); PersonDto person = creator.createPerson(); ContactDto contact = creator.createContact(user.toReference(), person.toReference()); @@ -377,8 +375,7 @@ public void testGetVisitsByContactAndPeriod() { @Test public void testGetLastVisitByCase() { - - UserDto user = creator.createUser(creator.createRDCFEntities(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); + UserDto user = creator.createUser(creator.createRDCF(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); PersonDto person = creator.createPerson(); CaseDataDto caze = creator.createCase(user.toReference(), person.toReference(), creator.createRDCF()); @@ -391,8 +388,7 @@ public void testGetLastVisitByCase() { @Test public void testGetIndexList() { - - UserDto user = creator.createUser(creator.createRDCFEntities(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); + UserDto user = creator.createUser(creator.createRDCF(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); PersonDto person = creator.createPerson(); PersonDto person2 = creator.createPerson(); From e0a475657b9ec6ebe9f5512891d8628abe865048 Mon Sep 17 00:00:00 2001 From: Jonas Cirotzki Date: Thu, 10 Feb 2022 10:37:43 +0100 Subject: [PATCH 054/253] [#7907] leave old provider for now --- .../src/main/java/de/symeda/sormas/api/AuthProvider.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/AuthProvider.java b/sormas-api/src/main/java/de/symeda/sormas/api/AuthProvider.java index 305f546301d..d621cc6e263 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/AuthProvider.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/AuthProvider.java @@ -50,9 +50,13 @@ private AuthProvider(ConfigFacade configFacade) { name = configuredProvider; } - public static synchronized AuthProvider getProvider(ConfigFacade configFacade) { + public static AuthProvider getProvider(ConfigFacade configFacade) { if (provider == null) { - provider = new AuthProvider(configFacade); + synchronized (AuthProvider.class) { + if (provider == null) { + provider = new AuthProvider(configFacade); + } + } } return provider; } From 868becc744929cbc478df2786fbb8d3718058718 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Thu, 10 Feb 2022 10:42:18 +0100 Subject: [PATCH 055/253] fixes --- .../steps/web/application/cases/CaseDirectorySteps.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java index 568c90a1182..f7d2560591a 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java @@ -308,7 +308,7 @@ public CaseDirectorySteps( And( "I fill Cases from input to {int} days before mocked Case created on Case directory page", (Integer number) -> { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M/d/yyyy"); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy"); webDriverHelpers.fillInWebElement( DATE_FROM_COMBOBOX, formatter.format( @@ -320,7 +320,7 @@ public CaseDirectorySteps( And( "I fill Cases from input to {int} days after before mocked Case created on Case directory page", (Integer number) -> { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M/d/yyyy"); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy"); webDriverHelpers.fillInWebElement( DATE_FROM_COMBOBOX, formatter.format(LocalDate.now().plusDays(number))); }); @@ -395,7 +395,7 @@ public CaseDirectorySteps( And( "I fill Cases to input to {int} days after mocked Case created on Case directory page", (Integer number) -> { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M/d/yyyy"); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy"); webDriverHelpers.fillInWebElement( DATE_TO_COMBOBOX, formatter.format( From b56f7e1f65470a507e0b7017810d8770bff7003c Mon Sep 17 00:00:00 2001 From: Jonas Cirotzki Date: Thu, 10 Feb 2022 11:47:36 +0100 Subject: [PATCH 056/253] [#7907] fix tests --- .../resources/doc/SORMAS_Data_Dictionary.xlsx | Bin 257041 -> 257040 bytes .../resources/doc/SORMAS_User_Rights.xlsx | Bin 19173 -> 19172 bytes .../DocumentTemplateEntitiesBuilder.java | 4 +- .../backend/user/CurrentUserService.java | 4 ++ .../sormas/backend/TestDataCreator.java | 8 ++- .../CaseFacadeEjbPseudonymizationTest.java | 3 - .../backend/caze/CaseFacadeEjbTest.java | 58 +++++++++--------- .../ClinicalCourseFacadeEjbTest.java | 2 +- .../backend/contact/ContactFacadeEjbTest.java | 8 +-- .../QuarantineOrderFacadeEjbTest.java | 2 +- .../backend/event/EventFacadeEjbTest.java | 4 +- .../backend/sample/SampleFacadeEjbTest.java | 2 +- .../backend/task/TaskFacadeEjbTest.java | 6 +- .../therapy/PrescriptionFacadeEjbTest.java | 2 +- .../therapy/TreatmentFacadeEjbTest.java | 2 +- .../backend/user/UserFacadeEjbTest.java | 6 +- 16 files changed, 60 insertions(+), 51 deletions(-) diff --git a/sormas-api/src/main/resources/doc/SORMAS_Data_Dictionary.xlsx b/sormas-api/src/main/resources/doc/SORMAS_Data_Dictionary.xlsx index 34253040e7479d495f6c45134224274a9e11ba08..bb9e2868ba3bfbc1920b0650ff1060d94fef2e91 100644 GIT binary patch delta 12389 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 Y{b2K5$7`|<6Z%{v+FQb^rhX delta 11997 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 Q%JBJxVpVxzJRYIy|LASa9RL6T diff --git a/sormas-api/src/main/resources/doc/SORMAS_User_Rights.xlsx b/sormas-api/src/main/resources/doc/SORMAS_User_Rights.xlsx index 1b720fab85d2435178df547750bc5036e54c452f..cc4d50e8473a75a99e40e916e49f2b77a07be55b 100644 GIT binary patch delta 605 zcmaDlmGQ|`M&1B#W)=|!4h{|mjaaXZywZ%!Kzg$_V;z_=c@5JUkig_>W|jI_@52Tn zZU4Pa)>cpQYirr&Jf(4gMZuy9@kz~fhQvM+MIt55j-CgD%9Tk1Jfmu6p(XcY=PpmOGJl8XA$N!^!feB!v(-OUuxUG7} z+#OGMDm87MHCsQxo1LTK#h1^lj0_ALffyzHHXmR~=K=?y7QYe`nBgy|3JKD3Aw@7_ zlDo?0{la#}AlXgsVUS>s^e_YQCr|RQ1Jjp1tT}=F5U@>?#XTXi0iM!Kn^-2FXA#p5 z@MdHZVSqNyw~co~p^%;a^RGGIf`dP*}oPJZbr2j+2kNi$|nR`b%7 z2U%n#eC&(7F$2Sa$xI9q$l4itC+B&oD}dD0Ecf>k1ln;Fh*8yia+}QWE;aeQmjIim H2S_&nTqo8! delta 564 zcmaDdmGS9RM&1B#W)=|!4h{|mpE%ErywZ%!Kzg$_V;z_=c@5JUkig_>W|jK8UPlZB z+~Su$**ABKYoYUP*D0)yg$KJH#d;jucH_?km)*a=Eh}BSz)5e?&vPb>pa&tW< zO$PUn70vB7rysWSzL@fVd!lF9rw8p*XD!p5eX6xv`00n5^4}YH=JQqk+wE{EMBP-F zuhLl8zTe5Mj%EBz|H$v(z(DPsL8Ly1ZMaNszSoFOh^$D zrvKekHt!R*GX_ilcMF4vMtGQkLwcfz9hko4Va*8)`4F&Olf^tCvi_dZOq*FIpJNf@ z5AbGW5@CSH-Q2UlmqiPy`&klCaZdBf_Z^JUf<+gFLecw i1vSh4y##?CISRxQ49MWK+hjg>smbTO1lYVhKoS6ir_t{K diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateEntitiesBuilder.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateEntitiesBuilder.java index bcc6c04dcee..7b3cc67e2cb 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateEntitiesBuilder.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateEntitiesBuilder.java @@ -55,6 +55,7 @@ import de.symeda.sormas.api.sample.SampleDto; import de.symeda.sormas.api.sample.SampleReferenceDto; import de.symeda.sormas.api.travelentry.TravelEntryDto; +import de.symeda.sormas.api.user.UserDto; import de.symeda.sormas.api.vaccination.VaccinationDto; import de.symeda.sormas.api.vaccination.VaccinationReferenceDto; import de.symeda.sormas.backend.caze.CaseFacadeEjb.CaseFacadeEjbLocal; @@ -315,7 +316,8 @@ private DocumentTemplateEntities buildEntities( entities.addEntity(RootEntityType.ROOT_VACCINATION, vaccination); } - entities.addEntity(RootEntityType.ROOT_USER, userFacade.getCurrentUser()); + final UserDto currentUser = userFacade.getCurrentUser(); + entities.addEntity(RootEntityType.ROOT_USER, currentUser); return entities; } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/CurrentUserService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/CurrentUserService.java index b968dfa37b1..93449eebedd 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/CurrentUserService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/CurrentUserService.java @@ -52,6 +52,10 @@ public CurrentUser getCurrentUser() { final CriteriaQuery cq = cb.createQuery(User.class); final Root from = cq.from(User.class); + // avoid "Hibernate could not initialize proxy – no Session" Exception + // do eager loading in this case + from.fetch(User.ADDRESS); + // case-insensitive check cq.where(cb.equal(cb.lower(from.get(User.USER_NAME)), userNameParam)); final TypedQuery q = em.createQuery(cq).setParameter(userNameParam, userName.toLowerCase()); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java index 20e129318f5..52566fc5dd1 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java @@ -337,8 +337,12 @@ public PersonContactDetailDto createPersonContactDetail( public CaseDataDto createUnclassifiedCase(Disease disease) { RDCFEntities rdcf = createRDCFEntities("Region", "District", "Community", "Facility"); - UserDto user = - createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); + UserDto user = beanTest.getUserFacade().getByUserName("SurvSup"); + if (user == null) { + user = + createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); + } + PersonDto cazePerson = createPerson("Case", "Person", Sex.UNKNOWN); return createCase( user.toReference(), diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbPseudonymizationTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbPseudonymizationTest.java index bf028e2ec76..1378965cdfd 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbPseudonymizationTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbPseudonymizationTest.java @@ -239,11 +239,8 @@ public void testUpdateCaseInJurisdiction() { @Test public void testUpdatePseudonymizedCase() { - CaseDataDto caze = createCase(rdcf1, user1); - loginWith(observerUser); - updateCase(caze, observerUser); assertPseudonymizedDataNotUpdated(caze, rdcf1, user1); } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java index cc9f3d79a74..b04bb7fd19d 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java @@ -71,7 +71,6 @@ import de.symeda.sormas.api.caze.CaseDataDto; import de.symeda.sormas.api.caze.CaseExportDto; import de.symeda.sormas.api.caze.CaseExportType; -import de.symeda.sormas.api.caze.CaseFacade; import de.symeda.sormas.api.caze.CaseIndexDto; import de.symeda.sormas.api.caze.CaseLogic; import de.symeda.sormas.api.caze.CaseOutcome; @@ -834,7 +833,7 @@ public void testGetExportListNoDuplicates() { caze = getCaseFacade().save(caze); List result = - getCaseFacade().getExportList(new CaseCriteria(), Collections.emptySet(), CaseExportType.CASE_SURVEILLANCE, 0, 100, null, Language.EN); + getCaseFacade().getExportList(new CaseCriteria(), Collections.emptySet(), CaseExportType.CASE_SURVEILLANCE, 0, 100, null, Language.EN); assertThat(result, hasSize(1)); CaseExportDto exportDto = result.get(0); assertNotNull(exportDto.getEpiDataId()); @@ -844,14 +843,13 @@ public void testGetExportListNoDuplicates() { @Test public void testCaseDeletion() throws ExternalSurveillanceToolException { - Date since = new Date(); RDCFEntities rdcf = creator.createRDCFEntities("Region", "District", "Community", "Facility"); UserDto user = creator .createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); - UserDto admin = creator.createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Ad", "Min", UserRole.ADMIN); - String adminUuid = admin.getUuid(); + UserDto admin = getUserFacade().getByUserName("AdMin"); + PersonDto cazePerson = creator.createPerson("Case", "Person"); CaseDataDto caze = creator.createCase( user.toReference(), @@ -1275,7 +1273,7 @@ public void testMergeCase() throws IOException { // 1. Create // Create leadCase - UserDto leadUser = creator.createUser("", "", "", "", ""); + UserDto leadUser = creator.createUser("", "", "", "First", "User"); UserReferenceDto leadUserReference = new UserReferenceDto(leadUser.getUuid()); PersonDto leadPerson = creator.createPerson("Alex", "Miller"); PersonReferenceDto leadPersonReference = new PersonReferenceDto(leadPerson.getUuid()); @@ -1300,7 +1298,7 @@ public void testMergeCase() throws IOException { getVisitFacade().saveVisit(leadVisit); // Create otherCase - UserDto otherUser = creator.createUser("", "", "", "", ""); + UserDto otherUser = creator.createUser("", "", "", "Second", "User"); UserReferenceDto otherUserReference = new UserReferenceDto(otherUser.getUuid()); PersonDto otherPerson = creator.createPerson("Max", "Smith"); otherPerson.setBirthWeight(2); @@ -1632,10 +1630,9 @@ public void testArchiveAllArchivableCases() { @Test public void testCreateInvestigationTask() { - - RDCFEntities rdcf = creator.createRDCFEntities(); - UserReferenceDto user = creator.createUser(rdcf, UserRole.SURVEILLANCE_SUPERVISOR).toReference(); - UserReferenceDto surveillanceOfficer = creator.createUser(rdcf, UserRole.SURVEILLANCE_OFFICER).toReference(); + RDCF rdcf = creator.createRDCF(); + UserReferenceDto user = creator.createUser(rdcf, "First", "User", UserRole.SURVEILLANCE_SUPERVISOR).toReference(); + UserReferenceDto surveillanceOfficer = creator.createUser(rdcf, "Second", "User", UserRole.SURVEILLANCE_OFFICER).toReference(); PersonReferenceDto person = creator.createPerson("Case", "Person").toReference(); CaseDataDto caze = creator.createCase(user, person, rdcf); @@ -1646,12 +1643,12 @@ public void testCreateInvestigationTask() { @Test public void testSetResponsibleSurveillanceOfficer() { - RDCFEntities rdcf = creator.createRDCFEntities(); - RDCFEntities rdcf2 = creator.createRDCFEntities("Region2", "District2", "Community2", "Facility2"); - RDCFEntities rdcf3 = creator.createRDCFEntities("Region3", "District3", "Community3", "Facility3"); - creator.createUser(rdcf, UserRole.SURVEILLANCE_OFFICER).toReference(); - UserReferenceDto survOff2 = creator.createUser(rdcf, UserRole.SURVEILLANCE_OFFICER).toReference(); - UserReferenceDto survOff3 = creator.createUser(rdcf2, UserRole.SURVEILLANCE_OFFICER).toReference(); + RDCF rdcf = creator.createRDCF(); + RDCF rdcf2 = creator.createRDCF("Region2", "District2", "Community2", "Facility2"); + RDCF rdcf3 = creator.createRDCF("Region3", "District3", "Community3", "Facility3"); + creator.createUser(rdcf, "First", "User", UserRole.SURVEILLANCE_OFFICER).toReference(); + UserReferenceDto survOff2 = creator.createUser(rdcf, "Second", "User", UserRole.SURVEILLANCE_OFFICER).toReference(); + UserReferenceDto survOff3 = creator.createUser(rdcf2, "Third", "User", UserRole.SURVEILLANCE_OFFICER).toReference(); UserDto informant = creator.createUser(rdcf, UserRole.HOSPITAL_INFORMANT); informant.setAssociatedOfficer(survOff3); getUserFacade().saveUser(informant); @@ -1680,15 +1677,14 @@ public void testSetResponsibleSurveillanceOfficer() { @Test public void testSearchCasesFreetext() { RDCF rdcf = creator.createRDCF(); - CaseDataDto caze = - creator.createCase(creator.createUser(rdcf, UserRole.SURVEILLANCE_OFFICER).toReference(), creator.createPerson().toReference(), rdcf); + final UserReferenceDto user = creator.createUser(rdcf, UserRole.SURVEILLANCE_OFFICER).toReference(); + CaseDataDto caze = creator.createCase(user, creator.createPerson().toReference(), rdcf); caze.setInternalToken("internalToken"); caze.setExternalToken("externalToken"); caze.setExternalID("externalID"); getCaseFacade().save(caze); - CaseDataDto secondCaze = - creator.createCase(creator.createUser(rdcf, UserRole.SURVEILLANCE_OFFICER).toReference(), creator.createPerson().toReference(), rdcf); + CaseDataDto secondCaze = creator.createCase(user, creator.createPerson().toReference(), rdcf); secondCaze.setInternalToken("internalToken2"); getCaseFacade().save(secondCaze); @@ -1774,7 +1770,8 @@ public void testGetDuplicates() { p.setBirthdateYYYY(1968); }); - CaseDataDto caze = creator.createCase(creator.createUser(rdcf, UserRole.SURVEILLANCE_OFFICER).toReference(), rdcf, (c) -> { + final UserReferenceDto user = creator.createUser(rdcf, UserRole.SURVEILLANCE_OFFICER).toReference(); + CaseDataDto caze = creator.createCase(user, rdcf, (c) -> { c.setPerson(person.toReference()); c.setExternalID("test-ext-id"); c.setExternalToken("test-ext-token"); @@ -1788,17 +1785,17 @@ public void testGetDuplicates() { p.setBirthdateMM(3); p.setBirthdateYYYY(1968); }); - creator.createCase(creator.createUser(rdcf, UserRole.SURVEILLANCE_OFFICER).toReference(), rdcf, (c) -> { + creator.createCase(user, rdcf, (c) -> { c.setPerson(person2.toReference()); c.setDisease(Disease.CORONAVIRUS); }); - creator.createCase(creator.createUser(rdcf, UserRole.SURVEILLANCE_OFFICER).toReference(), rdcf, (c) -> { + creator.createCase(user, rdcf, (c) -> { c.setPerson(creator.createPerson().toReference()); c.setDisease(Disease.CHOLERA); }); - creator.createCase(creator.createUser(rdcf, UserRole.SURVEILLANCE_OFFICER).toReference(), rdcf, (c) -> { + creator.createCase(user, rdcf, (c) -> { c.setPerson(person.toReference()); c.setDisease(Disease.CHOLERA); }); @@ -1938,7 +1935,11 @@ public void testSearchByFacilityTypeAndGroup() { private CaseDataDto createCaseOfFacilityType(RDCF rdcf, PersonReferenceDto personDto, FacilityType facilityType) { CaseDataDto caze1 = CaseDataDto.build(personDto, Disease.CORONAVIRUS); caze1.setReportDate(new Date()); - caze1.setReportingUser(creator.createUser(rdcf, UserRole.SURVEILLANCE_OFFICER).toReference()); + UserDto user = getUserFacade().getByUserName("SomeUser"); + if (user == null) { + user = creator.createUser(rdcf, "Some", "User", UserRole.SURVEILLANCE_OFFICER); + } + caze1.setReportingUser(user.toReference()); caze1.setCaseClassification(CaseClassification.PROBABLE); caze1.setInvestigationStatus(InvestigationStatus.PENDING); caze1.setDisease(Disease.CORONAVIRUS); @@ -1969,7 +1970,8 @@ public void testGetDuplicatesWithReportDateThreshold() { p.setBirthdateYYYY(1968); }); - CaseDataDto caze = creator.createCase(creator.createUser(rdcf, UserRole.SURVEILLANCE_OFFICER).toReference(), rdcf, (c) -> { + final UserReferenceDto user = creator.createUser(rdcf, UserRole.SURVEILLANCE_OFFICER).toReference(); + CaseDataDto caze = creator.createCase(user, rdcf, (c) -> { c.setPerson(person.toReference()); c.setDisease(Disease.CORONAVIRUS); c.setDistrict(rdcf.district); @@ -1980,7 +1982,7 @@ public void testGetDuplicatesWithReportDateThreshold() { p.setBirthdateMM(3); p.setBirthdateYYYY(1968); }); - creator.createCase(creator.createUser(rdcf, UserRole.SURVEILLANCE_OFFICER).toReference(), rdcf, (c) -> { + creator.createCase(user, rdcf, (c) -> { c.setPerson(person2.toReference()); c.setDisease(Disease.CORONAVIRUS); c.setReportDate(new DateTime(now).minusDays(1).toDate()); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/clinicalcourse/ClinicalCourseFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/clinicalcourse/ClinicalCourseFacadeEjbTest.java index 248dc12b60f..0d768263ddb 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/clinicalcourse/ClinicalCourseFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/clinicalcourse/ClinicalCourseFacadeEjbTest.java @@ -24,7 +24,7 @@ public void testClinicalVisitDeletion() { RDCFEntities rdcf = creator.createRDCFEntities(); UserDto user = creator.createUser(rdcf, UserRole.SURVEILLANCE_SUPERVISOR, UserRole.CASE_SUPERVISOR); - UserDto admin = creator.createUser(rdcf, UserRole.ADMIN); + UserDto admin = getUserFacade().getByUserName("admin"); PersonDto casePerson = creator.createPerson("Case", "Person"); CaseDataDto caze = creator.createCase(user.toReference(), casePerson.toReference(), rdcf); ClinicalVisitDto visit = creator.createClinicalVisit(caze); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java index a5fd96e8b75..e862e10a1ce 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java @@ -397,10 +397,10 @@ public void testContactDeletion() { Date since = new Date(); - RDCFEntities rdcf = creator.createRDCFEntities("Region", "District", "Community", "Facility"); + RDCF rdcf = creator.createRDCF("Region", "District", "Community", "Facility"); UserDto user = creator .createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); - UserDto admin = creator.createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Ad", "Min", UserRole.ADMIN); + UserDto admin = creator.createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Another", "Admin", UserRole.ADMIN); String adminUuid = admin.getUuid(); PersonDto cazePerson = creator.createPerson("Case", "Person"); CaseDataDto caze = creator.createCase( @@ -1446,7 +1446,7 @@ public void testMergeContact() throws IOException { // 1. Create // Create leadContact - UserDto leadUser = creator.createUser("", "", "", "", ""); + UserDto leadUser = creator.createUser("", "", "", "First", "User"); UserReferenceDto leadUserReference = new UserReferenceDto(leadUser.getUuid()); PersonDto leadPerson = creator.createPerson("Alex", "Miller"); PersonContactDetailDto leadContactDetail = @@ -1481,7 +1481,7 @@ public void testMergeContact() throws IOException { getVisitFacade().saveVisit(leadVisit); // Create otherContact - UserDto otherUser = creator.createUser("", "", "", "", ""); + UserDto otherUser = creator.createUser("", "", "", "Some", "User"); UserReferenceDto otherUserReference = new UserReferenceDto(otherUser.getUuid()); PersonDto otherPerson = creator.createPerson("Max", "Smith"); PersonContactDetailDto otherContactDetail = diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjbTest.java index 4f75f7b4cf6..587e27d6d41 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjbTest.java @@ -243,7 +243,7 @@ public void testBulkCaseDocumentCreation() throws DocumentTemplateException, IOE @Test public void testBulkContactDocumentCreation() throws DocumentTemplateException, IOException { ReferenceDto rootEntityReference = contactDto.toReference(); - + loginWith(creator.createUser(creator.createRDCF(), UserRole.SURVEILLANCE_SUPERVISOR)); Properties properties = new Properties(); properties.setProperty("extraremark1", "the first remark"); properties.setProperty("extra.remark.no3", "the third remark"); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbTest.java index 83f3b259ee8..dcd538e45f5 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbTest.java @@ -77,7 +77,7 @@ public void testEventDeletion() throws ExternalSurveillanceToolException { RDCF rdcf = creator.createRDCF("Region", "District", "Community", "Facility"); UserDto user = creator .createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); - UserDto admin = creator.createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Ad", "Min", UserRole.ADMIN); + UserDto admin = getUserFacade().getByUserName("admin"); EventDto event = creator.createEvent( EventStatus.SIGNAL, EventInvestigationStatus.PENDING, @@ -116,7 +116,7 @@ public void testEventUpdate() { RDCF rdcf = creator.createRDCF("Region", "District", "Community", "Facility"); UserDto user = creator .createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); - UserDto admin = creator.createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Ad", "Min", UserRole.ADMIN); + UserDto admin = getUserFacade().getByUserName("admin"); EventDto event = creator.createEvent( EventStatus.SIGNAL, EventInvestigationStatus.PENDING, diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/SampleFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/SampleFacadeEjbTest.java index 1c4ec4ebb3a..ed95bbad989 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/SampleFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/SampleFacadeEjbTest.java @@ -328,7 +328,7 @@ public void testSampleDeletion() { RDCFEntities rdcf = creator.createRDCFEntities("Region", "District", "Community", "Facility"); UserDto user = creator .createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); - UserDto admin = creator.createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Ad", "Min", UserRole.ADMIN); + UserDto admin = getUserFacade().getByUserName("admin"); String adminUuid = admin.getUuid(); PersonDto cazePerson = creator.createPerson("Case", "Person"); CaseDataDto caze = creator.createCase( diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/task/TaskFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/task/TaskFacadeEjbTest.java index bb3ddc4c7b8..8e2fd0ec4fc 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/task/TaskFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/task/TaskFacadeEjbTest.java @@ -69,7 +69,7 @@ public void testSampleDeletion() { RDCF rdcf = creator.createRDCF("Region", "District", "Community", "Facility"); UserDto user = creator .createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); - UserDto admin = creator.createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Ad", "Min", UserRole.ADMIN); + UserDto admin = getUserFacade().getByUserName("admin"); String adminUuid = admin.getUuid(); TaskDto task = creator.createTask( TaskContext.GENERAL, @@ -379,8 +379,8 @@ public void testGetPendingTaskCountPerUser() { // 1. one user with tasks, one without RDCF rdcf = new RDCF(creator.createRDCFEntities()); - UserDto user1 = creator.createUser(rdcf, UserRole.SURVEILLANCE_SUPERVISOR); - UserDto user2 = creator.createUser(rdcf, UserRole.SURVEILLANCE_SUPERVISOR); + UserDto user1 = creator.createUser(rdcf, "First", "User", UserRole.SURVEILLANCE_SUPERVISOR); + UserDto user2 = creator.createUser(rdcf, "Second", "User", UserRole.SURVEILLANCE_SUPERVISOR); creator.createTask(user1.toReference()); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/therapy/PrescriptionFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/therapy/PrescriptionFacadeEjbTest.java index bc76d063712..fa7bf007366 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/therapy/PrescriptionFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/therapy/PrescriptionFacadeEjbTest.java @@ -24,7 +24,7 @@ public void testPrescriptionDeletion() { RDCFEntities rdcf = creator.createRDCFEntities(); UserDto user = creator.createUser(rdcf, UserRole.SURVEILLANCE_SUPERVISOR, UserRole.CASE_SUPERVISOR); - UserDto admin = creator.createUser(rdcf, UserRole.ADMIN); + UserDto admin = getUserFacade().getByUserName("admin"); PersonDto casePerson = creator.createPerson("Case", "Person"); CaseDataDto caze = creator.createCase(user.toReference(), casePerson.toReference(), rdcf); PrescriptionDto prescription = creator.createPrescription(caze); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/therapy/TreatmentFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/therapy/TreatmentFacadeEjbTest.java index ff5927ce407..f2116856b62 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/therapy/TreatmentFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/therapy/TreatmentFacadeEjbTest.java @@ -24,7 +24,7 @@ public void testTreatmentDeletion() { RDCFEntities rdcf = creator.createRDCFEntities(); UserDto user = creator.createUser(rdcf, UserRole.SURVEILLANCE_SUPERVISOR, UserRole.CASE_SUPERVISOR); - UserDto admin = creator.createUser(rdcf, UserRole.ADMIN); + UserDto admin = getUserFacade().getByUserName("admin"); PersonDto casePerson = creator.createPerson("Case", "Person"); CaseDataDto caze = creator.createCase(user.toReference(), casePerson.toReference(), rdcf); TreatmentDto treatment = creator.createTreatment(caze); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/user/UserFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/user/UserFacadeEjbTest.java index f0b64325205..56179e1815e 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/user/UserFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/user/UserFacadeEjbTest.java @@ -112,7 +112,7 @@ public void testGetUsersByRegionAndRight() { // Has LAB_MASSAGES right UserDto natUser = creator.createUser(rdcf, NATIONAL_USER); // Does not have LAB_MASSAGES right - creator.createUser(rdcf, POE_INFORMANT); + creator.createUser(rdcf, "Some", "User", POE_INFORMANT); result = getUserFacade().getUsersByRegionAndRight(region, UserRight.LAB_MESSAGES); assertThat(result, contains(equalTo(natUser.toReference()))); @@ -140,8 +140,8 @@ public void testGetIndexList() { creator.createUser(rdcf, "my", "User", CASE_OFFICER, CONTACT_OFFICER); // some other users to be filtered out - creator.createUser(rdcf, SURVEILLANCE_SUPERVISOR, CONTACT_SUPERVISOR); - creator.createUser(rdcf, SURVEILLANCE_OFFICER, DISTRICT_OBSERVER); + creator.createUser(rdcf, "Some", "User", SURVEILLANCE_SUPERVISOR, CONTACT_SUPERVISOR); + creator.createUser(rdcf, "Other", "User", SURVEILLANCE_OFFICER, DISTRICT_OBSERVER); List result; From 815da0c22ed73e07bc8d93bf446a1368cd8d4c0f Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Thu, 10 Feb 2022 13:59:01 +0200 Subject: [PATCH 057/253] #7836 - use limited disease filter for contacts / immunizations & travel entries --- .../backend/contact/ContactService.java | 13 +++++-- .../DirectoryImmunizationService.java | 14 ++++++- .../immunization/ImmunizationService.java | 21 ++++++++--- .../services/BaseTravelEntryService.java | 12 +++++- .../ImmunizationFacadeEjbTest.java | 37 +++++++++++++++++++ 5 files changed, 83 insertions(+), 14 deletions(-) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java index 6770c5881e5..2f6bc340da3 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java @@ -45,7 +45,6 @@ import javax.transaction.Transactional; import javax.validation.constraints.NotNull; -import de.symeda.sormas.backend.common.AbstractCoreAdoService; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -82,12 +81,11 @@ import de.symeda.sormas.backend.caze.CaseService; import de.symeda.sormas.backend.caze.CaseUserFilterCriteria; import de.symeda.sormas.backend.clinicalcourse.HealthConditions; -import de.symeda.sormas.backend.clinicalcourse.HealthConditionsService; -import de.symeda.sormas.backend.common.AbstractDeletableAdoService; +import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.ChangeDateFilterBuilder; -import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; +import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.contact.transformers.ContactListEntryDtoResultTransformer; import de.symeda.sormas.backend.disease.DiseaseConfigurationFacadeEjb.DiseaseConfigurationFacadeEjbLocal; import de.symeda.sormas.backend.epidata.EpiData; @@ -986,6 +984,13 @@ public Predicate createUserFilterWithoutCase(ContactQueryContext qc, ContactCrit default: } + if (currentUser.getLimitedDisease() != null) { + filter = CriteriaBuilderHelper.and( + cb, + filter, + cb.or(cb.equal(contactPath.get(Contact.DISEASE), currentUser.getLimitedDisease()), cb.isNull(contactPath.get(Contact.DISEASE)))); + } + return filter; } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/DirectoryImmunizationService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/DirectoryImmunizationService.java index 9d8fc801626..46c785dd834 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/DirectoryImmunizationService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/DirectoryImmunizationService.java @@ -21,6 +21,7 @@ import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; +import de.symeda.sormas.backend.contact.Contact; import org.apache.commons.collections4.CollectionUtils; import de.symeda.sormas.api.feature.FeatureType; @@ -325,11 +326,14 @@ private String getDateFieldFromDateType(ImmunizationDateType immunizationDateTyp private Predicate createUserFilter(DirectoryImmunizationQueryContext qc) { final User currentUser = userService.getCurrentUser(); + final CriteriaBuilder cb = qc.getCriteriaBuilder(); + + Predicate filter; if (!featureConfigurationFacade.isPropertyValueTrue(FeatureType.IMMUNIZATION_MANAGEMENT, FeatureTypeProperty.REDUCED)) { - return DirectoryImmunizationJurisdictionPredicateValidator.of(qc, currentUser).inJurisdictionOrOwned(); + filter = DirectoryImmunizationJurisdictionPredicateValidator.of(qc, currentUser).inJurisdictionOrOwned(); } else { - return CriteriaBuilderHelper.or( + filter = CriteriaBuilderHelper.or( qc.getCriteriaBuilder(), qc.getCriteriaBuilder().equal(qc.getRoot().get(Immunization.REPORTING_USER), currentUser), PersonJurisdictionPredicateValidator @@ -341,5 +345,11 @@ private Predicate createUserFilter(DirectoryImmunizationQueryContext getByPersonUuids(List personUuids) { private Predicate createUserFilter(ImmunizationQueryContext qc) { final User currentUser = userService.getCurrentUser(); + final CriteriaBuilder cb = qc.getCriteriaBuilder(); + Predicate filter; if (!featureConfigurationFacade.isPropertyValueTrue(FeatureType.IMMUNIZATION_MANAGEMENT, FeatureTypeProperty.REDUCED)) { - return ImmunizationJurisdictionPredicateValidator.of(qc, currentUser).inJurisdictionOrOwned(); + filter = ImmunizationJurisdictionPredicateValidator.of(qc, currentUser).inJurisdictionOrOwned(); } else { - return CriteriaBuilderHelper.or( - qc.getCriteriaBuilder(), - qc.getCriteriaBuilder().equal(qc.getRoot().get(Immunization.REPORTING_USER), currentUser), + filter = CriteriaBuilderHelper.or( + cb, + cb.equal(qc.getRoot().get(Immunization.REPORTING_USER), currentUser), PersonJurisdictionPredicateValidator .of( qc.getQuery(), - qc.getCriteriaBuilder(), + cb, new PersonJoins<>(((ImmunizationJoins) qc.getJoins()).getPerson()), currentUser, false) .inJurisdictionOrOwned()); } + + if (currentUser.getLimitedDisease() != null) { + filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(qc.getRoot().get(Contact.DISEASE), currentUser.getLimitedDisease())); + } + + return filter; } private Predicate createDateFilter(CriteriaBuilder cb, Root from, ImmunizationSimilarityCriteria criteria) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java index 212fbb9ff65..98a9ef11750 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java @@ -12,6 +12,8 @@ import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.backend.common.AbstractCoreAdoService; +import de.symeda.sormas.backend.common.CriteriaBuilderHelper; +import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.travelentry.TravelEntry; import de.symeda.sormas.backend.travelentry.TravelEntryJurisdictionPredicateValidator; import de.symeda.sormas.backend.travelentry.TravelEntryQueryContext; @@ -44,8 +46,14 @@ public Predicate createDefaultFilter(CriteriaBuilder cb, From ro return cb.isFalse(root.get(TravelEntry.DELETED)); } - protected Predicate createUserFilter(TravelEntryQueryContext travelEntryQueryContext) { - return inJurisdictionOrOwned(travelEntryQueryContext); + protected Predicate createUserFilter(TravelEntryQueryContext qc) { + final User currentUser = userService.getCurrentUser(); + final CriteriaBuilder cb = qc.getCriteriaBuilder(); + Predicate filter = inJurisdictionOrOwned(qc); + if (currentUser.getLimitedDisease() != null) { + filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(qc.getRoot().get(Contact.DISEASE), currentUser.getLimitedDisease())); + } + return filter; } public List getAllActiveAfter(Date date) { diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjbTest.java index 63fca1b0b8a..807017d10df 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjbTest.java @@ -52,6 +52,7 @@ public class ImmunizationFacadeEjbTest extends AbstractBeanTest { private UserDto districtUser1; private UserDto districtUser2; private UserDto nationalUser; + private UserDto covidLimitedDistrictUser; @Override public void init() { @@ -72,6 +73,11 @@ public void init() { districtUser2 = creator .createUser(rdcf2.region.getUuid(), rdcf2.district.getUuid(), rdcf2.facility.getUuid(), "Surv", "Off2", UserRole.SURVEILLANCE_OFFICER); + + covidLimitedDistrictUser = creator + .createUser(rdcf1.region.getUuid(), rdcf1.district.getUuid(), rdcf1.facility.getUuid(), "Surv", "OffCovid", UserRole.SURVEILLANCE_OFFICER); + covidLimitedDistrictUser.setLimitedDisease(Disease.CORONAVIRUS); + getUserFacade().saveUser(covidLimitedDistrictUser); } @Test @@ -619,4 +625,35 @@ public void testNoImmunizationStatusUpdateWhenNotAcquired() { Assert.assertEquals(ImmunizationStatus.NOT_ACQUIRED, immWithTwoVac.getImmunizationStatus()); } + @Test + public void testGetIndexListIsFilteredByCurrentUserLimitedDisease() { + loginWith(nationalUser); + + final PersonDto person = creator.createPerson("John", "Doe"); + + creator.createImmunization( + Disease.ANTHRAX, + person.toReference(), + nationalUser.toReference(), + ImmunizationStatus.ACQUIRED, + MeansOfImmunization.VACCINATION, + ImmunizationManagementStatus.COMPLETED, + rdcf1); + + creator.createImmunization( + Disease.CORONAVIRUS, + person.toReference(), + nationalUser.toReference(), + ImmunizationStatus.ACQUIRED, + MeansOfImmunization.VACCINATION, + ImmunizationManagementStatus.COMPLETED, + rdcf1); + + loginWith(districtUser1); + Assert.assertEquals(2, getImmunizationFacade().getIndexList(new ImmunizationCriteria(), 0, 100, null).size()); + + loginWith(covidLimitedDistrictUser); + Assert.assertEquals(1, getImmunizationFacade().getIndexList(new ImmunizationCriteria(), 0, 100, null).size()); + } + } From a14bf6e9898d24cc04063057241af998bf7f0984 Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Thu, 10 Feb 2022 14:28:40 +0100 Subject: [PATCH 058/253] Edited scenario in Event.feature [SORDEV-5570] --- .../web/application/events/EventDirectorySteps.java | 12 +++++++++++- .../test/resources/features/sanity/web/Event.feature | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index ce53fdb8a6e..18e8b59a1d0 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -266,8 +266,18 @@ public EventDirectorySteps( "I click Create Case for Event Participant", () -> webDriverHelpers.clickOnWebElementBySelector(CREATE_CASE_BUTTON)); + Then( + "I check that number of displayed Event results is {int}", + (Integer number) -> + assertHelpers.assertWithPoll20Second( + () -> + Assert.assertEquals( + webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), + number.intValue(), + "Number of displayed cases is not correct"))); + Then( - "I check that number of displayed Event results is {int}", + "I check the number of displayed Event results from All button is {int}", (Integer number) -> assertHelpers.assertWithPoll20Second( () -> diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature index 33fc9d10bb3..c413a304440 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature @@ -252,4 +252,4 @@ Feature: Create events And I click on Edit event group button from event groups box And I click on Edit event button for the first event in Events section And I click on the Navigate to event directory filtered on this event group - And I check that number of displayed Event results is 1 \ No newline at end of file + And I check the number of displayed Event results from All button is 1 \ No newline at end of file From cf81bb80264f358a16e182b8a01dc53016b35a5e Mon Sep 17 00:00:00 2001 From: Pawel Kujawa Date: Thu, 10 Feb 2022 14:39:02 +0100 Subject: [PATCH 059/253] sorqa65 --- .../pages/application/cases/EditCasePage.java | 9 ++ .../web/application/cases/EditCaseSteps.java | 100 +++++++++++++++++- .../contacts/ContactDirectorySteps.java | 10 ++ .../features/sanity/web/Case.feature | 65 +++++++++++- 4 files changed, 179 insertions(+), 5 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EditCasePage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EditCasePage.java index b87bcc8d6a3..4e06293df46 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EditCasePage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EditCasePage.java @@ -91,7 +91,16 @@ public class EditCasePage { By.cssSelector("#quarantineHomePossible label"); public static final By QUARANTINE_COMBOBOX = By.cssSelector("#quarantine div"); public static final By QUARANTINE_DATE_FROM = By.cssSelector("#quarantineFrom"); + public static final By QUARANTINE_DATE_FROM_INPUT = By.cssSelector("#quarantineFrom input"); public static final By QUARANTINE_DATE_TO = By.cssSelector("#quarantineTo"); + public static final By QUARANTINE_DATE_TO_INPUT = By.cssSelector("#quarantineTo input"); + public static final By QUARANTINE_CHANGE_COMMENT = By.cssSelector("#quarantineChangeComment"); + public static final By QUARANTINE_POPUP_MESSAGE = + By.xpath("//div[@class='v-label v-widget v-has-width']"); + public static final By QUARANTINE_POPUP_SAVE_BUTTON = + By.cssSelector(".popupContent #actionConfirm"); + public static final By QUARANTINE_POPUP_DISCARD_BUTTON = + By.cssSelector(".popupContent #actionCancel"); public static final By QUARANTINE_ORDERED_VERBALLY_CHECKBOX_LABEL = By.xpath("//*[@id='quarantineOrderedVerbally']/label"); public static final By QUARANTINE_ORDERED_VERBALLY_CHECKBOX_INPUT = diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java index 80a728123b7..dfc6d242b3b 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java @@ -21,6 +21,7 @@ import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.*; import static org.sormas.e2etests.pages.application.cases.EditCasePage.*; import static org.sormas.e2etests.pages.application.cases.SymptomsTabPage.SAVE_BUTTON; +import static org.sormas.e2etests.pages.application.contacts.EditContactPage.FOLLOW_UP_UNTIL_DATE; import static org.sormas.e2etests.pages.application.contacts.EditContactPage.UUID_INPUT; import cucumber.api.java8.En; @@ -54,6 +55,7 @@ public class EditCaseSteps implements En { private static Case editedCase; public static QuarantineOrder aQuarantineOrder; private static Case specificCaseData; + private static LocalDate dateFollowUp; public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("M/d/yyyy"); public static final String userDirPath = System.getProperty("user.dir"); @@ -251,6 +253,100 @@ public EditCaseSteps( editedCase = editedCase.toBuilder().quarantine(option).build(); }); + When( + "I set place for Quarantine as ([^\"]*)", + (String option) -> { + webDriverHelpers.selectFromCombobox(QUARANTINE_COMBOBOX, CaseOutcome.getValueFor(option)); + }); + + When( + "I set Start date of Quarantine ([^\"]*) days ago", + (Integer days) -> { + webDriverHelpers.scrollToElement(QUARANTINE_DATE_TO_INPUT); + webDriverHelpers.fillInWebElement( + QUARANTINE_DATE_FROM_INPUT, DATE_FORMATTER.format(LocalDate.now().minusDays(days))); + }); + + When( + "I set End date of Quarantine to ([^\"]*) days", + (Integer days) -> { + webDriverHelpers.scrollToElement(QUARANTINE_DATE_TO_INPUT); + webDriverHelpers.fillInWebElement( + QUARANTINE_DATE_TO_INPUT, DATE_FORMATTER.format(LocalDate.now().plusDays(days))); + }); + + When( + "I check if ([^\"]*) quarantine popup is displayed", + (String option) -> { + String quarantineText; + String expectedTextReduce = "Are you sure you want to reduce the quarantine?"; + String expectedTextExtend = "Are you sure you want to extend the quarantine?"; + webDriverHelpers.clickOnWebElementBySelector(QUARANTINE_ORDERED_VERBALLY_CHECKBOX_LABEL); + webDriverHelpers.waitUntilIdentifiedElementIsPresent(QUARANTINE_POPUP_MESSAGE); + quarantineText = webDriverHelpers.getTextFromWebElement(QUARANTINE_POPUP_MESSAGE); + if (option.equals("Reduce")) softly.assertEquals(quarantineText, expectedTextReduce); + else if (option.equals("Extend")) softly.assertEquals(quarantineText, expectedTextExtend); + softly.assertAll(); + }); + + When( + "I check if Quarantine End date stayed reduce to ([^\"]*) days", + (Integer days) -> { + String date = webDriverHelpers.getValueFromWebElement(QUARANTINE_DATE_TO_INPUT); + LocalDate endDate = LocalDate.now().plusDays(days); + softly.assertEquals(DATE_FORMATTER.format(endDate), date); + softly.assertAll(); + }); + When( + "I check if Quarantine Follow up until date was extended to ([^\"]*) day", + (Integer days) -> { + String date = webDriverHelpers.getValueFromWebElement(FOLLOW_UP_UNTIL_DATE); + softly.assertEquals(DATE_FORMATTER.format(dateFollowUp.plusDays(days)), date); + softly.assertAll(); + }); + + When( + "I set the quarantine end to a date ([^\"]*) day after the Follow-up until date", + (Integer days) -> { + dateFollowUp = + LocalDate.parse( + webDriverHelpers.getValueFromWebElement(FOLLOW_UP_UNTIL_DATE), DATE_FORMATTER); + webDriverHelpers.scrollToElement(QUARANTINE_DATE_TO_INPUT); + webDriverHelpers.fillInWebElement( + QUARANTINE_DATE_TO_INPUT, DATE_FORMATTER.format(dateFollowUp.plusDays(days))); + webDriverHelpers.clickOnWebElementBySelector(QUARANTINE_DATE_FROM_INPUT); + }); + + When( + "I fill Quarantine change comment field", + () -> { + webDriverHelpers.scrollToElement(QUARANTINE_CHANGE_COMMENT); + webDriverHelpers.fillInWebElement(QUARANTINE_CHANGE_COMMENT, dateFollowUp.toString()); + }); + + When( + "I check if Quarantine change comment field was saved correctly", + () -> { + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(40); + String commentText = webDriverHelpers.getValueFromWebElement(QUARANTINE_CHANGE_COMMENT); + softly.assertEquals(commentText, dateFollowUp.toString()); + softly.assertAll(); + }); + + When( + "I click on yes quarantine popup button", + () -> webDriverHelpers.clickOnWebElementBySelector(QUARANTINE_POPUP_SAVE_BUTTON)); + + When( + "I click on yes Extend follow up period popup button", + () -> { + webDriverHelpers.clickOnWebElementBySelector(QUARANTINE_POPUP_SAVE_BUTTON); + }); + + When( + "I discard changes in quarantine popup", + () -> webDriverHelpers.clickOnWebElementBySelector(QUARANTINE_POPUP_DISCARD_BUTTON)); + When( "I check if Quarantine start field is available", () -> webDriverHelpers.waitUntilElementIsVisibleAndClickable(QUARANTINE_DATE_FROM)); @@ -643,7 +739,6 @@ private Case collectSpecificData() { } private LocalDate getDateOfReport() { - String dateOfReport = webDriverHelpers.getValueFromWebElement(REPORT_DATE_INPUT); return LocalDate.parse(dateOfReport, DATE_FORMATTER); } @@ -655,21 +750,18 @@ private LocalDate getDateReceivedAtDistrictLevel() { } private LocalDate getDateReceivedAtRegionLevel() { - String dateOfReport = webDriverHelpers.getValueFromWebElement(DATE_RECEIVED_AT_REGION_LEVEL_INPUT); return LocalDate.parse(dateOfReport, DATE_FORMATTER); } private LocalDate getDateReceivedAtNationalLevel() { - String dateOfReport = webDriverHelpers.getValueFromWebElement(DATE_RECEIVED_AT_NATIONAL_LEVEL_INPUT); return LocalDate.parse(dateOfReport, DATE_FORMATTER); } private Case getUserInformation() { - String userInfo = webDriverHelpers.getTextFromWebElement(USER_INFORMATION); String[] userInfos = userInfo.split(" "); LocalDate localDate = LocalDate.parse(userInfos[3].replace(")", ""), DATE_FORMATTER); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/ContactDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/ContactDirectorySteps.java index fb6ff6f110b..ff4efead918 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/ContactDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/ContactDirectorySteps.java @@ -24,6 +24,7 @@ import static org.sormas.e2etests.pages.application.contacts.ContactDirectoryPage.GRID_HEADERS; import static org.sormas.e2etests.pages.application.contacts.ContactDirectoryPage.RESULTS_GRID_HEADER; import static org.sormas.e2etests.pages.application.contacts.CreateNewContactPage.FIRST_NAME_OF_CONTACT_PERSON_INPUT; +import static org.sormas.e2etests.pages.application.contacts.CreateNewContactPage.SAVE_BUTTON; import static org.sormas.e2etests.pages.application.contacts.EditContactPage.UUID_INPUT; import cucumber.api.java8.En; @@ -84,6 +85,15 @@ public ContactDirectorySteps( webDriverHelpers.clickWhileOtherButtonIsDisplayed( NEW_CONTACT_BUTTON, FIRST_NAME_OF_CONTACT_PERSON_INPUT)); + When( + "I click on save Contact button", + () -> { + webDriverHelpers.scrollToElement(SAVE_BUTTON); + webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(40); + }); + When( "I click on the DETAILED radiobutton from Contact directory", () -> { diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature index ccbb21ce506..f8016bf558e 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature @@ -262,4 +262,67 @@ Feature: Case end to end tests And I set Cardiovascular disease including hypertension radio button to UNKNOWN And I set Cardiovascular disease including hypertension radio button to UNKNOWN Then I click Save button on Clinical Course Tab - And I check if Case saved popup appeared and close it \ No newline at end of file + And I check if Case saved popup appeared and close it + + @issue=SORDEV-8412 + Scenario: Change of Isolation/Quarantine should be documented + When API: I create a new person + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Then API: I create a new case + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in as a Admin User + And I click on the Cases button from navbar + And I open the last created Case via API + Then I set place for Quarantine as Home + And I set Start date of Quarantine 2 days ago + And I set End date of Quarantine to 5 days + Then I click on save case button + And I set End date of Quarantine to 4 days + And I check if Reduce quarantine popup is displayed + Then I click on yes quarantine popup button + Then I click on save case button + And I set End date of Quarantine to 6 days + And I check if Extend quarantine popup is displayed + Then I discard changes in quarantine popup + And I check if Quarantine End date stayed reduce to 4 days + And I set the quarantine end to a date 1 day after the Follow-up until date + Then I click on yes quarantine popup button + Then I click on yes Extend follow up period popup button + Then I click on save case button + And I check if Quarantine Follow up until date was extended to 1 day + And I fill Quarantine change comment field + Then I click on save case button + And I check if Quarantine change comment field was saved correctly + When API: I create a new person + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Then API: I create a new contact + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Then I click on the Contacts button from navbar + Then I open the last created contact + Then I set place for Quarantine as Home + And I set Start date of Quarantine 2 days ago + And I set End date of Quarantine to 5 days + Then I click on save Contact button + And I set End date of Quarantine to 4 days + And I check if Reduce quarantine popup is displayed + Then I click on yes quarantine popup button + Then I click on save Contact button + And I set End date of Quarantine to 6 days + And I check if Extend quarantine popup is displayed + Then I discard changes in quarantine popup + And I check if Quarantine End date stayed reduce to 4 days + And I set the quarantine end to a date 1 day after the Follow-up until date + Then I click on yes quarantine popup button + Then I click on yes Extend follow up period popup button + Then I click on save Contact button + And I check if Quarantine Follow up until date was extended to 1 day + And I fill Quarantine change comment field + Then I click on save Contact button + And I check if Quarantine change comment field was saved correctly + + + From 29376e87b1bc158f50dc2ceab9a49ccc1aeea4e5 Mon Sep 17 00:00:00 2001 From: Jonas Cirotzki Date: Thu, 10 Feb 2022 15:08:07 +0100 Subject: [PATCH 060/253] [#7907] fix document test --- .../backend/docgeneration/QuarantineOrderFacadeEjbTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjbTest.java index 587e27d6d41..a9811c32bca 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/docgeneration/QuarantineOrderFacadeEjbTest.java @@ -243,7 +243,6 @@ public void testBulkCaseDocumentCreation() throws DocumentTemplateException, IOE @Test public void testBulkContactDocumentCreation() throws DocumentTemplateException, IOException { ReferenceDto rootEntityReference = contactDto.toReference(); - loginWith(creator.createUser(creator.createRDCF(), UserRole.SURVEILLANCE_SUPERVISOR)); Properties properties = new Properties(); properties.setProperty("extraremark1", "the first remark"); properties.setProperty("extra.remark.no3", "the third remark"); From 287e6bc2452b4e3e9abf985558394ab7ca9b49fd Mon Sep 17 00:00:00 2001 From: Jonas Cirotzki Date: Thu, 10 Feb 2022 15:28:22 +0100 Subject: [PATCH 061/253] [#7907] add script to find duplicates --- .../src/main/resources/sql/sormas_schema.sql | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sormas-backend/src/main/resources/sql/sormas_schema.sql b/sormas-backend/src/main/resources/sql/sormas_schema.sql index 80f6baea399..2fa865dbcda 100644 --- a/sormas-backend/src/main/resources/sql/sormas_schema.sql +++ b/sormas-backend/src/main/resources/sql/sormas_schema.sql @@ -9950,6 +9950,18 @@ ALTER TABLE eventparticipant_history ADD COLUMN archived BOOLEAN; INSERT INTO schema_version (version_number, comment) VALUES (440, 'Refactor CoreAdo to include archiving #7246'); -- 2022-02-09 Align username handling of Keycloak and legacy login #7907 +/* +* In case the current DB violates the new uniqueness constraint on usernames, please use the following script to detect +* all conflicting usernames. Usernames are case-insensitive now, that means "ADMIN" and "admin" will both map to the +* same user in the DB. To resolve the conflict, rename the conflicting usernames found with the script. +* +* SELECT username, creationdate, id, uuid FROM users +* WHERE LOWER(username) IN +* (SELECT LOWER(username) FROM users GROUP BY LOWER(username) HAVING COUNT(*) > 1) +* ORDER BY username, creationdate; +* +*/ + DROP INDEX idx_users_username; CREATE UNIQUE INDEX idx_users_username_lower ON users(LOWER(username)); REINDEX INDEX idx_users_username_lower; From 6f8b8d61e8d9d514ed8c385e3c39585b6065ba7d Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Thu, 10 Feb 2022 16:45:40 +0200 Subject: [PATCH 062/253] #7747-Fix-Allure-Report : finished fixes for broken allure report --- .../cases/ClinicalCourseTabCaseSteps.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/ClinicalCourseTabCaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/ClinicalCourseTabCaseSteps.java index f2b2c139b65..176dc2abf29 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/ClinicalCourseTabCaseSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/ClinicalCourseTabCaseSteps.java @@ -1,6 +1,19 @@ package org.sormas.e2etests.steps.web.application.cases; -import static org.sormas.e2etests.pages.application.cases.ClinicalCourseTabCasePage.*; +import static org.sormas.e2etests.pages.application.cases.ClinicalCourseTabCasePage.CARDIOVASCULAR_DISEASE_INCLUDING_HYPERTENSION_RADIO_BUTTON; +import static org.sormas.e2etests.pages.application.cases.ClinicalCourseTabCasePage.CHRONIC_NEUROLOGICAL_NEUROMUSCULAR_DISEASE_RADIO_BUTTON; +import static org.sormas.e2etests.pages.application.cases.ClinicalCourseTabCasePage.CHRONIC_PULMONARY_DISEASE_RADIO_BUTTON; +import static org.sormas.e2etests.pages.application.cases.ClinicalCourseTabCasePage.CLEAR_ALL_OPTION; +import static org.sormas.e2etests.pages.application.cases.ClinicalCourseTabCasePage.DIABETES_RADIO_BUTTON; +import static org.sormas.e2etests.pages.application.cases.ClinicalCourseTabCasePage.EDIT_BUTTON; +import static org.sormas.e2etests.pages.application.cases.ClinicalCourseTabCasePage.IMMUNODEFICIENCY_INCLUDING_HIV_RADIO_BUTTON; +import static org.sormas.e2etests.pages.application.cases.ClinicalCourseTabCasePage.LIVER_DISEASE_RADIO_BUTTON; +import static org.sormas.e2etests.pages.application.cases.ClinicalCourseTabCasePage.MALIGNANCY_RADIO_BUTTON; +import static org.sormas.e2etests.pages.application.cases.ClinicalCourseTabCasePage.NEW_CLINICAL_ASSESEMENT_BUTTON; +import static org.sormas.e2etests.pages.application.cases.ClinicalCourseTabCasePage.RENAL_DISEASE_RADIO_BUTTON; +import static org.sormas.e2etests.pages.application.cases.ClinicalCourseTabCasePage.SAVE_BUTTON; +import static org.sormas.e2etests.pages.application.cases.ClinicalCourseTabCasePage.SAVE_CLINICAL_VISIT_BUTTON; +import static org.sormas.e2etests.pages.application.cases.ClinicalCourseTabCasePage.SET_OPTIONS; import static org.sormas.e2etests.pages.application.cases.EditCasePage.CASE_SAVED_POPUP; import static org.sormas.e2etests.pages.application.cases.FollowUpTabPage.CURRENT_BODY_TEMPERATURE_COMBOBOX; import static org.sormas.e2etests.pages.application.cases.FollowUpTabPage.DATE_OF_VISIT_INPUT; From 6dc761c53fe632d80ac7c9058e1723b59eb09d09 Mon Sep 17 00:00:00 2001 From: Pawel Kujawa Date: Thu, 10 Feb 2022 18:38:04 +0100 Subject: [PATCH 063/253] fixes --- .../e2etests/pages/application/tasks/CreateNewTaskPage.java | 2 +- .../sormas/e2etests/steps/web/application/NavBarSteps.java | 3 ++- .../steps/web/application/cases/CaseDirectorySteps.java | 2 +- .../e2etests/steps/web/application/cases/EditCaseSteps.java | 6 ++++-- .../steps/web/application/tasks/CreateNewTaskSteps.java | 2 -- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/tasks/CreateNewTaskPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/tasks/CreateNewTaskPage.java index e215a2930e4..f2d53c4403f 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/tasks/CreateNewTaskPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/tasks/CreateNewTaskPage.java @@ -23,7 +23,7 @@ public class CreateNewTaskPage { public static final By TASK_POPUP = By.xpath("(//div[@class='popupContent'])[2]"); public static final By TASK_TYPE_COMBOBOX = By.cssSelector(".v-window #taskType input+div"); - public static final By TASK_TYPE_INPUT = By.cssSelector(".v-window #taskType div"); + public static final By TASK_TYPE_INPUT = By.cssSelector(".v-window #taskType input"); public static final By SUGGESTED_START_DATE_INPUT = By.cssSelector(".v-window #suggestedStart_date input"); public static final By DUE_DATE_DATE_INPUT = By.cssSelector(".v-window #dueDate_date input"); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/NavBarSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/NavBarSteps.java index 692ccffc5f5..23922ec5ebb 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/NavBarSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/NavBarSteps.java @@ -89,7 +89,8 @@ public NavBarSteps(WebDriverHelpers webDriverHelpers) { webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(NavBarPage.TASKS_BUTTON); webDriverHelpers.clickOnWebElementBySelector(NavBarPage.TASKS_BUTTON); startTime = ZonedDateTime.now().toInstant().toEpochMilli(); - TimeUnit.SECONDS.sleep(2); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(40); }); When( diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java index 7599402f8f4..1c550c514fe 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java @@ -66,7 +66,7 @@ public CaseDirectorySteps( () -> { webDriverHelpers.fillAndSubmitInWebElement( NAME_UUID_EPID_NUMBER_LIKE_INPUT, EditCaseSteps.aCase.getUuid()); - TimeUnit.SECONDS.sleep(2); + webDriverHelpers.waitForPageLoaded(); webDriverHelpers.waitForPageLoadingSpinnerToDisappear(40); }); When( diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java index 987f3eb626e..7b4e7b353ad 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java @@ -125,7 +125,8 @@ public EditCaseSteps( Case.builder() .investigationStatus("Investigation " + investigationStatus) .build(); // TODO: Create POJO updater class - TimeUnit.SECONDS.sleep(1); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(40); }); When( @@ -151,7 +152,8 @@ public EditCaseSteps( webDriverHelpers.clickWebElementByText( SEQUELAE_OPTIONS, CaseOutcome.getValueFor(option).toUpperCase()); editedCase = editedCase.toBuilder().sequelae(option).build(); - TimeUnit.SECONDS.sleep(1); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(40); }); When( diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/tasks/CreateNewTaskSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/tasks/CreateNewTaskSteps.java index d80857fda08..ca52822b264 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/tasks/CreateNewTaskSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/tasks/CreateNewTaskSteps.java @@ -24,7 +24,6 @@ import java.time.LocalDate; import java.time.LocalTime; import java.time.format.DateTimeFormatter; -import java.util.concurrent.TimeUnit; import javax.inject.Inject; import org.sormas.e2etests.helpers.WebDriverHelpers; import org.sormas.e2etests.pojo.helpers.ComparisonHelper; @@ -61,7 +60,6 @@ public CreateNewTaskSteps(WebDriverHelpers webDriverHelpers, TaskService taskSer When( "^I check the created task is correctly displayed on Edit task page", () -> { - TimeUnit.SECONDS.sleep(2); webDriverHelpers.waitForPageLoaded(); final Task actualTask = collectTaskData(); ComparisonHelper.compareEqualEntities(task, actualTask); From b7854d2726f54e66e75802d7d3d9fb5c4d9825a8 Mon Sep 17 00:00:00 2001 From: Alexandru Caruntu Date: Thu, 10 Feb 2022 21:01:28 +0200 Subject: [PATCH 064/253] #7787 - Discard facility fields --- .../sormas/ui/location/LocationEditForm.java | 15 +++++++++++++++ .../sormas/ui/person/PersonController.java | 19 ++++++------------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/location/LocationEditForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/location/LocationEditForm.java index 431a3c39f08..415ef64c8f7 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/location/LocationEditForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/location/LocationEditForm.java @@ -558,6 +558,21 @@ public String getFormattedHtmlMessage() { setFacilityContactPersonFieldsVisible(facilityType.getValue() != null, true); } + @Override + public void discard() throws SourceException { + super.discard(); + LocationDto locationDto = getValue(); + if (locationDto != null) { + FacilityType facilityType = locationDto.getFacilityType(); + if (facilityType != null) { + facilityTypeGroup.setValue(facilityType.getFacilityTypeGroup()); + } else { + facilityTypeGroup.setValue(null); + } + facility.setValue(locationDto.getFacility()); + } + } + private void updateRegionCombo(ComboBox region, ComboBox country) { InfrastructureFieldsHelper.updateRegionBasedOnCountry(country, region, (isServerCountry) -> { if (districtRequiredOnDefaultCountry) { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonController.java index f0d5db1d42d..78951d57294 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonController.java @@ -48,7 +48,6 @@ import de.symeda.sormas.ui.UserProvider; import de.symeda.sormas.ui.caze.CaseDataView; import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent; -import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent.CommitListener; import de.symeda.sormas.ui.utils.VaadinUiUtil; import de.symeda.sormas.ui.utils.ViewMode; import de.symeda.sormas.ui.utils.components.page.title.TitleLayout; @@ -159,19 +158,13 @@ public CommitDiscardWrapperComponent getPersonEditComponent( PersonEditForm editForm = new PersonEditForm(personContext, disease, diseaseDetails, viewMode, personDto.isPseudonymized()); editForm.setValue(personDto); - final CommitDiscardWrapperComponent editView = new CommitDiscardWrapperComponent( - editForm, - UserProvider.getCurrent().hasUserRight(editUserRight), - editForm.getFieldGroup()); - - editView.addCommitListener(new CommitListener() { + final CommitDiscardWrapperComponent editView = + new CommitDiscardWrapperComponent<>(editForm, UserProvider.getCurrent().hasUserRight(editUserRight), editForm.getFieldGroup()); - @Override - public void onCommit() { - if (!editForm.getFieldGroup().isModified()) { - PersonDto dto = editForm.getValue(); - savePerson(dto); - } + editView.addCommitListener(() -> { + if (!editForm.getFieldGroup().isModified()) { + PersonDto dto = editForm.getValue(); + savePerson(dto); } }); From 30175bd24625703da8f238eb92a85c825a20dcf3 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Fri, 11 Feb 2022 11:00:00 +0200 Subject: [PATCH 065/253] #7246 - fill contact and EvP archived flags (#7961) * #7246 - use wrapper for archived flag to avoid NPE for entities that don't have this flag mandatory yet * #7246 - set archived flags to not null + set them to false for event participants and contacts * #7246 - set archived flags default values for evP and contact --- .../symeda/sormas/backend/common/CoreAdo.java | 3 +-- .../src/main/resources/sql/sormas_schema.sql | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CoreAdo.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CoreAdo.java index 5cbc1ef2568..8dd425f3c1a 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CoreAdo.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CoreAdo.java @@ -33,7 +33,7 @@ public class CoreAdo extends DeletableAdo { private boolean archived; - @Column + @Column(nullable = false) public boolean isArchived() { return archived; } @@ -41,5 +41,4 @@ public boolean isArchived() { public void setArchived(boolean archived) { this.archived = archived; } - } diff --git a/sormas-backend/src/main/resources/sql/sormas_schema.sql b/sormas-backend/src/main/resources/sql/sormas_schema.sql index 2fa865dbcda..f2531cc21a4 100644 --- a/sormas-backend/src/main/resources/sql/sormas_schema.sql +++ b/sormas-backend/src/main/resources/sql/sormas_schema.sql @@ -9968,4 +9968,21 @@ REINDEX INDEX idx_users_username_lower; INSERT INTO schema_version (version_number, comment) VALUES (441, ' Align username handling of Keycloak and legacy login #7907 '); +-- 2022-02-02 Refactor CoreAdo to include archiving #7246 + +UPDATE contact set archived = false; +UPDATE contact_history set archived = false; +UPDATE eventparticipant set archived = false; +UPDATE eventparticipant_history set archived = false; +ALTER TABLE contact ALTER COLUMN archived SET NOT NULL; +ALTER TABLE contact ALTER COLUMN archived SET DEFAULT false; +ALTER TABLE contact_history ALTER COLUMN archived SET NOT NULL; +ALTER TABLE contact_history ALTER COLUMN archived SET DEFAULT false; +ALTER TABLE eventparticipant ALTER COLUMN archived SET NOT NULL; +ALTER TABLE eventparticipant ALTER COLUMN archived SET DEFAULT false; +ALTER TABLE eventparticipant_history ALTER COLUMN archived SET NOT NULL; +ALTER TABLE eventparticipant_history ALTER COLUMN archived SET DEFAULT false; + +INSERT INTO schema_version (version_number, comment) VALUES (442, 'Refactor CoreAdo to include archiving #7246'); + -- *** Insert new sql commands BEFORE this line. Remember to always consider _history tables. *** From 8b9ff8fb9a29df8ef72b890297642b60a1cc9060 Mon Sep 17 00:00:00 2001 From: Alexandru Caruntu Date: Fri, 11 Feb 2022 11:19:11 +0200 Subject: [PATCH 066/253] #7386 - Hide urine p.m enum value for covid 19 --- .../main/java/de/symeda/sormas/api/sample/SampleMaterial.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleMaterial.java b/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleMaterial.java index a558f0fc3cc..73f3c405aea 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleMaterial.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleMaterial.java @@ -47,6 +47,8 @@ public enum SampleMaterial { Disease.CORONAVIRUS }, hide = true) CORNEA_PM, SALIVA, + @Diseases(value = { + Disease.CORONAVIRUS }, hide = true) URINE_PM, @Diseases(value = { Disease.CORONAVIRUS }, hide = true) From 8b37de3cbf25b0251a08f7e23194260c43a30d87 Mon Sep 17 00:00:00 2001 From: Christopher Riedel Date: Fri, 11 Feb 2022 10:40:34 +0100 Subject: [PATCH 067/253] #5285: Map PCR test specipication from TestReport to PathogenTest (#7919) --- .../sormas/api/labmessage/TestReportDto.java | 11 ++++++++ .../sormas/backend/labmessage/TestReport.java | 12 +++++++++ .../labmessage/TestReportFacadeEjb.java | 2 ++ .../src/main/resources/sql/sormas_schema.sql | 6 +++++ .../TestReportFacadeEjbMappingTest.java | 26 ++++++++++++------- .../ui/labmessage/LabMessageMapper.java | 7 ++++- 6 files changed, 53 insertions(+), 11 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/labmessage/TestReportDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/labmessage/TestReportDto.java index 1e77a85ec26..c2551f067b8 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/labmessage/TestReportDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/labmessage/TestReportDto.java @@ -7,6 +7,7 @@ import de.symeda.sormas.api.EntityDto; import de.symeda.sormas.api.i18n.Validations; +import de.symeda.sormas.api.sample.PCRTestSpecification; import de.symeda.sormas.api.sample.PathogenTestResultType; import de.symeda.sormas.api.sample.PathogenTestType; import de.symeda.sormas.api.utils.DataHelper; @@ -24,6 +25,7 @@ public class TestReportDto extends EntityDto { public static final String TEST_TYPE = "testType"; public static final String TEST_DATE_TIME = "testDateTime"; public static final String TEST_RESULT = "testResult"; + public static final String TEST_PCR_TEST_SPECIFICATION = "testPcrTestSpecification"; @Required private LabMessageReferenceDto labMessage; @@ -55,6 +57,7 @@ public class TestReportDto extends EntityDto { private String testedDiseaseVariantDetails; private Boolean preliminary; + private PCRTestSpecification testPcrTestSpecification; public LabMessageReferenceDto getLabMessage() { return labMessage; @@ -197,4 +200,12 @@ public Boolean getPreliminary() { public void setPreliminary(Boolean preliminary) { this.preliminary = preliminary; } + + public PCRTestSpecification getTestPcrTestSpecification() { + return testPcrTestSpecification; + } + + public void setTestPcrTestSpecification(PCRTestSpecification testPcrTestSpecification) { + this.testPcrTestSpecification = testPcrTestSpecification; + } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/TestReport.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/TestReport.java index 5fedd0b5cc2..d9bd20a209b 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/TestReport.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/TestReport.java @@ -16,6 +16,7 @@ import javax.persistence.TemporalType; import de.symeda.auditlog.api.Audited; +import de.symeda.sormas.api.sample.PCRTestSpecification; import de.symeda.sormas.api.sample.PathogenTestResultType; import de.symeda.sormas.api.sample.PathogenTestType; import de.symeda.sormas.backend.common.DeletableAdo; @@ -38,6 +39,7 @@ public class TestReport extends DeletableAdo { public static final String TEST_RESULT = "testResult"; public static final String TEST_RESULT_VERIFIED = "testResultVerified"; public static final String TEST_RESULT_TEXT = "testResultText"; + public static final String TEST_PCR_TEST_SPECIFICATION = "testPcrTestSpecification"; private LabMessage labMessage; private String testLabName; @@ -56,6 +58,7 @@ public class TestReport extends DeletableAdo { private String testedDiseaseVariant; private String testedDiseaseVariantDetails; private Boolean preliminary; + private PCRTestSpecification testPcrTestSpecification; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(nullable = false) @@ -198,4 +201,13 @@ public Boolean getPreliminary() { public void setPreliminary(Boolean preliminary) { this.preliminary = preliminary; } + + @Enumerated(EnumType.STRING) + public PCRTestSpecification getTestPcrTestSpecification() { + return testPcrTestSpecification; + } + + public void setTestPcrTestSpecification(PCRTestSpecification testPcrTestSpecification) { + this.testPcrTestSpecification = testPcrTestSpecification; + } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/TestReportFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/TestReportFacadeEjb.java index 6c4c5f7aee3..539b9ea9b87 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/TestReportFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/labmessage/TestReportFacadeEjb.java @@ -78,6 +78,7 @@ public static TestReportDto toDto(TestReport source) { target.setTestedDiseaseVariant(source.getTestedDiseaseVariant()); target.setTestedDiseaseVariantDetails(source.getTestedDiseaseVariantDetails()); target.setPreliminary(source.getPreliminary()); + target.setTestPcrTestSpecification(source.getTestPcrTestSpecification()); return target; } @@ -101,6 +102,7 @@ public TestReport fromDto(@NotNull TestReportDto source, @NotNull LabMessage lab target.setTestedDiseaseVariant(source.getTestedDiseaseVariant()); target.setTestedDiseaseVariantDetails(source.getTestedDiseaseVariantDetails()); target.setPreliminary(source.getPreliminary()); + target.setTestPcrTestSpecification(source.getTestPcrTestSpecification()); return target; } diff --git a/sormas-backend/src/main/resources/sql/sormas_schema.sql b/sormas-backend/src/main/resources/sql/sormas_schema.sql index f2531cc21a4..4658f5172b0 100644 --- a/sormas-backend/src/main/resources/sql/sormas_schema.sql +++ b/sormas-backend/src/main/resources/sql/sormas_schema.sql @@ -9985,4 +9985,10 @@ ALTER TABLE eventparticipant_history ALTER COLUMN archived SET DEFAULT false; INSERT INTO schema_version (version_number, comment) VALUES (442, 'Refactor CoreAdo to include archiving #7246'); +-- 2022-02-11 Map variant specific Nucleic acid detection methods #5285 +ALTER TABLE testreport ADD COLUMN testpcrtestspecification varchar(255); +ALTER TABLE testreport_history ADD COLUMN testpcrtestspecification varchar(255); + +INSERT INTO schema_version (version_number, comment) VALUES (443, 'Map variant specific Nucleic acid detection methods #5285'); + -- *** Insert new sql commands BEFORE this line. Remember to always consider _history tables. *** diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/labmessage/TestReportFacadeEjbMappingTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/labmessage/TestReportFacadeEjbMappingTest.java index cb4731337a1..c1ad16cd856 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/labmessage/TestReportFacadeEjbMappingTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/labmessage/TestReportFacadeEjbMappingTest.java @@ -1,22 +1,24 @@ package de.symeda.sormas.backend.labmessage; +import static org.mockito.Mockito.when; + +import java.sql.Timestamp; +import java.util.Date; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + import de.symeda.sormas.api.labmessage.LabMessageReferenceDto; import de.symeda.sormas.api.labmessage.TestReportDto; +import de.symeda.sormas.api.sample.PCRTestSpecification; import de.symeda.sormas.api.sample.PathogenTestResultType; import de.symeda.sormas.api.sample.PathogenTestType; import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.backend.sample.PathogenTestService; import junit.framework.TestCase; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -import java.sql.Timestamp; -import java.util.Date; - -import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class TestReportFacadeEjbMappingTest extends TestCase { @@ -58,6 +60,7 @@ public void testFromDto() { source.setTestResult(PathogenTestResultType.POSITIVE); source.setTestResultVerified(true); source.setTestResultText("Test result text"); + source.setTestPcrTestSpecification(PCRTestSpecification.VARIANT_SPECIFIC); TestReport result = sut.fromDto(source, true); @@ -74,6 +77,7 @@ public void testFromDto() { assertEquals(source.getTestResult(), result.getTestResult()); assertEquals(source.isTestResultVerified(), result.isTestResultVerified()); assertEquals(source.getTestResultText(), result.getTestResultText()); + assertEquals(source.getTestPcrTestSpecification(), result.getTestPcrTestSpecification()); } @@ -98,6 +102,7 @@ public void testToDto() { source.setTestResult(PathogenTestResultType.POSITIVE); source.setTestResultVerified(true); source.setTestResultText("Test result text"); + source.setTestPcrTestSpecification(PCRTestSpecification.VARIANT_SPECIFIC); TestReportDto result = sut.toDto(source); @@ -114,6 +119,7 @@ public void testToDto() { assertEquals(source.getTestResult(), result.getTestResult()); assertEquals(source.isTestResultVerified(), result.isTestResultVerified()); assertEquals(source.getTestResultText(), result.getTestResultText()); + assertEquals(source.getTestPcrTestSpecification(), result.getTestPcrTestSpecification()); } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/labmessage/LabMessageMapper.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/labmessage/LabMessageMapper.java index 1310b5c4213..014de6359df 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/labmessage/LabMessageMapper.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/labmessage/LabMessageMapper.java @@ -211,7 +211,12 @@ public List mapToPathogenTest(TestReportDto sourceTestReport, Pathogen pathogenTest::setPreliminary, pathogenTest.getPreliminary(), sourceTestReport.getPreliminary(), - PathogenTestDto.PRELIMINARY)))); + PathogenTestDto.PRELIMINARY), + Mapping.of( + pathogenTest::setPcrTestSpecification, + pathogenTest.getPcrTestSpecification(), + sourceTestReport.getTestPcrTestSpecification(), + PathogenTestDto.PCR_TEST_SPECIFICATION)))); } changedFields.addAll( From de3eab8bec22f5d82e98638ddbe421fc7cef4d58 Mon Sep 17 00:00:00 2001 From: Levente Gal Date: Fri, 11 Feb 2022 11:59:17 +0200 Subject: [PATCH 068/253] #7957 [Custom Case Export] Hide 'Education' field in German systems --- .../src/main/java/de/symeda/sormas/api/caze/CaseExportDto.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseExportDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseExportDto.java index dae2743f622..91bc995c26d 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseExportDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseExportDto.java @@ -17,6 +17,7 @@ *******************************************************************************/ package de.symeda.sormas.api.caze; +import de.symeda.sormas.api.utils.HideForCountries; import java.io.Serializable; import java.util.ArrayList; import java.util.Date; @@ -1640,6 +1641,7 @@ public String getOtherContactDetails() { CaseDataDto.PERSON, PersonDto.EDUCATION_TYPE }) @ExportGroup(ExportGroupType.PERSON) + @HideForCountries(countries = {CountryHelper.COUNTRY_CODE_GERMANY, CountryHelper.COUNTRY_CODE_FRANCE}) public EducationType getEducationType() { return educationType; } From f31c30e5a4ae0cbdfdc26f024403e1e1319ded02 Mon Sep 17 00:00:00 2001 From: Pawel Kujawa Date: Fri, 11 Feb 2022 13:56:25 +0100 Subject: [PATCH 069/253] fixes --- .../steps/web/application/tasks/TaskManagementSteps.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/tasks/TaskManagementSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/tasks/TaskManagementSteps.java index 8918fdffb34..17dff4ca8ed 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/tasks/TaskManagementSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/tasks/TaskManagementSteps.java @@ -228,6 +228,7 @@ public TaskManagementSteps( When( "^I collect the task column objects$", () -> { + webDriverHelpers.waitForPageLoaded(); webDriverHelpers.waitForPageLoadingSpinnerToDisappear(40); List> tableRowsData = getTableRowsData(); taskTableRows = new ArrayList<>(); @@ -308,7 +309,7 @@ private Map extractColumnHeadersHashMap() { } private LocalDateTime getLocalDateTimeFromColumns(String date) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M/d/yyyy h:mm a"); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M/d/yyyy h:m a"); try { return LocalDateTime.parse(date.trim(), formatter); } catch (Exception e) { From 39eebf3d42c606652977433f874a2f629aea24fd Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Fri, 11 Feb 2022 18:49:41 +0200 Subject: [PATCH 070/253] #7747-Fix-Allure-Report : refactored lost changes --- .../configprovider/ConfigFileReader.java | 47 +++++++++++ .../e2etests/envconfig/dto/EnvUser.java | 37 ++++++++ .../e2etests/envconfig/dto/Environment.java | 37 ++++++++ .../e2etests/envconfig/dto/Environments.java | 34 ++++++++ .../envconfig/manager/EnvironmentManager.java | 84 +++++++++++++++++++ 5 files changed, 239 insertions(+) create mode 100644 sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/configprovider/ConfigFileReader.java create mode 100644 sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/EnvUser.java create mode 100644 sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environment.java create mode 100644 sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environments.java create mode 100644 sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/manager/EnvironmentManager.java diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/configprovider/ConfigFileReader.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/configprovider/ConfigFileReader.java new file mode 100644 index 00000000000..ed1dd099446 --- /dev/null +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/configprovider/ConfigFileReader.java @@ -0,0 +1,47 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.sormas.e2etests.envconfig.configprovider; + +import java.io.File; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public abstract class ConfigFileReader { + + private static final String systemVariableName = "envConfig"; + + @SneakyThrows + public static File getConfigurationFile() { + String jsonPath; + try { + log.info("Looking after environment environmentconfig file"); + jsonPath = System.getProperty(systemVariableName); + } catch (NullPointerException e) { + throw new Exception("Unable to find environment environmentconfig file: " + e.getMessage()); + } + try { + log.info("Returning environmentconfig file path"); + return new File(jsonPath); + } catch (Exception any) { + throw new Exception( + "Unable to convert provided environmentconfig file into File object: " + + any.getMessage()); + } + } +} diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/EnvUser.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/EnvUser.java new file mode 100644 index 00000000000..9eb1721472a --- /dev/null +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/EnvUser.java @@ -0,0 +1,37 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.sormas.e2etests.envconfig.dto; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.NoArgsConstructor; +import lombok.Value; + +@Value +@AllArgsConstructor +@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) +@Builder(toBuilder = true, builderClassName = "builder") +public class EnvUser { + + String userRole; + String username; + String password; + String uuid; +} diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environment.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environment.java new file mode 100644 index 00000000000..41a9109e3d5 --- /dev/null +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environment.java @@ -0,0 +1,37 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.sormas.e2etests.envconfig.dto; + +import java.util.List; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.NoArgsConstructor; +import lombok.Value; + +@Value +@AllArgsConstructor +@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) +@Builder(toBuilder = true, builderClassName = "builder") +public class Environment { + + String name; + String locale; + String url; + List users; +} diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environments.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environments.java new file mode 100644 index 00000000000..33f66b411f9 --- /dev/null +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environments.java @@ -0,0 +1,34 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.sormas.e2etests.envconfig.dto; + +import java.util.List; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.NoArgsConstructor; +import lombok.Value; + +@Value +@AllArgsConstructor +@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) +@Builder(toBuilder = true, builderClassName = "builder") +public class Environments { + + List environments; +} \ No newline at end of file diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/manager/EnvironmentManager.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/manager/EnvironmentManager.java new file mode 100644 index 00000000000..7ccae4048c1 --- /dev/null +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/manager/EnvironmentManager.java @@ -0,0 +1,84 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.sormas.e2etests.envconfig.manager; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.sormas.e2etests.envconfig.configprovider.ConfigFileReader; +import org.sormas.e2etests.envconfig.dto.EnvUser; +import org.sormas.e2etests.envconfig.dto.Environment; +import org.sormas.e2etests.envconfig.dto.Environments; + +import java.util.List; + +@Slf4j +public class EnvironmentManager { + + private static EnvironmentManager environmentManager; + private ObjectMapper objectMapper; + private static Environments environments; + + @SneakyThrows + private EnvironmentManager() { + objectMapper = new ObjectMapper(); + environments = + objectMapper.readValue(ConfigFileReader.getConfigurationFile(), Environments.class); + } + + public static EnvironmentManager getInstance() { + if (environmentManager == null) environmentManager = new EnvironmentManager(); + return environmentManager; + } + + @SneakyThrows + public static String getEnvironmentUrlForMarket(String market) { + try { + return environments.getEnvironments().stream() + .filter(env -> env.getLocale().equalsIgnoreCase(market)) + .findFirst() + .get() + .getUrl(); + } catch (NullPointerException e) { + throw new Exception(String.format("Unable to get Environment for market: %s", market)); + } + } + + @SneakyThrows + public static EnvUser getUserByRole(String market, String role) { + try { + List users = getEnvironment(market).getUsers(); + return users.stream() + .filter(user -> user.getUserRole().equalsIgnoreCase(role)) + .findFirst() + .get(); + } catch (NullPointerException e) { + throw new Exception( + String.format( + "Unable to get Environment User for market: %s, and role: %s", market, role)); + } + } + + private static Environment getEnvironment(String market) { + return environments.getEnvironments().stream() + .filter(env -> env.getLocale().equalsIgnoreCase(market)) + .findFirst() + .get(); + } +} + From df46b05db28213814aa21694e24d52e904c7f0b8 Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Sat, 12 Feb 2022 11:27:55 +0100 Subject: [PATCH 071/253] Removed duplicate method --- .../persons/PersonDirectorySteps.java | 9 ------ .../features/sanity/web/Persons.feature | 32 +++++++++---------- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java index e510cd2c076..8cbef9226d0 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java @@ -159,15 +159,6 @@ public PersonDirectorySteps( "Number of displayed persons is not correct")); }); - When( - "I click on the APPLY FILTERS button for Person", - () -> { - webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable( - APPLY_FILTERS_BUTTON, 30); - webDriverHelpers.clickOnWebElementBySelector(APPLY_FILTERS_BUTTON); - TimeUnit.SECONDS.sleep(10); - }); - Then( "I change Year of birth filter by random value for Person", () -> { diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature index b4962f7195e..03571573f32 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature @@ -36,52 +36,52 @@ Feature: Edit Persons And I choose random value of Region in Persons for the last created person by API And I choose random value of District in Persons for the last created person by API And I choose random value of Community in Persons for the last created person by API - Then I click on the APPLY FILTERS button for Person + Then I apply on the APPLY FILTERS button And I check that number of displayed Person results is 1 And I change Year of birth filter by random value for Person - Then I click on the APPLY FILTERS button for Person + Then I apply on the APPLY FILTERS button And I check that number of displayed Person results is 0 Then I choose random value for Year of birth filter in Persons for the last created person by API - Then I click on the APPLY FILTERS button for Person + Then I apply on the APPLY FILTERS button And I check that number of displayed Person results is 1 And I change Month of birth filter by random value for Person - Then I click on the APPLY FILTERS button for Person + Then I apply on the APPLY FILTERS button And I check that number of displayed Person results is 0 And I choose random value for Month of birth filter in Persons for the last created person by API - Then I click on the APPLY FILTERS button for Person + Then I apply on the APPLY FILTERS button And I check that number of displayed Person results is 1 And I change Day of birth filter by random value for Person - Then I click on the APPLY FILTERS button for Person + Then I apply on the APPLY FILTERS button And I check that number of displayed Person results is 0 And I choose random value for Day of birth filter in Persons for the last created person by API - Then I click on the APPLY FILTERS button for Person + Then I apply on the APPLY FILTERS button And I search after last created person from API by factor "full name" in Person directory - And I click on the APPLY FILTERS button for Person + And I apply on the APPLY FILTERS button And I check that number of displayed Person results is 1 Then I change "full name" information data field for Person - And I click on the APPLY FILTERS button for Person + And I apply on the APPLY FILTERS button And I check that number of displayed Person results is 0 Then I fill Persons UUID for the last created person by API And I change present condition filter to random for Person - And I click on the APPLY FILTERS button for Person + And I apply on the APPLY FILTERS button And I check that number of displayed Person results is 0 And I choose present condition field from specific range for the last created person by API - Then I click on the APPLY FILTERS button for Person + Then I apply on the APPLY FILTERS button And I check that number of displayed Person results is 1 And I change REGION filter to "Berlin" for Person - And I click on the APPLY FILTERS button for Person + And I apply on the APPLY FILTERS button And I check that number of displayed Person results is 0 And I choose random value of Region in Persons for the last created person by API And I choose random value of District in Persons for the last created person by API - Then I click on the APPLY FILTERS button for Person + Then I apply on the APPLY FILTERS button And I check that number of displayed Person results is 1 Then I change Community filter to "Community2" for Person - And I click on the APPLY FILTERS button for Person + And I apply on the APPLY FILTERS button And I check that number of displayed Person results is 0 And I choose random value of Community in Persons for the last created person by API - Then I click on the APPLY FILTERS button for Person + Then I apply on the APPLY FILTERS button And I check that number of displayed Person results is 1 - And I click on the APPLY FILTERS button for Person + And I apply on the APPLY FILTERS button And I click on the RESET FILTERS button for Person @issue=SORDEV-8468 From 24dbd73a46e9fce2fdd7ee1086cc4a9ab43f4072 Mon Sep 17 00:00:00 2001 From: Alexandru Caruntu Date: Sun, 13 Feb 2022 08:54:13 +0200 Subject: [PATCH 072/253] #7910 - Fix translations for table headers in data dictionary --- .../de/symeda/sormas/api/i18n/Captions.java | 22 +++++++---- .../src/main/resources/captions.properties | 37 +++++++++++-------- .../common/DefaultEntitiesCreator.java | 7 ++-- .../outbreak/OutbreakOverviewGrid.java | 8 ++-- .../sharedinfo/SharedInfoField.java | 4 +- .../PreviousHospitalizationsField.java | 6 +-- 6 files changed, 48 insertions(+), 36 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java index e1846799623..8b03f045779 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java @@ -114,6 +114,7 @@ public interface Captions { String actionYes = "actionYes"; String actionYesForAll = "actionYesForAll"; String actionYesForSome = "actionYesForSome"; + String ActivityAsCase = "ActivityAsCase"; String ActivityAsCase_activityAsCaseDate = "ActivityAsCase.activityAsCaseDate"; String ActivityAsCase_activityAsCaseType = "ActivityAsCase.activityAsCaseType"; String ActivityAsCase_activityAsCaseTypeDetails = "ActivityAsCase.activityAsCaseTypeDetails"; @@ -557,7 +558,7 @@ public interface Captions { String columnNumberOfPendingTasks = "columnNumberOfPendingTasks"; String columnVaccineManufacturer = "columnVaccineManufacturer"; String columnVaccineName = "columnVaccineName"; - String community = "community"; + String Community = "Community"; String Community_archived = "Community.archived"; String Community_externalID = "Community.externalID"; String communityActiveCommunities = "communityActiveCommunities"; @@ -732,7 +733,7 @@ public interface Captions { String contactResumeFollowUp = "contactResumeFollowUp"; String contactSelect = "contactSelect"; String contactSourceCase = "contactSourceCase"; - String continent = "continent"; + String Continent = "Continent"; String Continent_archived = "Continent.archived"; String Continent_defaultName = "Continent.defaultName"; String Continent_displayName = "Continent.displayName"; @@ -742,7 +743,7 @@ public interface Captions { String continentArchivedContinents = "continentArchivedContinents"; String convertContactToCase = "convertContactToCase"; String convertEventParticipantToCase = "convertEventParticipantToCase"; - String country = "country"; + String Country = "Country"; String Country_archived = "Country.archived"; String Country_defaultName = "Country.defaultName"; String Country_displayName = "Country.displayName"; @@ -944,7 +945,7 @@ public interface Captions { String DiseaseBurden_outbreakDistrictCount = "DiseaseBurden.outbreakDistrictCount"; String DiseaseBurden_previousCaseCount = "DiseaseBurden.previousCaseCount"; String diseaseVariantDetails = "diseaseVariantDetails"; - String district = "district"; + String District = "District"; String District_archived = "District.archived"; String District_epidCode = "District.epidCode"; String District_externalID = "District.externalID"; @@ -1186,6 +1187,7 @@ public interface Captions { String exportSelectSormasData = "exportSelectSormasData"; String exportSormasData = "exportSormasData"; String exportUserRoles = "exportUserRoles"; + String Exposure = "Exposure"; String Exposure_animalCondition = "Exposure.animalCondition"; String Exposure_animalContactType = "Exposure.animalContactType"; String Exposure_animalContactTypeDetails = "Exposure.animalContactTypeDetails"; @@ -1248,7 +1250,7 @@ public interface Captions { String ExternalSurveillanceToolGateway_send = "ExternalSurveillanceToolGateway.send"; String ExternalSurveillanceToolGateway_title = "ExternalSurveillanceToolGateway.title"; String ExternalSurveillanceToolGateway_unableToSend = "ExternalSurveillanceToolGateway.unableToSend"; - String facility = "facility"; + String Facility = "Facility"; String Facility_additionalInformation = "Facility.additionalInformation"; String Facility_archived = "Facility.archived"; String Facility_areaType = "Facility.areaType"; @@ -1645,6 +1647,7 @@ public interface Captions { String Person_transporter_occupationDetails = "Person.transporter.occupationDetails"; String Person_uuid = "Person.uuid"; String personAgeAndBirthdate = "personAgeAndBirthdate"; + String PersonContactDetail = "PersonContactDetail"; String PersonContactDetail_additionalInformation = "PersonContactDetail.additionalInformation"; String PersonContactDetail_contactInformation = "PersonContactDetail.contactInformation"; String PersonContactDetail_details = "PersonContactDetail.details"; @@ -1673,7 +1676,7 @@ public interface Captions { String personsReplaceGeoCoordinates = "personsReplaceGeoCoordinates"; String personsSetMissingGeoCoordinates = "personsSetMissingGeoCoordinates"; String personsUpdated = "personsUpdated"; - String pointOfEntry = "pointOfEntry"; + String PointOfEntry = "PointOfEntry"; String PointOfEntry_active = "PointOfEntry.active"; String PointOfEntry_archived = "PointOfEntry.archived"; String PointOfEntry_externalID = "PointOfEntry.externalID"; @@ -1713,6 +1716,7 @@ public interface Captions { String PortHealthInfo_vesselDetails = "PortHealthInfo.vesselDetails"; String PortHealthInfo_vesselName = "PortHealthInfo.vesselName"; String postcode = "postcode"; + String Prescription = "Prescription"; String Prescription_additionalNotes = "Prescription.additionalNotes"; String Prescription_dose = "Prescription.dose"; String Prescription_drugIntakeDetails = "Prescription.drugIntakeDetails"; @@ -1731,7 +1735,7 @@ public interface Captions { String PrescriptionExport_caseName = "PrescriptionExport.caseName"; String PrescriptionExport_caseUuid = "PrescriptionExport.caseUuid"; String prescriptionNewPrescription = "prescriptionNewPrescription"; - String region = "region"; + String Region = "Region"; String Region_archived = "Region.archived"; String Region_country = "Region.country"; String Region_epidCode = "Region.epidCode"; @@ -1959,7 +1963,7 @@ public interface Captions { String statisticsSpecifySelection = "statisticsSpecifySelection"; String statisticsStatistics = "statisticsStatistics"; String statisticsVisualizationType = "statisticsVisualizationType"; - String subcontinent = "subcontinent"; + String Subcontinent = "Subcontinent"; String Subcontinent_archived = "Subcontinent.archived"; String Subcontinent_continent = "Subcontinent.continent"; String Subcontinent_defaultName = "Subcontinent.defaultName"; @@ -2224,6 +2228,7 @@ public interface Captions { String taskNewTask = "taskNewTask"; String taskNoTasks = "taskNoTasks"; String taskOfficerTasks = "taskOfficerTasks"; + String TestReport = "TestReport"; String TestReport_testDateTime = "TestReport.testDateTime"; String TestReport_testLabCity = "TestReport.testLabCity"; String TestReport_testLabExternalId = "TestReport.testLabExternalId"; @@ -2283,6 +2288,7 @@ public interface Captions { String travelEntryOpenResultingCase = "travelEntryOpenResultingCase"; String travelEntryPointOfEntry = "travelEntryPointOfEntry"; String travelEntryTravelEntriesList = "travelEntryTravelEntriesList"; + String Treatment = "Treatment"; String Treatment_additionalNotes = "Treatment.additionalNotes"; String Treatment_dose = "Treatment.dose"; String Treatment_drugIntakeDetails = "Treatment.drugIntakeDetails"; diff --git a/sormas-api/src/main/resources/captions.properties b/sormas-api/src/main/resources/captions.properties index b5208b38a9b..c804e47aac6 100644 --- a/sormas-api/src/main/resources/captions.properties +++ b/sormas-api/src/main/resources/captions.properties @@ -21,12 +21,10 @@ area=Area city=City postcode=Postcode address=Address -community=Community communityName=Community date=Date description=Description disease=Disease -district=District districtName=District edit=Edit epiWeekFrom=From Epi Week @@ -44,10 +42,6 @@ menu=Menu moreActions=More name=Name options=Options -continent=Continent -subcontinent=Subcontinent -country=Country -region=Region regionName=Region system=System to=To @@ -57,8 +51,6 @@ creationDate=Creation date notAvailableShort=NA inaccessibleValue=Confidential numberOfCharacters=Number of characters: %d / %d -facility=Facility -pointOfEntry=Point of entry remove=Remove reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Cases list caseInfrastructureDataChanged=Infrastructure data has changed -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Case Documents caseEditData=Edit data @@ -608,7 +601,7 @@ caseImportMergeCase=Override existing case with changes from the imported case? # CasePreviousHospitalization CasePreviousHospitalization=Previous hospitalization CasePreviousHospitalization.admissionAndDischargeDate=Date of admission & discharge -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date of admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date of discharge or transfer @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=External ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Active districts districtArchivedDistricts=Archived districts districtAllDistricts=All districts +District=District District.archived=Archived District.epidCode=Epid code District.growthRate=Growth rate @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Home or other place Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker -HealthConditions.formerSmoker=Former smoker +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Active regions regionArchivedRegions=Archived regions regionAllRegions=All regions +Region=Region Region.archived=Archived Region.epidCode=Epid code Region.growthRate=Growth rate @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/DefaultEntitiesCreator.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/DefaultEntitiesCreator.java index 8d1f8214bba..81a0526e534 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/DefaultEntitiesCreator.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/DefaultEntitiesCreator.java @@ -4,7 +4,6 @@ import javax.ejb.LocalBean; import javax.ejb.Stateless; -import javax.xml.crypto.Data; import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; @@ -28,7 +27,7 @@ public class DefaultEntitiesCreator { public Continent createDefaultContinent(boolean randomUuid) { Continent continent = new Continent(); continent.setUuid(createUuid(randomUuid, DefaultEntityHelper.DefaultInfrastructureUuidSeed.CONTINENT)); - continent.setDefaultName(I18nProperties.getCaption(Captions.continent, "Default Continent")); + continent.setDefaultName(I18nProperties.getCaption(Captions.Continent, "Default Continent")); continent.setExternalId("CONT"); return continent; } @@ -44,7 +43,7 @@ private String createUuid(boolean randomUuid, DefaultEntityHelper.DefaultInfrast public Subcontinent createDefaultSubcontinent(Continent continent, boolean randomUuid) { Subcontinent subcontinent = new Subcontinent(); subcontinent.setUuid(createUuid(randomUuid, DefaultEntityHelper.DefaultInfrastructureUuidSeed.SUBCONTINENT)); - subcontinent.setDefaultName(I18nProperties.getCaption(Captions.subcontinent, "Default Subcontinent")); + subcontinent.setDefaultName(I18nProperties.getCaption(Captions.Subcontinent, "Default Subcontinent")); subcontinent.setExternalId("SUB-CNT"); subcontinent.setContinent(continent); return subcontinent; @@ -53,7 +52,7 @@ public Subcontinent createDefaultSubcontinent(Continent continent, boolean rando public Country createDefaultCountry(Subcontinent subcontinent, boolean randomUuid) { Country country = new Country(); country.setUuid(createUuid(randomUuid, DefaultEntityHelper.DefaultInfrastructureUuidSeed.COUNTRY)); - country.setDefaultName(I18nProperties.getCaption(Captions.country, "Default Country")); + country.setDefaultName(I18nProperties.getCaption(Captions.Country, "Default Country")); country.setExternalId("CNT"); country.setSubcontinent(subcontinent); return country; diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/outbreak/OutbreakOverviewGrid.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/outbreak/OutbreakOverviewGrid.java index 0ee39e723b5..ddd850c3563 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/outbreak/OutbreakOverviewGrid.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/outbreak/OutbreakOverviewGrid.java @@ -34,10 +34,10 @@ import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; -import de.symeda.sormas.api.outbreak.OutbreakCriteria; -import de.symeda.sormas.api.outbreak.OutbreakDto; import de.symeda.sormas.api.infrastructure.district.DistrictReferenceDto; import de.symeda.sormas.api.infrastructure.region.RegionReferenceDto; +import de.symeda.sormas.api.outbreak.OutbreakCriteria; +import de.symeda.sormas.api.outbreak.OutbreakDto; import de.symeda.sormas.api.user.UserDto; import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.utils.DataHelper; @@ -49,7 +49,7 @@ @SuppressWarnings("serial") public class OutbreakOverviewGrid extends Grid implements ItemClickListener { - private static final String REGION = Captions.region; + private static final String REGION = Captions.Region; private UserDto user; @@ -61,7 +61,7 @@ public OutbreakOverviewGrid() { user = UserProvider.getCurrent().getUser(); addColumn(REGION, RegionReferenceDto.class).setMaximumWidth(200); - getColumn(REGION).setHeaderCaption(I18nProperties.getCaption(Captions.region)); + getColumn(REGION).setHeaderCaption(I18nProperties.getCaption(Captions.Region)); for (Disease disease : FacadeProvider.getDiseaseConfigurationFacade().getAllDiseases(true, true, true)) { addColumn(disease, OutbreakRegionConfiguration.class).setMaximumWidth(200) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/components/linelisting/sharedinfo/SharedInfoField.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/components/linelisting/sharedinfo/SharedInfoField.java index d1795b7baed..fd6558d8405 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/components/linelisting/sharedinfo/SharedInfoField.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/components/linelisting/sharedinfo/SharedInfoField.java @@ -40,8 +40,8 @@ public SharedInfoField(CaseReferenceDto caseReferenceDto, Disease initialDisease ? new CaseSelector(caseReferenceDto) : new CaseSelector(I18nProperties.getString(Strings.infoNoSourceCaseSelectedLineListing)); disease = new ComboBox<>(I18nProperties.getCaption(Captions.lineListingDiseaseOfSourceCase)); - region = new ComboBox<>(I18nProperties.getCaption(Captions.region)); - district = new ComboBox<>(I18nProperties.getCaption(Captions.district)); + region = new ComboBox<>(I18nProperties.getCaption(Captions.Region)); + district = new ComboBox<>(I18nProperties.getCaption(Captions.District)); this.initialDiseaseValue = initialDiseaseValue; } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/hospitalization/PreviousHospitalizationsField.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/hospitalization/PreviousHospitalizationsField.java index 0e00ee96f00..ec1b836e219 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/hospitalization/PreviousHospitalizationsField.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/hospitalization/PreviousHospitalizationsField.java @@ -22,12 +22,12 @@ import com.vaadin.ui.Window; import com.vaadin.v7.ui.Table; -import de.symeda.sormas.api.infrastructure.facility.FacilityReferenceDto; import de.symeda.sormas.api.hospitalization.PreviousHospitalizationDto; import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Strings; import de.symeda.sormas.api.infrastructure.district.DistrictReferenceDto; +import de.symeda.sormas.api.infrastructure.facility.FacilityReferenceDto; import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; @@ -44,8 +44,8 @@ public class PreviousHospitalizationsField extends AbstractTableField { private static final String PERIOD = Captions.CasePreviousHospitalization_prevHospPeriod; - private static final String COMMUNITY = Captions.community; - private static final String DISTRICT = Captions.district; + private static final String COMMUNITY = Captions.Community; + private static final String DISTRICT = Captions.District; private FieldVisibilityCheckers fieldVisibilityCheckers; From c7f61eaf7fb10cd779886115776a444ec3276cb4 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Mon, 14 Feb 2022 08:07:04 +0200 Subject: [PATCH 073/253] #6879 - move health conditions from ClinicalCourse to Cases backend & vaadin part --- .../symeda/sormas/api/caze/CaseDataDto.java | 24 ++-- .../symeda/sormas/api/caze/CaseExportDto.java | 3 +- .../api/clinicalcourse/ClinicalCourseDto.java | 29 +---- .../de/symeda/sormas/backend/caze/Case.java | 16 +++ .../sormas/backend/caze/CaseFacadeEjb.java | 18 ++- .../sormas/backend/caze/CaseService.java | 5 +- .../clinicalcourse/ClinicalCourse.java | 14 --- .../ClinicalCourseFacadeEjb.java | 104 ----------------- .../HealthConditionsMapper.java | 106 ++++++++++++++++++ .../backend/contact/ContactFacadeEjb.java | 10 +- .../immunization/ImmunizationFacadeEjb.java | 2 +- .../de/symeda/sormas/backend/util/test.sql | 50 +++++++++ .../vaccination/VaccinationFacadeEjb.java | 11 +- .../de/symeda/sormas/utils/CaseJoins.java | 8 +- .../src/main/resources/sql/sormas_schema.sql | 13 +++ .../SormasToSormasCaseFacadeEjbTest.java | 8 +- .../symeda/sormas/ui/caze/CaseController.java | 2 +- .../symeda/sormas/ui/caze/CaseDataForm.java | 10 +- .../ui/clinicalcourse/ClinicalCourseForm.java | 4 +- 19 files changed, 249 insertions(+), 188 deletions(-) create mode 100644 sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/HealthConditionsMapper.java create mode 100644 sormas-backend/src/main/java/de/symeda/sormas/backend/util/test.sql diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java index 562631b3540..d5ea150cbb7 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java @@ -123,6 +123,7 @@ public class CaseDataDto extends SormasToSormasShareableDto { public static final String CLINICAL_COURSE = "clinicalCourse"; public static final String MATERNAL_HISTORY = "maternalHistory"; public static final String PORT_HEALTH_INFO = "portHealthInfo"; + public static final String HEALTH_CONDITIONS = "healthConditions"; public static final String PREGNANT = "pregnant"; public static final String VACCINATION_STATUS = "vaccinationStatus"; public static final String SMALLPOX_VACCINATION_SCAR = "smallpoxVaccinationScar"; @@ -320,6 +321,10 @@ public class CaseDataDto extends SormasToSormasShareableDto { @SensitiveData @Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong) private String healthFacilityDetails; + + @Valid + private HealthConditionsDto healthConditions; + private YesNoUnknown pregnant; @Diseases({ Disease.AFP, @@ -558,7 +563,7 @@ public class CaseDataDto extends SormasToSormasShareableDto { private Map externalData; public static CaseDataDto build(PersonReferenceDto person, Disease disease) { - return build(person, disease, null); + return build(person, disease, HealthConditionsDto.build()); } public static CaseDataDto build(PersonReferenceDto person, Disease disease, HealthConditionsDto healthConditions) { @@ -569,13 +574,8 @@ public static CaseDataDto build(PersonReferenceDto person, Disease disease, Heal caze.setEpiData(EpiDataDto.build()); caze.setSymptoms(SymptomsDto.build()); caze.setTherapy(TherapyDto.build()); - - if (healthConditions == null) { - caze.setClinicalCourse(ClinicalCourseDto.build()); - } else { - caze.setClinicalCourse(ClinicalCourseDto.build(healthConditions)); - } - + caze.setHealthConditions(healthConditions); + caze.setClinicalCourse(ClinicalCourseDto.build()); caze.setMaternalHistory(MaternalHistoryDto.build()); caze.setPortHealthInfo(PortHealthInfoDto.build()); caze.setDisease(disease); @@ -1658,6 +1658,14 @@ public void setExternalData(Map externalData) { this.externalData = externalData; } + public HealthConditionsDto getHealthConditions() { + return healthConditions; + } + + public void setHealthConditions(HealthConditionsDto healthConditions) { + this.healthConditions = healthConditions; + } + @Override public String toString() { return this.getUuid() + " - " + this.getExternalID(); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseExportDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseExportDto.java index 91bc995c26d..19adacd58fa 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseExportDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseExportDto.java @@ -29,7 +29,6 @@ import de.symeda.sormas.api.CountryHelper; import de.symeda.sormas.api.Disease; -import de.symeda.sormas.api.clinicalcourse.ClinicalCourseDto; import de.symeda.sormas.api.clinicalcourse.HealthConditionsDto; import de.symeda.sormas.api.contact.FollowUpStatus; import de.symeda.sormas.api.contact.QuarantineType; @@ -1902,7 +1901,7 @@ public SymptomsDto getSymptoms() { @Order(122) @ExportTarget(caseExportTypes = { CaseExportType.CASE_MANAGEMENT }) - @ExportProperty(ClinicalCourseDto.HEALTH_CONDITIONS) + @ExportProperty(CaseDataDto.HEALTH_CONDITIONS) @ExportGroup(ExportGroupType.CASE_MANAGEMENT) public HealthConditionsDto getHealthConditions() { return healthConditions; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/clinicalcourse/ClinicalCourseDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/clinicalcourse/ClinicalCourseDto.java index fddfec4369d..681777972fa 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/clinicalcourse/ClinicalCourseDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/clinicalcourse/ClinicalCourseDto.java @@ -1,36 +1,16 @@ package de.symeda.sormas.api.clinicalcourse; -import javax.validation.Valid; - import de.symeda.sormas.api.EntityDto; import de.symeda.sormas.api.utils.DataHelper; public class ClinicalCourseDto extends EntityDto { - private static final long serialVersionUID = -2664896907352864261L; - public static final String I18N_PREFIX = "ClinicalCourse"; - - public static final String HEALTH_CONDITIONS = "healthConditions"; - - @Valid - private HealthConditionsDto healthConditions; + private static final long serialVersionUID = -2664896907352864261L; public static ClinicalCourseDto build() { - return build(null); - } - - public static ClinicalCourseDto build(HealthConditionsDto healthConditions) { - ClinicalCourseDto clinicalCourse = new ClinicalCourseDto(); clinicalCourse.setUuid(DataHelper.createUuid()); - - if (healthConditions == null) { - clinicalCourse.setHealthConditions(HealthConditionsDto.build()); - } else { - clinicalCourse.setHealthConditions(healthConditions); - } - return clinicalCourse; } @@ -38,11 +18,4 @@ public ClinicalCourseReferenceDto toReference() { return new ClinicalCourseReferenceDto(getUuid()); } - public HealthConditionsDto getHealthConditions() { - return healthConditions; - } - - public void setHealthConditions(HealthConditionsDto healthConditions) { - this.healthConditions = healthConditions; - } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/Case.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/Case.java index 852ae6c396f..4dc4550d726 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/Case.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/Case.java @@ -42,6 +42,7 @@ import javax.persistence.TemporalType; import javax.persistence.Transient; +import de.symeda.sormas.backend.clinicalcourse.HealthConditions; import org.hibernate.annotations.Type; import de.symeda.auditlog.api.Audited; @@ -149,6 +150,9 @@ public class Case extends CoreAdo implements SormasToSormasShareable, HasExterna public static final String CLINICAL_COURSE = "clinicalCourse"; public static final String MATERNAL_HISTORY = "maternalHistory"; public static final String PORT_HEALTH_INFO = "portHealthInfo"; + + public static final String HEALTH_CONDITIONS = "healthConditions"; + public static final String PREGNANT = "pregnant"; public static final String VACCINATION_STATUS = "vaccinationStatus"; public static final String EPID_NUMBER = "epidNumber"; @@ -298,6 +302,8 @@ public class Case extends CoreAdo implements SormasToSormasShareable, HasExterna private Symptoms symptoms; + private HealthConditions healthConditions; + private YesNoUnknown pregnant; private VaccinationStatus vaccinationStatus; @@ -872,6 +878,16 @@ public void setConvertedContact(List convertedContact) { this.convertedContact = convertedContact; } + @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @AuditedIgnore + public HealthConditions getHealthConditions() { + return healthConditions; + } + + public void setHealthConditions(HealthConditions healthConditions) { + this.healthConditions = healthConditions; + } + @Enumerated(EnumType.STRING) public YesNoUnknown getPregnant() { return pregnant; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java index a27efbe60dd..9e1c33a3ece 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java @@ -53,6 +53,7 @@ import javax.ejb.TransactionAttributeType; import javax.enterprise.concurrent.ManagedScheduledExecutorService; import javax.inject.Inject; +import javax.persistence.Tuple; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; @@ -68,6 +69,7 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; +import de.symeda.sormas.backend.clinicalcourse.HealthConditionsMapper; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTime; @@ -123,7 +125,6 @@ import de.symeda.sormas.api.contact.ContactCriteria; import de.symeda.sormas.api.contact.ContactDto; import de.symeda.sormas.api.contact.ContactReferenceDto; -import de.symeda.sormas.api.deletionconfiguration.AutomaticDeletionInfoDto; import de.symeda.sormas.api.document.DocumentRelatedEntityType; import de.symeda.sormas.api.epidata.EpiDataDto; import de.symeda.sormas.api.epidata.EpiDataHelper; @@ -446,6 +447,9 @@ public class CaseFacadeEjb extends AbstractCoreFacadeEjb getExportList( .stream() .collect(Collectors.toMap(e -> (Long) e[0], e -> ((Long) e[1]).intValue())); } - if (ExportHelper.shouldExportFields(exportConfiguration, ClinicalCourseDto.HEALTH_CONDITIONS)) { + if (ExportHelper.shouldExportFields(exportConfiguration, CaseDataDto.HEALTH_CONDITIONS)) { List healthConditionsList = null; CriteriaQuery healthConditionsCq = cb.createQuery(HealthConditions.class); Root healthConditionsRoot = healthConditionsCq.from(HealthConditions.class); @@ -1027,7 +1031,7 @@ public List getExportList( } if (healthConditions != null) { Optional.ofNullable(healthConditions.get(exportDto.getHealthConditionsId())) - .ifPresent(healthCondition -> exportDto.setHealthConditions(ClinicalCourseFacadeEjb.toHealthConditionsDto(healthCondition))); + .ifPresent(healthCondition -> exportDto.setHealthConditions(healthConditionsMapper.toDto(healthCondition))); } if (firstPreviousHospitalizations != null) { Optional.ofNullable(firstPreviousHospitalizations.get(exportDto.getHospitalizationId())) @@ -2351,7 +2355,7 @@ public void pseudonymizeDto(Case source, CaseDataDto dto, Pseudonymizer pseudony exp -> inJurisdiction, (exp, expInJurisdiction) -> pseudonymizer.pseudonymizeDto(LocationDto.class, exp.getLocation(), expInJurisdiction, null))); - pseudonymizer.pseudonymizeDto(HealthConditionsDto.class, c.getClinicalCourse().getHealthConditions(), inJurisdiction, null); + pseudonymizer.pseudonymizeDto(HealthConditionsDto.class, c.getHealthConditions(), inJurisdiction, null); pseudonymizer.pseudonymizeDtoCollection( PreviousHospitalizationDto.class, @@ -2394,8 +2398,8 @@ public void restorePseudonymizedDto(CaseDataDto dto, CaseDataDto existingCaseDto pseudonymizer.restorePseudonymizedValues( HealthConditionsDto.class, - dto.getClinicalCourse().getHealthConditions(), - existingCaseDto.getClinicalCourse().getHealthConditions(), + dto.getHealthConditions(), + existingCaseDto.getHealthConditions(), inJurisdiction); dto.getHospitalization() @@ -2466,6 +2470,7 @@ public CaseDataDto toDto(Case source) { if (source.getClinicalCourse() != null) { target.setClinicalCourse(ClinicalCourseFacadeEjb.toDto(source.getClinicalCourse())); } + target.setHealthConditions(healthConditionsMapper.toDto(source.getHealthConditions())); if (source.getMaternalHistory() != null) { target.setMaternalHistory(MaternalHistoryFacadeEjb.toDto(source.getMaternalHistory())); } @@ -2647,6 +2652,7 @@ public Case fillOrBuildEntity(@NotNull CaseDataDto source, Case target, boolean source.setTherapy(TherapyDto.build()); } target.setTherapy(therapyFacade.fromDto(source.getTherapy(), checkChangeDate)); + target.setHealthConditions(healthConditionsMapper.fromDto(source.getHealthConditions(), checkChangeDate)); if (source.getClinicalCourse() == null) { source.setClinicalCourse(ClinicalCourseDto.build()); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java index 50ccb941297..b2ca5f11fb4 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java @@ -237,8 +237,7 @@ public List getAllActiveCasesAfter(Date date, boolean includeExtendedChang Root from = cq.from(getElementClass()); from.fetch(Case.SYMPTOMS); from.fetch(Case.THERAPY); - Fetch clinicalCourseFetch = from.fetch(Case.CLINICAL_COURSE); - clinicalCourseFetch.fetch(ClinicalCourse.HEALTH_CONDITIONS); + from.fetch(Case.HEALTH_CONDITIONS); from.fetch(Case.HOSPITALIZATION); from.fetch(Case.EPI_DATA); from.fetch(Case.PORT_HEALTH_INFO); @@ -996,7 +995,7 @@ private ChangeDateFilterBuilder addChangeDateFilter( filterBuilder = filterBuilder.add(casePath, Case.THERAPY) .add(clinicalCourse) - .add(clinicalCourse, ClinicalCourse.HEALTH_CONDITIONS) + .add(casePath, Case.HEALTH_CONDITIONS) .add(casePath, Case.MATERNAL_HISTORY) .add(casePath, Case.PORT_HEALTH_INFO) .add(casePath, Case.SORMAS_TO_SORMAS_ORIGIN_INFO) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/ClinicalCourse.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/ClinicalCourse.java index 2cbed4f17f7..6123e232f11 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/ClinicalCourse.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/ClinicalCourse.java @@ -2,11 +2,9 @@ import javax.persistence.CascadeType; import javax.persistence.Entity; -import javax.persistence.FetchType; import javax.persistence.OneToOne; import de.symeda.auditlog.api.Audited; -import de.symeda.auditlog.api.AuditedIgnore; import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.common.AbstractDomainObject; @@ -18,22 +16,10 @@ public class ClinicalCourse extends AbstractDomainObject { public static final String TABLE_NAME = "clinicalcourse"; - public static final String HEALTH_CONDITIONS = "healthConditions"; public static final String CASE = "caze"; - private HealthConditions healthConditions; private Case caze; - @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) - @AuditedIgnore - public HealthConditions getHealthConditions() { - return healthConditions; - } - - public void setHealthConditions(HealthConditions healthConditions) { - this.healthConditions = healthConditions; - } - @OneToOne(cascade = CascadeType.ALL, mappedBy = Case.CLINICAL_COURSE) public Case getCaze() { return caze; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/ClinicalCourseFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/ClinicalCourseFacadeEjb.java index 3224928aed9..0bc430ccd12 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/ClinicalCourseFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/ClinicalCourseFacadeEjb.java @@ -3,44 +3,18 @@ import javax.ejb.EJB; import javax.ejb.LocalBean; import javax.ejb.Stateless; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; import javax.validation.constraints.NotNull; import de.symeda.sormas.api.clinicalcourse.ClinicalCourseDto; import de.symeda.sormas.api.clinicalcourse.ClinicalCourseFacade; import de.symeda.sormas.api.clinicalcourse.ClinicalCourseReferenceDto; -import de.symeda.sormas.api.clinicalcourse.HealthConditionsDto; -import de.symeda.sormas.backend.caze.CaseFacadeEjb.CaseFacadeEjbLocal; -import de.symeda.sormas.backend.caze.CaseService; -import de.symeda.sormas.backend.person.PersonService; -import de.symeda.sormas.backend.symptoms.SymptomsFacadeEjb.SymptomsFacadeEjbLocal; -import de.symeda.sormas.backend.user.UserService; import de.symeda.sormas.backend.util.DtoHelper; -import de.symeda.sormas.backend.util.ModelConstants; @Stateless(name = "ClinicalCourseFacade") public class ClinicalCourseFacadeEjb implements ClinicalCourseFacade { - @PersistenceContext(unitName = ModelConstants.PERSISTENCE_UNIT_NAME) - private EntityManager em; - @EJB private ClinicalCourseService service; - @EJB - private ClinicalVisitService clinicalVisitService; - @EJB - private SymptomsFacadeEjbLocal symptomsFacade; - @EJB - private UserService userService; - @EJB - private CaseFacadeEjbLocal caseFacade; - @EJB - private CaseService caseService; - @EJB - private PersonService personService; - @EJB - private HealthConditionsService healthConditionsService; public static ClinicalCourseReferenceDto toReferenceDto(ClinicalCourse entity) { @@ -61,90 +35,12 @@ public static ClinicalCourseDto toDto(ClinicalCourse source) { ClinicalCourseDto target = new ClinicalCourseDto(); DtoHelper.fillDto(target, source); - if (source.getHealthConditions() != null) { - target.setHealthConditions(toHealthConditionsDto(source.getHealthConditions())); - } - return target; } public ClinicalCourse fromDto(@NotNull ClinicalCourseDto source, boolean checkChangeDate) { ClinicalCourse target = DtoHelper.fillOrBuildEntity(source, service.getByUuid(source.getUuid()), ClinicalCourse::new, checkChangeDate); - - if (source.getHealthConditions() != null) { - target.setHealthConditions(fromHealthConditionsDto(source.getHealthConditions(), checkChangeDate)); - } - - return target; - } - - public static HealthConditionsDto toHealthConditionsDto(HealthConditions source) { - - if (source == null) { - return null; - } - - HealthConditionsDto target = new HealthConditionsDto(); - DtoHelper.fillDto(target, source); - - target.setAsplenia(source.getAsplenia()); - target.setChronicHeartFailure(source.getChronicHeartFailure()); - target.setChronicKidneyDisease(source.getChronicKidneyDisease()); - target.setChronicLiverDisease(source.getChronicLiverDisease()); - target.setChronicNeurologicCondition(source.getChronicNeurologicCondition()); - target.setChronicPulmonaryDisease(source.getChronicPulmonaryDisease()); - target.setDiabetes(source.getDiabetes()); - target.setHepatitis(source.getHepatitis()); - target.setHiv(source.getHiv()); - target.setHivArt(source.getHivArt()); - target.setMalignancyChemotherapy(source.getMalignancyChemotherapy()); - target.setTuberculosis(source.getTuberculosis()); - target.setDownSyndrome(source.getDownSyndrome()); - target.setCongenitalSyphilis(source.getCongenitalSyphilis()); - target.setOtherConditions(source.getOtherConditions()); - target.setImmunodeficiencyOtherThanHiv(source.getImmunodeficiencyOtherThanHiv()); - target.setCardiovascularDiseaseIncludingHypertension(source.getCardiovascularDiseaseIncludingHypertension()); - target.setCardiovascularDiseaseIncludingHypertension(source.getCardiovascularDiseaseIncludingHypertension()); - target.setObesity(source.getObesity()); - target.setCurrentSmoker(source.getCurrentSmoker()); - target.setFormerSmoker(source.getFormerSmoker()); - target.setAsthma(source.getAsthma()); - target.setSickleCellDisease(source.getSickleCellDisease()); - target.setImmunodeficiencyIncludingHiv(source.getImmunodeficiencyIncludingHiv()); - - return target; - } - - public HealthConditions fromHealthConditionsDto(@NotNull HealthConditionsDto source, boolean checkChangeDate) { - - HealthConditions target = - DtoHelper.fillOrBuildEntity(source, healthConditionsService.getByUuid(source.getUuid()), HealthConditions::new, checkChangeDate); - - target.setAsplenia(source.getAsplenia()); - target.setChronicHeartFailure(source.getChronicHeartFailure()); - target.setChronicKidneyDisease(source.getChronicKidneyDisease()); - target.setChronicLiverDisease(source.getChronicLiverDisease()); - target.setChronicNeurologicCondition(source.getChronicNeurologicCondition()); - target.setChronicPulmonaryDisease(source.getChronicPulmonaryDisease()); - target.setDiabetes(source.getDiabetes()); - target.setHepatitis(source.getHepatitis()); - target.setHiv(source.getHiv()); - target.setHivArt(source.getHivArt()); - target.setMalignancyChemotherapy(source.getMalignancyChemotherapy()); - target.setTuberculosis(source.getTuberculosis()); - target.setDownSyndrome(source.getDownSyndrome()); - target.setCongenitalSyphilis(source.getCongenitalSyphilis()); - target.setOtherConditions(source.getOtherConditions()); - target.setImmunodeficiencyOtherThanHiv(source.getImmunodeficiencyOtherThanHiv()); - target.setCardiovascularDiseaseIncludingHypertension(source.getCardiovascularDiseaseIncludingHypertension()); - target.setObesity(source.getObesity()); - target.setCurrentSmoker(source.getCurrentSmoker()); - target.setFormerSmoker(source.getFormerSmoker()); - target.setAsthma(source.getAsthma()); - target.setSickleCellDisease(source.getSickleCellDisease()); - target.setImmunodeficiencyIncludingHiv(source.getImmunodeficiencyIncludingHiv()); - return target; } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/HealthConditionsMapper.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/HealthConditionsMapper.java new file mode 100644 index 00000000000..518344f024d --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/clinicalcourse/HealthConditionsMapper.java @@ -0,0 +1,106 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package de.symeda.sormas.backend.clinicalcourse; + +import javax.ejb.EJB; +import javax.ejb.LocalBean; +import javax.ejb.Stateless; +import javax.inject.Inject; +import javax.validation.constraints.NotNull; + +import de.symeda.sormas.api.clinicalcourse.HealthConditionsDto; +import de.symeda.sormas.backend.util.DtoHelper; + +@LocalBean +@Stateless(name = "HealthConditionsMapper") +public class HealthConditionsMapper { + + @EJB + private HealthConditionsService healthConditionsService; + + public HealthConditionsDto toDto(HealthConditions source) { + + if (source == null) { + return null; + } + + HealthConditionsDto target = new HealthConditionsDto(); + DtoHelper.fillDto(target, source); + + target.setAsplenia(source.getAsplenia()); + target.setChronicHeartFailure(source.getChronicHeartFailure()); + target.setChronicKidneyDisease(source.getChronicKidneyDisease()); + target.setChronicLiverDisease(source.getChronicLiverDisease()); + target.setChronicNeurologicCondition(source.getChronicNeurologicCondition()); + target.setChronicPulmonaryDisease(source.getChronicPulmonaryDisease()); + target.setDiabetes(source.getDiabetes()); + target.setHepatitis(source.getHepatitis()); + target.setHiv(source.getHiv()); + target.setHivArt(source.getHivArt()); + target.setMalignancyChemotherapy(source.getMalignancyChemotherapy()); + target.setTuberculosis(source.getTuberculosis()); + target.setDownSyndrome(source.getDownSyndrome()); + target.setCongenitalSyphilis(source.getCongenitalSyphilis()); + target.setOtherConditions(source.getOtherConditions()); + target.setImmunodeficiencyOtherThanHiv(source.getImmunodeficiencyOtherThanHiv()); + target.setCardiovascularDiseaseIncludingHypertension(source.getCardiovascularDiseaseIncludingHypertension()); + target.setCardiovascularDiseaseIncludingHypertension(source.getCardiovascularDiseaseIncludingHypertension()); + target.setObesity(source.getObesity()); + target.setCurrentSmoker(source.getCurrentSmoker()); + target.setFormerSmoker(source.getFormerSmoker()); + target.setAsthma(source.getAsthma()); + target.setSickleCellDisease(source.getSickleCellDisease()); + target.setImmunodeficiencyIncludingHiv(source.getImmunodeficiencyIncludingHiv()); + + return target; + } + + public HealthConditions fromDto(@NotNull HealthConditionsDto source, boolean checkChangeDate) { + if (source == null) { + return null; + } + + HealthConditions target = + DtoHelper.fillOrBuildEntity(source, healthConditionsService.getByUuid(source.getUuid()), HealthConditions::new, checkChangeDate); + + target.setAsplenia(source.getAsplenia()); + target.setChronicHeartFailure(source.getChronicHeartFailure()); + target.setChronicKidneyDisease(source.getChronicKidneyDisease()); + target.setChronicLiverDisease(source.getChronicLiverDisease()); + target.setChronicNeurologicCondition(source.getChronicNeurologicCondition()); + target.setChronicPulmonaryDisease(source.getChronicPulmonaryDisease()); + target.setDiabetes(source.getDiabetes()); + target.setHepatitis(source.getHepatitis()); + target.setHiv(source.getHiv()); + target.setHivArt(source.getHivArt()); + target.setMalignancyChemotherapy(source.getMalignancyChemotherapy()); + target.setTuberculosis(source.getTuberculosis()); + target.setDownSyndrome(source.getDownSyndrome()); + target.setCongenitalSyphilis(source.getCongenitalSyphilis()); + target.setOtherConditions(source.getOtherConditions()); + target.setImmunodeficiencyOtherThanHiv(source.getImmunodeficiencyOtherThanHiv()); + target.setCardiovascularDiseaseIncludingHypertension(source.getCardiovascularDiseaseIncludingHypertension()); + target.setObesity(source.getObesity()); + target.setCurrentSmoker(source.getCurrentSmoker()); + target.setFormerSmoker(source.getFormerSmoker()); + target.setAsthma(source.getAsthma()); + target.setSickleCellDisease(source.getSickleCellDisease()); + target.setImmunodeficiencyIncludingHiv(source.getImmunodeficiencyIncludingHiv()); + + return target; + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java index f0399ac8e78..c61adc885ec 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java @@ -62,6 +62,7 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; +import de.symeda.sormas.backend.clinicalcourse.HealthConditionsMapper; import org.apache.commons.collections.CollectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -237,8 +238,6 @@ public class ContactFacadeEjb extends AbstractCoreFacadeEjb vaccinationDtos = new ArrayList<>(); for (Vaccination vaccination : entity.getVaccinations()) { - VaccinationDto vaccinationDto = VaccinationFacadeEjbLocal.toDto(vaccination); + VaccinationDto vaccinationDto = vaccinationFacade.toDto(vaccination); vaccinationDtos.add(vaccinationDto); } dto.setVaccinations(vaccinationDtos); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/util/test.sql b/sormas-backend/src/main/java/de/symeda/sormas/backend/util/test.sql new file mode 100644 index 00000000000..41489f99e15 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/util/test.sql @@ -0,0 +1,50 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +select distinct new de.symeda.sormas.api.caze.CaseExportDto(generatedAlias0.id, generatedAlias1.id, generatedAlias2.id, generatedAlias3.id, generatedAlias4.id, generatedAlias5.id, generatedAlias6.id, generatedAlias0.uuid, generatedAlias0.epidNumber, generatedAlias0.disease, generatedAlias0.diseaseVariant, generatedAlias0.diseaseDetails, generatedAlias0.diseaseVariantDetails, generatedAlias1.uuid, generatedAlias1.firstName, generatedAlias1.lastName, generatedAlias1.salutation, generatedAlias1.otherSalutation, generatedAlias1.sex, generatedAlias0.pregnant, generatedAlias1.approximateAge, generatedAlias1.approximateAgeType, generatedAlias1.birthdateDD, generatedAlias1.birthdateMM, generatedAlias1.birthdateYYYY, generatedAlias0.reportDate, generatedAlias7.name, generatedAlias8.name, generatedAlias9.name, generatedAlias0.facilityType, generatedAlias10.name, generatedAlias10.uuid, generatedAlias0.healthFacilityDetails, generatedAlias11.name, generatedAlias11.uuid, generatedAlias0.pointOfEntryDetails, generatedAlias0.caseClassification, generatedAlias0.clinicalConfirmation, generatedAlias0.epidemiologicalConfirmation, generatedAlias0.laboratoryDiagnosticConfirmation, generatedAlias0.notACaseReasonNegativeTest, generatedAlias0.notACaseReasonPhysicianInformation, generatedAlias0.notACaseReasonDifferentPathogen, generatedAlias0.notACaseReasonOther, generatedAlias0.notACaseReasonDetails, generatedAlias0.investigationStatus, generatedAlias0.investigatedDate, generatedAlias0.outcome, generatedAlias0.outcomeDate, generatedAlias0.sequelae, generatedAlias0.sequelaeDetails, generatedAlias0.bloodOrganOrTissueDonated, generatedAlias0.followUpStatus, generatedAlias0.followUpUntil, generatedAlias0.nosocomialOutbreak, generatedAlias0.infectionSetting, generatedAlias0.prohibitionToWork, generatedAlias0.prohibitionToWorkFrom, generatedAlias0.prohibitionToWorkUntil, generatedAlias0.reInfection, generatedAlias0.previousInfectionDate, generatedAlias0.reinfectionStatus, generatedAlias0.reinfectionDetails, generatedAlias0.quarantine, generatedAlias0.quarantineTypeDetails, generatedAlias0.quarantineFrom, generatedAlias0.quarantineTo, generatedAlias0.quarantineHelpNeeded, generatedAlias0.quarantineOrderedVerbally, generatedAlias0.quarantineOrderedOfficialDocument, generatedAlias0.quarantineOrderedVerballyDate, generatedAlias0.quarantineOrderedOfficialDocumentDate, generatedAlias0.quarantineExtended, generatedAlias0.quarantineReduced, generatedAlias0.quarantineOfficialOrderSent, generatedAlias0.quarantineOfficialOrderSentDate, generatedAlias5.admittedToHealthFacility, generatedAlias5.admissionDate, generatedAlias5.dischargeDate, generatedAlias5.leftAgainstAdvice, generatedAlias1.presentCondition, generatedAlias1.deathDate, generatedAlias1.burialDate, generatedAlias1.burialConductor, generatedAlias1.burialPlaceDescription, generatedAlias12.name, generatedAlias13.name, generatedAlias14.name, generatedAlias2.city, generatedAlias2.street, generatedAlias2.houseNumber, generatedAlias2.additionalInformation, generatedAlias2.postalCode, generatedAlias15.name, generatedAlias15.uuid, generatedAlias2.facilityDetails, (select generatedAlias16.contactInformation from PersonContactDetail as generatedAlias16 where ( generatedAlias16.person=generatedAlias1 ) and ( generatedAlias16.primaryContact = true ) and ( generatedAlias16.personContactDetailType=:param0 )), (select case when generatedAlias17.thirdParty = true then generatedAlias17.thirdPartyName else 'This person' end from PersonContactDetail as generatedAlias17 where ( generatedAlias17.person=generatedAlias1 ) and ( generatedAlias17.primaryContact = true ) and ( generatedAlias17.personContactDetailType=:param1 )), (select generatedAlias18.contactInformation from PersonContactDetail as generatedAlias18 where ( generatedAlias18.person=generatedAlias1 ) and ( generatedAlias18.primaryContact = true ) and ( generatedAlias18.personContactDetailType=:param2 )), (select function('array_to_string', function('array_agg', case when generatedAlias19.personContactDetailType=:param3 then ((generatedAlias19.contactInformation || ' (') || (generatedAlias19.details || ')')) else ((generatedAlias19.contactInformation || ' (') || (generatedAlias19.personContactDetailType || ')')) end), ', ') from PersonContactDetail as generatedAlias19 where ( generatedAlias19.person=generatedAlias1 ) and ( ( generatedAlias19.primaryContact = false ) or ( generatedAlias19.personContactDetailType=:param4 ) )), generatedAlias1.educationType, generatedAlias1.educationDetails, generatedAlias1.occupationType, generatedAlias1.occupationDetails, generatedAlias1.armedForcesRelationType, generatedAlias3.contactWithSourceCaseKnown, generatedAlias0.vaccinationStatus, generatedAlias0.postpartum, generatedAlias0.trimester, (select count(distinct generatedAlias20.id) from EventParticipant as generatedAlias21 inner join generatedAlias21.event as generatedAlias20 inner join generatedAlias21.resultingCase as generatedAlias22 where ( generatedAlias22.id=generatedAlias0.id ) and ( generatedAlias20.deleted = false ) and ( generatedAlias20.archived = false ) and ( generatedAlias21.deleted = false )), generatedAlias0.externalID, generatedAlias0.externalToken, generatedAlias0.internalToken, generatedAlias1.birthName, generatedAlias23.isoCode, generatedAlias23.defaultName, generatedAlias24.isoCode, generatedAlias24.defaultName, generatedAlias0.caseIdentificationSource, generatedAlias0.screeningType, generatedAlias25.name, generatedAlias26.name, generatedAlias27.name, generatedAlias0.clinicianName, generatedAlias0.clinicianPhone, generatedAlias0.clinicianEmail, generatedAlias28.id, generatedAlias29.id, generatedAlias0.previousQuarantineTo, generatedAlias0.quarantineChangeComment, case when ( ( generatedAlias0.reportingUser is not null ) and ( generatedAlias0.reportingUser.id=15L ) ) or ( ( generatedAlias0.responsibleDistrict.id=11L ) or ( generatedAlias0.district.id=11L ) ) then true else false end) +from cases as generatedAlias0 + left join generatedAlias0.person as generatedAlias1 + left join generatedAlias1.address as generatedAlias2 + left join generatedAlias2.region as generatedAlias12 + left join generatedAlias2.district as generatedAlias13 + left join generatedAlias2.community as generatedAlias14 + left join generatedAlias1.address as generatedAlias30 + left join generatedAlias30.facility as generatedAlias15 + left join generatedAlias1.birthCountry as generatedAlias23 + left join generatedAlias1.citizenship as generatedAlias24 + left join generatedAlias1.address as generatedAlias31 + left join generatedAlias0.epiData as generatedAlias3 + left join generatedAlias0.symptoms as generatedAlias4 + left join generatedAlias0.hospitalization as generatedAlias5 + left join generatedAlias0.healthConditions as generatedAlias6 + left join generatedAlias0.region as generatedAlias7 + left join generatedAlias0.district as generatedAlias8 + left join generatedAlias0.community as generatedAlias9 + left join generatedAlias0.healthFacility as generatedAlias10 + left join generatedAlias0.pointOfEntry as generatedAlias11 + left join generatedAlias0.responsibleRegion as generatedAlias25 + left join generatedAlias0.responsibleDistrict as generatedAlias26 + left join generatedAlias0.responsibleCommunity as generatedAlias27 + left join generatedAlias0.reportingUser as generatedAlias28 + left join generatedAlias0.followUpStatusChangeUser as generatedAlias29 + left join generatedAlias0.contacts as generatedAlias32 +where (((((generatedAlias0.district.id = 11 L) or (generatedAlias0.responsibleDistrict.id = 11 L)) or + (((generatedAlias32.reportingUser = :param5) or (generatedAlias32.contactOfficer = :param6)) or + (generatedAlias32.district.id = 11 L))) or (generatedAlias0.sharedToCountry = true)) or + (((generatedAlias0.reportingUser.id = 15 L) or (generatedAlias0.surveillanceOfficer.id = 15 L)) or + (generatedAlias0.caseOfficer.id = 15 L))) + and (generatedAlias0.deleted = :param7) +order by generatedAlias0.reportDate desc, generatedAlias0.id desc \ No newline at end of file diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/vaccination/VaccinationFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/vaccination/VaccinationFacadeEjb.java index 902bbca3f21..c99ba093302 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/vaccination/VaccinationFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/vaccination/VaccinationFacadeEjb.java @@ -56,6 +56,7 @@ import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.caze.CaseService; import de.symeda.sormas.backend.clinicalcourse.ClinicalCourseFacadeEjb; +import de.symeda.sormas.backend.clinicalcourse.HealthConditionsMapper; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.contact.ContactService; import de.symeda.sormas.backend.event.Event; @@ -91,6 +92,8 @@ public class VaccinationFacadeEjb implements VaccinationFacade { private ContactService contactService; @EJB private EventParticipantService eventParticipantService; + @EJB + private HealthConditionsMapper healthConditionsMapper; public VaccinationDto save(@Valid VaccinationDto dto) { @@ -226,7 +229,7 @@ private boolean addImmunizationToVaccination(Vaccination vaccination, String per public List getAllVaccinations(String personUuid, Disease disease) { List immunizations = immunizationService.getByPersonAndDisease(personUuid, disease, false); - return immunizations.stream().flatMap(i -> i.getVaccinations().stream()).map(VaccinationFacadeEjb::toDto).collect(Collectors.toList()); + return immunizations.stream().flatMap(i -> i.getVaccinations().stream()).map(v -> toDto(v)).collect(Collectors.toList()); } @Override @@ -449,7 +452,7 @@ private Vaccination fillOrBuildEntity(@NotNull VaccinationDto source, Vaccinatio target = DtoHelper.fillOrBuildEntity(source, target, Vaccination::new, checkChangeDate); target.setImmunization(immunizationService.getByReferenceDto(source.getImmunization())); - target.setHealthConditions(clinicalCourseFacade.fromHealthConditionsDto(source.getHealthConditions(), checkChangeDate)); + target.setHealthConditions(healthConditionsMapper.fromDto(source.getHealthConditions(), checkChangeDate)); target.setReportDate(source.getReportDate()); target.setReportingUser(userService.getByReferenceDto(source.getReportingUser())); target.setVaccinationDate(source.getVaccinationDate()); @@ -470,7 +473,7 @@ private Vaccination fillOrBuildEntity(@NotNull VaccinationDto source, Vaccinatio return target; } - public static VaccinationDto toDto(Vaccination entity) { + public VaccinationDto toDto(Vaccination entity) { if (entity == null) { return null; } @@ -478,7 +481,7 @@ public static VaccinationDto toDto(Vaccination entity) { DtoHelper.fillDto(dto, entity); dto.setImmunization(ImmunizationFacadeEjb.toReferenceDto(entity.getImmunization())); - dto.setHealthConditions(ClinicalCourseFacadeEjb.toHealthConditionsDto(entity.getHealthConditions())); + dto.setHealthConditions(healthConditionsMapper.toDto(entity.getHealthConditions())); dto.setReportDate(entity.getReportDate()); dto.setReportingUser(UserFacadeEjb.toReferenceDto(entity.getReportingUser())); dto.setVaccinationDate(entity.getVaccinationDate()); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/utils/CaseJoins.java b/sormas-backend/src/main/java/de/symeda/sormas/utils/CaseJoins.java index fd4cb10e6a1..8957e7615a6 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/utils/CaseJoins.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/utils/CaseJoins.java @@ -65,7 +65,7 @@ public class CaseJoins extends AbstractDomainObjectJoins { private Join epiData; private Join symptoms; private Join clinicalCourse; - private Join healthConditions; + private Join healthConditions; private Join eventParticipants; private Join> personAddresses; private Join samples; @@ -248,11 +248,11 @@ private void setClinicalCourse(Join clinicalCourse) { this.clinicalCourse = clinicalCourse; } - public Join getHealthConditions() { - return getOrCreate(healthConditions, ClinicalCourse.HEALTH_CONDITIONS, JoinType.LEFT, getClinicalCourse(), this::setHealthConditions); + public Join getHealthConditions() { + return getOrCreate(healthConditions, Case.HEALTH_CONDITIONS, JoinType.LEFT, this::setHealthConditions); } - private void setHealthConditions(Join healthConditions) { + private void setHealthConditions(Join healthConditions) { this.healthConditions = healthConditions; } diff --git a/sormas-backend/src/main/resources/sql/sormas_schema.sql b/sormas-backend/src/main/resources/sql/sormas_schema.sql index 4658f5172b0..246a0fae7bf 100644 --- a/sormas-backend/src/main/resources/sql/sormas_schema.sql +++ b/sormas-backend/src/main/resources/sql/sormas_schema.sql @@ -9991,4 +9991,17 @@ ALTER TABLE testreport_history ADD COLUMN testpcrtestspecification varchar(255); INSERT INTO schema_version (version_number, comment) VALUES (443, 'Map variant specific Nucleic acid detection methods #5285'); +-- 2022-02-02 Move health conditions from clinical course to the case #6879 + +ALTER TABLE cases ADD COLUMN healthconditions_id bigint; +ALTER TABLE cases_history ADD COLUMN healthconditions_id bigint; +ALTER TABLE cases ADD CONSTRAINT fk_cases_healthconditions_id FOREIGN KEY (healthconditions_id) REFERENCES healthconditions (id); + +UPDATE cases c SET healthconditions_id = (SELECT cc.healthconditions_id from clinicalcourse cc where cc.id = c.clinicalcourse_id); + +ALTER TABLE clinicalcourse DROP CONSTRAINT fk_clinicalcourse_healthconditions_id; +ALTER TABLE clinicalcourse DROP COLUMN healthconditions_id; + +INSERT INTO schema_version (version_number, comment) VALUES (443, 'Move health conditions from clinical course to the case #6879'); + -- *** Insert new sql commands BEFORE this line. Remember to always consider _history tables. *** diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/sormastosormas/entities/SormasToSormasCaseFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/sormastosormas/entities/SormasToSormasCaseFacadeEjbTest.java index 4597f94a7aa..3ebb34575f2 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/sormastosormas/entities/SormasToSormasCaseFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/sormastosormas/entities/SormasToSormasCaseFacadeEjbTest.java @@ -283,7 +283,7 @@ public void testSaveSharedCaseWithInfrastructureName() throws SormasToSormasExce ExposureDto exposure = ExposureDto.build(ExposureType.ANIMAL_CONTACT); exposure.setAnimalContactType(AnimalContactType.TOUCH); caze.getEpiData().getExposures().add(exposure); - caze.getClinicalCourse().getHealthConditions().setAsplenia(YesNoUnknown.YES); + caze.getHealthConditions().setAsplenia(YesNoUnknown.YES); caze.getMaternalHistory().setChildrenNumber(2); SormasToSormasDto shareData = new SormasToSormasDto(); @@ -303,7 +303,7 @@ public void testSaveSharedCaseWithInfrastructureName() throws SormasToSormasExce assertThat(savedCase.getHospitalization().getAdmittedToHealthFacility(), is(YesNoUnknown.YES)); assertThat(savedCase.getSymptoms().getAgitation(), is(SymptomState.YES)); assertThat(savedCase.getEpiData().getExposures().get(0).getAnimalContactType(), is(AnimalContactType.TOUCH)); - assertThat(savedCase.getClinicalCourse().getHealthConditions().getAsplenia(), is(YesNoUnknown.YES)); + assertThat(savedCase.getHealthConditions().getAsplenia(), is(YesNoUnknown.YES)); assertThat(savedCase.getMaternalHistory().getChildrenNumber(), is(2)); assertThat(savedCase.getSormasToSormasOriginInfo().getOrganizationId(), is(DEFAULT_SERVER_ID)); @@ -330,7 +330,7 @@ public void testSaveSharedCaseWithInfrastructureExternalId() throws SormasToSorm ExposureDto exposure = ExposureDto.build(ExposureType.ANIMAL_CONTACT); exposure.setAnimalContactType(AnimalContactType.TOUCH); caze.getEpiData().getExposures().add(exposure); - caze.getClinicalCourse().getHealthConditions().setAsplenia(YesNoUnknown.YES); + caze.getHealthConditions().setAsplenia(YesNoUnknown.YES); caze.getMaternalHistory().setChildrenNumber(2); SormasToSormasDto shareData = new SormasToSormasDto(); @@ -350,7 +350,7 @@ public void testSaveSharedCaseWithInfrastructureExternalId() throws SormasToSorm assertThat(savedCase.getHospitalization().getAdmittedToHealthFacility(), is(YesNoUnknown.YES)); assertThat(savedCase.getSymptoms().getAgitation(), is(SymptomState.YES)); assertThat(savedCase.getEpiData().getExposures().get(0).getAnimalContactType(), is(AnimalContactType.TOUCH)); - assertThat(savedCase.getClinicalCourse().getHealthConditions().getAsplenia(), is(YesNoUnknown.YES)); + assertThat(savedCase.getHealthConditions().getAsplenia(), is(YesNoUnknown.YES)); assertThat(savedCase.getMaternalHistory().getChildrenNumber(), is(2)); assertThat(savedCase.getSormasToSormasOriginInfo().getOrganizationId(), is(DEFAULT_SERVER_ID)); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java index 240ad1a0981..1fdcef532f7 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java @@ -657,7 +657,7 @@ public CommitDiscardWrapperComponent getCaseCreateComponent( dto.getSymptoms().setOnsetDate(createForm.getOnsetDate()); dto.getSymptoms().setUuid(DataHelper.createUuid()); - dto.getClinicalCourse().getHealthConditions().setUuid(DataHelper.createUuid()); + dto.getHealthConditions().setUuid(DataHelper.createUuid()); dto.getEpiData().setUuid(DataHelper.createUuid()); dto.getEpiData().getExposures().forEach(exposure -> { exposure.setUuid(DataHelper.createUuid()); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java index d5247b8ef18..4bcdb97d188 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java @@ -131,6 +131,7 @@ import de.symeda.sormas.ui.ControllerProvider; import de.symeda.sormas.ui.UserProvider; import de.symeda.sormas.ui.caze.surveillancereport.CaseReinfectionCheckBoxTree; +import de.symeda.sormas.ui.clinicalcourse.HealthConditionsForm; import de.symeda.sormas.ui.location.AccessibleTextField; import de.symeda.sormas.ui.utils.AbstractEditForm; import de.symeda.sormas.ui.utils.ButtonHelper; @@ -269,7 +270,7 @@ public class CaseDataForm extends AbstractEditForm { fluidRowLocs(CaseDataDto.FOLLOW_UP_STATUS_CHANGE_DATE, CaseDataDto.FOLLOW_UP_STATUS_CHANGE_USER) + fluidRowLocs(CaseDataDto.FOLLOW_UP_UNTIL, EXPECTED_FOLLOW_UP_UNTIL_DATE_LOC, CaseDataDto.OVERWRITE_FOLLOW_UP_UNTIL) + fluidRowLocs(CaseDataDto.FOLLOW_UP_COMMENT); - + private static final String PAPER_FORM_DATES_AND_COMMENTS_HTML_LAYOUT = fluidRowLocs(6, CaseDataDto.SURVEILLANCE_OFFICER) + loc(PAPER_FORM_DATES_LOC) + @@ -1234,6 +1235,8 @@ protected void addFields() { List medicalInformationFields = Arrays.asList(CaseDataDto.PREGNANT, CaseDataDto.VACCINATION_STATUS, CaseDataDto.SMALLPOX_VACCINATION_RECEIVED); + addField(CaseDataDto.HEALTH_CONDITIONS, HealthConditionsForm.class).setCaption(null); + for (String medicalInformationField : medicalInformationFields) { if (getFieldGroup().getField(medicalInformationField).isVisible()) { Label medicalInformationCaptionLabel = new Label(I18nProperties.getString(Strings.headingMedicalInformation)); @@ -1732,7 +1735,10 @@ private void updateFacility() { @Override protected String createHtmlLayout() { - return MAIN_HTML_LAYOUT + (caseFollowUpEnabled ? FOLLOWUP_LAYOUT : "") + PAPER_FORM_DATES_AND_COMMENTS_HTML_LAYOUT; + return MAIN_HTML_LAYOUT + + (caseFollowUpEnabled ? FOLLOWUP_LAYOUT : "") + + fluidRowLocs(CaseDataDto.HEALTH_CONDITIONS) + + PAPER_FORM_DATES_AND_COMMENTS_HTML_LAYOUT; } private void setEpidNumberError(TextField epidField, Button assignNewEpidNumberButton, Label epidNumberWarningLabel, String fieldValue) { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/ClinicalCourseForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/ClinicalCourseForm.java index 361924b7962..2ea5a563bfe 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/ClinicalCourseForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/clinicalcourse/ClinicalCourseForm.java @@ -12,7 +12,7 @@ public class ClinicalCourseForm extends AbstractEditForm { private static final long serialVersionUID = 1L; - private static final String HTML_LAYOUT = fluidRowLocs(ClinicalCourseDto.HEALTH_CONDITIONS); + private static final String HTML_LAYOUT = ""; public ClinicalCourseForm(boolean isPseudonymized) { super( @@ -25,8 +25,6 @@ public ClinicalCourseForm(boolean isPseudonymized) { @Override protected void addFields() { - addField(ClinicalCourseDto.HEALTH_CONDITIONS, HealthConditionsForm.class).setCaption(null); - initializeVisibilitiesAndAllowedVisibilities(); initializeAccessAndAllowedAccesses(); } From d5888828e395897a79ef92be8d44d82d4f141e27 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Mon, 14 Feb 2022 09:44:16 +0200 Subject: [PATCH 074/253] #6879 - fix merge issue - move health conditions to the correct place in case data form - hide save & discard buttons on clinical course form --- sormas-backend/src/main/resources/sql/sormas_schema.sql | 2 +- .../main/java/de/symeda/sormas/ui/caze/CaseController.java | 3 +++ .../main/java/de/symeda/sormas/ui/caze/CaseDataForm.java | 6 +++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/sormas-backend/src/main/resources/sql/sormas_schema.sql b/sormas-backend/src/main/resources/sql/sormas_schema.sql index 246a0fae7bf..b582be42223 100644 --- a/sormas-backend/src/main/resources/sql/sormas_schema.sql +++ b/sormas-backend/src/main/resources/sql/sormas_schema.sql @@ -10002,6 +10002,6 @@ UPDATE cases c SET healthconditions_id = (SELECT cc.healthconditions_id from cli ALTER TABLE clinicalcourse DROP CONSTRAINT fk_clinicalcourse_healthconditions_id; ALTER TABLE clinicalcourse DROP COLUMN healthconditions_id; -INSERT INTO schema_version (version_number, comment) VALUES (443, 'Move health conditions from clinical course to the case #6879'); +INSERT INTO schema_version (version_number, comment) VALUES (444, 'Move health conditions from clinical course to the case #6879'); -- *** Insert new sql commands BEFORE this line. Remember to always consider _history tables. *** diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java index 1fdcef532f7..44758ccb9ea 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java @@ -1294,6 +1294,9 @@ public CommitDiscardWrapperComponent getClinicalCourseCompon } }); + view.getCommitButton().setVisible(false); + view.getDiscardButton().setVisible(false); + return view; } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java index 4bcdb97d188..76774c11f66 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java @@ -271,8 +271,9 @@ public class CaseDataForm extends AbstractEditForm { fluidRowLocs(CaseDataDto.FOLLOW_UP_UNTIL, EXPECTED_FOLLOW_UP_UNTIL_DATE_LOC, CaseDataDto.OVERWRITE_FOLLOW_UP_UNTIL) + fluidRowLocs(CaseDataDto.FOLLOW_UP_COMMENT); - private static final String PAPER_FORM_DATES_AND_COMMENTS_HTML_LAYOUT = + private static final String PAPER_FORM_DATES_AND_HEALTH_CONDITIONS_HTML_LAYOUT = fluidRowLocs(6, CaseDataDto.SURVEILLANCE_OFFICER) + + fluidRowLocs(CaseDataDto.HEALTH_CONDITIONS) + loc(PAPER_FORM_DATES_LOC) + fluidRowLocs(CaseDataDto.DISTRICT_LEVEL_DATE, CaseDataDto.REGION_LEVEL_DATE, CaseDataDto.NATIONAL_LEVEL_DATE) + loc(GENERAL_COMMENT_LOC) + fluidRowLocs(CaseDataDto.ADDITIONAL_DETAILS); @@ -1737,8 +1738,7 @@ private void updateFacility() { protected String createHtmlLayout() { return MAIN_HTML_LAYOUT + (caseFollowUpEnabled ? FOLLOWUP_LAYOUT : "") - + fluidRowLocs(CaseDataDto.HEALTH_CONDITIONS) - + PAPER_FORM_DATES_AND_COMMENTS_HTML_LAYOUT; + + PAPER_FORM_DATES_AND_HEALTH_CONDITIONS_HTML_LAYOUT; } private void setEpidNumberError(TextField epidField, Button assignNewEpidNumberButton, Label epidNumberWarningLabel, String fieldValue) { From 326c5068f895652b4810c5f3c70c30c53732a052 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Mon, 14 Feb 2022 09:43:03 +0100 Subject: [PATCH 075/253] Test scenario for event group --- .../events/EventDirectoryPage.java | 17 +++- .../events/EventDirectorySteps.java | 78 ++++++++++++++++++- .../features/sanity/web/Event.feature | 48 ++++++++++++ 3 files changed, 139 insertions(+), 4 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java index 5b4c5530647..45e6393b3ef 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java @@ -53,7 +53,22 @@ public class EventDirectoryPage { public static final By EVENT_CLUSTER = By.id("status-Cluster"); public static final By EVENT_DROPPED = By.id("status-Dropped"); public static final By CREATED_PARTICIPANT = By.cssSelector("[role='gridcell'] a"); - + public static final By EVENTS_RADIO_BUTTON = By.cssSelector(".v-radiobutton"); + public static final By LINK_EVENT_BUTTON = By.id("Link event"); + public static final By LINK_EVENT_BUTTON_EDIT_PAGE = By.id("Link event group"); + public static final By UNLINK_EVENT_BUTTON = By.id("unlink-event-0"); + public static final By ID_FIELD_FILTER = By.id("search"); + public static final By LINKED_EVENT_GROUP_ID = + By.xpath( + "/html/body/div[1]/div/div[2]/div/div[2]/div/div/div[3]/div/div/div/div/div[8]/div/div[2]/div/div/div/div/div/div/div[1]/div/div/div/div/div/div/div[2]/div/div[2]/div/div/div"); + public static final By SAVE_BUTTON_IN_LINK_FORM = + By.xpath("/html/body/div[2]/div[3]/div/div/div[3]/div/div/div[2]/div/div/div[3]/div"); + public static final By FILTERED_EVENT_LINK_EVENT_FORM = + By.xpath( + "//*[@id=\"sormasui-1655777373-overlays\"]/div[3]/div/div/div[3]/div/div/div[1]/div/div[2]/div/div/div[5]/div/div[3]/table/tbody/tr[1]/td[1]"); + public static final By FIRST_EVENT_GROUP = + By.xpath( + "/html/body/div[2]/div[3]/div/div/div[3]/div/div/div[1]/div/div[2]/div/div/div[7]/div/div[3]/table/tbody/tr[1]/td[1]"); /*public static By getByEventUuid(String eventUuid) { return By.cssSelector("a[title=" + eventUuid + "]"); }*/ diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index 5f67d338414..c350a5c2416 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -19,8 +19,33 @@ package org.sormas.e2etests.steps.web.application.events; import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_GRID_RESULTS_ROWS; -import static org.sormas.e2etests.pages.application.events.EditEventPage.*; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.*; +import static org.sormas.e2etests.pages.application.events.EditEventPage.EVENT_PARTICIPANTS_TAB; +import static org.sormas.e2etests.pages.application.events.EditEventPage.NEW_TASK_BUTTON; +import static org.sormas.e2etests.pages.application.events.EditEventPage.TITLE_INPUT; +import static org.sormas.e2etests.pages.application.events.EditEventPage.UUID_INPUT; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.APPLY_FILTER; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.CREATED_PARTICIPANT; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.CREATE_CASE_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENTS_RADIO_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_STATUS_FILTER_BUTTONS; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTERED_EVENT_LINK_EVENT_FORM; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_DISEASE; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_RISK_LEVEL; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_SOURCE_TYPE; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_TYPE_OF_PLACE; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FIRST_EVENT_GROUP; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FIRST_EVENT_ID_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.ID_FIELD_FILTER; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.LINKED_EVENT_GROUP_ID; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.LINK_EVENT_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.LINK_EVENT_BUTTON_EDIT_PAGE; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.RESET_FILTER; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.SAVE_BUTTON_IN_LINK_FORM; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.SEARCH_EVENT_BY_FREE_TEXT; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.SEARCH_EVENT_BY_FREE_TEXT_INPUT; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.TOTAL_EVENTS_COUNTER; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.UNLINK_EVENT_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.getByEventUuid; import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.APPLY_FILTERS_BUTTON; import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.RESET_FILTERS_BUTTON; @@ -28,8 +53,11 @@ import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.inject.Named; +import org.openqa.selenium.By; import org.sormas.e2etests.common.DataOperations; -import org.sormas.e2etests.enums.*; +import org.sormas.e2etests.enums.DiseasesValues; +import org.sormas.e2etests.enums.RiskLevelValues; +import org.sormas.e2etests.enums.SourceTypeValues; import org.sormas.e2etests.enums.cases.epidemiologicalData.TypeOfPlace; import org.sormas.e2etests.helpers.AssertHelpers; import org.sormas.e2etests.helpers.WebDriverHelpers; @@ -57,6 +85,50 @@ public EventDirectorySteps( dataOperations.getPartialUuidFromAssociatedLink(eventUuid)); }); + When( + "^I click on ([^\"]*) Radiobutton on Event Directory Page$", + (String buttonName) -> { + webDriverHelpers.clickWebElementByText(EVENTS_RADIO_BUTTON, buttonName); + webDriverHelpers.waitForPageLoaded(); + }); + + When( + "^I click on Link Event button on Event Directory Page$", + () -> webDriverHelpers.clickOnWebElementBySelector(LINK_EVENT_BUTTON)); + When( + "^I click on Link Event button on Edit Event Page$", + () -> webDriverHelpers.clickOnWebElementBySelector(LINK_EVENT_BUTTON_EDIT_PAGE)); + + When( + "^I click on Unlink Event button on Event Directory Page$", + () -> webDriverHelpers.clickOnWebElementBySelector(UNLINK_EVENT_BUTTON)); + + When( + "^I fill Id filter with Id of last created event in Link Event to group form$", + () -> + webDriverHelpers.fillInWebElement( + ID_FIELD_FILTER, apiState.getCreatedEvent().getUuid())); + When( + "^I click on filtered Event in Link Event to group form$", + () -> webDriverHelpers.clickOnWebElementBySelector(FILTERED_EVENT_LINK_EVENT_FORM)); + When( + "^I click on first Event Group on the list in Link Event form$", + () -> webDriverHelpers.clickOnWebElementBySelector(FIRST_EVENT_GROUP)); + + When( + "^I click on SAVE button in Link Event to group form$", + () -> webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON_IN_LINK_FORM)); + + When( + "^I click on Linked Group Id on Edit Event Page$", + () -> webDriverHelpers.clickOnWebElementBySelector(LINKED_EVENT_GROUP_ID)); + When( + "^I click on Group Id in Events result on Event Directory Page$", + () -> + webDriverHelpers.clickOnWebElementBySelector( + By.xpath( + "/html/body/div[1]/div/div[2]/div/div[2]/div/div/div/div[2]/div/div/div[3]/div/div[3]/table/tbody/tr/td[15]"))); + When( "I click on the NEW EVENT button", () -> diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature index c413a304440..317e91f9895 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature @@ -235,6 +235,54 @@ Feature: Create events And I select Dropped filter from quick filter And I click on the RESET FILTERS button + @issue=SORDEV-5571 + Scenario: Event group screen + Given API: I create a new event + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in with National User + And I click on the Events button from navbar + And I click on GROUPS Radiobutton on Event Directory Page + And I open the first event from events list + And I click on Link Event button on Event Directory Page + And I fill Id filter with Id of last created event in Link Event to group form + And I click on filtered Event in Link Event to group form + And I click on SAVE button in Link Event to group form + And I click on Unlink Event button on Event Directory Page + + @issue=SORDEV-5571 + Scenario: Event group screens + Given API: I create a new event + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in with National User + And I click on the Events button from navbar + And I fill EVENT ID filter by API + And I apply on the APPLY FILTERS button from Event + And I open the first event from events list + And I click on Link Event button on Edit Event Page + And I click on first Event Group on the list in Link Event form + And I click on SAVE button in Link Event to group form + And I click on Linked Group Id on Edit Event Page + And I click on Unlink Event button on Event Directory Page + + @issue=SORDEV-5571 + Scenario: Event group screenss + Given API: I create a new event + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in with National User + And I click on the Events button from navbar + And I fill EVENT ID filter by API + And I apply on the APPLY FILTERS button from Event + And I open the first event from events list + And I click on Link Event button on Edit Event Page + And I click on first Event Group on the list in Link Event form + And I click on SAVE button in Link Event to group form + And I click on the Events button from navbar + And I click on Group Id in Events result on Event Directory Page + And I click on Unlink Event button on Event Directory Page + @issue=SORDEV-5570 Scenario: Testing Event screen Impact Given API: I create a new event From 1815e6af582849fdfceec3c20891873f96243af3 Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Mon, 14 Feb 2022 12:17:42 +0200 Subject: [PATCH 076/253] #7747-Fix-Allure-Report :implemented main changes --- sormas-e2e-tests/scripts/runTests.sh | 2 +- .../sormas/e2etests/common/CommonModule.java | 8 ++ .../configprovider/ConfigFileReader.java | 36 ++++---- .../e2etests/envconfig/dto/EnvUser.java | 8 +- .../e2etests/envconfig/dto/Environment.java | 8 +- .../e2etests/envconfig/dto/Environments.java | 4 +- .../envconfig/manager/EnvironmentManager.java | 86 +++++++++---------- .../org/sormas/e2etests/steps/BaseSteps.java | 16 ++++ .../steps/web/application/LoginSteps.java | 31 ++++--- .../events/EventDirectorySteps.java | 18 ++-- .../features/sanity/web/Login.feature | 2 +- 11 files changed, 120 insertions(+), 99 deletions(-) diff --git a/sormas-e2e-tests/scripts/runTests.sh b/sormas-e2e-tests/scripts/runTests.sh index 856c7d031b6..6963aefed88 100644 --- a/sormas-e2e-tests/scripts/runTests.sh +++ b/sormas-e2e-tests/scripts/runTests.sh @@ -25,7 +25,7 @@ rm -rf ./allureReports echo "Executing gradle clean..." ./gradlew clean goJF echo "Starting all BDD tests under @$1 tag..." -./gradlew startTests -Dcucumber.tags=\"@$1\" -Dheadless=true -Dcourgette.threads=9 +./gradlew startTests -Dcucumber.tags=\"@$1\" -Dheadless=true -Dcourgette.threads=9 -DenvConfig=C:/Users/Zack/Desktop/data.json echo "Deleting test downloads folder..." rm -rf ./downloads diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/CommonModule.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/CommonModule.java index 310996ebf45..5cd45bafab6 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/CommonModule.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/CommonModule.java @@ -34,6 +34,7 @@ import javax.inject.Singleton; import lombok.SneakyThrows; import org.sormas.e2etests.enums.TestDataUser; +import org.sormas.e2etests.envconfig.manager.EnvironmentManager; import org.sormas.e2etests.webdriver.DriverManager; import org.testng.asserts.SoftAssert; @@ -52,6 +53,13 @@ Faker provideFaker() { return new Faker(Locale.GERMANY); } + @Provides + @Singleton + @Exposed + EnvironmentManager provideEnvManager() { + return new EnvironmentManager(); + } + @Provides @Singleton @Exposed diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/configprovider/ConfigFileReader.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/configprovider/ConfigFileReader.java index ed1dd099446..b270aacb8ba 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/configprovider/ConfigFileReader.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/configprovider/ConfigFileReader.java @@ -24,24 +24,24 @@ @Slf4j public abstract class ConfigFileReader { - private static final String systemVariableName = "envConfig"; + private static final String systemVariableName = "envConfig"; - @SneakyThrows - public static File getConfigurationFile() { - String jsonPath; - try { - log.info("Looking after environment environmentconfig file"); - jsonPath = System.getProperty(systemVariableName); - } catch (NullPointerException e) { - throw new Exception("Unable to find environment environmentconfig file: " + e.getMessage()); - } - try { - log.info("Returning environmentconfig file path"); - return new File(jsonPath); - } catch (Exception any) { - throw new Exception( - "Unable to convert provided environmentconfig file into File object: " - + any.getMessage()); - } + @SneakyThrows + public static File getConfigurationFile() { + String jsonPath; + try { + log.info("Looking after environment environmentconfig file"); + jsonPath = System.getProperty(systemVariableName); + } catch (NullPointerException e) { + throw new Exception("Unable to find environment environmentconfig file: " + e.getMessage()); } + try { + log.info("Returning environmentconfig file path"); + return new File(jsonPath); + } catch (Exception any) { + throw new Exception( + "Unable to convert provided environmentconfig file into File object: " + + any.getMessage()); + } + } } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/EnvUser.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/EnvUser.java index 9eb1721472a..e0a21a0571f 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/EnvUser.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/EnvUser.java @@ -30,8 +30,8 @@ @Builder(toBuilder = true, builderClassName = "builder") public class EnvUser { - String userRole; - String username; - String password; - String uuid; + String userRole; + String username; + String password; + String uuid; } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environment.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environment.java index 41a9109e3d5..07088ebf6d4 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environment.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environment.java @@ -30,8 +30,8 @@ @Builder(toBuilder = true, builderClassName = "builder") public class Environment { - String name; - String locale; - String url; - List users; + String name; + String locale; + String url; + List users; } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environments.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environments.java index 33f66b411f9..dcbd83847d9 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environments.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environments.java @@ -30,5 +30,5 @@ @Builder(toBuilder = true, builderClassName = "builder") public class Environments { - List environments; -} \ No newline at end of file + List environments; +} diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/manager/EnvironmentManager.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/manager/EnvironmentManager.java index 7ccae4048c1..79bf5d063ce 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/manager/EnvironmentManager.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/manager/EnvironmentManager.java @@ -18,6 +18,7 @@ package org.sormas.e2etests.envconfig.manager; import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.List; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.sormas.e2etests.envconfig.configprovider.ConfigFileReader; @@ -25,60 +26,51 @@ import org.sormas.e2etests.envconfig.dto.Environment; import org.sormas.e2etests.envconfig.dto.Environments; -import java.util.List; - @Slf4j public class EnvironmentManager { - private static EnvironmentManager environmentManager; - private ObjectMapper objectMapper; - private static Environments environments; - - @SneakyThrows - private EnvironmentManager() { - objectMapper = new ObjectMapper(); - environments = - objectMapper.readValue(ConfigFileReader.getConfigurationFile(), Environments.class); - } + private ObjectMapper objectMapper; + private static Environments environments; - public static EnvironmentManager getInstance() { - if (environmentManager == null) environmentManager = new EnvironmentManager(); - return environmentManager; - } + @SneakyThrows + public EnvironmentManager() { + objectMapper = new ObjectMapper(); + environments = + objectMapper.readValue(ConfigFileReader.getConfigurationFile(), Environments.class); + } - @SneakyThrows - public static String getEnvironmentUrlForMarket(String market) { - try { - return environments.getEnvironments().stream() - .filter(env -> env.getLocale().equalsIgnoreCase(market)) - .findFirst() - .get() - .getUrl(); - } catch (NullPointerException e) { - throw new Exception(String.format("Unable to get Environment for market: %s", market)); - } + @SneakyThrows + public String getEnvironmentUrlForMarket(String market) { + try { + return environments.getEnvironments().stream() + .filter(env -> env.getLocale().equalsIgnoreCase(market)) + .findFirst() + .get() + .getUrl(); + } catch (NullPointerException e) { + throw new Exception(String.format("Unable to get Environment for market: %s", market)); } + } - @SneakyThrows - public static EnvUser getUserByRole(String market, String role) { - try { - List users = getEnvironment(market).getUsers(); - return users.stream() - .filter(user -> user.getUserRole().equalsIgnoreCase(role)) - .findFirst() - .get(); - } catch (NullPointerException e) { - throw new Exception( - String.format( - "Unable to get Environment User for market: %s, and role: %s", market, role)); - } + @SneakyThrows + public EnvUser getUserByRole(String market, String role) { + try { + List users = getEnvironment(market).getUsers(); + return users.stream() + .filter(user -> user.getUserRole().equalsIgnoreCase(role)) + .findFirst() + .get(); + } catch (NullPointerException e) { + throw new Exception( + String.format( + "Unable to get Environment User for market: %s, and role: %s", market, role)); } + } - private static Environment getEnvironment(String market) { - return environments.getEnvironments().stream() - .filter(env -> env.getLocale().equalsIgnoreCase(market)) - .findFirst() - .get(); - } + private Environment getEnvironment(String market) { + return environments.getEnvironments().stream() + .filter(env -> env.getLocale().equalsIgnoreCase(market)) + .findFirst() + .get(); + } } - diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java index aed78cfaac3..774dd02d0ae 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java @@ -39,6 +39,7 @@ public class BaseSteps implements StepLifecycleListener { public static RemoteWebDriver driver; + public static String locale; private final DriverManager driverManager; @Inject @@ -50,6 +51,11 @@ public RemoteWebDriver getDriver() { return driver; } + @Before(order = 0) + public void setRunningLocale(Scenario scenario) { + setLocale(scenario); + } + @Before(value = "@UI") public void beforeScenario(Scenario scenario) { if (isNonApiScenario(scenario)) { @@ -90,4 +96,14 @@ public void generateMeasurementsReport() { private static boolean isNonApiScenario(Scenario scenario) { return !scenario.getSourceTagNames().contains("@API"); } + + private void setLocale(Scenario scenario) { + String localeTag = + scenario.getSourceTagNames().stream() + .filter(value -> value.contains("Locale")) + .findFirst() + .get(); + int indexOfSubstring = localeTag.indexOf("_"); + locale = localeTag.substring(indexOfSubstring + 1); + } } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/LoginSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/LoginSteps.java index bfd053a9708..fb752a6adc4 100755 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/LoginSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/LoginSteps.java @@ -20,11 +20,14 @@ import static org.sormas.e2etests.enums.TestDataUser.*; import static org.sormas.e2etests.pages.application.dashboard.Surveillance.SurveillanceDashboardPage.LOGOUT_BUTTON; +import static org.sormas.e2etests.steps.BaseSteps.locale; import com.google.inject.Inject; import cucumber.api.java8.En; import javax.inject.Named; import org.openqa.selenium.NoSuchElementException; +import org.sormas.e2etests.envconfig.dto.EnvUser; +import org.sormas.e2etests.envconfig.manager.EnvironmentManager; import org.sormas.e2etests.helpers.WebDriverHelpers; import org.sormas.e2etests.pages.application.LoginPage; import org.sormas.e2etests.pages.application.dashboard.Surveillance.SurveillanceDashboardPage; @@ -36,6 +39,7 @@ public class LoginSteps implements En { public LoginSteps( WebDriverHelpers webDriverHelpers, BaseSteps baseSteps, + EnvironmentManager environmentManager, @Named("ENVIRONMENT_URL") String environmentUrl) { Given( @@ -48,7 +52,10 @@ public LoginSteps( }); Given( - "^I navigate to SORMAS login page$", () -> webDriverHelpers.accessWebSite(environmentUrl)); + "^I navigate to SORMAS login page$", + () -> { + webDriverHelpers.accessWebSite(environmentManager.getEnvironmentUrlForMarket(locale)); + }); Given( "I click on the Log In button", @@ -57,16 +64,15 @@ public LoginSteps( And( "I log in with National User", () -> { - webDriverHelpers.accessWebSite(environmentUrl); + EnvUser user = environmentManager.getUserByRole(locale, "National User"); + webDriverHelpers.accessWebSite(environmentManager.getEnvironmentUrlForMarket(locale)); webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.waitUntilIdentifiedElementIsPresent(LoginPage.USER_NAME_INPUT); int attempts = 1; - LOOP: while (attempts <= 3) { - webDriverHelpers.fillInWebElement( - LoginPage.USER_NAME_INPUT, NATIONAL_USER.getUsername()); - webDriverHelpers.fillInWebElement( - LoginPage.USER_PASSWORD_INPUT, NATIONAL_USER.getPassword()); + webDriverHelpers.fillInWebElement(LoginPage.USER_NAME_INPUT, user.getUsername()); + webDriverHelpers.fillInWebElement(LoginPage.USER_PASSWORD_INPUT, user.getPassword()); webDriverHelpers.clickOnWebElementBySelector(LoginPage.LOGIN_BUTTON); webDriverHelpers.waitForPageLoaded(); boolean wasUserLoggedIn; @@ -88,15 +94,14 @@ public LoginSteps( Given( "^I log in as a ([^\"]*)$", (String userRole) -> { - webDriverHelpers.accessWebSite(environmentUrl); + webDriverHelpers.accessWebSite(environmentManager.getEnvironmentUrlForMarket(locale)); webDriverHelpers.waitUntilIdentifiedElementIsPresent(LoginPage.USER_NAME_INPUT); - webDriverHelpers.fillInWebElement( - LoginPage.USER_NAME_INPUT, gertUserByRole(userRole).getUsername()); - webDriverHelpers.fillInWebElement( - LoginPage.USER_PASSWORD_INPUT, gertUserByRole(userRole).getPassword()); + EnvUser user = environmentManager.getUserByRole(locale, userRole); + webDriverHelpers.fillInWebElement(LoginPage.USER_NAME_INPUT, user.getUsername()); + webDriverHelpers.fillInWebElement(LoginPage.USER_PASSWORD_INPUT, user.getPassword()); webDriverHelpers.clickOnWebElementBySelector(LoginPage.LOGIN_BUTTON); webDriverHelpers.waitForPageLoaded(); - webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(LOGOUT_BUTTON, 30); + webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(LOGOUT_BUTTON, 50); }); } } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index 5f67d338414..53e011921f9 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -266,15 +266,15 @@ public EventDirectorySteps( "I click Create Case for Event Participant", () -> webDriverHelpers.clickOnWebElementBySelector(CREATE_CASE_BUTTON)); - Then( - "I check that number of displayed Event results is {int}", - (Integer number) -> - assertHelpers.assertWithPoll20Second( - () -> - Assert.assertEquals( - webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), - number.intValue(), - "Number of displayed cases is not correct"))); + Then( + "I check that number of displayed Event results is {int}", + (Integer number) -> + assertHelpers.assertWithPoll20Second( + () -> + Assert.assertEquals( + webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), + number.intValue(), + "Number of displayed cases is not correct"))); Then( "I check the number of displayed Event results from All button is {int}", diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Login.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Login.feature index 5bd407dc1f1..886ad4f2a1a 100755 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Login.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Login.feature @@ -1,7 +1,7 @@ @UI @Sanity @Login Feature: Login with different type of users -# @issue=5402 + @Locale_DE Scenario Outline: Login with user Given I navigate to SORMAS login page Then I log in as a From 617c3fcf57fb3422561252a910008dc45c00dfa9 Mon Sep 17 00:00:00 2001 From: Pawel Kujawa Date: Mon, 14 Feb 2022 11:58:59 +0100 Subject: [PATCH 077/253] sorqa70 --- .../pages/application/NavBarPage.java | 1 + .../application/users/CreateNewUserPage.java | 3 + .../sormas/e2etests/services/UserService.java | 34 +++++ .../steps/web/application/NavBarSteps.java | 7 + .../application/users/CreateNewUserSteps.java | 135 +++++++++++++++++- .../features/sanity/web/User.feature | 12 ++ 6 files changed, 191 insertions(+), 1 deletion(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/NavBarPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/NavBarPage.java index 2acd2b01293..feba91400c7 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/NavBarPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/NavBarPage.java @@ -33,4 +33,5 @@ public class NavBarPage { public static final By CONFIRM_NAVIGATION = By.cssSelector(("[id=actionConfirm]")); public static final By REPORTS_BUTTON = By.cssSelector("div#reports"); public static final By CONFIGURATION_BUTTON = By.cssSelector("div#configuration"); + public static final By LOGOUT_BUTTON = By.cssSelector("[id='actionLogout-2']"); } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/users/CreateNewUserPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/users/CreateNewUserPage.java index 4688198f4ac..23bd715a10c 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/users/CreateNewUserPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/users/CreateNewUserPage.java @@ -50,5 +50,8 @@ public class CreateNewUserPage { public static final By LIMITED_DISEASE_COMBOBOX = By.cssSelector("#limitedDisease > div"); public static final By DISCARD_BUTTON = By.id("discard"); public static final By SAVE_BUTTON = By.id("commit"); + public static final By PASSWORD_FIELD = + By.xpath( + "//div[contains(@class, 'popupContent')]//div[@class='v-label v-widget h2 v-label-h2 v-label-undef-w']"); public static final By CLOSE_DIALOG_BUTTON = By.className("v-window-closebox"); } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/UserService.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/UserService.java index bbf04b311c2..56ea6e342a2 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/UserService.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/UserService.java @@ -74,6 +74,40 @@ public User buildGeneratedUserWithRole(String role) { .build(); } + public User buildGeneratedUserWithRoleAndDisease(String role, String disease) { + firstName = faker.name().firstName(); + lastName = faker.name().lastName(); + return User.builder() + .firstName(firstName) + .lastName(lastName) + .emailAddress(ASCIIHelper.convertASCIIToLatin(firstName + "." + lastName + emailDomain)) + .phoneNumber(generatePhoneNumber()) + .language("English") + .country("Germany") + .region(RegionsValues.VoreingestellteBundeslander.getName()) + .district(DistrictsValues.VoreingestellterLandkreis.getName()) + .community(CommunityValues.VoreingestellteGemeinde.getName()) + .facilityCategory("Accommodation") + .facilityType("Campsite") + .facility("Other facility") + .facilityNameAndDescription("qa-automation run") + .street(faker.address().streetAddress()) + .houseNumber(faker.address().buildingNumber()) + .additionalInformation( + "Additional Information ".concat(String.valueOf(System.currentTimeMillis()))) + .postalCode(faker.address().zipCode()) + .city(faker.address().city()) + .areaType("Urban") + .gpsLatitude(faker.random().nextInt(10, 20).toString()) + .gpsLongitude(faker.random().nextInt(20, 40).toString()) + .gpsAccuracy("1") + .active(true) + .userName("AutomationUser-".concat(LocalTime.now().toString())) + .userRole(role) + .limitedDisease(disease) + .build(); + } + public User buildEditUser() { long currentTimeMillis = System.currentTimeMillis(); firstName = faker.name().firstName(); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/NavBarSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/NavBarSteps.java index fd9a703b807..11593c96d25 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/NavBarSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/NavBarSteps.java @@ -164,6 +164,13 @@ public NavBarSteps(WebDriverHelpers webDriverHelpers) { startTime = ZonedDateTime.now().toInstant().toEpochMilli(); }); + When( + "I click on logout button from navbar$", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.clickOnWebElementBySelector(NavBarPage.LOGOUT_BUTTON); + }); + Then( "I wait for {string} page to load and calculate elapsed time", (String page) -> { diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/users/CreateNewUserSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/users/CreateNewUserSteps.java index 85c20b4278a..e96322f1339 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/users/CreateNewUserSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/users/CreateNewUserSteps.java @@ -18,23 +18,108 @@ package org.sormas.e2etests.steps.web.application.users; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_DETAILED_COLUMN_HEADERS; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_DETAILED_TABLE_DATA; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_DETAILED_TABLE_ROWS; +import static org.sormas.e2etests.pages.application.dashboard.Surveillance.SurveillanceDashboardPage.LOGOUT_BUTTON; import static org.sormas.e2etests.pages.application.users.CreateNewUserPage.*; import cucumber.api.java8.En; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; import javax.inject.Inject; +import org.openqa.selenium.WebElement; import org.sormas.e2etests.helpers.WebDriverHelpers; +import org.sormas.e2etests.pages.application.LoginPage; import org.sormas.e2etests.pages.application.users.CreateNewUserPage; import org.sormas.e2etests.pojo.User; import org.sormas.e2etests.services.UserService; +import org.sormas.e2etests.steps.BaseSteps; +import org.sormas.e2etests.steps.web.application.cases.CaseDetailedTableViewHeaders; +import org.testng.asserts.SoftAssert; public class CreateNewUserSteps implements En { private final WebDriverHelpers webDriverHelpers; public static User user; public static User editUser; + public static String userName; + public static String userPass; + private final BaseSteps baseSteps; @Inject - public CreateNewUserSteps(WebDriverHelpers webDriverHelpers, UserService userService) { + public CreateNewUserSteps( + WebDriverHelpers webDriverHelpers, + UserService userService, + BaseSteps baseSteps, + SoftAssert softly) { this.webDriverHelpers = webDriverHelpers; + this.baseSteps = baseSteps; + + When( + "I create new ([^\"]*) with limited disease to ([^\"]*)", + (String role, String disease) -> { + user = userService.buildGeneratedUserWithRoleAndDisease(role, disease); + fillFirstName(user.getFirstName()); + fillLastName(user.getLastName()); + fillEmailAddress(user.getEmailAddress()); + fillPhoneNumber(user.getPhoneNumber()); + selectLanguage(user.getLanguage()); + selectCountry(user.getCountry()); + selectRegion(user.getRegion()); + selectDistrict(user.getDistrict()); + selectCommunity(user.getCommunity()); + selectFacilityCategory(user.getFacilityCategory()); + selectFacilityType(user.getFacilityType()); + selectFacility(user.getFacility()); + fillFacilityNameAndDescription(user.getFacilityNameAndDescription()); + fillStreet(user.getStreet()); + fillHouseNr(user.getHouseNumber()); + fillAdditionalInformation(user.getAdditionalInformation()); + fillPostalCode(user.getPostalCode()); + fillCity(user.getCity()); + selectAreaType(user.getAreaType()); + fillGpsLatitude(user.getGpsLatitude()); + fillGpsLongitude(user.getGpsLongitude()); + fillGpsAccuracy(user.getGpsAccuracy()); + selectActive(user.getActive()); + fillUserName(user.getUserName()); + selectUserRole(role); + selectLimitedDisease(user.getLimitedDisease()); + userName = user.getUserName(); + webDriverHelpers.scrollToElement(SAVE_BUTTON); + webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON); + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(20); + userPass = webDriverHelpers.getTextFromWebElement(PASSWORD_FIELD); + closeNewPasswordPopUp(); + }); + + When( + "As a new created user with limited disease view I log in", + () -> { + webDriverHelpers.waitUntilIdentifiedElementIsPresent(LoginPage.USER_NAME_INPUT); + webDriverHelpers.fillInWebElement(LoginPage.USER_NAME_INPUT, userName); + webDriverHelpers.fillInWebElement(LoginPage.USER_PASSWORD_INPUT, userPass); + webDriverHelpers.clickOnWebElementBySelector(LoginPage.LOGIN_BUTTON); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(LOGOUT_BUTTON, 30); + }); + + When( + "I check if user have limited disease view to ([^\"]*) only", + (String disease) -> { + List> tableRowsData = getTableRowsData(); + for (int i = 0; i < tableRowsData.size(); i++) { + Map detailedCaseDTableRow = tableRowsData.get(i); + softly.assertTrue( + detailedCaseDTableRow + .get(CaseDetailedTableViewHeaders.DISEASE.toString()) + .contains(disease), + "Disease is not correct"); + softly.assertAll(); + } + }); + When( "^I create a new user with ([^\"]*)$", (String role) -> { @@ -231,4 +316,52 @@ private void selectLimitedDisease(String limitedDisease) { webDriverHelpers.scrollToElement(LIMITED_DISEASE_COMBOBOX); webDriverHelpers.selectFromCombobox(LIMITED_DISEASE_COMBOBOX, limitedDisease); } + + private List> getTableRowsData() { + Map headers = extractColumnHeadersHashMap(); + List tableRows = getTableRows(); + List> tableDataList = new ArrayList<>(); + tableRows.forEach( + table -> { + HashMap indexWithData = new HashMap<>(); + AtomicInteger atomicInt = new AtomicInteger(); + List tableData = table.findElements(CASE_DETAILED_TABLE_DATA); + tableData.forEach( + dataText -> { + webDriverHelpers.scrollToElementUntilIsVisible(dataText); + indexWithData.put(atomicInt.getAndIncrement(), dataText.getText()); + }); + tableDataList.add(indexWithData); + }); + List> tableObjects = new ArrayList<>(); + tableDataList.forEach( + row -> { + ConcurrentHashMap objects = new ConcurrentHashMap<>(); + headers.forEach((headerText, index) -> objects.put(headerText, row.get(index))); + tableObjects.add(objects); + }); + return tableObjects; + } + + private List getTableRows() { + webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(CASE_DETAILED_COLUMN_HEADERS); + return baseSteps.getDriver().findElements(CASE_DETAILED_TABLE_ROWS); + } + + private Map extractColumnHeadersHashMap() { + AtomicInteger atomicInt = new AtomicInteger(); + HashMap headerHashmap = new HashMap<>(); + webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(CASE_DETAILED_COLUMN_HEADERS); + webDriverHelpers.waitUntilAListOfWebElementsAreNotEmpty(CASE_DETAILED_COLUMN_HEADERS); + webDriverHelpers.scrollToElementUntilIsVisible(CASE_DETAILED_COLUMN_HEADERS); + baseSteps + .getDriver() + .findElements(CASE_DETAILED_COLUMN_HEADERS) + .forEach( + webElement -> { + webDriverHelpers.scrollToElementUntilIsVisible(webElement); + headerHashmap.put(webElement.getText(), atomicInt.getAndIncrement()); + }); + return headerHashmap; + } } diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/User.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/User.feature index f2faddd1b00..45a3fb4be6b 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/User.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/User.feature @@ -35,3 +35,15 @@ Feature: Create user | rights | | National User | | POE National User | + + @issue=SORDEV-9366 + Scenario: Users with limited disease + Given I log in as a Admin User + And I click on the Users from navbar + And I click on the NEW USER button + And I create new National User with limited disease to Cholera + Then I click on logout button from navbar + And As a new created user with limited disease view I log in + Then I click on the Cases button from navbar + And I check if user have limited disease view to Cholera only + From d0ec1ac1d64aa354e4d80ea4368e1d77a396fb86 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Mon, 14 Feb 2022 12:59:44 +0200 Subject: [PATCH 078/253] #6879 - move health conditions from ClinicalCourse to Cases - android part --- .../symeda/sormas/app/backend/caze/Case.java | 25 +++++++++--- .../sormas/app/backend/caze/CaseDao.java | 9 ++--- .../app/backend/caze/CaseDtoHelper.java | 14 +++++++ .../clinicalcourse/ClinicalCourse.java | 7 ++-- .../clinicalcourse/ClinicalCourseDao.java | 11 +----- .../ClinicalCourseDtoHelper.java | 10 ----- .../app/backend/common/DatabaseHelper.java | 38 +++++++++++-------- .../CaseEditHealthConditionsFragment.java | 2 +- .../CaseReadHealthConditionsFragment.java | 2 +- 9 files changed, 66 insertions(+), 52 deletions(-) diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/Case.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/Case.java index 78f778a930c..cf6e2c463f6 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/Case.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/Case.java @@ -18,6 +18,12 @@ import static de.symeda.sormas.api.utils.FieldConstraints.CHARACTER_LIMIT_BIG; import static de.symeda.sormas.api.utils.FieldConstraints.CHARACTER_LIMIT_DEFAULT; +import com.j256.ormlite.field.DataType; +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; + +import org.apache.commons.lang3.StringUtils; + import java.util.Date; import javax.persistence.Column; @@ -26,12 +32,6 @@ import javax.persistence.Enumerated; import javax.persistence.Transient; -import org.apache.commons.lang3.StringUtils; - -import com.j256.ormlite.field.DataType; -import com.j256.ormlite.field.DatabaseField; -import com.j256.ormlite.table.DatabaseTable; - import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.caze.CaseClassification; import de.symeda.sormas.api.caze.CaseIdentificationSource; @@ -58,6 +58,7 @@ import de.symeda.sormas.app.backend.caze.maternalhistory.MaternalHistory; import de.symeda.sormas.app.backend.caze.porthealthinfo.PortHealthInfo; import de.symeda.sormas.app.backend.clinicalcourse.ClinicalCourse; +import de.symeda.sormas.app.backend.clinicalcourse.HealthConditions; import de.symeda.sormas.app.backend.common.DatabaseHelper; import de.symeda.sormas.app.backend.common.PseudonymizableAdo; import de.symeda.sormas.app.backend.epidata.EpiData; @@ -101,6 +102,7 @@ public class Case extends PseudonymizableAdo { public static final String REGION = "region"; public static final String COMPLETENESS = "completeness"; public static final String VACCINATION_STATUS = "vaccinationStatus"; + public static final String HEALTH_CONDITIONS = "healthConditions"; @DatabaseField(foreign = true, foreignAutoRefresh = true, canBeNull = false, maxForeignAutoRefreshLevel = 3) private Person person; @@ -217,6 +219,9 @@ public class Case extends PseudonymizableAdo { @Enumerated(EnumType.STRING) private YesNoUnknown pregnant; + @DatabaseField(foreign = true, foreignAutoRefresh = true) + private HealthConditions healthConditions; + @Enumerated(EnumType.STRING) @DatabaseField(columnName = "vaccination") private VaccinationStatus vaccinationStatus; @@ -654,6 +659,14 @@ public void setInvestigationStatus(InvestigationStatus investigationStatus) { this.investigationStatus = investigationStatus; } + public HealthConditions getHealthConditions() { + return healthConditions; + } + + public void setHealthConditions(HealthConditions healthConditions) { + this.healthConditions = healthConditions; + } + public YesNoUnknown getPregnant() { return pregnant; } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseDao.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseDao.java index 7730570e906..a97228504c3 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseDao.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseDao.java @@ -165,11 +165,7 @@ public Date getLatestChangeDate() { date = clinicalCourseDate; } - Date healthConditionsDate = getLatestChangeDateSubJoinReverse( - ClinicalCourse.TABLE_NAME, - Case.CLINICAL_COURSE, - HealthConditions.TABLE_NAME, - ClinicalCourse.HEALTH_CONDITIONS); + Date healthConditionsDate = getLatestChangeDateJoin(HealthConditions.TABLE_NAME, Case.HEALTH_CONDITIONS); if (healthConditionsDate != null && healthConditionsDate.after(date)) { date = healthConditionsDate; } @@ -258,6 +254,9 @@ public Case build(Person person) { // Port Health Info caze.setPortHealthInfo(DatabaseHelper.getPortHealthInfoDao().build()); + + // health conditions + caze.setHealthConditions(DatabaseHelper.getHealthConditionsDao().build()); // Location User currentUser = ConfigProvider.getUser(); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseDtoHelper.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseDtoHelper.java index 26ce3804cae..a80737c6420 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseDtoHelper.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseDtoHelper.java @@ -26,6 +26,8 @@ import de.symeda.sormas.app.backend.caze.porthealthinfo.PortHealthInfoDtoHelper; import de.symeda.sormas.app.backend.clinicalcourse.ClinicalCourse; import de.symeda.sormas.app.backend.clinicalcourse.ClinicalCourseDtoHelper; +import de.symeda.sormas.app.backend.clinicalcourse.HealthConditions; +import de.symeda.sormas.app.backend.clinicalcourse.HealthConditionsDtoHelper; import de.symeda.sormas.app.backend.common.DatabaseHelper; import de.symeda.sormas.app.backend.epidata.EpiData; import de.symeda.sormas.app.backend.epidata.EpiDataDtoHelper; @@ -65,6 +67,7 @@ public class CaseDtoHelper extends PersonDependentDtoHelper { private MaternalHistoryDtoHelper maternalHistoryDtoHelper = new MaternalHistoryDtoHelper(); private PortHealthInfoDtoHelper portHealthInfoDtoHelper = new PortHealthInfoDtoHelper(); private SormasToSormasOriginInfoDtoHelper sormasToSormasOriginInfoDtoHelper = new SormasToSormasOriginInfoDtoHelper(); + private HealthConditionsDtoHelper healthConditionsDtoHelper = new HealthConditionsDtoHelper(); @Override protected Class getAdoClass() { @@ -146,6 +149,9 @@ public void fillInnerFromDto(Case target, CaseDataDto source) { target.setClinicianPhone(source.getClinicianPhone()); target.setClinicianEmail(source.getClinicianEmail()); target.setPregnant(source.getPregnant()); + + target.setHealthConditions(healthConditionsDtoHelper.fillOrCreateFromDto(target.getHealthConditions(), source.getHealthConditions())); + target.setVaccinationStatus(source.getVaccinationStatus()); target.setSmallpoxVaccinationScar(source.getSmallpoxVaccinationScar()); target.setSmallpoxVaccinationReceived(source.getSmallpoxVaccinationReceived()); @@ -476,6 +482,14 @@ public void fillInnerFromAdo(CaseDataDto target, Case source) { target.setNotACaseReasonDetails(source.getNotACaseReasonDetails()); target.setFollowUpStatusChangeDate(source.getFollowUpStatusChangeDate()); target.setFollowUpStatusChangeUser(UserDtoHelper.toReferenceDto(source.getFollowUpStatusChangeUser())); + + if (source.getHealthConditions() != null) { + HealthConditions healthConditions = DatabaseHelper.getHealthConditionsDao().queryForId(source.getHealthConditions().getId()); + target.setHealthConditions(healthConditionsDtoHelper.adoToDto(healthConditions)); + } else { + target.setHealthConditions(null); + } + } @Override diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/clinicalcourse/ClinicalCourse.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/clinicalcourse/ClinicalCourse.java index 870f88f7c7b..f106b88c8e7 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/clinicalcourse/ClinicalCourse.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/clinicalcourse/ClinicalCourse.java @@ -15,11 +15,11 @@ package de.symeda.sormas.app.backend.clinicalcourse; -import javax.persistence.Entity; - import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; +import javax.persistence.Entity; + import de.symeda.sormas.app.backend.common.AbstractDomainObject; import de.symeda.sormas.app.backend.common.EmbeddedAdo; @@ -33,8 +33,7 @@ public class ClinicalCourse extends AbstractDomainObject { public static final String TABLE_NAME = "clinicalCourse"; public static final String I18N_PREFIX = "ClinicalCourse"; - public static final String HEALTH_CONDITIONS = "healthConditions"; - + @Deprecated @DatabaseField(foreign = true, foreignAutoRefresh = true) private HealthConditions healthConditions; diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/clinicalcourse/ClinicalCourseDao.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/clinicalcourse/ClinicalCourseDao.java index 629730cc94b..3706e2506e7 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/clinicalcourse/ClinicalCourseDao.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/clinicalcourse/ClinicalCourseDao.java @@ -15,12 +15,11 @@ package de.symeda.sormas.app.backend.clinicalcourse; -import java.util.Date; - import com.j256.ormlite.dao.Dao; +import java.util.Date; + import de.symeda.sormas.app.backend.common.AbstractAdoDao; -import de.symeda.sormas.app.backend.common.DatabaseHelper; public class ClinicalCourseDao extends AbstractAdoDao { @@ -31,7 +30,6 @@ public ClinicalCourseDao(Dao innerDao) { @Override public ClinicalCourse build() { ClinicalCourse clinicalCourse = super.build(); - clinicalCourse.setHealthConditions(DatabaseHelper.getHealthConditionsDao().build()); return clinicalCourse; } @@ -42,11 +40,6 @@ public Date getLatestChangeDate() { return null; } - Date healthConditionsDate = getLatestChangeDateJoin(HealthConditions.TABLE_NAME, ClinicalCourse.HEALTH_CONDITIONS); - if (healthConditionsDate != null && healthConditionsDate.after(date)) { - date = healthConditionsDate; - } - return date; } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/clinicalcourse/ClinicalCourseDtoHelper.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/clinicalcourse/ClinicalCourseDtoHelper.java index b6193155b1f..03d433c3d19 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/clinicalcourse/ClinicalCourseDtoHelper.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/clinicalcourse/ClinicalCourseDtoHelper.java @@ -21,14 +21,11 @@ import de.symeda.sormas.api.clinicalcourse.ClinicalCourseDto; import de.symeda.sormas.api.clinicalcourse.ClinicalCourseReferenceDto; import de.symeda.sormas.app.backend.common.AdoDtoHelper; -import de.symeda.sormas.app.backend.common.DatabaseHelper; import de.symeda.sormas.app.rest.NoConnectionException; import retrofit2.Call; public class ClinicalCourseDtoHelper extends AdoDtoHelper { - private HealthConditionsDtoHelper healthConditionsDtoHelper = new HealthConditionsDtoHelper(); - @Override protected Class getAdoClass() { return ClinicalCourse.class; @@ -56,17 +53,10 @@ protected Call> pushAll(List clinicalCourseD @Override public void fillInnerFromDto(ClinicalCourse target, ClinicalCourseDto source) { - target.setHealthConditions(healthConditionsDtoHelper.fillOrCreateFromDto(target.getHealthConditions(), source.getHealthConditions())); } @Override public void fillInnerFromAdo(ClinicalCourseDto target, ClinicalCourse source) { - if (source.getHealthConditions() != null) { - HealthConditions healthConditions = DatabaseHelper.getHealthConditionsDao().queryForId(source.getHealthConditions().getId()); - target.setHealthConditions(healthConditionsDtoHelper.adoToDto(healthConditions)); - } else { - target.setHealthConditions(null); - } } @Override diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java index 7d748a51c04..db41e10a650 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java @@ -15,6 +15,21 @@ package de.symeda.sormas.app.backend.common; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.text.TextUtils; +import android.util.Log; + +import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; +import com.j256.ormlite.dao.Dao; +import com.j256.ormlite.dao.GenericRawResults; +import com.j256.ormlite.field.DataType; +import com.j256.ormlite.support.ConnectionSource; +import com.j256.ormlite.table.TableUtils; + +import org.apache.commons.lang3.StringUtils; + import java.lang.reflect.Array; import java.math.BigInteger; import java.sql.SQLException; @@ -30,21 +45,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.commons.lang3.StringUtils; - -import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; -import com.j256.ormlite.dao.Dao; -import com.j256.ormlite.dao.GenericRawResults; -import com.j256.ormlite.field.DataType; -import com.j256.ormlite.support.ConnectionSource; -import com.j256.ormlite.table.TableUtils; - -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.text.TextUtils; -import android.util.Log; - import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.caze.VaccinationStatus; import de.symeda.sormas.api.caze.Vaccine; @@ -183,7 +183,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { public static final String DATABASE_NAME = "sormas.db"; // any time you make changes to your database objects, you may have to increase the database version - public static final int DATABASE_VERSION = 331; + public static final int DATABASE_VERSION = 332; private static DatabaseHelper instance = null; @@ -2943,6 +2943,12 @@ public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int getDao(EventParticipant.class).executeRaw( "UPDATE eventParticipants SET reportingUser_id = (SELECT reportingUser_id FROM events WHERE events.id = eventParticipants.event_id) WHERE reportingUser_id IS NULL;"); + case 331: + currentVersion = 331; + getDao(Case.class).executeRaw( + "ALTER TABLE cases ADD COLUMN healthConditions_id BIGINT REFERENCES healthConditions(id);" + + "UPDATE cases c SET healthConditions_id = (SELECT cc.healthConditions_id from clinicalCourse cc where cc.id = c.clinicalCourse_id);"); + // ATTENTION: break should only be done after last version break; diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/CaseEditHealthConditionsFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/CaseEditHealthConditionsFragment.java index 059aafab0c2..ce6f13e5bfa 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/CaseEditHealthConditionsFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/edit/CaseEditHealthConditionsFragment.java @@ -38,6 +38,6 @@ public static CaseEditHealthConditionsFragment newInstance(Case activityRootData @Override protected void prepareFragmentData() { - record = getActivityRootData().getClinicalCourse().getHealthConditions(); + record = getActivityRootData().getHealthConditions(); } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/read/CaseReadHealthConditionsFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/read/CaseReadHealthConditionsFragment.java index 75e4feb632f..2b0bc3e7aab 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/read/CaseReadHealthConditionsFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/read/CaseReadHealthConditionsFragment.java @@ -39,6 +39,6 @@ public static CaseReadHealthConditionsFragment newInstance(Case activityRootData @Override protected void prepareFragmentData(Bundle savedInstanceState) { - record = getActivityRootData().getClinicalCourse().getHealthConditions(); + record = getActivityRootData().getHealthConditions(); } } From b4f5e93876b59c44b6759195d5f693c31fc465cd Mon Sep 17 00:00:00 2001 From: sergiupacurariu <62688603+sergiupacurariu@users.noreply.github.com> Date: Mon, 14 Feb 2022 17:29:04 +0200 Subject: [PATCH 079/253] #7982 - Campaign synchronization not working --- .../backend/campaign/CampaignService.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignService.java index e9f85bf5cd5..f4cc4e6aef0 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignService.java @@ -1,5 +1,6 @@ package de.symeda.sormas.backend.campaign; +import java.util.Date; import java.util.List; import javax.ejb.LocalBean; @@ -104,4 +105,26 @@ public List getAllActive() { public Predicate createActiveCampaignsFilter(CriteriaBuilder cb, Root root) { return cb.and(cb.isFalse(root.get(Campaign.ARCHIVED)), cb.isFalse(root.get(Campaign.DELETED))); } + + public List getAllAfter(Date since) { + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(getElementClass()); + Root root = cq.from(getElementClass()); + + Predicate filter = createUserFilter(cb, cq, root); + if (since != null) { + Predicate dateFilter = createChangeDateFilter(cb, root, since); + if (filter != null) { + filter = cb.and(filter, dateFilter); + } else { + filter = dateFilter; + } + } + if (filter != null) { + cq.where(filter); + } + cq.orderBy(cb.desc(root.get(AbstractDomainObject.CHANGE_DATE))); + + return em.createQuery(cq).getResultList(); + } } From bd87f1a20eebf702363d0ddb31c4d35249de0af6 Mon Sep 17 00:00:00 2001 From: sergiupacurariu <62688603+sergiupacurariu@users.noreply.github.com> Date: Mon, 14 Feb 2022 17:33:34 +0200 Subject: [PATCH 080/253] #7982 - Campaign synchronization not working --- .../java/de/symeda/sormas/backend/campaign/CampaignService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignService.java index f4cc4e6aef0..5dfa96c05b5 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignService.java @@ -106,6 +106,7 @@ public Predicate createActiveCampaignsFilter(CriteriaBuilder cb, Root return cb.and(cb.isFalse(root.get(Campaign.ARCHIVED)), cb.isFalse(root.get(Campaign.DELETED))); } + @Override public List getAllAfter(Date since) { CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(getElementClass()); From 4f710ba5695503b6eb8dec57f79ff655d983bc84 Mon Sep 17 00:00:00 2001 From: Marin Date: Tue, 15 Feb 2022 08:07:22 +0200 Subject: [PATCH 081/253] #7757 - Info dialog does not show whole content. Where fixed: 1. Window size that header with health departament is displayed totally. 2. Was added new line passing for header line (prior all errors) 3. Was added new line passing for all errors. 4. Was adjusted width for groupErrorsLayout in order to see all complete words in errors(as sometime 1 word is missing) --- .../sormastosormas/SormasToSormasController.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/sormastosormas/SormasToSormasController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/sormastosormas/SormasToSormasController.java index 7cd1d6a7cbb..5e13539c423 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/sormastosormas/SormasToSormasController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/sormastosormas/SormasToSormasController.java @@ -201,7 +201,7 @@ private void handleSormasToSormasRequest(SormasToSormasRequest request, Runnable VaadinUiUtil.showPopupWindowWithWidth( new VerticalLayout(messageComponent), I18nProperties.getCaption(Captions.sormasToSormasErrorDialogTitle), - 38); + 48); } } catch (SormasToSormasValidationException ex) { Component messageComponent = buildShareErrorMessage(ex.getMessage(), ex.getErrors()); @@ -209,12 +209,13 @@ private void handleSormasToSormasRequest(SormasToSormasRequest request, Runnable VaadinUiUtil.showPopupWindowWithWidth( new VerticalLayout(messageComponent), I18nProperties.getCaption(Captions.sormasToSormasErrorDialogTitle), - 38); + 48); } } private Component buildShareErrorMessage(String message, List errors) { Label errorMessageLabel = new Label(message, ContentMode.HTML); + errorMessageLabel.addStyleName(CssStyles.LABEL_WHITE_SPACE_NORMAL); if (errors == null || errors.isEmpty()) { return errorMessageLabel; @@ -228,6 +229,7 @@ private Component buildShareErrorMessage(String message, List groupErrorsLayout.setMargin(false); groupErrorsLayout.setSpacing(false); groupErrorsLayout.setStyleName(CssStyles.HSPACE_LEFT_3); + groupErrorsLayout.setWidth(92, Sizeable.Unit.PERCENTAGE); VerticalLayout layout = new VerticalLayout(groupLabel, groupErrorsLayout); layout.setMargin(false); @@ -248,11 +250,12 @@ private Component[] formatSubGroupErrors(ValidationErrors errors) { return errors.getSubGroups().stream().map(e -> { Label groupLabel = new Label(e.getHumanMessage() + ":"); groupLabel.addStyleName(CssStyles.LABEL_BOLD); - HorizontalLayout layout = new HorizontalLayout( - groupLabel, - new Label( + Label label = new Label( String - .join(", ", e.getMessages().stream().map(ValidationErrorMessage::getHumanMessage).collect(Collectors.toList()).toString()))); + .join(", ", e.getMessages().stream().map(ValidationErrorMessage::getHumanMessage).collect(Collectors.toList()).toString())); + HorizontalLayout layout = new HorizontalLayout( + groupLabel, label); + label.addStyleName(CssStyles.LABEL_WHITE_SPACE_NORMAL); layout.setMargin(false); return layout; From aebdce51d57773eca242e21d8fb2eee48a8ed736 Mon Sep 17 00:00:00 2001 From: Stefan Kock Date: Tue, 15 Feb 2022 07:37:03 +0100 Subject: [PATCH 082/253] #7978: Refactor: Replaced usages of commons-lang by commons-lang3 commons-lang is a transitive dependency of velocity that will vanish --- .../backend/customizableenum/CustomizableEnumConverter.java | 2 +- .../backend/docgeneration/DocumentTemplateFacadeEjb.java | 2 +- .../java/de/symeda/sormas/backend/event/EventFacadeEjb.java | 2 +- .../validation/InfraValidationSoundnessTest.java | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumConverter.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumConverter.java index 91f42b37308..37ed910f221 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumConverter.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/customizableenum/CustomizableEnumConverter.java @@ -19,7 +19,7 @@ import javax.naming.NamingException; import javax.persistence.AttributeConverter; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import de.symeda.sormas.api.customizableenum.CustomizableEnum; import de.symeda.sormas.api.customizableenum.CustomizableEnumFacade; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java index 8b4f163acf3..f08d25a6664 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java @@ -37,7 +37,7 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import de.symeda.sormas.api.EntityDtoAccessHelper; import de.symeda.sormas.api.HasUuid; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java index 5cc851e3127..8860ebb0674 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java @@ -57,7 +57,7 @@ import javax.validation.constraints.NotNull; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/sormastosormas/validation/InfraValidationSoundnessTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/sormastosormas/validation/InfraValidationSoundnessTest.java index c351f37588e..24c764cc27f 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/sormastosormas/validation/InfraValidationSoundnessTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/sormastosormas/validation/InfraValidationSoundnessTest.java @@ -22,9 +22,9 @@ import java.util.stream.Stream; import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang.NotImplementedException; -import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.NotImplementedException; +import org.apache.commons.lang3.StringUtils; import org.junit.Ignore; import org.junit.Test; From 93f61b5675406e5194cc4d2aa83c323c15d3da27 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Tue, 15 Feb 2022 08:14:13 +0100 Subject: [PATCH 083/253] test scenario for bulk edit --- .../application/cases/CaseDirectoryPage.java | 4 +++ .../application/cases/CaseDirectorySteps.java | 32 ++++++++++++++++++- .../features/sanity/web/Case.feature | 20 ++++++++++++ .../features/sanity/web/CaseFilters.feature | 2 +- 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java index a34e0de445d..03b56ae00ac 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java @@ -125,5 +125,9 @@ public class CaseDirectoryPage { public static final By INVESTIGATION_DISCARDED_BUTTON = By.id("Investigation discarded"); public static final By DATE_FROM_COMBOBOX = By.cssSelector("#dateFrom input"); public static final By DATE_TO_COMBOBOX = By.cssSelector("#dateTo input"); + public static final By MORE_BUTTON = By.id("more"); + public static final By ENTER_BULK_EDIT_MODE = By.id("actionEnterBulkEditMode"); + public static final By FIRST_CHECKBOX = + By.xpath("//th[@role='columnheader']//input[@type='checkbox']/../.."); // TODO refactor the other headers based on the last one added } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java index 7a852fa1119..5655dd8b1b9 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java @@ -82,6 +82,23 @@ public CaseDirectorySteps( By.xpath(String.format(RESULTS_GRID_HEADER, "Sex")), 20); webDriverHelpers.waitUntilANumberOfElementsAreVisibleAndClickable(GRID_HEADERS, 41); }); + When( + "I click on the More button on Case directory page", + () -> { + webDriverHelpers.clickOnWebElementBySelector(MORE_BUTTON); + }); + When( + "I click Enter Bulk Edit Mode on Case directory page", + () -> { + webDriverHelpers.clickOnWebElementBySelector(ENTER_BULK_EDIT_MODE); + webDriverHelpers.waitForPageLoaded(); + }); + When( + "I click checkbox to choose all Case results", + () -> { + webDriverHelpers.clickOnWebElementBySelector(FIRST_CHECKBOX); + webDriverHelpers.waitForPageLoaded(); + }); When( "I filter by CaseID on Case directory page", @@ -215,6 +232,7 @@ public CaseDirectorySteps( apiState.getLastCreatedPerson().getFirstName() + " " + apiState.getLastCreatedPerson().getLastName())); + And( "I apply mocked Person Id filter on Case directory page", () -> @@ -269,7 +287,7 @@ public CaseDirectorySteps( () -> { webDriverHelpers.clickOnWebElementBySelector( CASE_DIRECTORY_DETAILED_PAGE_APPLY_FILTER_BUTTON); - TimeUnit.SECONDS.sleep(3); // needed for table refresh + TimeUnit.SECONDS.sleep(5); // needed for table refresh }); Then( @@ -324,6 +342,18 @@ public CaseDirectorySteps( ZoneId.systemDefault()) .minusDays(number))); }); + And( + "I fill Cases from input to {int} days before mocked Cases created on Case directory page", + (Integer number) -> { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy"); + webDriverHelpers.fillInWebElement( + DATE_FROM_COMBOBOX, + formatter.format( + LocalDate.ofInstant( + apiState.getCreatedCases().get(0).getReportDate().toInstant(), + ZoneId.systemDefault()) + .minusDays(number))); + }); And( "I fill Cases from input to {int} days after before mocked Case created on Case directory page", (Integer number) -> { diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature index f8016bf558e..dd9f4d2af03 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature @@ -324,5 +324,25 @@ Feature: Case end to end tests Then I click on save Contact button And I check if Quarantine change comment field was saved correctly + @issue=SORDEV-7452 + Scenario: Bulk mode for linking/adding to Events + When API: I create a new person + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + When API: I create 10 new cases + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in as a Admin User + And I click on the Cases button from navbar + And I click SHOW MORE FILTERS button on Case directory page + And I apply Date type filter to "Case report date" on Case directory page + And I fill Cases from input to 1 days before mocked Cases created on Case directory page + And I apply last created api Person Id filter on Case directory page + And I click APPLY BUTTON in Case Directory Page + And I click on the More button on Case directory page + And I click Enter Bulk Edit Mode on Case directory page + And I click checkbox to choose all Case results + And I click on New Sample + diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature index d8242bc7f87..f002a5a4099 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature @@ -62,7 +62,7 @@ Feature: Case filter functionality Given API: I create a new case Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 - Given I log in with National User + Given I log in as a Admin User And I click on the Cases button from navbar And I apply Case origin "In-Country" on Case directory page And I filter by CaseID on Case directory page From 79ddceae3af15ef54c9ba6107f4688b75c91ef9c Mon Sep 17 00:00:00 2001 From: Jonas Cirotzki Date: Tue, 15 Feb 2022 11:09:11 +0100 Subject: [PATCH 084/253] [#7813] cache current user (#7821) * [#7813] remove config face from cache * [#7813] do not inject --- .../resources/doc/SORMAS_Data_Dictionary.xlsx | Bin 257040 -> 257098 bytes .../resources/doc/SORMAS_User_Rights.xlsx | Bin 19172 -> 19172 bytes .../sormas/backend/common/BaseAdoService.java | 21 ++---- .../backend/sample/SampleFacadeEjb.java | 3 +- .../sormas/backend/user/CurrentUser.java | 34 ---------- .../backend/user/CurrentUserQualifier.java | 28 -------- .../backend/user/CurrentUserService.java | 61 +++++++++++------- .../de/symeda/sormas/backend/user/User.java | 11 ++++ .../symeda/sormas/backend/user/UserCache.java | 55 ++++++++++++++++ .../sormas/backend/user/UserFacadeEjb.java | 30 ++++----- .../sormas/backend/user/UserService.java | 5 -- .../sormas/backend/AbstractBeanTest.java | 5 -- .../de/symeda/sormas/ui/AbstractBeanTest.java | 3 - 13 files changed, 121 insertions(+), 135 deletions(-) delete mode 100644 sormas-backend/src/main/java/de/symeda/sormas/backend/user/CurrentUser.java delete mode 100644 sormas-backend/src/main/java/de/symeda/sormas/backend/user/CurrentUserQualifier.java create mode 100644 sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserCache.java diff --git a/sormas-api/src/main/resources/doc/SORMAS_Data_Dictionary.xlsx b/sormas-api/src/main/resources/doc/SORMAS_Data_Dictionary.xlsx index bb9e2868ba3bfbc1920b0650ff1060d94fef2e91..ef45161daa88d2e3942854b058a02a388c6f6495 100644 GIT binary patch delta 44740 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 TR$!Xb%N0xqdO3sX>0Z77oPfk6 diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/BaseAdoService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/BaseAdoService.java index 3586f523613..cfbffdfecdf 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/BaseAdoService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/BaseAdoService.java @@ -25,7 +25,6 @@ import java.util.function.BiFunction; import java.util.stream.Collectors; -import javax.enterprise.inject.Instance; import javax.inject.Inject; import javax.persistence.EntityExistsException; import javax.persistence.EntityManager; @@ -43,14 +42,13 @@ import javax.persistence.criteria.Subquery; import javax.validation.constraints.NotNull; +import de.symeda.sormas.backend.user.CurrentUserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import de.symeda.sormas.api.EntityDto; import de.symeda.sormas.api.ReferenceDto; import de.symeda.sormas.api.utils.DateHelper; -import de.symeda.sormas.backend.user.CurrentUser; -import de.symeda.sormas.backend.user.CurrentUserQualifier; import de.symeda.sormas.backend.user.User; import de.symeda.sormas.backend.util.ModelConstants; import de.symeda.sormas.backend.util.QueryHelper; @@ -63,8 +61,7 @@ public class BaseAdoService implements AdoServ private final Class elementClass; @Inject - @CurrentUserQualifier - private Instance currentUser; + private CurrentUserService currentUserService; // protected to be used by implementations @PersistenceContext(unitName = ModelConstants.PERSISTENCE_UNIT_NAME) @@ -74,18 +71,8 @@ protected BaseAdoService(Class elementClass) { this.elementClass = elementClass; } - protected User getCurrentUser() { - return currentUser.get().getUser(); - } - - /** - * Should only be used for testing scenarios of user rights & jurisdiction! - * - * @param user - */ - @Deprecated - public void setCurrentUser(User user) { - currentUser.get().setUser(user); + public User getCurrentUser() { + return currentUserService.getCurrentUser(); } protected Class getElementClass() { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java index 8dcfc4de807..b1fc1fc1dfd 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java @@ -90,7 +90,6 @@ import de.symeda.sormas.backend.contact.ContactFacadeEjb.ContactFacadeEjbLocal; import de.symeda.sormas.backend.contact.ContactService; import de.symeda.sormas.backend.event.Event; -import de.symeda.sormas.backend.event.EventFacadeEjb.EventFacadeEjbLocal; import de.symeda.sormas.backend.event.EventParticipant; import de.symeda.sormas.backend.event.EventParticipantFacadeEjb; import de.symeda.sormas.backend.event.EventParticipantFacadeEjb.EventParticipantFacadeEjbLocal; @@ -160,7 +159,7 @@ public class SampleFacadeEjb implements SampleFacade { @EJB private EventParticipantFacadeEjbLocal eventParticipantFacade; @EJB - private EventFacadeEjbLocal eventFacade; + private EventFacadeEjb.EventFacadeEjbLocal eventFacade; @EJB private MessagingService messagingService; @EJB diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/CurrentUser.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/CurrentUser.java deleted file mode 100644 index cde68a3d9bc..00000000000 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/CurrentUser.java +++ /dev/null @@ -1,34 +0,0 @@ -package de.symeda.sormas.backend.user; - -import java.io.Serializable; - -import javax.enterprise.context.RequestScoped; - -@RequestScoped -// FIXME @TransactionScoped would be better for performance, but is not support by novatec.bean-test (see their github #4) -public class CurrentUser implements Serializable { - - private static final long serialVersionUID = 1L; - - private User user; - - public CurrentUser() { - } - - public CurrentUser(User user) { - this.user = user; - } - - public User getUser() { - return user; - } - - /** - * Should only be used for testing scenarios of user rights & jurisdiction! - * @param user - */ - @Deprecated - public void setUser(User user) { - this.user = user; - } -} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/CurrentUserQualifier.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/CurrentUserQualifier.java deleted file mode 100644 index 644b0e87cba..00000000000 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/CurrentUserQualifier.java +++ /dev/null @@ -1,28 +0,0 @@ -package de.symeda.sormas.backend.user; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import javax.inject.Qualifier; - -/** - * Used as a Qualifier to identify the User entity produced as the current user - */ -@Target({ - TYPE, - METHOD, - PARAMETER, - FIELD }) -@Retention(RUNTIME) -@Documented -@Qualifier -public @interface CurrentUserQualifier { - -} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/CurrentUserService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/CurrentUserService.java index 93449eebedd..6d029065b61 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/CurrentUserService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/CurrentUserService.java @@ -5,21 +5,18 @@ import javax.ejb.SessionContext; import javax.ejb.Stateless; import javax.enterprise.context.RequestScoped; -import javax.enterprise.inject.Produces; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.ParameterExpression; +import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import javax.transaction.Transactional; import de.symeda.sormas.backend.util.ModelConstants; -/** - * The class CurrentUserService. - */ @Stateless @LocalBean public class CurrentUserService { @@ -30,42 +27,58 @@ public class CurrentUserService { @PersistenceContext(unitName = ModelConstants.PERSISTENCE_UNIT_NAME) private EntityManager em; + private final UserCache userCache; + + public CurrentUserService() { + this.userCache = UserCache.getInstance(); + } + /** * Returns the User entity corresponding to the current user. - * - * @return */ - @Produces - @CurrentUserQualifier - @Transactional @RequestScoped // FIXME @TransactionScoped would be better for performance, but is not support by novatec.bean-test (see their github #4) - public CurrentUser getCurrentUser() { + public User getCurrentUser() { + final String currentUsername = context.getCallerPrincipal().getName(); + + User cachedUser = userCache.get(currentUsername); + if (cachedUser != null) { + return cachedUser; + } + + // todo prohibit these names + if (currentUsername.equals("ANONYMOUS") || currentUsername.equals("SYSTEM")) { + return null; + } - final String userName = context.getCallerPrincipal().getName(); - if (userName.equalsIgnoreCase("ANONYMOUS")) { - return new CurrentUser(null); + final User currentUser = fetchUser(currentUsername); + + if (currentUser == null) { + return null; + } else { + userCache.put(currentUsername, currentUser); + return currentUser; } + } + // We need a clean transaction as we do not want call potential entity listeners which would lead to recursion + @Transactional(Transactional.TxType.REQUIRES_NEW) + User fetchUser(String userName) { final CriteriaBuilder cb = em.getCriteriaBuilder(); final ParameterExpression userNameParam = cb.parameter(String.class, User.USER_NAME); final CriteriaQuery cq = cb.createQuery(User.class); - final Root from = cq.from(User.class); // avoid "Hibernate could not initialize proxy – no Session" Exception // do eager loading in this case - from.fetch(User.ADDRESS); + final Root user = cq.from(User.class); + user.fetch(User.ADDRESS); - // case-insensitive check - cq.where(cb.equal(cb.lower(from.get(User.USER_NAME)), userNameParam)); - final TypedQuery q = em.createQuery(cq).setParameter(userNameParam, userName.toLowerCase()); + final Predicate equal = cb.equal(cb.lower(user.get(User.USER_NAME)), userNameParam); + cq.select(user).distinct(true); + cq.where(equal); - final User user = q.getResultList().stream().findFirst().orElse(null); + final TypedQuery q = em.createQuery(cq).setParameter(userNameParam, userName.toLowerCase()); - if (user != null) { - return new CurrentUser(user); - } else { - return new CurrentUser(null); - } + return q.getResultList().stream().findFirst().orElse(null); } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/User.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/User.java index 26494b0b081..fe8121dc8bb 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/User.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/User.java @@ -27,6 +27,7 @@ import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Entity; +import javax.persistence.EntityListeners; import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.FetchType; @@ -57,6 +58,7 @@ @Entity(name = User.TABLE_NAME) @Audited +@EntityListeners(User.UserListener.class) public class User extends AbstractDomainObject { private static final long serialVersionUID = -629432920970152112L; @@ -377,4 +379,13 @@ public static String buildCaptionForNotification(User user) { } return caption; } + + static class UserListener { + + @PrePersist + @PreUpdate + private void beforeAnyUpdate(User user) { + UserCache.getInstance().remove(user.getUserName()); + } + } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserCache.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserCache.java new file mode 100644 index 00000000000..de0ae09f8b7 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserCache.java @@ -0,0 +1,55 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.symeda.sormas.backend.user; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * Create a mapping between the username provided by the session context and the actual DB entry to save round trips. + */ +public final class UserCache { + + private static UserCache instance; + + ConcurrentHashMap cache; + + private UserCache() { + cache = new ConcurrentHashMap<>(); + } + + public static synchronized UserCache getInstance() { + if (instance == null) { + instance = new UserCache(); + } + return instance; + } + + public void flush() { + cache.clear(); + } + + public void put(String name, User user) { + cache.put(name.toLowerCase(), user); + } + + public User get(String name) { + return cache.get(name.toLowerCase()); + } + + public void remove(String name) { + cache.remove(name.toLowerCase()); + } + +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserFacadeEjb.java index 084da585f75..c5c7ab0cd7d 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserFacadeEjb.java @@ -1,20 +1,17 @@ -/******************************************************************************* +/* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2018 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) - * + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - *******************************************************************************/ + */ package de.symeda.sormas.backend.user; import java.util.ArrayList; @@ -46,6 +43,7 @@ import javax.validation.Valid; import javax.validation.ValidationException; +import de.symeda.sormas.api.EntityDto; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Validations; import org.apache.commons.beanutils.BeanUtils; @@ -186,7 +184,6 @@ public static UserDto toDto(User source) { target.setLanguage(source.getLanguage()); target.setHasConsentedToGdpr(source.isHasConsentedToGdpr()); - source.getUserRoles().size(); target.setUserRoles(new HashSet<>(source.getUserRoles())); return target; } @@ -206,7 +203,6 @@ public static UserReferenceDto toReferenceDto(UserReference entity) { } private List toUuidList(HasUuid hasUuid) { - /* * Supports conversion of a null object into a list with one "null" value in it. * Uncertain if that use case exists, but wasn't suppose to be broken when replacing the Dto to Entity lookup. @@ -404,7 +400,7 @@ public List getUsersHavingCaseInJurisdiction(CaseReferenceDto caseJurisdictionSubquery.select(caseRoot) .where( cb.and( - cb.equal(caseRoot.get(Case.UUID), caseReferenceDto.getUuid()), + cb.equal(caseRoot.get(AbstractDomainObject.UUID), caseReferenceDto.getUuid()), cb.isTrue(caseJurisdictionPredicateValidator.inJurisdictionOrOwned()))); return caseJurisdictionSubquery; }); @@ -422,7 +418,7 @@ public List getUsersHavingContactInJurisdiction(ContactReferen contactJurisdictionSubquery.select(contactRoot) .where( cb.and( - cb.equal(contactRoot.get(Contact.UUID), contactReferenceDto.getUuid()), + cb.equal(contactRoot.get(AbstractDomainObject.UUID), contactReferenceDto.getUuid()), cb.isTrue(contactJurisdictionPredicateValidator.inJurisdictionOrOwned()))); return contactJurisdictionSubquery; }); @@ -441,7 +437,7 @@ public List getUsersHavingEventInJurisdiction(EventReferenceDt eventJurisdictionSubquery.select(eventRoot) .where( cb.and( - cb.equal(eventRoot.get(de.symeda.sormas.backend.event.Event.UUID), eventReferenceDto.getUuid()), + cb.equal(eventRoot.get(AbstractDomainObject.UUID), eventReferenceDto.getUuid()), cb.isTrue(eventJurisdictionPredicateValidator.inJurisdictionOrOwned()))); return eventJurisdictionSubquery; }); @@ -460,7 +456,7 @@ public List getUsersHavingTravelEntryInJurisdiction(TravelEntr travelEntrySubquery.select(travelEntryRoot) .where( cb.and( - cb.equal(travelEntryRoot.get(TravelEntry.UUID), travelEntryReferenceDto.getUuid()), + cb.equal(travelEntryRoot.get(AbstractDomainObject.UUID), travelEntryReferenceDto.getUuid()), cb.isTrue(travelEntryJurisdictionPredicateValidator.inJurisdictionOrOwned()))); return travelEntrySubquery; }); @@ -477,7 +473,7 @@ public List getUsersHavingE cq.where(CriteriaBuilderHelper.and(cb, cb.isTrue(root.get(User.ACTIVE)), cb.exists(subqueryBuilder.buildSubquery(cb, cq, root)))); cq.distinct(true); - cq.orderBy(cb.asc(root.get(User.ID))); + cq.orderBy(cb.asc(root.get(AbstractDomainObject.ID))); List resultList = em.createQuery(cq).setHint(ModelConstants.HINT_HIBERNATE_READ_ONLY, true).getResultList(); return resultList.stream().map(UserFacadeEjb::toReferenceDto).collect(Collectors.toList()); } @@ -591,7 +587,7 @@ public List getIndexList(UserCriteria userCriteria, Integer first, Inte for (SortProperty sortProperty : sortProperties) { Expression expression; switch (sortProperty.propertyName) { - case UserDto.UUID: + case EntityDto.UUID: case UserDto.ACTIVE: case UserDto.USER_NAME: case UserDto.USER_EMAIL: @@ -618,7 +614,7 @@ public List getIndexList(UserCriteria userCriteria, Integer first, Inte } cq.orderBy(order); } else { - cq.orderBy(cb.desc(user.get(User.CHANGE_DATE))); + cq.orderBy(cb.desc(user.get(AbstractDomainObject.CHANGE_DATE))); } cq.select(user); @@ -719,7 +715,7 @@ public void removeUserAsSurveillanceAndContactOfficer(String userUuid) { Root caseRoot = caseQuery.from(Case.class); Join surveillanceOfficerJoin = caseRoot.join(Case.SURVEILLANCE_OFFICER, JoinType.LEFT); - caseQuery.where(cb.equal(surveillanceOfficerJoin.get(User.UUID), userUuid)); + caseQuery.where(cb.equal(surveillanceOfficerJoin.get(AbstractDomainObject.UUID), userUuid)); List cases = em.createQuery(caseQuery).getResultList(); cases.forEach(c -> { c.setSurveillanceOfficer(null); @@ -732,7 +728,7 @@ public void removeUserAsSurveillanceAndContactOfficer(String userUuid) { Root contactRoot = contactQuery.from(Contact.class); Join contactOfficerJoin = contactRoot.join(Contact.CONTACT_OFFICER, JoinType.LEFT); - contactQuery.where(cb.equal(contactOfficerJoin.get(User.UUID), userUuid)); + contactQuery.where(cb.equal(contactOfficerJoin.get(AbstractDomainObject.UUID), userUuid)); List contacts = em.createQuery(contactQuery).getResultList(); contacts.forEach(c -> { c.setContactOfficer(null); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserService.java index c4c980b8e05..86f32e42c15 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserService.java @@ -86,11 +86,6 @@ public User createUser() { return user; } - @Override - public User getCurrentUser() { - return super.getCurrentUser(); - } - /** * Fetches a use from the DB by its username. The check is done case-insensitive. * diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java index 040d91f2110..644fa03d928 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/AbstractBeanTest.java @@ -33,12 +33,10 @@ import de.symeda.sormas.api.campaign.data.CampaignFormDataFacade; import de.symeda.sormas.api.campaign.diagram.CampaignDiagramDefinitionFacade; import de.symeda.sormas.api.campaign.form.CampaignFormMetaFacade; -import de.symeda.sormas.api.caze.CaseFacade; import de.symeda.sormas.api.caze.CaseStatisticsFacade; import de.symeda.sormas.api.caze.surveillancereport.SurveillanceReportFacade; import de.symeda.sormas.api.clinicalcourse.ClinicalCourseFacade; import de.symeda.sormas.api.clinicalcourse.ClinicalVisitFacade; -import de.symeda.sormas.api.contact.ContactFacade; import de.symeda.sormas.api.customizableenum.CustomizableEnumFacade; import de.symeda.sormas.api.dashboard.DashboardFacade; import de.symeda.sormas.api.disease.DiseaseConfigurationFacade; @@ -207,7 +205,6 @@ import de.symeda.sormas.backend.therapy.TreatmentFacadeEjb.TreatmentFacadeEjbLocal; import de.symeda.sormas.backend.therapy.TreatmentService; import de.symeda.sormas.backend.travelentry.TravelEntryFacadeEjb; -import de.symeda.sormas.backend.user.CurrentUser; import de.symeda.sormas.backend.user.CurrentUserService; import de.symeda.sormas.backend.user.UserFacadeEjb.UserFacadeEjbLocal; import de.symeda.sormas.backend.user.UserRightsFacadeEjb.UserRightsFacadeEjbLocal; @@ -674,8 +671,6 @@ protected UserDto useNationalUserLogin() { protected void loginWith(UserDto user) { when(MockProducer.getPrincipal().getName()).thenReturn(user.getUserName()); - final CurrentUser currentUser = getCurrentUserService().getCurrentUser(); - getUserService().setCurrentUser(currentUser.getUser()); } public PathogenTestService getPathogenTestService() { diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/AbstractBeanTest.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/AbstractBeanTest.java index 9f3a0f8c153..96c7001f0ad 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/AbstractBeanTest.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/AbstractBeanTest.java @@ -78,7 +78,6 @@ import de.symeda.sormas.backend.sample.PathogenTestFacadeEjb; import de.symeda.sormas.backend.sample.SampleFacadeEjb; import de.symeda.sormas.backend.travelentry.TravelEntryFacadeEjb; -import de.symeda.sormas.backend.user.CurrentUser; import de.symeda.sormas.backend.user.CurrentUserService; import de.symeda.sormas.backend.user.UserService; import info.novatec.beantest.api.BaseBeanTest; @@ -217,7 +216,5 @@ public CSVReader getCsvReader(InputStream inputStream) { protected void loginWith(UserDto user) { when(MockProducer.getPrincipal().getName()).thenReturn(user.getUserName()); - final CurrentUser currentUser = getCurrentUserService().getCurrentUser(); - getUserService().setCurrentUser(currentUser.getUser()); } } From 4083432ee696791287a86644ee7e916f41a70f5c Mon Sep 17 00:00:00 2001 From: Stefan Kock Date: Tue, 15 Feb 2022 11:06:43 +0100 Subject: [PATCH 085/253] #6830: Update poi-ooxml 3.17 -> 5.2.0 Fixed breaking changes: - color definition not with awt, directly with rgb colors (new helper) - table configuration after filling cells with reference (new helper) Refactorings along the way: - Suppressed a warning locally - Added a private constructor for helper class - Removed commented code in Generator class --- .../sormas/backend/info/InfoFacadeEjb.java | 47 +++++-------------- .../backend/user/UserRightsFacadeEjb.java | 26 +++++----- .../sormas/backend/util/XssfHelper.java | 32 +++++++++++++ .../backend/doc/UserRightsGenerator.java | 2 - sormas-base/pom.xml | 2 +- 5 files changed, 61 insertions(+), 48 deletions(-) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/info/InfoFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/info/InfoFacadeEjb.java index 0d128ff0983..06d86f176c7 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/info/InfoFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/info/InfoFacadeEjb.java @@ -46,7 +46,6 @@ import org.apache.poi.xssf.usermodel.XSSFCell; import org.apache.poi.xssf.usermodel.XSSFRow; import org.apache.poi.xssf.usermodel.XSSFSheet; -import org.apache.poi.xssf.usermodel.XSSFTable; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import de.symeda.sormas.api.EntityDto; @@ -251,31 +250,23 @@ private void createEntitySheet( EnumSet entityColumns, List extraColumns, Map> extraCells) { + String name = I18nProperties.getCaption(i18nPrefix); String safeName = WorkbookUtil.createSafeSheetName(name); XSSFSheet sheet = workbook.createSheet(safeName); - // Create - XSSFTable table = sheet.createTable(); - String safeTableName = getSafeTableName(safeName); - table.setName(safeTableName); - table.setDisplayName(safeTableName); - - XssfHelper.styleTable(table, 1); - int columnCount = entityColumns.size() + extraColumns.size(); int rowNumber = 0; + // header XSSFRow headerRow = sheet.createRow(rowNumber++); entityColumns.forEach(column -> { - table.addColumn(); int colIndex = Math.max(headerRow.getLastCellNum(), 0); headerRow.createCell(colIndex).setCellValue(column.toString()); sheet.setColumnWidth(colIndex, column.getWidth()); }); extraColumns.forEach(c -> { - table.addColumn(); short colIndex = headerRow.getLastCellNum(); headerRow.createCell(colIndex).setCellValue(c.header); sheet.setColumnWidth(colIndex, c.width); @@ -310,7 +301,9 @@ private void createEntitySheet( Class fieldType = field.getType(); if (fieldType.isEnum()) { if (!usedEnums.contains(fieldType)) { - usedEnums.add((Class>) fieldType); + @SuppressWarnings("unchecked") + Class> enumType = (Class>) fieldType; + usedEnums.add(enumType); } } else if (FacilityReferenceDto.class.isAssignableFrom(fieldType)) { usesFacilityReference = true; @@ -328,10 +321,10 @@ private void createEntitySheet( } } + // Configure table AreaReference reference = workbook.getCreationHelper().createAreaReference(new CellReference(0, 0), new CellReference(rowNumber - 1, columnCount - 1)); - table.setCellReferences(reference); - table.getCTTable().addNewAutoFilter(); + XssfHelper.configureTable(reference, getSafeTableName(safeName), sheet, XssfHelper.TABLE_STYLE_PRIMARY); // constant facilities if (usesFacilityReference) { @@ -347,13 +340,6 @@ private void createEntitySheet( private int createFacilityTable(XSSFSheet sheet, int startRow, CellStyle defaultCellStyle) { - // Create - XSSFTable table = sheet.createTable(); - String safeTableName = getSafeTableName(sheet.getSheetName() + DataHelper.getHumanClassName(FacilityReferenceDto.class)); - table.setName(safeTableName); - table.setDisplayName(safeTableName); - XssfHelper.styleTable(table, 2); - int columnCount = EnumColumn.values().length - 1; int rowNumber = startRow; @@ -363,7 +349,6 @@ private int createFacilityTable(XSSFSheet sheet, int startRow, CellStyle default if (EnumColumn.SHORT.equals(column)) { continue; } - table.addColumn(); String columnCaption = column.toString(); columnCaption = columnCaption.charAt(0) + columnCaption.substring(1).toLowerCase(); headerRow.createCell(column.ordinal()).setCellValue(columnCaption); @@ -392,10 +377,11 @@ private int createFacilityTable(XSSFSheet sheet, int startRow, CellStyle default cell.setCellValue(DataHelper.equal(caption, desc) ? "" : desc); } + // Configure table AreaReference reference = new AreaReference(new CellReference(startRow, 0), new CellReference(rowNumber - 1, columnCount - 1), SpreadsheetVersion.EXCEL2007); - table.setCellReferences(reference); - table.getCTTable().addNewAutoFilter(); + String safeTableName = getSafeTableName(sheet.getSheetName() + DataHelper.getHumanClassName(FacilityReferenceDto.class)); + XssfHelper.configureTable(reference, safeTableName, sheet, XssfHelper.TABLE_STYLE_SECONDARY); return rowNumber; } @@ -415,20 +401,12 @@ public String toString() { private int createEnumTable(XSSFSheet sheet, int startRow, Class> enumType) { - // Create - XSSFTable table = sheet.createTable(); - String safeTableName = getSafeTableName(sheet.getSheetName() + enumType.getSimpleName()); - table.setName(safeTableName); - table.setDisplayName(safeTableName); - XssfHelper.styleTable(table, 2); - int columnCount = EnumColumn.values().length; int rowNumber = startRow; // header XSSFRow headerRow = sheet.createRow(rowNumber++); for (EnumColumn column : EnumColumn.values()) { - table.addColumn(); String columnCaption = column.toString(); columnCaption = columnCaption.charAt(0) + columnCaption.substring(1).toLowerCase(); headerRow.createCell(column.ordinal()).setCellValue(columnCaption); @@ -461,10 +439,11 @@ private int createEnumTable(XSSFSheet sheet, int startRow, Class> enumTy cell.setCellValue(DataHelper.equal(caption, shortCaption) ? "" : shortCaption); } + // Configure table AreaReference reference = new AreaReference(new CellReference(startRow, 0), new CellReference(rowNumber - 1, columnCount - 1), SpreadsheetVersion.EXCEL2007); - table.setCellReferences(reference); - table.getCTTable().addNewAutoFilter(); + String safeTableName = getSafeTableName(sheet.getSheetName() + enumType.getSimpleName()); + XssfHelper.configureTable(reference, safeTableName, sheet, XssfHelper.TABLE_STYLE_SECONDARY); return rowNumber; } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserRightsFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserRightsFacadeEjb.java index d25dc5accc8..b8b35b30aaa 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserRightsFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserRightsFacadeEjb.java @@ -15,7 +15,6 @@ package de.symeda.sormas.backend.user; -import java.awt.*; import java.io.IOException; import java.io.OutputStream; import java.nio.file.Files; @@ -89,31 +88,36 @@ private void generateUserRightsDocument(Map> userRoleRi String safeName = WorkbookUtil.createSafeSheetName(I18nProperties.getCaption(Captions.userRights)); XSSFSheet sheet = workbook.createSheet(safeName); + // Define colors + final XSSFColor green = XssfHelper.createColor(0, 153, 0); + final XSSFColor red = XssfHelper.createColor(255, 0, 0); + final XSSFColor black = XssfHelper.createColor(0, 0, 0); + // Initialize cell styles // Authorized style XSSFCellStyle authorizedStyle = workbook.createCellStyle(); authorizedStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); - authorizedStyle.setFillForegroundColor(new XSSFColor(new Color(0, 153, 0))); + authorizedStyle.setFillForegroundColor(green); authorizedStyle.setBorderBottom(BorderStyle.THIN); authorizedStyle.setBorderLeft(BorderStyle.THIN); authorizedStyle.setBorderTop(BorderStyle.THIN); authorizedStyle.setBorderRight(BorderStyle.THIN); - authorizedStyle.setBorderColor(BorderSide.BOTTOM, new XSSFColor(Color.BLACK)); - authorizedStyle.setBorderColor(BorderSide.LEFT, new XSSFColor(Color.BLACK)); - authorizedStyle.setBorderColor(BorderSide.TOP, new XSSFColor(Color.BLACK)); - authorizedStyle.setBorderColor(BorderSide.RIGHT, new XSSFColor(Color.BLACK)); + authorizedStyle.setBorderColor(BorderSide.BOTTOM, black); + authorizedStyle.setBorderColor(BorderSide.LEFT, black); + authorizedStyle.setBorderColor(BorderSide.TOP, black); + authorizedStyle.setBorderColor(BorderSide.RIGHT, black); // Unauthorized style XSSFCellStyle unauthorizedStyle = workbook.createCellStyle(); unauthorizedStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); - unauthorizedStyle.setFillForegroundColor(new XSSFColor(Color.RED)); + unauthorizedStyle.setFillForegroundColor(red); unauthorizedStyle.setBorderBottom(BorderStyle.THIN); unauthorizedStyle.setBorderLeft(BorderStyle.THIN); unauthorizedStyle.setBorderTop(BorderStyle.THIN); unauthorizedStyle.setBorderRight(BorderStyle.THIN); - unauthorizedStyle.setBorderColor(BorderSide.BOTTOM, new XSSFColor(Color.BLACK)); - unauthorizedStyle.setBorderColor(BorderSide.LEFT, new XSSFColor(Color.BLACK)); - unauthorizedStyle.setBorderColor(BorderSide.TOP, new XSSFColor(Color.BLACK)); - unauthorizedStyle.setBorderColor(BorderSide.RIGHT, new XSSFColor(Color.BLACK)); + unauthorizedStyle.setBorderColor(BorderSide.BOTTOM, black); + unauthorizedStyle.setBorderColor(BorderSide.LEFT, black); + unauthorizedStyle.setBorderColor(BorderSide.TOP, black); + unauthorizedStyle.setBorderColor(BorderSide.RIGHT, black); // Bold style XSSFFont boldFont = workbook.createFont(); boldFont.setBold(true); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/util/XssfHelper.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/util/XssfHelper.java index ea74b48963a..5c434b9f260 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/util/XssfHelper.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/util/XssfHelper.java @@ -14,7 +14,10 @@ */ package de.symeda.sormas.backend.util; +import org.apache.poi.ss.util.AreaReference; +import org.apache.poi.xssf.usermodel.DefaultIndexedColorMap; import org.apache.poi.xssf.usermodel.XSSFCell; +import org.apache.poi.xssf.usermodel.XSSFColor; import org.apache.poi.xssf.usermodel.XSSFRow; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFTable; @@ -25,6 +28,24 @@ public final class XssfHelper { + private XssfHelper() { + // Hide utility class constructor + } + + public static final int TABLE_STYLE_PRIMARY = 1; + public static final int TABLE_STYLE_SECONDARY = 2; + + public static XSSFTable configureTable(AreaReference reference, String safeTableName, XSSFSheet sheet, int styleNumber) { + + XSSFTable table = sheet.createTable(reference); + table.setName(safeTableName); + table.setDisplayName(safeTableName); + XssfHelper.styleTable(table, styleNumber); + table.getCTTable().addNewAutoFilter(); + + return table; + } + public static void styleTable(XSSFTable table, int styleNumber) { // Style the table - can this be simplified? @@ -50,4 +71,15 @@ public static void addAboutSheet(XSSFWorkbook workbook) { cell = row.createCell(0); cell.setCellValue(InfoProvider.get().getVersion()); } + + public static final XSSFColor createColor(int red, int green, int blue) { + + byte[] rgb = new byte[3]; + rgb[0] = (byte) red; + rgb[1] = (byte) green; + rgb[2] = (byte) blue; + + XSSFColor color = new XSSFColor(rgb, new DefaultIndexedColorMap()); + return color; + } } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/doc/UserRightsGenerator.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/doc/UserRightsGenerator.java index 89066bf8c53..56d4f3b9302 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/doc/UserRightsGenerator.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/doc/UserRightsGenerator.java @@ -39,7 +39,5 @@ public void generateUserRights() throws IOException { String documentPath = getUserRightsFacade().generateUserRightsDocument(false); Files.copy(Paths.get(documentPath), output.toPath(), StandardCopyOption.REPLACE_EXISTING); - -// Desktop.getDesktop().open(new File(filePath)); } } diff --git a/sormas-base/pom.xml b/sormas-base/pom.xml index 76e183d75a7..f241a14146a 100644 --- a/sormas-base/pom.xml +++ b/sormas-base/pom.xml @@ -791,7 +791,7 @@ org.apache.poi poi-ooxml - 3.17 + 5.2.0 From 6ad243dacc5c09e1082f315f19294d6957ffd331 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Tue, 15 Feb 2022 12:24:15 +0100 Subject: [PATCH 086/253] Test scenarios for event group screen --- .../events/EventDirectoryPage.java | 16 ++++------ .../webdriver/RemoteDriverFactory.java | 4 +-- .../events/EventDirectorySteps.java | 30 ++++++++----------- .../features/sanity/web/Event.feature | 6 ++-- 4 files changed, 24 insertions(+), 32 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java index 45e6393b3ef..9c1c2b621b1 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java @@ -59,19 +59,15 @@ public class EventDirectoryPage { public static final By UNLINK_EVENT_BUTTON = By.id("unlink-event-0"); public static final By ID_FIELD_FILTER = By.id("search"); public static final By LINKED_EVENT_GROUP_ID = - By.xpath( - "/html/body/div[1]/div/div[2]/div/div[2]/div/div/div[3]/div/div/div/div/div[8]/div/div[2]/div/div/div/div/div/div/div[1]/div/div/div/div/div/div/div[2]/div/div[2]/div/div/div"); - public static final By SAVE_BUTTON_IN_LINK_FORM = - By.xpath("/html/body/div[2]/div[3]/div/div/div[3]/div/div/div[2]/div/div/div[3]/div"); - public static final By FILTERED_EVENT_LINK_EVENT_FORM = - By.xpath( - "//*[@id=\"sormasui-1655777373-overlays\"]/div[3]/div/div/div[3]/div/div/div[1]/div/div[2]/div/div/div[5]/div/div[3]/table/tbody/tr[1]/td[1]"); - public static final By FIRST_EVENT_GROUP = - By.xpath( - "/html/body/div[2]/div[3]/div/div/div[3]/div/div/div[1]/div/div[2]/div/div/div[7]/div/div[3]/table/tbody/tr[1]/td[1]"); + By.xpath("//div[@location = 'event-groups']//div[contains(@class, 'v-slot')]//a"); + public static final By SAVE_BUTTON_IN_LINK_FORM = By.cssSelector(".popupContent #commit"); + public static final By FILTERED_EVENT_LINK_EVENT_FORM = By.xpath("//tr[@role='row']"); + public static final By FIRST_EVENT_GROUP = By.xpath("//tr[@role='row']"); /*public static By getByEventUuid(String eventUuid) { return By.cssSelector("a[title=" + eventUuid + "]"); }*/ + + public static final By EVENT_GROUP_ID_IN_GRID = By.xpath("//tr[@role='row']//td[15]/a"); public static final By FIRST_EVENT_ID_BUTTON = By.cssSelector(".v-grid-row-has-data a[title]"); public static final By CREATE_CASE_BUTTON = By.xpath("//td//span[contains(@class, 'v-icon-edit')]"); diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/RemoteDriverFactory.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/RemoteDriverFactory.java index 88350df2699..ba427b86a3f 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/RemoteDriverFactory.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/RemoteDriverFactory.java @@ -53,7 +53,7 @@ public RemoteDriverFactory( @Override public ChromeDriver getRemoteWebDriver() { log.info("Setting Chrome Driver's path"); - System.setProperty("webdriver.chrome.driver", "/usr/lib64/chromium-browser/chromedriver"); + System.setProperty("webdriver.chrome.driver", "C:\\chromedriver_win32\\chromedriver.exe"); log.info("Adding all chrome preferences"); final ChromeOptions options = new ChromeOptions(); final HashMap chromePreferences = new HashMap<>(); @@ -62,7 +62,7 @@ public ChromeDriver getRemoteWebDriver() { options.addArguments("--no-default-browser-check"); options.setUnhandledPromptBehaviour(UnexpectedAlertBehaviour.IGNORE); options.addArguments("disable-infobars"); - options.addArguments("--headless"); + // options.addArguments("--headless"); options.addArguments("enable-automation"); options.addArguments("--no-sandbox"); options.addArguments("--disable-browser-side-navigation"); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index c350a5c2416..f63d71f2b5b 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -27,6 +27,7 @@ import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.CREATED_PARTICIPANT; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.CREATE_CASE_BUTTON; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENTS_RADIO_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_GROUP_ID_IN_GRID; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_STATUS_FILTER_BUTTONS; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTERED_EVENT_LINK_EVENT_FORM; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_DISEASE; @@ -53,7 +54,6 @@ import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.inject.Named; -import org.openqa.selenium.By; import org.sormas.e2etests.common.DataOperations; import org.sormas.e2etests.enums.DiseasesValues; import org.sormas.e2etests.enums.RiskLevelValues; @@ -124,10 +124,7 @@ public EventDirectorySteps( () -> webDriverHelpers.clickOnWebElementBySelector(LINKED_EVENT_GROUP_ID)); When( "^I click on Group Id in Events result on Event Directory Page$", - () -> - webDriverHelpers.clickOnWebElementBySelector( - By.xpath( - "/html/body/div[1]/div/div[2]/div/div[2]/div/div/div/div[2]/div/div/div[3]/div/div[3]/table/tbody/tr/td[15]"))); + () -> webDriverHelpers.clickOnWebElementBySelector(EVENT_GROUP_ID_IN_GRID)); When( "I click on the NEW EVENT button", @@ -322,9 +319,8 @@ public EventDirectorySteps( When( "I click on the created event participant from the list", - () -> { - webDriverHelpers.clickOnWebElementBySelector(CREATED_PARTICIPANT); - }); + () -> + webDriverHelpers.clickOnWebElementBySelector(CREATED_PARTICIPANT)); When( "I click on New Task from event tab", @@ -338,15 +334,15 @@ public EventDirectorySteps( "I click Create Case for Event Participant", () -> webDriverHelpers.clickOnWebElementBySelector(CREATE_CASE_BUTTON)); - Then( - "I check that number of displayed Event results is {int}", - (Integer number) -> - assertHelpers.assertWithPoll20Second( - () -> - Assert.assertEquals( - webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), - number.intValue(), - "Number of displayed cases is not correct"))); + Then( + "I check that number of displayed Event results is {int}", + (Integer number) -> + assertHelpers.assertWithPoll20Second( + () -> + Assert.assertEquals( + webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), + number.intValue(), + "Number of displayed cases is not correct"))); Then( "I check the number of displayed Event results from All button is {int}", diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature index 317e91f9895..2cde902d6bb 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature @@ -236,7 +236,7 @@ Feature: Create events And I click on the RESET FILTERS button @issue=SORDEV-5571 - Scenario: Event group screen + Scenario: Event group screen from Event Directory Page Given API: I create a new event Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 @@ -251,7 +251,7 @@ Feature: Create events And I click on Unlink Event button on Event Directory Page @issue=SORDEV-5571 - Scenario: Event group screens + Scenario: Event group screen using Group Id on Edit Event Page Given API: I create a new event Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 @@ -267,7 +267,7 @@ Feature: Create events And I click on Unlink Event button on Event Directory Page @issue=SORDEV-5571 - Scenario: Event group screenss + Scenario: Event group screen using Group Id in grid Given API: I create a new event Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 From 76b3276766bb2131bb449ac67419aeb531b5588c Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Tue, 15 Feb 2022 12:31:41 +0100 Subject: [PATCH 087/253] remote driver fix --- .../org/sormas/e2etests/webdriver/RemoteDriverFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/RemoteDriverFactory.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/RemoteDriverFactory.java index ba427b86a3f..88350df2699 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/RemoteDriverFactory.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/RemoteDriverFactory.java @@ -53,7 +53,7 @@ public RemoteDriverFactory( @Override public ChromeDriver getRemoteWebDriver() { log.info("Setting Chrome Driver's path"); - System.setProperty("webdriver.chrome.driver", "C:\\chromedriver_win32\\chromedriver.exe"); + System.setProperty("webdriver.chrome.driver", "/usr/lib64/chromium-browser/chromedriver"); log.info("Adding all chrome preferences"); final ChromeOptions options = new ChromeOptions(); final HashMap chromePreferences = new HashMap<>(); @@ -62,7 +62,7 @@ public ChromeDriver getRemoteWebDriver() { options.addArguments("--no-default-browser-check"); options.setUnhandledPromptBehaviour(UnexpectedAlertBehaviour.IGNORE); options.addArguments("disable-infobars"); - // options.addArguments("--headless"); + options.addArguments("--headless"); options.addArguments("enable-automation"); options.addArguments("--no-sandbox"); options.addArguments("--disable-browser-side-navigation"); From 308a9380c450a7efe08a3edccbf0012bd89878b8 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Wed, 16 Feb 2022 08:51:01 +0200 Subject: [PATCH 088/253] #6879 - fix unit tests --- .../de/symeda/sormas/app/CaseBackendTest.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/CaseBackendTest.java b/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/CaseBackendTest.java index e187424d0c2..63180339285 100644 --- a/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/CaseBackendTest.java +++ b/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/CaseBackendTest.java @@ -23,19 +23,19 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; -import java.sql.SQLException; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import androidx.test.rule.ActivityTestRule; +import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import androidx.test.rule.ActivityTestRule; -import androidx.test.runner.AndroidJUnit4; +import java.sql.SQLException; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import de.symeda.sormas.api.caze.CaseClassification; import de.symeda.sormas.api.caze.CaseDataDto; @@ -154,6 +154,7 @@ public void shouldMergeAsExpected() throws DaoException { mergeCase.getPortHealthInfo().setId(null); mergeCase.getTherapy().setId(null); mergeCase.getClinicalCourse().getHealthConditions().setId(null); + mergeCase.getHealthConditions().setId(null); mergeCase.getMaternalHistory().setId(null); mergeCase.setEpidNumber("ServerEpidNumber"); @@ -254,6 +255,7 @@ public void shouldCreateSyncLogEntry() throws DaoException { mergeCase.getPortHealthInfo().setId(null); mergeCase.getTherapy().setId(null); mergeCase.getClinicalCourse().getHealthConditions().setId(null); + mergeCase.getHealthConditions().setId(null); mergeCase.getMaternalHistory().setId(null); mergeCase.setEpidNumber("ServerEpidNumber"); From 1cb34bce9d43ab7f51442e73618fa80436b71fb9 Mon Sep 17 00:00:00 2001 From: Frank Hautpmann Date: Wed, 16 Feb 2022 11:10:12 +0100 Subject: [PATCH 089/253] New Crowdin updates (#7908) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * New translations enum.properties (Urdu (Pakistan)) * New translations enum.properties (Spanish, Cuba) * New translations validations.properties (Urdu (Pakistan)) * New translations descriptions.properties (Urdu (Pakistan)) * New translations enum.properties (Romanian) * New translations enum.properties (Spanish) * New translations enum.properties (Czech) * New translations enum.properties (Finnish) * New translations enum.properties (Chinese Simplified) * New translations enum.properties (Italian) * New translations enum.properties (Japanese) * New translations enum.properties (Dutch) * New translations enum.properties (Norwegian) * New translations enum.properties (Polish) * New translations enum.properties (Portuguese) * New translations enum.properties (Russian) * New translations enum.properties (Swedish) * New translations enum.properties (Turkish) * New translations enum.properties (Ukrainian) * New translations strings.properties (Swedish) * New translations strings.properties (Turkish) * New translations strings.properties (Italian, Switzerland) * New translations captions.properties (German, Switzerland) * New translations captions.properties (French) * New translations captions.properties (German) * New translations strings.properties (English, Ghana) * New translations strings.properties (English, Nigeria) * New translations strings.properties (English, Afghanistan) * New translations strings.properties (Spanish, Cuba) * New translations strings.properties (Pashto) * New translations strings.properties (Dari) * New translations strings.properties (French, Switzerland) * New translations strings.properties (Ukrainian) * New translations strings.properties (German, Switzerland) * New translations strings.properties (Swahili) * New translations strings.properties (Fijian) * New translations strings.properties (Filipino) * New translations strings.properties (Hindi) * New translations strings.properties (Croatian) * New translations strings.properties (Spanish, Ecuador) * New translations strings.properties (Urdu (Pakistan)) * New translations strings.properties (Chinese Simplified) * New translations captions.properties (Spanish, Cuba) * New translations captions.properties (Urdu (Pakistan)) * New translations strings.properties (Spanish) * New translations enum.properties (Swahili) * New translations enum.properties (French, Switzerland) * New translations enum.properties (Italian, Switzerland) * New translations enum.properties (Dari) * New translations enum.properties (Pashto) * New translations enum.properties (English, Afghanistan) * New translations enum.properties (English, Nigeria) * New translations enum.properties (English, Ghana) * New translations strings.properties (Romanian) * New translations strings.properties (Czech) * New translations enum.properties (Filipino) * New translations strings.properties (Finnish) * New translations strings.properties (Italian) * New translations strings.properties (Japanese) * New translations strings.properties (Dutch) * New translations strings.properties (Norwegian) * New translations strings.properties (Polish) * New translations strings.properties (Portuguese) * New translations strings.properties (Russian) * New translations strings.properties (Swedish) * New translations strings.properties (Turkish) * New translations enum.properties (Fijian) * New translations enum.properties (Hindi) * New translations enum.properties (German, Switzerland) * New translations enum.properties (Italian) * New translations strings.properties (French) * New translations strings.properties (German) * New translations enum.properties (French) * New translations enum.properties (Urdu (Pakistan)) * New translations enum.properties (Spanish, Cuba) * New translations enum.properties (Romanian) * New translations enum.properties (Spanish) * New translations enum.properties (Czech) * New translations enum.properties (German) * New translations enum.properties (Finnish) * New translations enum.properties (Japanese) * New translations enum.properties (Croatian) * New translations enum.properties (Dutch) * New translations enum.properties (Norwegian) * New translations enum.properties (Polish) * New translations enum.properties (Portuguese) * New translations enum.properties (Russian) * New translations enum.properties (Swedish) * New translations enum.properties (Turkish) * New translations enum.properties (Ukrainian) * New translations enum.properties (Chinese Simplified) * New translations enum.properties (Spanish, Ecuador) * New translations strings.properties (Ukrainian) * New translations strings.properties (Chinese Simplified) * New translations captions.properties (Hindi) * New translations captions.properties (Polish) * New translations captions.properties (Portuguese) * New translations captions.properties (Russian) * New translations captions.properties (Swedish) * New translations captions.properties (Turkish) * New translations captions.properties (Ukrainian) * New translations captions.properties (Chinese Simplified) * New translations captions.properties (Spanish, Ecuador) * New translations captions.properties (Croatian) * New translations captions.properties (Filipino) * New translations captions.properties (Dutch) * New translations captions.properties (Fijian) * New translations captions.properties (Swahili) * New translations captions.properties (German, Switzerland) * New translations captions.properties (French, Switzerland) * New translations captions.properties (Italian, Switzerland) * New translations captions.properties (Dari) * New translations captions.properties (Pashto) * New translations captions.properties (Spanish, Cuba) * New translations captions.properties (English, Afghanistan) * New translations captions.properties (English, Nigeria) * New translations captions.properties (Norwegian) * New translations captions.properties (Japanese) * New translations strings.properties (Urdu (Pakistan)) * New translations strings.properties (Dari) * New translations strings.properties (Spanish, Ecuador) * New translations strings.properties (Croatian) * New translations strings.properties (Hindi) * New translations strings.properties (Filipino) * New translations strings.properties (Fijian) * New translations strings.properties (Swahili) * New translations strings.properties (German, Switzerland) * New translations strings.properties (French, Switzerland) * New translations strings.properties (Italian, Switzerland) * New translations strings.properties (Pashto) * New translations captions.properties (Italian) * New translations strings.properties (Spanish, Cuba) * New translations strings.properties (English, Afghanistan) * New translations strings.properties (English, Nigeria) * New translations strings.properties (English, Ghana) * New translations captions.properties (German) * New translations captions.properties (Romanian) * New translations captions.properties (French) * New translations captions.properties (Spanish) * New translations captions.properties (Czech) * New translations captions.properties (Finnish) * New translations captions.properties (English, Ghana) * New translations enum.properties (German, Switzerland) * New translations strings.properties (German, Switzerland) * New translations captions.properties (German, Switzerland) * New translations strings.properties (French) * New translations validations.properties (Czech) * New translations strings.properties (Dari) * New translations strings.properties (Pashto) * New translations strings.properties (Spanish, Cuba) * New translations strings.properties (English, Afghanistan) * New translations strings.properties (English, Nigeria) * New translations strings.properties (English, Ghana) * New translations validations.properties (Romanian) * New translations validations.properties (French) * New translations validations.properties (Spanish) * New translations validations.properties (German) * New translations strings.properties (French, Switzerland) * New translations validations.properties (Finnish) * New translations validations.properties (Italian) * New translations validations.properties (Japanese) * New translations validations.properties (Dutch) * New translations validations.properties (Norwegian) * New translations validations.properties (Polish) * New translations validations.properties (Portuguese) * New translations validations.properties (Russian) * New translations validations.properties (Swedish) * New translations validations.properties (Turkish) * New translations strings.properties (Italian, Switzerland) * New translations strings.properties (German, Switzerland) * New translations strings.properties (German) * New translations strings.properties (Portuguese) * New translations validations.properties (Urdu (Pakistan)) * New translations strings.properties (Romanian) * New translations strings.properties (Spanish) * New translations strings.properties (Czech) * New translations strings.properties (Finnish) * New translations strings.properties (Italian) * New translations strings.properties (Japanese) * New translations strings.properties (Dutch) * New translations strings.properties (Norwegian) * New translations strings.properties (Polish) * New translations strings.properties (Russian) * New translations strings.properties (Swahili) * New translations strings.properties (Swedish) * New translations strings.properties (Turkish) * New translations strings.properties (Ukrainian) * New translations strings.properties (Chinese Simplified) * New translations strings.properties (Urdu (Pakistan)) * New translations strings.properties (Spanish, Ecuador) * New translations strings.properties (Croatian) * New translations strings.properties (Hindi) * New translations strings.properties (Filipino) * New translations strings.properties (Fijian) * New translations validations.properties (Ukrainian) * New translations validations.properties (Chinese Simplified) * New translations validations.properties (Spanish, Ecuador) * New translations validations.properties (Croatian) * New translations validations.properties (Hindi) * New translations validations.properties (Filipino) * New translations validations.properties (Fijian) * New translations validations.properties (Swahili) * New translations validations.properties (German, Switzerland) * New translations validations.properties (French, Switzerland) * New translations validations.properties (Italian, Switzerland) * New translations validations.properties (Dari) * New translations validations.properties (Pashto) * New translations validations.properties (Spanish, Cuba) * New translations validations.properties (English, Afghanistan) * New translations validations.properties (English, Nigeria) * New translations validations.properties (English, Ghana) * New translations strings.properties (French) * New translations enum.properties (French) * New translations strings.properties (German, Switzerland) * New translations strings.properties (Spanish, Cuba) * New translations captions.properties (Norwegian) * New translations captions.properties (Romanian) * New translations captions.properties (French) * New translations captions.properties (Spanish) * New translations captions.properties (Czech) * New translations captions.properties (Finnish) * New translations captions.properties (Italian) * New translations captions.properties (Japanese) * New translations captions.properties (Dutch) * New translations captions.properties (German) * New translations captions.properties (Dari) * New translations captions.properties (German, Switzerland) * New translations captions.properties (French, Switzerland) * New translations captions.properties (Italian, Switzerland) * New translations captions.properties (Urdu (Pakistan)) * New translations captions.properties (Pashto) * New translations captions.properties (Spanish, Cuba) * New translations captions.properties (English, Afghanistan) * New translations captions.properties (English, Nigeria) * New translations captions.properties (Fijian) * New translations captions.properties (Swahili) * New translations captions.properties (Ukrainian) * New translations captions.properties (Filipino) * New translations captions.properties (Hindi) * New translations captions.properties (Croatian) * New translations captions.properties (Spanish, Ecuador) * New translations captions.properties (Chinese Simplified) * New translations captions.properties (Turkish) * New translations captions.properties (Swedish) * New translations captions.properties (Russian) * New translations captions.properties (Portuguese) * New translations captions.properties (Polish) * New translations captions.properties (English, Ghana) Co-authored-by: Maté Strysewske --- .../main/resources/captions_cs-CZ.properties | 37 +++++++++++-------- .../main/resources/captions_de-CH.properties | 37 +++++++++++-------- .../main/resources/captions_de-DE.properties | 37 +++++++++++-------- .../main/resources/captions_en-AF.properties | 37 +++++++++++-------- .../main/resources/captions_en-GH.properties | 37 +++++++++++-------- .../main/resources/captions_en-NG.properties | 37 +++++++++++-------- .../main/resources/captions_es-CU.properties | 37 +++++++++++-------- .../main/resources/captions_es-EC.properties | 37 +++++++++++-------- .../main/resources/captions_es-ES.properties | 37 +++++++++++-------- .../main/resources/captions_fa-AF.properties | 37 +++++++++++-------- .../main/resources/captions_fi-FI.properties | 37 +++++++++++-------- .../main/resources/captions_fil-PH.properties | 37 +++++++++++-------- .../main/resources/captions_fj-FJ.properties | 37 +++++++++++-------- .../main/resources/captions_fr-CH.properties | 37 +++++++++++-------- .../main/resources/captions_fr-FR.properties | 37 +++++++++++-------- .../main/resources/captions_hi-IN.properties | 37 +++++++++++-------- .../main/resources/captions_hr-HR.properties | 37 +++++++++++-------- .../main/resources/captions_it-CH.properties | 37 +++++++++++-------- .../main/resources/captions_it-IT.properties | 37 +++++++++++-------- .../main/resources/captions_ja-JP.properties | 37 +++++++++++-------- .../main/resources/captions_nl-NL.properties | 37 +++++++++++-------- .../main/resources/captions_no-NO.properties | 37 +++++++++++-------- .../main/resources/captions_pl-PL.properties | 37 +++++++++++-------- .../main/resources/captions_ps-AF.properties | 37 +++++++++++-------- .../main/resources/captions_pt-PT.properties | 37 +++++++++++-------- .../main/resources/captions_ro-RO.properties | 37 +++++++++++-------- .../main/resources/captions_ru-RU.properties | 37 +++++++++++-------- .../main/resources/captions_sv-SE.properties | 37 +++++++++++-------- .../main/resources/captions_sw-KE.properties | 37 +++++++++++-------- .../main/resources/captions_tr-TR.properties | 37 +++++++++++-------- .../main/resources/captions_uk-UA.properties | 37 +++++++++++-------- .../main/resources/captions_ur-PK.properties | 35 +++++++++++------- .../main/resources/captions_zh-CN.properties | 37 +++++++++++-------- .../src/main/resources/enum_fr-FR.properties | 4 +- .../main/resources/strings_cs-CZ.properties | 9 +++-- .../main/resources/strings_de-CH.properties | 7 ++-- .../main/resources/strings_de-DE.properties | 7 ++-- .../main/resources/strings_en-AF.properties | 7 ++-- .../main/resources/strings_en-GH.properties | 7 ++-- .../main/resources/strings_en-NG.properties | 7 ++-- .../main/resources/strings_es-CU.properties | 7 ++-- .../main/resources/strings_es-EC.properties | 7 ++-- .../main/resources/strings_es-ES.properties | 7 ++-- .../main/resources/strings_fa-AF.properties | 7 ++-- .../main/resources/strings_fi-FI.properties | 7 ++-- .../main/resources/strings_fil-PH.properties | 7 ++-- .../main/resources/strings_fj-FJ.properties | 7 ++-- .../main/resources/strings_fr-CH.properties | 7 ++-- .../main/resources/strings_fr-FR.properties | 21 ++++++----- .../main/resources/strings_hi-IN.properties | 7 ++-- .../main/resources/strings_hr-HR.properties | 7 ++-- .../main/resources/strings_it-CH.properties | 7 ++-- .../main/resources/strings_it-IT.properties | 7 ++-- .../main/resources/strings_ja-JP.properties | 7 ++-- .../main/resources/strings_nl-NL.properties | 7 ++-- .../main/resources/strings_no-NO.properties | 7 ++-- .../main/resources/strings_pl-PL.properties | 7 ++-- .../main/resources/strings_ps-AF.properties | 7 ++-- .../main/resources/strings_pt-PT.properties | 7 ++-- .../main/resources/strings_ro-RO.properties | 7 ++-- .../main/resources/strings_ru-RU.properties | 7 ++-- .../main/resources/strings_sv-SE.properties | 7 ++-- .../main/resources/strings_sw-KE.properties | 7 ++-- .../main/resources/strings_tr-TR.properties | 7 ++-- .../main/resources/strings_uk-UA.properties | 7 ++-- .../main/resources/strings_ur-PK.properties | 7 ++-- .../main/resources/strings_zh-CN.properties | 7 ++-- .../resources/validations_cs-CZ.properties | 2 +- .../resources/validations_de-CH.properties | 2 +- .../resources/validations_de-DE.properties | 2 +- .../resources/validations_en-AF.properties | 2 +- .../resources/validations_en-GH.properties | 2 +- .../resources/validations_en-NG.properties | 2 +- .../resources/validations_es-CU.properties | 2 +- .../resources/validations_es-EC.properties | 2 +- .../resources/validations_es-ES.properties | 2 +- .../resources/validations_fa-AF.properties | 2 +- .../resources/validations_fi-FI.properties | 2 +- .../resources/validations_fil-PH.properties | 2 +- .../resources/validations_fj-FJ.properties | 2 +- .../resources/validations_fr-CH.properties | 2 +- .../resources/validations_fr-FR.properties | 2 +- .../resources/validations_hi-IN.properties | 2 +- .../resources/validations_hr-HR.properties | 2 +- .../resources/validations_it-CH.properties | 2 +- .../resources/validations_it-IT.properties | 2 +- .../resources/validations_ja-JP.properties | 2 +- .../resources/validations_nl-NL.properties | 2 +- .../resources/validations_no-NO.properties | 2 +- .../resources/validations_pl-PL.properties | 2 +- .../resources/validations_ps-AF.properties | 2 +- .../resources/validations_pt-PT.properties | 2 +- .../resources/validations_ro-RO.properties | 2 +- .../resources/validations_ru-RU.properties | 2 +- .../resources/validations_sv-SE.properties | 2 +- .../resources/validations_sw-KE.properties | 2 +- .../resources/validations_tr-TR.properties | 2 +- .../resources/validations_uk-UA.properties | 2 +- .../resources/validations_ur-PK.properties | 2 +- .../resources/validations_zh-CN.properties | 2 +- 100 files changed, 901 insertions(+), 635 deletions(-) diff --git a/sormas-api/src/main/resources/captions_cs-CZ.properties b/sormas-api/src/main/resources/captions_cs-CZ.properties index c301580adda..042a264f8fa 100644 --- a/sormas-api/src/main/resources/captions_cs-CZ.properties +++ b/sormas-api/src/main/resources/captions_cs-CZ.properties @@ -21,12 +21,10 @@ area=Oblast city=Město postcode=PSČ address=Adresa -community=Komunita communityName=Komunita date=Datum description=Popis disease=Nemoc -district=Okres districtName=Okres edit=Upravit epiWeekFrom=Od týdne Epidemie @@ -44,10 +42,6 @@ menu=Menu moreActions=Více name=Jméno options=Možnosti -continent=Kontinent -subcontinent=Subkontinent -country=Země -region=Oblast regionName=Oblast system=Systém to=Komu @@ -57,8 +51,6 @@ creationDate=Datum vytvoření notAvailableShort=Není dostupné inaccessibleValue=Důvěrné numberOfCharacters=Počet znaků\: %d / %d -facility=Zařízení -pointOfEntry=Místo vstupu remove=Smazat reportingUser=Oznamující uživatel notTestedYet=Zatím netestováno @@ -182,6 +174,7 @@ actionDiscardAndContinue=Zahodit a pokračovat activityAsCaseFlightNumber=Číslo letu +ActivityAsCase=Activity as case ActivityAsCase.startDate=Začátek aktivity ActivityAsCase.endDate=Konec aktivity ActivityAsCase.activityAsCaseDate=Datum aktivity @@ -322,7 +315,7 @@ CampaignFormData.edit=Upravit # CaseData caseCasesList=Seznam případů caseInfrastructureDataChanged=Údaje o infrastruktuře se změnily -caseCloneCaseWithNewDisease=Vytvořit nový případ pro +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Kontakty caseDocuments=Dokumenty případu caseEditData=Upravit data @@ -608,7 +601,7 @@ caseImportMergeCase=Přepsat existující případ změnami z importovaného př # CasePreviousHospitalization CasePreviousHospitalization=Předchozí hospitalizace CasePreviousHospitalization.admissionAndDischargeDate=Datum přijetí a propuštění -CasePreviousHospitalization.admittedToHealthFacility =Byl pacient přijat v zařízení jako neodkladný? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Datum přijetí CasePreviousHospitalization.description=Popis CasePreviousHospitalization.dischargeDate=Datum propuštění nebo přemístění @@ -647,6 +640,7 @@ columnVaccineManufacturer=Výrobce očkovací látky # Community +Community=Community Community.archived=Archivováno Community.externalID=Externí ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Aktivní okresy districtArchivedDistricts=Archivované okresy districtAllDistricts=Všechny okresy +District=District District.archived=Archivováno District.epidCode=Epid kód District.growthRate=Míra růstu @@ -1088,7 +1083,7 @@ eventSearchEvent=Hledat událost eventSearchSpecificEvent=Hledat konkrétní událost linkEvent=Propojit případ linkEventGroup=Propojit skupinu událostí -eventSelect=Vyberte událost +eventSelect=Select event eventSelectGroup=Vyberte skupinu událostí eventDefaultView=Události eventActionsView=Akce @@ -1293,6 +1288,7 @@ exposureFlightNumber=Číslo letu exposureTimePeriod=Časové období exposureSourceCaseName=Název zdrojového případu +Exposure=Exposure Exposure.probableInfectionEnvironment= Pravděpodobné infekční prostředí Exposure.startDate=Začátek expozice Exposure.endDate=Konec expozice @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Konfigurované zařízení Facility.NO_FACILITY=Domov nebo jiné místo Facility.OTHER_FACILITY=Ostatní zařízení +Facility=Facility Facility.additionalInformation=Další informace Facility.archived=Archivováno Facility.areaType=Typ oblasti (městská/venkov) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Další relevantní již existující podmínky HealthConditions.immunodeficiencyOtherThanHiv=Selhání imunity jiné než HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Kardiovaskulární onemocnění včetně hypertenze HealthConditions.obesity=Obezita -HealthConditions.currentSmoker=Aktivní kuřák\t\t -HealthConditions.formerSmoker=Bývalý kuřák\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Astma -HealthConditions.sickleCellDisease=Srpkovitá anémie +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Selhání imunity včetně HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Jméno vlastníka personContactDetailThisPerson = Tato osoba personContactDetailThirdParty = Shromažďovat kontaktní údaje jiné osoby nebo zařízení +PersonContactDetail = Person contact detail PersonContactDetail.person = Osoba PersonContactDetail.primaryContact = Hlavní kontaktní údaje PersonContactDetail.personContactDetailType = Typ kontaktních údajů @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Ostatní letiště PointOfEntry.OTHER_SEAPORT=Ostatní námořní přístav PointOfEntry.OTHER_GROUND_CROSSING=Ostatní pozemní přejezdy PointOfEntry.OTHER_POE=Ostatní vstupní místo + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Typ vstupního místa PointOfEntry.active=Aktivní? PointOfEntry.latitude=Zeměpisná šířka @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Údaje o vstupním místě # Prescription prescriptionNewPrescription=Nový předpis +Prescription=Prescription Prescription.additionalNotes=Doplňkové poznámky Prescription.dose=Dávka Prescription.drugIntakeDetails=Název léku @@ -1807,6 +1808,7 @@ continentActiveContinents=Aktivní kontinenty continentArchivedContinents=Archivované kontinenty continentAllContinents=Všechny kontinenty +Continent=Continent Continent.archived=Archivováno Continent.externalId=Externí ID Continent.defaultName=Výchozí název @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Aktivní subkontinenty subcontinentArchivedSubcontinents=Archivované subkontinenty subcontinentAllSubcontinents=Všechny subkontinenty +Subcontinent=Subcontinent Subcontinent.archived=Archivováno Subcontinent.externalId=Externí ID Subcontinent.defaultName=Výchozí název @@ -1828,6 +1831,7 @@ countryActiveCountries=Aktivní země countryArchivedCountries=Archivované země countryAllCountries=Všechny země +Country=Country Country.archived=Archivováno Country.externalId=Externí ID Country.defaultName=Výchozí název @@ -1841,6 +1845,7 @@ regionActiveRegions=Aktivní regiony regionArchivedRegions=Archivované regiony regionAllRegions=Všechny regiony +Region=Region Region.archived=Archivováno Region.epidCode=Epid kód Region.growthRate=Míra růstu @@ -2294,6 +2299,7 @@ Task.taskPriority=Priorita úkolu Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Datum a čas výsledku TestReport.testLabCity=Město laboratoře TestReport.testLabExternalId=Externí ID laboratoře @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Pouze obnovené položky travelEntryOnlyVaccinatedEntries=Pouze očkované položky travelEntryOnlyEntriesTestedNegative=Pouze negativně testované položky travelEntryOnlyEntriesConvertedToCase=Pouze položky převedeny na případ -travelEntryOpenResultingCase=Otevřít případ tohoto cestovního vstupu +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Aktivní cestovní vstupy travelEntryArchivedTravelEntries=Archivované cestovní vstupy travelEntryAllTravelEntries=Všechny cestovní vstupy @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Vytvořit léčbu treatmentNewTreatment=Nová léčba treatmentOpenPrescription=Otevřít předpis +Treatment=Treatment Treatment.additionalNotes=Doplňkové poznámky Treatment.dose=Dávka Treatment.drugIntakeDetails=Název léku diff --git a/sormas-api/src/main/resources/captions_de-CH.properties b/sormas-api/src/main/resources/captions_de-CH.properties index d1eb54458eb..bedeb0e977b 100644 --- a/sormas-api/src/main/resources/captions_de-CH.properties +++ b/sormas-api/src/main/resources/captions_de-CH.properties @@ -21,12 +21,10 @@ area=Gebiet city=Stadt postcode=Postleitzahl address=Adresse -community=Gemeinde communityName=Gemeinde date=Datum description=Beschreibung disease=Krankheit -district=Bezirk districtName=Bezirk edit=Bearbeiten epiWeekFrom=Von Epi Woche @@ -44,10 +42,6 @@ menu=Menü moreActions=Mehr name=Name options=Einstellungen -continent=Kontinent -subcontinent=Subkontinent -country=Land -region=Kanton regionName=Kanton system=System to=Bis @@ -57,8 +51,6 @@ creationDate=Erstellungsdatum notAvailableShort=k. A inaccessibleValue=Vertraulich numberOfCharacters=Anzahl der Zeichen\: %d / %d -facility=Einrichtung -pointOfEntry=Einreiseort remove=Entfernen reportingUser=Meldender Nutzer notTestedYet=Noch nicht getestet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Verwerfen und fortfahren activityAsCaseFlightNumber=Flugnummer +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start der Aktivität ActivityAsCase.endDate=Ende der Aktivität ActivityAsCase.activityAsCaseDate=Datum der Aktivität @@ -322,7 +315,7 @@ CampaignFormData.edit=Bearbeiten # CaseData caseCasesList=Fall-Liste caseInfrastructureDataChanged=Infrastrukturdaten wurden geändert -caseCloneCaseWithNewDisease=Neuen Fall erstellen für +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Kontakte caseDocuments=Dokumente caseEditData=Daten bearbeiten @@ -608,7 +601,7 @@ caseImportMergeCase=Bestehenden Fall mit Änderungen aus dem importierten Fall # CasePreviousHospitalization CasePreviousHospitalization=Vorheriger Krankenhausaufenthalt CasePreviousHospitalization.admissionAndDischargeDate=Datum der Aufnahme & Entlassung -CasePreviousHospitalization.admittedToHealthFacility =Wurde der Patient im Krankenhaus stationär aufgenommen? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Datum der Aufnahme CasePreviousHospitalization.description=Beschreibung CasePreviousHospitalization.dischargeDate=Datum der Entlassung / Verlegung @@ -647,6 +640,7 @@ columnVaccineManufacturer=Impfstoffhersteller # Community +Community=Community Community.archived=Archiviert Community.externalID=Externe ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Aktive Bezirke districtArchivedDistricts=Archivierte Bezirke districtAllDistricts=Alle Bezirke +District=District District.archived=Archiviert District.epidCode=EPID-Nummer District.growthRate=Wachstumsrate @@ -1088,7 +1083,7 @@ eventSearchEvent=Ereignis suchen eventSearchSpecificEvent=Nach einem bestimmten Ereignis suchen linkEvent=Ereignis verknüpfen linkEventGroup=Ereignisgruppe verknüpfen -eventSelect=Ereignis auswählen +eventSelect=Select event eventSelectGroup=Ereignisgruppe auswählen eventDefaultView=Ereignisse eventActionsView=Aktionen @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flugnummer exposureTimePeriod=Zeitraum exposureSourceCaseName=Name des Indexfalls +Exposure=Exposure Exposure.probableInfectionEnvironment= Wahrscheinlichste infektiöse Exposition Exposure.startDate=Beginn der Exposition Exposure.endDate=Ende der Exposition @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Konfigurierte Einrichtung Facility.NO_FACILITY=Zuhause oder anderer Ort Facility.OTHER_FACILITY=Andere Einrichtung +Facility=Facility Facility.additionalInformation=Weitere Informationen Facility.archived=Archiviert Facility.areaType=Gebietsart (städtisch/ländlich) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Zusätzliche relevante Vorerkrankungen HealthConditions.immunodeficiencyOtherThanHiv=Immundefekt außer HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Herz-Kreislauf-Erkrankung einschliesslich Hypertonie HealthConditions.obesity=Adipositas -HealthConditions.currentSmoker=Raucher -HealthConditions.formerSmoker=Ehemaliger Raucher +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma bronchiale -HealthConditions.sickleCellDisease=Sichelzellenanämie +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunschwäche, einschließlich HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Name des Besitzers personContactDetailThisPerson = Diese Person personContactDetailThirdParty = Kontaktdaten einer anderen Person oder Einrichtung erheben +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primäre Kontaktdetails PersonContactDetail.personContactDetailType = Art der Kontaktdetails @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Anderer Flughafen PointOfEntry.OTHER_SEAPORT=Anderer Seehafen PointOfEntry.OTHER_GROUND_CROSSING=Anderer Bodenübergang PointOfEntry.OTHER_POE=Anderer Einreiseort + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Art des Einreiseorts PointOfEntry.active=Aktiv? PointOfEntry.latitude=Breitengrad @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Einreiseort Details # Prescription prescriptionNewPrescription=Neues Rezept +Prescription=Prescription Prescription.additionalNotes=Zusätzliche Bemerkungen Prescription.dose=Dosis Prescription.drugIntakeDetails=Medikamentenname @@ -1807,6 +1808,7 @@ continentActiveContinents=Aktive Kontinente continentArchivedContinents=Archivierte Kontinente continentAllContinents=Alle Kontinente +Continent=Continent Continent.archived=Archiviert Continent.externalId=Externe ID Continent.defaultName=Standardname @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Aktive Subkontinente subcontinentArchivedSubcontinents=Archivierte Subkontinente subcontinentAllSubcontinents=Alle Subkontinente +Subcontinent=Subcontinent Subcontinent.archived=Archiviert Subcontinent.externalId=Externe ID Subcontinent.defaultName=Standardname @@ -1828,6 +1831,7 @@ countryActiveCountries=Aktive Länder countryArchivedCountries=Archivierte Länder countryAllCountries=Alle Länder +Country=Country Country.archived=Archiviert Country.externalId=Externe ID Country.defaultName=Standardname @@ -1841,6 +1845,7 @@ regionActiveRegions=Aktive Kantone regionArchivedRegions=Archivierte Kantone regionAllRegions=Alle Kantone +Region=Region Region.archived=Archiviert Region.epidCode=EPID-Nummer Region.growthRate=Wachstumsrate @@ -2294,6 +2299,7 @@ Task.taskPriority=Aufgabenpriorität Task.travelEntry=Einreise # TestReport +TestReport=Test report TestReport.testDateTime=Datum und Uhrzeit des Ergebnisses TestReport.testLabCity=Labor Stadt TestReport.testLabExternalId=Labor Externe ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Nur genesene Einreisende travelEntryOnlyVaccinatedEntries=Nur geimpfte Einreisende travelEntryOnlyEntriesTestedNegative=Nur negativ getestete Einreisende travelEntryOnlyEntriesConvertedToCase=Nur in Fälle konvertierte Einreisen -travelEntryOpenResultingCase=Fall zu dieser Einreise öffnen +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Aktive Einreisen travelEntryArchivedTravelEntries=Archivierte Einreisen travelEntryAllTravelEntries=Alle Einreisen @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Behandlung erstellen treatmentNewTreatment=Neue Behandlung treatmentOpenPrescription=Öffne Verschreibung +Treatment=Treatment Treatment.additionalNotes=Zusätzliche Bemerkungen Treatment.dose=Dosis Treatment.drugIntakeDetails=Medikamentenname diff --git a/sormas-api/src/main/resources/captions_de-DE.properties b/sormas-api/src/main/resources/captions_de-DE.properties index b6ed83028cb..027cf337d9b 100644 --- a/sormas-api/src/main/resources/captions_de-DE.properties +++ b/sormas-api/src/main/resources/captions_de-DE.properties @@ -21,12 +21,10 @@ area=Gebiet city=Stadt postcode=Postleitzahl address=Adresse -community=Gemeinde communityName=Gemeinde date=Datum description=Beschreibung disease=Krankheit -district=Landkreis/Kreisfreie Stadt districtName=Landkreis/Kreisfreie Stadt edit=Bearbeiten epiWeekFrom=Von Epi Woche @@ -44,10 +42,6 @@ menu=Menü moreActions=Mehr name=Name options=Einstellungen -continent=Kontinent -subcontinent=Subkontinent -country=Land -region=Bundesland regionName=Bundesland system=System to=Bis @@ -57,8 +51,6 @@ creationDate=Erstellungsdatum notAvailableShort=k. A inaccessibleValue=Vertraulich numberOfCharacters=Anzahl der Zeichen\: %d / %d -facility=Einrichtung -pointOfEntry=Einreiseort remove=Entfernen reportingUser=Meldender Nutzer notTestedYet=Noch nicht getestet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Verwerfen und fortfahren activityAsCaseFlightNumber=Flugnummer +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start der Aktivität ActivityAsCase.endDate=Ende der Aktivität ActivityAsCase.activityAsCaseDate=Datum der Aktivität @@ -322,7 +315,7 @@ CampaignFormData.edit=Bearbeiten # CaseData caseCasesList=Fall-Liste caseInfrastructureDataChanged=Infrastrukturdaten wurden geändert -caseCloneCaseWithNewDisease=Neuen Fall erstellen für +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Kontakte caseDocuments=Dokumente caseEditData=Daten bearbeiten @@ -608,7 +601,7 @@ caseImportMergeCase=Bestehenden Fall mit Änderungen aus dem importierten Fall # CasePreviousHospitalization CasePreviousHospitalization=Vorheriger Krankenhausaufenthalt CasePreviousHospitalization.admissionAndDischargeDate=Datum der Aufnahme & Entlassung -CasePreviousHospitalization.admittedToHealthFacility =Wurde der Patient im Krankenhaus stationär aufgenommen? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Datum der Aufnahme CasePreviousHospitalization.description=Beschreibung CasePreviousHospitalization.dischargeDate=Datum der Entlassung / Verlegung @@ -647,6 +640,7 @@ columnVaccineManufacturer=Impfstoffhersteller # Community +Community=Community Community.archived=Archiviert Community.externalID=Externe ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Aktive Landkreise districtArchivedDistricts=Archivierte Landkreise districtAllDistricts=Alle Landkreise +District=District District.archived=Archiviert District.epidCode=EPID-Nummer District.growthRate=Wachstumsrate @@ -1088,7 +1083,7 @@ eventSearchEvent=Ereignis suchen eventSearchSpecificEvent=Nach einem bestimmten Ereignis suchen linkEvent=Ereignis verknüpfen linkEventGroup=Gruppe verknüpfen -eventSelect=Ereignis wählen +eventSelect=Select event eventSelectGroup=Ereignisgruppe auswählen eventDefaultView=Ereignisse eventActionsView=Aktionen @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flugnummer exposureTimePeriod=Zeitraum exposureSourceCaseName=Name des Indexfalls +Exposure=Exposure Exposure.probableInfectionEnvironment= Wahrscheinliches Infektionsumfeld Exposure.startDate=Beginn der Exposition Exposure.endDate=Ende der Exposition @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Konfigurierte Einrichtung Facility.NO_FACILITY=Zuhause oder anderer Ort Facility.OTHER_FACILITY=Andere Einrichtung +Facility=Facility Facility.additionalInformation=Weitere Informationen Facility.archived=Archiviert Facility.areaType=Gebietsart (städtisch/ländlich) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Zusätzliche relevante Vorerkrankungen HealthConditions.immunodeficiencyOtherThanHiv=Immundefekt außer HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Herz-Kreislauf-Erkrankung einschließlich Hypertonie HealthConditions.obesity=Adipositas -HealthConditions.currentSmoker=Raucher -HealthConditions.formerSmoker=Ehemaliger Raucher +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma bronchiale -HealthConditions.sickleCellDisease=Sichelzellenanämie +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunschwäche, einschließlich HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Name des Besitzers personContactDetailThisPerson = Diese Person personContactDetailThirdParty = Kontaktdaten einer anderen Person oder Einrichtung erheben +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primäre Kontaktdetails PersonContactDetail.personContactDetailType = Art der Kontaktdetails @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Anderer Flughafen PointOfEntry.OTHER_SEAPORT=Anderer Seehafen PointOfEntry.OTHER_GROUND_CROSSING=Anderer Grenzübergang/Landweg PointOfEntry.OTHER_POE=Anderer Einreiseort + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Art des Einreiseorts PointOfEntry.active=Aktiv? PointOfEntry.latitude=Breitengrad @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Einreiseort Details # Prescription prescriptionNewPrescription=Neue Verschreibung +Prescription=Prescription Prescription.additionalNotes=Zusätzliche Bemerkungen Prescription.dose=Dosis Prescription.drugIntakeDetails=Medikamentenname @@ -1807,6 +1808,7 @@ continentActiveContinents=Aktive Kontinente continentArchivedContinents=Archivierte Kontinente continentAllContinents=Alle Kontinente +Continent=Continent Continent.archived=Archiviert Continent.externalId=Externe ID Continent.defaultName=Standardname @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Aktive Subkontinente subcontinentArchivedSubcontinents=Archivierte Subkontinente subcontinentAllSubcontinents=Alle Subkontinente +Subcontinent=Subcontinent Subcontinent.archived=Archiviert Subcontinent.externalId=Externe ID Subcontinent.defaultName=Standardname @@ -1828,6 +1831,7 @@ countryActiveCountries=Aktive Länder countryArchivedCountries=Archivierte Länder countryAllCountries=Alle Länder +Country=Country Country.archived=Archiviert Country.externalId=Externe ID Country.defaultName=Standardname @@ -1841,6 +1845,7 @@ regionActiveRegions=Aktive Bundesländer regionArchivedRegions=Archivierte Bundesländer regionAllRegions=Alle Bundesländer +Region=Region Region.archived=Archiviert Region.epidCode=EPID-Nummer Region.growthRate=Wachstumsrate @@ -2294,6 +2299,7 @@ Task.taskPriority=Aufgabenpriorität Task.travelEntry=Einreise # TestReport +TestReport=Test report TestReport.testDateTime=Datum und Uhrzeit des Ergebnisses TestReport.testLabCity=Labor Stadt TestReport.testLabExternalId=Labor Externe ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Nur genesene Einreisende travelEntryOnlyVaccinatedEntries=Nur geimpfte Einreisende travelEntryOnlyEntriesTestedNegative=Nur negativ getestete Einreisende travelEntryOnlyEntriesConvertedToCase=Nur in Fälle konvertierte Einreisen -travelEntryOpenResultingCase=Fall zu dieser Einreise öffnen +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Aktive Einreisen travelEntryArchivedTravelEntries=Archivierte Einreisen travelEntryAllTravelEntries=Alle Einreisen @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Behandlung erstellen treatmentNewTreatment=Neue Behandlung treatmentOpenPrescription=Öffne Verschreibung +Treatment=Treatment Treatment.additionalNotes=Zusätzliche Bemerkungen Treatment.dose=Dosis Treatment.drugIntakeDetails=Medikamentenname diff --git a/sormas-api/src/main/resources/captions_en-AF.properties b/sormas-api/src/main/resources/captions_en-AF.properties index cdceddc040b..b61e42fd6c4 100644 --- a/sormas-api/src/main/resources/captions_en-AF.properties +++ b/sormas-api/src/main/resources/captions_en-AF.properties @@ -21,12 +21,10 @@ area=Region city=City postcode=Postcode address=Address -community=Cluster communityName=Cluster date=Date description=Description disease=Disease -district=District districtName=District edit=Edit epiWeekFrom=From Epi Week @@ -44,10 +42,6 @@ menu=Menu moreActions=More name=Name options=Options -continent=Continent -subcontinent=Subcontinent -country=Country -region=Province regionName=Province system=System to=To @@ -57,8 +51,6 @@ creationDate=Creation date notAvailableShort=NA inaccessibleValue=Confidential numberOfCharacters=Number of characters\: %d / %d -facility=Sub Cluster -pointOfEntry=Point of entry remove=Remove reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Cases list caseInfrastructureDataChanged=Infrastructure data has changed -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Case Documents caseEditData=Edit data @@ -608,7 +601,7 @@ caseImportMergeCase=Override existing case with changes from the imported case? # CasePreviousHospitalization CasePreviousHospitalization=Previous hospitalization CasePreviousHospitalization.admissionAndDischargeDate=Date of admission & discharge -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date of admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date of discharge or transfer @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=External ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Active districts districtArchivedDistricts=Archived districts districtAllDistricts=All districts +District=District District.archived=Archived District.epidCode=Epid code District.growthRate=Growth rate @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Home or other place Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker\t\t -HealthConditions.formerSmoker=Former smoker\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease\t +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Active provinces regionArchivedRegions=Archived provinces regionAllRegions=All provinces +Region=Region Region.archived=Archived Region.epidCode=Epid code Region.growthRate=Growth rate @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-api/src/main/resources/captions_en-GH.properties b/sormas-api/src/main/resources/captions_en-GH.properties index 835e7691e60..78974f4b078 100644 --- a/sormas-api/src/main/resources/captions_en-GH.properties +++ b/sormas-api/src/main/resources/captions_en-GH.properties @@ -21,12 +21,10 @@ area=Area city=City postcode=Postcode address=Address -community=Sub District communityName=Sub District date=Date description=Description disease=Disease -district=District districtName=District edit=Edit epiWeekFrom=From Epi Week @@ -44,10 +42,6 @@ menu=Menu moreActions=More name=Name options=Options -continent=Continent -subcontinent=Subcontinent -country=Country -region=Region regionName=Region system=System to=To @@ -57,8 +51,6 @@ creationDate=Creation date notAvailableShort=NA inaccessibleValue=Confidential numberOfCharacters=Number of characters\: %d / %d -facility=Facility -pointOfEntry=Point of entry remove=Remove reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Cases list caseInfrastructureDataChanged=Infrastructure data has changed -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Case Documents caseEditData=Edit data @@ -608,7 +601,7 @@ caseImportMergeCase=Override existing case with changes from the imported case? # CasePreviousHospitalization CasePreviousHospitalization=Previous hospitalization CasePreviousHospitalization.admissionAndDischargeDate=Date of admission & discharge -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date of admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date of discharge or transfer @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=External ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Active districts districtArchivedDistricts=Archived districts districtAllDistricts=All districts +District=District District.archived=Archived District.epidCode=Epid code District.growthRate=Growth rate @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Home or other place Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker\t\t -HealthConditions.formerSmoker=Former smoker\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease\t +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Active regions regionArchivedRegions=Archived regions regionAllRegions=All regions +Region=Region Region.archived=Archived Region.epidCode=Epid code Region.growthRate=Growth rate @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-api/src/main/resources/captions_en-NG.properties b/sormas-api/src/main/resources/captions_en-NG.properties index fb6dca2dbfd..10244f6a600 100644 --- a/sormas-api/src/main/resources/captions_en-NG.properties +++ b/sormas-api/src/main/resources/captions_en-NG.properties @@ -21,12 +21,10 @@ area=Area city=City postcode=Postcode address=Address -community=Ward communityName=Ward date=Date description=Description disease=Disease -district=LGA districtName=LGA edit=Edit epiWeekFrom=From Epi Week @@ -44,10 +42,6 @@ menu=Menu moreActions=More name=Name options=Options -continent=Continent -subcontinent=Subcontinent -country=Country -region=State regionName=State system=System to=To @@ -57,8 +51,6 @@ creationDate=Creation date notAvailableShort=NA inaccessibleValue=Confidential numberOfCharacters=Number of characters\: %d / %d -facility=Facility -pointOfEntry=Point of entry remove=Remove reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Cases list caseInfrastructureDataChanged=Infrastructure data has changed -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Case Documents caseEditData=Edit data @@ -608,7 +601,7 @@ caseImportMergeCase=Override existing case with changes from the imported case? # CasePreviousHospitalization CasePreviousHospitalization=Previous hospitalization CasePreviousHospitalization.admissionAndDischargeDate=Date of admission & discharge -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date of admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date of discharge or transfer @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=External ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Active LGAs districtArchivedDistricts=Archived LGAs districtAllDistricts=All LGAs +District=District District.archived=Archived District.epidCode=Epid code District.growthRate=Growth rate @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Home or other place Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker\t\t -HealthConditions.formerSmoker=Former smoker\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease\t +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Active states regionArchivedRegions=Archived states regionAllRegions=All states +Region=Region Region.archived=Archived Region.epidCode=Epid code Region.growthRate=Growth rate @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-api/src/main/resources/captions_es-CU.properties b/sormas-api/src/main/resources/captions_es-CU.properties index 38b23569751..d0cab7579c5 100644 --- a/sormas-api/src/main/resources/captions_es-CU.properties +++ b/sormas-api/src/main/resources/captions_es-CU.properties @@ -21,12 +21,10 @@ area=Zona city=Ciudad postcode=Código postal address=Dirección -community=Área de Salud communityName=Nombre del Área de Salud date=Fecha description=Descripción disease=Enfermedad -district=Municipio districtName=Nombre del Municipio edit=Editar epiWeekFrom=Desde Semana Epi @@ -44,10 +42,6 @@ menu=Menú moreActions=Más name=Nombre options=Opciones -continent=Continente -subcontinent=Subcontinente -country=País -region=Provincia regionName=Provincia system=Sistema to=Hasta @@ -57,8 +51,6 @@ creationDate=Fecha de creación notAvailableShort=ND inaccessibleValue=Confidencial numberOfCharacters=Número de caracteres\: %d / %d -facility=Centro -pointOfEntry=Punto de entrada remove=Eliminar reportingUser=Usuario informante notTestedYet=Aún no probado @@ -182,6 +174,7 @@ actionDiscardAndContinue=Descartar y continuar activityAsCaseFlightNumber=Número de vuelo +ActivityAsCase=Activity as case ActivityAsCase.startDate=Inicio de la actividad ActivityAsCase.endDate=Fin de la actividad ActivityAsCase.activityAsCaseDate=Fecha de actividad @@ -322,7 +315,7 @@ CampaignFormData.edit=Editar # CaseData caseCasesList=Lista de casos caseInfrastructureDataChanged=Los datos de infraestructura han cambiado -caseCloneCaseWithNewDisease=Generar nuevo caso para +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contactos caseDocuments=Documentos del caso caseEditData=Editar datos @@ -608,7 +601,7 @@ caseImportMergeCase=¿Sobrescribir el caso existente con los cambios del caso im # CasePreviousHospitalization CasePreviousHospitalization=Hospitalización anterior CasePreviousHospitalization.admissionAndDischargeDate=Fecha de admisión & alta -CasePreviousHospitalization.admittedToHealthFacility =¿El paciente se admitió en la instalación como paciente internado? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Fecha de admisión CasePreviousHospitalization.description=Descripción CasePreviousHospitalization.dischargeDate=Fecha de alta o transferencia @@ -647,6 +640,7 @@ columnVaccineManufacturer=Fabricante de vacuna # Community +Community=Community Community.archived=Archivado Community.externalID=ID externa @@ -1024,6 +1018,7 @@ districtActiveDistricts=Municipios activos districtArchivedDistricts=Municipios archivados districtAllDistricts=Todos los municipios +District=District District.archived=Archivado District.epidCode=Código epid District.growthRate=Tasa de crecimiento @@ -1088,7 +1083,7 @@ eventSearchEvent=Buscar evento eventSearchSpecificEvent=Buscar evento específico linkEvent=Vincular evento linkEventGroup=Vincular grupo de eventos -eventSelect=Seleccionar evento +eventSelect=Select event eventSelectGroup=Seleccionar grupo de eventos eventDefaultView=Eventos eventActionsView=Acciones @@ -1293,6 +1288,7 @@ exposureFlightNumber=Número de vuelo exposureTimePeriod=Periodo de tiempo exposureSourceCaseName=Nombre del caso de origen +Exposure=Exposure Exposure.probableInfectionEnvironment= Entorno de infección probable Exposure.startDate=Inicio de la exposición Exposure.endDate=Fin de la exposición @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Instalación configurada Facility.NO_FACILITY=Casa u otro lugar Facility.OTHER_FACILITY=Otra instalación +Facility=Facility Facility.additionalInformation=Información adicional Facility.archived=Archivado Facility.areaType=Tipo de zona (urbana/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Otras condiciones preexistentes relevantes HealthConditions.immunodeficiencyOtherThanHiv=Inmunodeficiencia distinta al VIH HealthConditions.cardiovascularDiseaseIncludingHypertension=Enfermedad cardiovascular, incluída la hipertensión HealthConditions.obesity=Obesidad -HealthConditions.currentSmoker=Fumador activo -HealthConditions.formerSmoker=Ex fumador +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asma -HealthConditions.sickleCellDisease=Enfermedad de células falciformes +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Inmunodeficiencia, incluido el VIH # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Nombre del propietario personContactDetailThisPerson = Esta persona personContactDetailThirdParty = Recopilar datos de contacto de otra persona o centro +PersonContactDetail = Person contact detail PersonContactDetail.person = Persona PersonContactDetail.primaryContact = Datos de contacto primarios PersonContactDetail.personContactDetailType = Detalles del tipo de contacto @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Otro aeropuerto PointOfEntry.OTHER_SEAPORT=Otro puerto marítimo PointOfEntry.OTHER_GROUND_CROSSING=Otro cruce fronterizo terrestre PointOfEntry.OTHER_POE=Otro punto de entrada + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Tipo de punto de entrada PointOfEntry.active=¿Activo? PointOfEntry.latitude=Latitud @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Detalles del punto de entrada # Prescription prescriptionNewPrescription=Nueva prescripción +Prescription=Prescription Prescription.additionalNotes=Notas adicionales Prescription.dose=Dosis Prescription.drugIntakeDetails=Nombre del medicamento @@ -1807,6 +1808,7 @@ continentActiveContinents=Continentes activos continentArchivedContinents=Continentes archivados continentAllContinents=Todos los continentes +Continent=Continent Continent.archived=Archivado Continent.externalId=ID externo Continent.defaultName=Nombre por defecto @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Subcontinentes activos subcontinentArchivedSubcontinents=Subcontinentes archivados subcontinentAllSubcontinents=Todos los subcontinentes +Subcontinent=Subcontinent Subcontinent.archived=Archivado Subcontinent.externalId=ID externo Subcontinent.defaultName=Nombre por defecto @@ -1828,6 +1831,7 @@ countryActiveCountries=Países activos countryArchivedCountries=Países archivados countryAllCountries=Todos los países +Country=Country Country.archived=Archivado Country.externalId=ID externa Country.defaultName=Nombre por defecto @@ -1841,6 +1845,7 @@ regionActiveRegions=Provincias activas regionArchivedRegions=Provincias archivadas regionAllRegions=Todas las provincias +Region=Region Region.archived=Archivado Region.epidCode=Código epid Region.growthRate=Tasa de crecimiento @@ -2294,6 +2299,7 @@ Task.taskPriority=Prioridad de tarea Task.travelEntry=Entrada de viaje # TestReport +TestReport=Test report TestReport.testDateTime=Fecha y hora del resultado TestReport.testLabCity=Ciudad del laboratorio TestReport.testLabExternalId=ID externa del laboratorio @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Sólo entradas recuperadas travelEntryOnlyVaccinatedEntries=Sólo entradas vacunadas travelEntryOnlyEntriesTestedNegative=Sólo entradas que dieron negativo travelEntryOnlyEntriesConvertedToCase=Sólo entradas convertidas en caso -travelEntryOpenResultingCase=Abrir caso de esta entrada de viaje +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Entradas de viaje activas travelEntryArchivedTravelEntries=Entradas de viaje archivadas travelEntryAllTravelEntries=Todas las entradas de viaje @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Crear tratamiento treatmentNewTreatment=Nuevo tratamiento treatmentOpenPrescription=Abrir prescripción +Treatment=Treatment Treatment.additionalNotes=Notas adicionales Treatment.dose=Dosis Treatment.drugIntakeDetails=Nombre del medicamento diff --git a/sormas-api/src/main/resources/captions_es-EC.properties b/sormas-api/src/main/resources/captions_es-EC.properties index 66349d6f4e6..1847f098faf 100644 --- a/sormas-api/src/main/resources/captions_es-EC.properties +++ b/sormas-api/src/main/resources/captions_es-EC.properties @@ -21,12 +21,10 @@ area=Area city=Ciudad postcode=Postcode address=Address -community=Comunidad communityName=Comunidad date=Date description=Description disease=Enfermedad -district=Distrito districtName=Distritos edit=Edit epiWeekFrom=Desde la semana EPI @@ -44,10 +42,6 @@ menu=Menú moreActions=Más name=Nombre options=Opciones -continent=Continent -subcontinent=Subcontinent -country=Country -region=Región regionName=Región system=Sistema to=A @@ -57,8 +51,6 @@ creationDate=Fecha de creación notAvailableShort=No aplicable inaccessibleValue=Confidential numberOfCharacters=Number of characters\: %d / %d -facility=Facility -pointOfEntry=Point of entry remove=Remove reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Lista de casos caseInfrastructureDataChanged=Los datos de infraestructura han cambiado -caseCloneCaseWithNewDisease=Generar nuevo caso para +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contactos caseDocuments=Case Documents caseEditData=Editar datos @@ -608,7 +601,7 @@ caseImportMergeCase=¿Sobrescribir el caso existente con los cambios del caso im # CasePreviousHospitalization CasePreviousHospitalization=Hospitalización previa CasePreviousHospitalization.admissionAndDischargeDate=Fecha de admisión & descargo -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Fecha de admisión CasePreviousHospitalization.description=Descripción CasePreviousHospitalization.dischargeDate=Fecha de descargo o transferencia @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=Id Externo @@ -1024,6 +1018,7 @@ districtActiveDistricts=Distritos activos districtArchivedDistricts=Distritos archivados districtAllDistricts=Todos los distritos +District=District District.archived=Archived District.epidCode=Código epidemiológico District.growthRate=Tasa de crecimiento @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Hogar u otro lugar Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Condiciones pre-existentes relevantes adicional HealthConditions.immunodeficiencyOtherThanHiv=Otra inmunodeficiencia además de HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Enfermedad cardiovascular incluyendo hipertensión HealthConditions.obesity=Obesidad -HealthConditions.currentSmoker=Fumador actual -HealthConditions.formerSmoker=Antiguo fumador +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asma -HealthConditions.sickleCellDisease=Sicklemia +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Otros aeropuertos PointOfEntry.OTHER_SEAPORT=Otros puertos PointOfEntry.OTHER_GROUND_CROSSING=Otros cruces fronterizos PointOfEntry.OTHER_POE=Otros puntos de entrada + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Tipo de punto de arribo PointOfEntry.active=¿Activo? PointOfEntry.latitude=Latitud @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Detalles del punto de ingreso # Prescription prescriptionNewPrescription=Nueva prescripción +Prescription=Prescription Prescription.additionalNotes=Notas adicionales Prescription.dose=Dosis Prescription.drugIntakeDetails=Nombre de la droga @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Regiones activas regionArchivedRegions=Regiones archivadas regionAllRegions=Todas las regiones +Region=Region Region.archived=Archived Region.epidCode=Código epidemiológico Region.growthRate=Tasa de crecimiento @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Crear tratamiento treatmentNewTreatment=Nuevo tratamiento treatmentOpenPrescription=Prescripción abierta +Treatment=Treatment Treatment.additionalNotes=Notas adicionales Treatment.dose=Dosis Treatment.drugIntakeDetails=Nombre de la droga diff --git a/sormas-api/src/main/resources/captions_es-ES.properties b/sormas-api/src/main/resources/captions_es-ES.properties index ac2e8617a71..4f8e2adc6c2 100644 --- a/sormas-api/src/main/resources/captions_es-ES.properties +++ b/sormas-api/src/main/resources/captions_es-ES.properties @@ -21,12 +21,10 @@ area=Area city=City postcode=Postcode address=Address -community=Community communityName=Community date=Date description=Description disease=Disease -district=District districtName=District edit=Edit epiWeekFrom=From Epi Week @@ -44,10 +42,6 @@ menu=Menu moreActions=More name=Name options=Options -continent=Continent -subcontinent=Subcontinent -country=Country -region=Region regionName=Region system=System to=To @@ -57,8 +51,6 @@ creationDate=Creation date notAvailableShort=NA inaccessibleValue=Confidential numberOfCharacters=Number of characters\: %d / %d -facility=Facility -pointOfEntry=Point of entry remove=Remove reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Cases list caseInfrastructureDataChanged=Infrastructure data has changed -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Case Documents caseEditData=Edit data @@ -608,7 +601,7 @@ caseImportMergeCase=Override existing case with changes from the imported case? # CasePreviousHospitalization CasePreviousHospitalization=Previous hospitalization CasePreviousHospitalization.admissionAndDischargeDate=Date of admission & discharge -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date of admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date of discharge or transfer @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=External ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Active districts districtArchivedDistricts=Archived districts districtAllDistricts=All districts +District=District District.archived=Archived District.epidCode=Epid code District.growthRate=Growth rate @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Home or other place Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker\t\t -HealthConditions.formerSmoker=Former smoker\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease\t +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Active regions regionArchivedRegions=Archived regions regionAllRegions=All regions +Region=Region Region.archived=Archived Region.epidCode=Epid code Region.growthRate=Growth rate @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-api/src/main/resources/captions_fa-AF.properties b/sormas-api/src/main/resources/captions_fa-AF.properties index eb29e66cc9c..a341da180e2 100644 --- a/sormas-api/src/main/resources/captions_fa-AF.properties +++ b/sormas-api/src/main/resources/captions_fa-AF.properties @@ -21,12 +21,10 @@ area=Area city=شهر postcode=پوست کود address=ادرس -community=جامعه communityName=نام جامعه date=تاریخ description=توضیح disease=مرض -district=ولسوالی districtName=نام ولسوالی edit=Edit epiWeekFrom=From Epi Week @@ -44,10 +42,6 @@ menu=مینو moreActions=اجرآت اضافی name=نام options=اختیارات -continent=Continent -subcontinent=Subcontinent -country=Country -region=حوزه regionName=نام حوزه system=سیستم to=به @@ -57,8 +51,6 @@ creationDate=تاریخ ایجاد notAvailableShort=NA inaccessibleValue=Confidential numberOfCharacters=Number of characters\: %d / %d -facility=مرکز صحی -pointOfEntry=Point of entry remove=برداشتن reportingUser=راپور دهنده notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=تصحیح کردن # CaseData caseCasesList=Cases list caseInfrastructureDataChanged=Infrastructure data has changed -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Case Documents caseEditData=Edit data @@ -608,7 +601,7 @@ caseImportMergeCase=Override existing case with changes from the imported case? # CasePreviousHospitalization CasePreviousHospitalization=Previous hospitalization CasePreviousHospitalization.admissionAndDischargeDate=Date of admission & discharge -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date of admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date of discharge or transfer @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=ارشیف شده Community.externalID=شناسنامه بیرونی @@ -1024,6 +1018,7 @@ districtActiveDistricts=ولسوالی های فعال districtArchivedDistricts=ولسوالی های ارشف شده districtAllDistricts=همه ی ولسوالی ها +District=District District.archived=ارشیف شده District.epidCode=ای پی کود District.growthRate=اندازه نشونمو @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=مرکز صحی تنظیم شده Facility.NO_FACILITY=عدم وجود مرکز صحی Facility.OTHER_FACILITY=دیگر مراکز صحی +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=ارشیف شده Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker\t\t -HealthConditions.formerSmoker=Former smoker\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease\t +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=کشورهای فعال countryArchivedCountries=کشورهای ارشیف شده countryAllCountries=همه کشور ها +Country=Country Country.archived=ارشیف شده Country.externalId=شناسنامه بیرونی Country.defaultName=نام معمول @@ -1841,6 +1845,7 @@ regionActiveRegions=حوزه های فعال regionArchivedRegions=حوزه های ارشیف شده regionAllRegions=همه حوزه ها +Region=Region Region.archived=ارشیف شده Region.epidCode=کود epid Region.growthRate=اندازه نشونما @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-api/src/main/resources/captions_fi-FI.properties b/sormas-api/src/main/resources/captions_fi-FI.properties index 3ffa634d28f..0a36a205e62 100644 --- a/sormas-api/src/main/resources/captions_fi-FI.properties +++ b/sormas-api/src/main/resources/captions_fi-FI.properties @@ -21,12 +21,10 @@ area=Area city=Paikkakunta postcode=Postinumero address=Osoite -community=Kunta communityName=Kunta date=Date description=Description disease=Sairaus -district=Sairaanhoitopiiri districtName=Sairaanhoitopiiri edit=Edit epiWeekFrom=Alkaen epidemiaviikosta @@ -44,10 +42,6 @@ menu=Valikko moreActions=Lisää name=Nimi options=Valinnat -continent=Continent -subcontinent=Subcontinent -country=Country -region=Erva-alue regionName=Erva-alue system=Järjestelmä to=Päättyen @@ -57,8 +51,6 @@ creationDate=Luontipäivä notAvailableShort=Havainto puuttuu inaccessibleValue=Luottamuksellinen numberOfCharacters=Merkkien määrä\: %d / %d -facility=Laitos -pointOfEntry=Maahantulopaikka remove=Poista reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Potilaslista caseInfrastructureDataChanged=Perusrakenteen tiedot ovat muuttuneet -caseCloneCaseWithNewDisease=Luo uusi potilastapaus +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Kontaktit caseDocuments=Case Documents caseEditData=Muokkaa arvoja @@ -608,7 +601,7 @@ caseImportMergeCase=Haluatko korvata olemassa olevan potilaan tietoja tuotavan p # CasePreviousHospitalization CasePreviousHospitalization=Aikaisemmat sairaalahoidot CasePreviousHospitalization.admissionAndDischargeDate=Sisään- ja uloskirjauksen päivämäärät -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Sisäänkirjauksen päivämäärä CasePreviousHospitalization.description=Kuvaus CasePreviousHospitalization.dischargeDate=Uloskirjauksen tai siirron päivämäärä @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=Ulkoinen tunniste @@ -1024,6 +1018,7 @@ districtActiveDistricts=Aktiiviset sairaanhoitopiirit districtArchivedDistricts=Arkistoidut sairaanhoitopiirit districtAllDistricts=Kaikki sairaanhoitopiirit +District=District District.archived=Archived District.epidCode=Epidemian tunnus District.growthRate=Kasvunopeus @@ -1088,7 +1083,7 @@ eventSearchEvent=Hae tapahtumaa eventSearchSpecificEvent=Etsi tietty tapahtuma linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Koti tai muu paikka Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Muut merkittävät aikaisemmin diagnosoidut sai HealthConditions.immunodeficiencyOtherThanHiv=Immuunipuutos, muu kuin HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Sydän- ja verisuonisairaus mukaanlukien korkea verenpaine HealthConditions.obesity=Lihavuus -HealthConditions.currentSmoker=Tupakoija -HealthConditions.formerSmoker=Entinen tupakoija +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Astma -HealthConditions.sickleCellDisease=Sirppisoluanemia +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immuunipuutos sisältäen HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Muu lentoasema PointOfEntry.OTHER_SEAPORT=Muu satama PointOfEntry.OTHER_GROUND_CROSSING=Muu maarajan ylityspaikka PointOfEntry.OTHER_POE=Muu maahantulopaikka + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Maahantulopaikan tyyppi PointOfEntry.active=Aktiivinen? PointOfEntry.latitude=Leveyspiiri @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Maahantulopaikan tiedot # Prescription prescriptionNewPrescription=Uusi lääkemääräys +Prescription=Prescription Prescription.additionalNotes=Lisähuomautukset Prescription.dose=Annos Prescription.drugIntakeDetails=Lääkkeen nimi @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Aktiiviset Erva-alueet regionArchivedRegions=Arkistoidut erva-alueet regionAllRegions=Kaikki erva-alueet +Region=Region Region.archived=Archived Region.epidCode=Epidemian tunnus Region.growthRate=Kasvunopeus @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Luo hoito treatmentNewTreatment=Uusi hoito treatmentOpenPrescription=Avaa lääkemääräys +Treatment=Treatment Treatment.additionalNotes=Lisähuomautukset Treatment.dose=Annos Treatment.drugIntakeDetails=Lääkkeen nimi diff --git a/sormas-api/src/main/resources/captions_fil-PH.properties b/sormas-api/src/main/resources/captions_fil-PH.properties index ac2e8617a71..4f8e2adc6c2 100644 --- a/sormas-api/src/main/resources/captions_fil-PH.properties +++ b/sormas-api/src/main/resources/captions_fil-PH.properties @@ -21,12 +21,10 @@ area=Area city=City postcode=Postcode address=Address -community=Community communityName=Community date=Date description=Description disease=Disease -district=District districtName=District edit=Edit epiWeekFrom=From Epi Week @@ -44,10 +42,6 @@ menu=Menu moreActions=More name=Name options=Options -continent=Continent -subcontinent=Subcontinent -country=Country -region=Region regionName=Region system=System to=To @@ -57,8 +51,6 @@ creationDate=Creation date notAvailableShort=NA inaccessibleValue=Confidential numberOfCharacters=Number of characters\: %d / %d -facility=Facility -pointOfEntry=Point of entry remove=Remove reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Cases list caseInfrastructureDataChanged=Infrastructure data has changed -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Case Documents caseEditData=Edit data @@ -608,7 +601,7 @@ caseImportMergeCase=Override existing case with changes from the imported case? # CasePreviousHospitalization CasePreviousHospitalization=Previous hospitalization CasePreviousHospitalization.admissionAndDischargeDate=Date of admission & discharge -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date of admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date of discharge or transfer @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=External ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Active districts districtArchivedDistricts=Archived districts districtAllDistricts=All districts +District=District District.archived=Archived District.epidCode=Epid code District.growthRate=Growth rate @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Home or other place Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker\t\t -HealthConditions.formerSmoker=Former smoker\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease\t +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Active regions regionArchivedRegions=Archived regions regionAllRegions=All regions +Region=Region Region.archived=Archived Region.epidCode=Epid code Region.growthRate=Growth rate @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-api/src/main/resources/captions_fj-FJ.properties b/sormas-api/src/main/resources/captions_fj-FJ.properties index ac2e8617a71..4f8e2adc6c2 100644 --- a/sormas-api/src/main/resources/captions_fj-FJ.properties +++ b/sormas-api/src/main/resources/captions_fj-FJ.properties @@ -21,12 +21,10 @@ area=Area city=City postcode=Postcode address=Address -community=Community communityName=Community date=Date description=Description disease=Disease -district=District districtName=District edit=Edit epiWeekFrom=From Epi Week @@ -44,10 +42,6 @@ menu=Menu moreActions=More name=Name options=Options -continent=Continent -subcontinent=Subcontinent -country=Country -region=Region regionName=Region system=System to=To @@ -57,8 +51,6 @@ creationDate=Creation date notAvailableShort=NA inaccessibleValue=Confidential numberOfCharacters=Number of characters\: %d / %d -facility=Facility -pointOfEntry=Point of entry remove=Remove reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Cases list caseInfrastructureDataChanged=Infrastructure data has changed -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Case Documents caseEditData=Edit data @@ -608,7 +601,7 @@ caseImportMergeCase=Override existing case with changes from the imported case? # CasePreviousHospitalization CasePreviousHospitalization=Previous hospitalization CasePreviousHospitalization.admissionAndDischargeDate=Date of admission & discharge -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date of admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date of discharge or transfer @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=External ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Active districts districtArchivedDistricts=Archived districts districtAllDistricts=All districts +District=District District.archived=Archived District.epidCode=Epid code District.growthRate=Growth rate @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Home or other place Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker\t\t -HealthConditions.formerSmoker=Former smoker\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease\t +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Active regions regionArchivedRegions=Archived regions regionAllRegions=All regions +Region=Region Region.archived=Archived Region.epidCode=Epid code Region.growthRate=Growth rate @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-api/src/main/resources/captions_fr-CH.properties b/sormas-api/src/main/resources/captions_fr-CH.properties index 2d4c0188d4c..57840783920 100644 --- a/sormas-api/src/main/resources/captions_fr-CH.properties +++ b/sormas-api/src/main/resources/captions_fr-CH.properties @@ -21,12 +21,10 @@ area=Zones city=Ville postcode=Code postal address=Adresse -community=commune communityName=commune date=Date description=Description disease=Maladie -district=Departement districtName=Departement edit=Modifier epiWeekFrom=De la Semaine de l’Epi @@ -44,10 +42,6 @@ menu=Menu moreActions=Plus name=Nom options=Paramètres -continent=Continent -subcontinent=Sous-continent -country=Pays -region=Région regionName=Région system=Système to=À @@ -57,8 +51,6 @@ creationDate=Date de création notAvailableShort=NA inaccessibleValue=Confidentiel numberOfCharacters=Nombre de caractères\: %d / %d -facility=Établissement de santé -pointOfEntry=Point d'entrée remove=Supprimer reportingUser=Utilisateur rapporteur notTestedYet=Pas encore testé @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Numéro de vol +ActivityAsCase=Activity as case ActivityAsCase.startDate=Début de l'activité ActivityAsCase.endDate=Fin d'activité ActivityAsCase.activityAsCaseDate=Date d'activité @@ -322,7 +315,7 @@ CampaignFormData.edit=Modifier # CaseData caseCasesList=Liste des cas caseInfrastructureDataChanged=Les données d'infrastructure ont changé -caseCloneCaseWithNewDisease=Générer un nouveau cas pour +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Documents de cas caseEditData=Modifier les données @@ -608,7 +601,7 @@ caseImportMergeCase=Remplacer le cas existant avec les modifications du cas impo # CasePreviousHospitalization CasePreviousHospitalization=Hospitalisation précédente CasePreviousHospitalization.admissionAndDischargeDate=Date d'admission & sortie -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date d'admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date de sortie ou transfert @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archivé Community.externalID=Identification externe @@ -1024,6 +1018,7 @@ districtActiveDistricts=Districts actifs districtArchivedDistricts=Districts archivés districtAllDistricts=Tous les districts +District=District District.archived=Archivé District.epidCode=Code epid District.growthRate=Taux de croissance @@ -1088,7 +1083,7 @@ eventSearchEvent=Rechercher un événement eventSearchSpecificEvent=Rechercher un événement spécifique linkEvent=Lier un événement linkEventGroup=Link event group -eventSelect=Sélectionnez un événement +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Événements eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Numéro de vol exposureTimePeriod=Période exposureSourceCaseName=Nom du cas source +Exposure=Exposure Exposure.probableInfectionEnvironment= L'exposition infectieuse la plus probable Exposure.startDate=Début d'exposition Exposure.endDate=Fin d'exposition @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Maison ou autre lieu Facility.OTHER_FACILITY=Autres établissements de santé +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archivé Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant health conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodéficience autre que le VIH HealthConditions.cardiovascularDiseaseIncludingHypertension=Maladie cardiovasculaire incluant l'hypertension HealthConditions.obesity=Obésité -HealthConditions.currentSmoker=Fumeur regulier -HealthConditions.formerSmoker=Ancien fumeur\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthme -HealthConditions.sickleCellDisease=Drépanocytose +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodéficience y compris VIH # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Autre aéroport PointOfEntry.OTHER_SEAPORT=Autre port maritime PointOfEntry.OTHER_GROUND_CROSSING=Autre passage au sol PointOfEntry.OTHER_POE=Autre point d'entrée + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Type de point d'entrée PointOfEntry.active=Actif ? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Détails du point d'entrée # Prescription prescriptionNewPrescription=Nouvelle prescription +Prescription=Prescription Prescription.additionalNotes=Notes Supplémentaires Prescription.dose=Dose Prescription.drugIntakeDetails=Nom du médicament @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=Identification externe Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=Identification externe Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archivé Country.externalId=ID externe Country.defaultName=Nom par défaut @@ -1841,6 +1845,7 @@ regionActiveRegions=Régions actives regionArchivedRegions=Régions archivées regionAllRegions=Toutes les régions +Region=Region Region.archived=Archivé Region.epidCode=Code Epid Region.growthRate=Taux de croissance @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Créer un traitement treatmentNewTreatment=Nouveau traitement treatmentOpenPrescription=Ouvrir une prescription +Treatment=Treatment Treatment.additionalNotes=Notes Supplémentaires Treatment.dose=Dose Treatment.drugIntakeDetails=Nom du médicament diff --git a/sormas-api/src/main/resources/captions_fr-FR.properties b/sormas-api/src/main/resources/captions_fr-FR.properties index 6f4231655c6..ad06918d9ca 100644 --- a/sormas-api/src/main/resources/captions_fr-FR.properties +++ b/sormas-api/src/main/resources/captions_fr-FR.properties @@ -21,12 +21,10 @@ area=Zones city=Ville postcode=Code postal address=Adresse -community=Communauté communityName=Communauté date=Date description=Description disease=Maladie -district=Département districtName=Département edit=Editer epiWeekFrom=De la Semaine @@ -44,10 +42,6 @@ menu=Menu moreActions=Plus name=Nom options=Paramètres -continent=Continent -subcontinent=Sous-continent -country=Pays -region=Région regionName=Région system=Système to=À @@ -57,8 +51,6 @@ creationDate=Date de création notAvailableShort=ND inaccessibleValue=Confidentiel numberOfCharacters=Nombre de caractères\: %d / %d -facility=Établissement -pointOfEntry=Point d'entrée remove=Retirer reportingUser=Rapport fait par notTestedYet=Pas encore testé @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Numéro de vol +ActivityAsCase=Activity as case ActivityAsCase.startDate=Début de l'activité ActivityAsCase.endDate=Fin d'activité ActivityAsCase.activityAsCaseDate=Date d'activité @@ -322,7 +315,7 @@ CampaignFormData.edit=Éditer # CaseData caseCasesList=Liste de cas caseInfrastructureDataChanged=Les données d'infrastructure ont changé -caseCloneCaseWithNewDisease=Générer un nouveau cas pour +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Documents de cas caseEditData=Modifier les données @@ -608,7 +601,7 @@ caseImportMergeCase=Remplacer le cas existant avec les modifications du cas impo # CasePreviousHospitalization CasePreviousHospitalization=Hospitalisation précédente CasePreviousHospitalization.admissionAndDischargeDate=Date d'admission & sortie -CasePreviousHospitalization.admittedToHealthFacility =Le patient a-t-il été admis dans l'établissement comme patient hospitalisé ? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date d'admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date de sortie ou transfert @@ -647,6 +640,7 @@ columnVaccineManufacturer=Fabricant du vaccin # Community +Community=Community Community.archived=Archivé Community.externalID=ID externe @@ -1024,6 +1018,7 @@ districtActiveDistricts=Départements actifs districtArchivedDistricts=Départements archivés districtAllDistricts=Tous les départements +District=District District.archived=Archivé District.epidCode=Code epid District.growthRate=Taux de croissance @@ -1088,7 +1083,7 @@ eventSearchEvent=Rechercher un événement eventSearchSpecificEvent=Rechercher un événement spécifique linkEvent=Link event linkEventGroup=Lier le groupe d'événements -eventSelect=Sélectionnez un événement +eventSelect=Select event eventSelectGroup=Sélectionner un groupe d'événements eventDefaultView=Evénements eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Numéro de vol exposureTimePeriod=Période exposureSourceCaseName=Nom du cas source +Exposure=Exposure Exposure.probableInfectionEnvironment= Environnement d'infection probable Exposure.startDate=Début d'exposition Exposure.endDate=Fin d'exposition @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configurer les Etablissements Facility.NO_FACILITY=Maison ou autre lieu Facility.OTHER_FACILITY=Autre établissement +Facility=Facility Facility.additionalInformation=Informations complémentaires Facility.archived=Archivé Facility.areaType=Type de zone (urbain/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Autres antécédents médicaux HealthConditions.immunodeficiencyOtherThanHiv=Immunodéficience autre que le VIH HealthConditions.cardiovascularDiseaseIncludingHypertension=Maladie cardiovasculaire incluant l'hypertension HealthConditions.obesity=Obésité -HealthConditions.currentSmoker=Fumeur\t -HealthConditions.formerSmoker=Ancien fumeur\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthme -HealthConditions.sickleCellDisease=Drépanocytose +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodéficience y compris VIH # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Nom du propriétaire personContactDetailThisPerson = Cette personne personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Autre aéroport PointOfEntry.OTHER_SEAPORT=Autre port maritime PointOfEntry.OTHER_GROUND_CROSSING=Autre point de passage terrestre PointOfEntry.OTHER_POE=Autre point d'entrée + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Type de point d'entrée PointOfEntry.active=Actif ? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Détails du point d'entrée # Prescription prescriptionNewPrescription=Nouvelle prescription +Prescription=Prescription Prescription.additionalNotes=Notes Supplémentaires Prescription.dose=Dose Prescription.drugIntakeDetails=Nom du médicament @@ -1807,6 +1808,7 @@ continentActiveContinents=Continents actifs continentArchivedContinents=Continents archivés continentAllContinents=Tous les continents +Continent=Continent Continent.archived=Archivé Continent.externalId=ID externe Continent.defaultName=Nom par défaut @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Sous-continents actifs subcontinentArchivedSubcontinents=Sous-continents archivés subcontinentAllSubcontinents=Tous les sous-continents +Subcontinent=Subcontinent Subcontinent.archived=Archivé Subcontinent.externalId=ID externe Subcontinent.defaultName=Nom par défaut @@ -1828,6 +1831,7 @@ countryActiveCountries=Pays actifs countryArchivedCountries=Pays archivés countryAllCountries=Tous les pays +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Régions actives regionArchivedRegions=Régions archivées regionAllRegions=Toutes les régions +Region=Region Region.archived=Archivé Region.epidCode=Code Epid Region.growthRate=Taux de croissance @@ -2294,6 +2299,7 @@ Task.taskPriority=Priorité de la tâche Task.travelEntry=Entrées de voyage # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Seulement les entrées récupérées travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Ouvrir le cas de cette entrée de voyage +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Créer un traitement treatmentNewTreatment=Nouveau traitement treatmentOpenPrescription=Ouvrir une prescription +Treatment=Treatment Treatment.additionalNotes=Notes supplémentaires Treatment.dose=Dose Treatment.drugIntakeDetails=Nom du médicament diff --git a/sormas-api/src/main/resources/captions_hi-IN.properties b/sormas-api/src/main/resources/captions_hi-IN.properties index ac2e8617a71..4f8e2adc6c2 100644 --- a/sormas-api/src/main/resources/captions_hi-IN.properties +++ b/sormas-api/src/main/resources/captions_hi-IN.properties @@ -21,12 +21,10 @@ area=Area city=City postcode=Postcode address=Address -community=Community communityName=Community date=Date description=Description disease=Disease -district=District districtName=District edit=Edit epiWeekFrom=From Epi Week @@ -44,10 +42,6 @@ menu=Menu moreActions=More name=Name options=Options -continent=Continent -subcontinent=Subcontinent -country=Country -region=Region regionName=Region system=System to=To @@ -57,8 +51,6 @@ creationDate=Creation date notAvailableShort=NA inaccessibleValue=Confidential numberOfCharacters=Number of characters\: %d / %d -facility=Facility -pointOfEntry=Point of entry remove=Remove reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Cases list caseInfrastructureDataChanged=Infrastructure data has changed -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Case Documents caseEditData=Edit data @@ -608,7 +601,7 @@ caseImportMergeCase=Override existing case with changes from the imported case? # CasePreviousHospitalization CasePreviousHospitalization=Previous hospitalization CasePreviousHospitalization.admissionAndDischargeDate=Date of admission & discharge -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date of admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date of discharge or transfer @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=External ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Active districts districtArchivedDistricts=Archived districts districtAllDistricts=All districts +District=District District.archived=Archived District.epidCode=Epid code District.growthRate=Growth rate @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Home or other place Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker\t\t -HealthConditions.formerSmoker=Former smoker\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease\t +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Active regions regionArchivedRegions=Archived regions regionAllRegions=All regions +Region=Region Region.archived=Archived Region.epidCode=Epid code Region.growthRate=Growth rate @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-api/src/main/resources/captions_hr-HR.properties b/sormas-api/src/main/resources/captions_hr-HR.properties index ac2e8617a71..4f8e2adc6c2 100644 --- a/sormas-api/src/main/resources/captions_hr-HR.properties +++ b/sormas-api/src/main/resources/captions_hr-HR.properties @@ -21,12 +21,10 @@ area=Area city=City postcode=Postcode address=Address -community=Community communityName=Community date=Date description=Description disease=Disease -district=District districtName=District edit=Edit epiWeekFrom=From Epi Week @@ -44,10 +42,6 @@ menu=Menu moreActions=More name=Name options=Options -continent=Continent -subcontinent=Subcontinent -country=Country -region=Region regionName=Region system=System to=To @@ -57,8 +51,6 @@ creationDate=Creation date notAvailableShort=NA inaccessibleValue=Confidential numberOfCharacters=Number of characters\: %d / %d -facility=Facility -pointOfEntry=Point of entry remove=Remove reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Cases list caseInfrastructureDataChanged=Infrastructure data has changed -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Case Documents caseEditData=Edit data @@ -608,7 +601,7 @@ caseImportMergeCase=Override existing case with changes from the imported case? # CasePreviousHospitalization CasePreviousHospitalization=Previous hospitalization CasePreviousHospitalization.admissionAndDischargeDate=Date of admission & discharge -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date of admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date of discharge or transfer @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=External ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Active districts districtArchivedDistricts=Archived districts districtAllDistricts=All districts +District=District District.archived=Archived District.epidCode=Epid code District.growthRate=Growth rate @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Home or other place Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker\t\t -HealthConditions.formerSmoker=Former smoker\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease\t +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Active regions regionArchivedRegions=Archived regions regionAllRegions=All regions +Region=Region Region.archived=Archived Region.epidCode=Epid code Region.growthRate=Growth rate @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-api/src/main/resources/captions_it-CH.properties b/sormas-api/src/main/resources/captions_it-CH.properties index 0e051ba9309..275d322ef35 100644 --- a/sormas-api/src/main/resources/captions_it-CH.properties +++ b/sormas-api/src/main/resources/captions_it-CH.properties @@ -21,12 +21,10 @@ area=Area city=Città postcode=Codice postale address=Indirizzo -community=Comune communityName=Comune date=Date description=Description disease=Malattia -district=Distretto districtName=Distretto edit=Edit epiWeekFrom=Dalla settimana Epi @@ -44,10 +42,6 @@ menu=Menu moreActions=Altro name=Nome options=Opzioni -continent=Continent -subcontinent=Subcontinent -country=Country -region=Cantone regionName=Cantone system=Sistema to=A @@ -57,8 +51,6 @@ creationDate=Data di creazione notAvailableShort=NA inaccessibleValue=Confidenziale numberOfCharacters=Numero di caratteri\: %d / %d -facility=Facility -pointOfEntry=Point of entry remove=Remove reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Elenco dei casi caseInfrastructureDataChanged=Dati dell'infrastruttura sono cambiati -caseCloneCaseWithNewDisease=Genera nuovo caso +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contatti caseDocuments=Case Documents caseEditData=Modifica dati @@ -608,7 +601,7 @@ caseImportMergeCase=Sovrascrivi il caso esistente con modifiche dal caso importa # CasePreviousHospitalization CasePreviousHospitalization=Ricoveri precedenti CasePreviousHospitalization.admissionAndDischargeDate=Data di ammissione e dimissione -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Data di ammissione CasePreviousHospitalization.description=Descrizione CasePreviousHospitalization.dischargeDate=Data di dimissione o trasferimento @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archiviato Community.externalID=ID esterno @@ -1024,6 +1018,7 @@ districtActiveDistricts=Distretti attivi districtArchivedDistricts=Distretti archiviati districtAllDistricts=Tutti i distretti +District=District District.archived=Archiviato District.epidCode=Codice Epid District.growthRate=Tasso di crescita @@ -1088,7 +1083,7 @@ eventSearchEvent=Cerca evento eventSearchSpecificEvent=Cerca evento specifico linkEvent=Link event linkEventGroup=Link event group -eventSelect=Seleziona evento +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Eventi eventActionsView=Azioni @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Casa o altro luogo Facility.OTHER_FACILITY=Altra struttura +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archiviato Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Ulteriori condizioni preesistenti pertinenti HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficienza diversa da HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Malattia cardiovascolare inclusa ipertensione HealthConditions.obesity=Obesità -HealthConditions.currentSmoker=Fumatore\t\t -HealthConditions.formerSmoker=Ex fumatore\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asma -HealthConditions.sickleCellDisease=Anemia falciforme +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficienza incluso HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Altro aereoporto PointOfEntry.OTHER_SEAPORT=Altro porto PointOfEntry.OTHER_GROUND_CROSSING=Altro punto d'ingresso sul terreno PointOfEntry.OTHER_POE=Altri punti di ingresso nel paese + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Tipi di punti d'ingresso nel paese PointOfEntry.active=Attivo? PointOfEntry.latitude=Latitudine @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Dettagli dei punti d'ingresso nel paese # Prescription prescriptionNewPrescription=Nuova prescrizione +Prescription=Prescription Prescription.additionalNotes=Note aggiuntive Prescription.dose=Dose Prescription.drugIntakeDetails=Nome medicinale @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Cantoni attivi regionArchivedRegions=Cantoni archiviati regionAllRegions=Tutti i Cantoni +Region=Region Region.archived=Archiviato Region.epidCode=Codice Epid Region.growthRate=Tasso di crescita @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Crea trattamento treatmentNewTreatment=Nuovo trattamento treatmentOpenPrescription=Apri prescrizione +Treatment=Treatment Treatment.additionalNotes=Note aggiuntive Treatment.dose=Dose Treatment.drugIntakeDetails=Nome medicinale diff --git a/sormas-api/src/main/resources/captions_it-IT.properties b/sormas-api/src/main/resources/captions_it-IT.properties index 9cda821a4e7..59baf5d68f9 100644 --- a/sormas-api/src/main/resources/captions_it-IT.properties +++ b/sormas-api/src/main/resources/captions_it-IT.properties @@ -21,12 +21,10 @@ area=Area city=Città postcode=Postcode address=Address -community=Comune communityName=Comune date=Date description=Description disease=Malattia -district=Distretto districtName=Distretto edit=Edit epiWeekFrom=Dalla settimana Epi @@ -44,10 +42,6 @@ menu=Menu moreActions=Altro name=Nome options=Opzioni -continent=Continent -subcontinent=Subcontinent -country=Country -region=Cantone regionName=Cantone system=Sistema to=A @@ -57,8 +51,6 @@ creationDate=Data di creazione notAvailableShort=NA inaccessibleValue=Confidential numberOfCharacters=Numero di caratteri\: %d / %d -facility=Facility -pointOfEntry=Point of entry remove=Remove reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Elenco dei casi caseInfrastructureDataChanged=Dati dell'infrastruttura sono cambiati -caseCloneCaseWithNewDisease=Genera nuovo caso +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contatti caseDocuments=Case Documents caseEditData=Modifica dati @@ -608,7 +601,7 @@ caseImportMergeCase=Sovrascrivi il caso esistente con modifiche dal caso importa # CasePreviousHospitalization CasePreviousHospitalization=Ricoveri precedenti CasePreviousHospitalization.admissionAndDischargeDate=Data di ammissione e dimissione -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Data di ammissione CasePreviousHospitalization.description=Descrizione CasePreviousHospitalization.dischargeDate=Data di dimissione o trasferimento @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=ID esterno @@ -1024,6 +1018,7 @@ districtActiveDistricts=Distretti attivi districtArchivedDistricts=Distretti archiviati districtAllDistricts=Tutti i distretti +District=District District.archived=Archived District.epidCode=Codice Epid District.growthRate=Tasso di crescita @@ -1088,7 +1083,7 @@ eventSearchEvent=Cerca evento eventSearchSpecificEvent=Cerca evento specifico linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Casa o altro luogo Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Ulteriori condizioni preesistenti pertinenti HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficienza diversa da HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Malattia cardiovascolare inclusa ipertensione HealthConditions.obesity=Obesità -HealthConditions.currentSmoker=Fumatore\t\t -HealthConditions.formerSmoker=Ex fumatore\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asma -HealthConditions.sickleCellDisease=Anemia falciforme +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficienza incluso HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Altro aereoporto PointOfEntry.OTHER_SEAPORT=Altro porto PointOfEntry.OTHER_GROUND_CROSSING=Altro punto d'ingresso sul terreno PointOfEntry.OTHER_POE=Altri punti di ingresso nel paese + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Tipi di punti d'ingresso nel paese PointOfEntry.active=Attivo? PointOfEntry.latitude=Latitudine @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Dettagli dei punti d'ingresso nel paese # Prescription prescriptionNewPrescription=Nuova prescrizione +Prescription=Prescription Prescription.additionalNotes=Note aggiuntive Prescription.dose=Dose Prescription.drugIntakeDetails=Nome medicinale @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Cantoni attivi regionArchivedRegions=Cantoni archiviati regionAllRegions=Tutti i Cantoni +Region=Region Region.archived=Archived Region.epidCode=Codice Epid Region.growthRate=Tasso di crescita @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Crea trattamento treatmentNewTreatment=Nuovo trattamento treatmentOpenPrescription=Apri prescrizione +Treatment=Treatment Treatment.additionalNotes=Note aggiuntive Treatment.dose=Dose Treatment.drugIntakeDetails=Nome medicinale diff --git a/sormas-api/src/main/resources/captions_ja-JP.properties b/sormas-api/src/main/resources/captions_ja-JP.properties index ac2e8617a71..4f8e2adc6c2 100644 --- a/sormas-api/src/main/resources/captions_ja-JP.properties +++ b/sormas-api/src/main/resources/captions_ja-JP.properties @@ -21,12 +21,10 @@ area=Area city=City postcode=Postcode address=Address -community=Community communityName=Community date=Date description=Description disease=Disease -district=District districtName=District edit=Edit epiWeekFrom=From Epi Week @@ -44,10 +42,6 @@ menu=Menu moreActions=More name=Name options=Options -continent=Continent -subcontinent=Subcontinent -country=Country -region=Region regionName=Region system=System to=To @@ -57,8 +51,6 @@ creationDate=Creation date notAvailableShort=NA inaccessibleValue=Confidential numberOfCharacters=Number of characters\: %d / %d -facility=Facility -pointOfEntry=Point of entry remove=Remove reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Cases list caseInfrastructureDataChanged=Infrastructure data has changed -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Case Documents caseEditData=Edit data @@ -608,7 +601,7 @@ caseImportMergeCase=Override existing case with changes from the imported case? # CasePreviousHospitalization CasePreviousHospitalization=Previous hospitalization CasePreviousHospitalization.admissionAndDischargeDate=Date of admission & discharge -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date of admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date of discharge or transfer @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=External ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Active districts districtArchivedDistricts=Archived districts districtAllDistricts=All districts +District=District District.archived=Archived District.epidCode=Epid code District.growthRate=Growth rate @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Home or other place Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker\t\t -HealthConditions.formerSmoker=Former smoker\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease\t +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Active regions regionArchivedRegions=Archived regions regionAllRegions=All regions +Region=Region Region.archived=Archived Region.epidCode=Epid code Region.growthRate=Growth rate @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-api/src/main/resources/captions_nl-NL.properties b/sormas-api/src/main/resources/captions_nl-NL.properties index 6418730489b..2434db79b3a 100644 --- a/sormas-api/src/main/resources/captions_nl-NL.properties +++ b/sormas-api/src/main/resources/captions_nl-NL.properties @@ -21,12 +21,10 @@ area=Area city=Stad postcode=Postcode address=Address -community=Gemeenschap communityName=Gemeenschap date=Date description=Description disease=Ziekte -district=District districtName=District edit=Edit epiWeekFrom=From Epi Week @@ -44,10 +42,6 @@ menu=Menu moreActions=Meer name=Naam options=Opties -continent=Continent -subcontinent=Subcontinent -country=Country -region=Regio regionName=Regio system=Systeem to=To @@ -57,8 +51,6 @@ creationDate=Creation date notAvailableShort=NA inaccessibleValue=Confidential numberOfCharacters=Number of characters\: %d / %d -facility=Facility -pointOfEntry=Point of entry remove=Remove reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Cases list caseInfrastructureDataChanged=Infrastructure data has changed -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Case Documents caseEditData=Edit data @@ -608,7 +601,7 @@ caseImportMergeCase=Override existing case with changes from the imported case? # CasePreviousHospitalization CasePreviousHospitalization=Previous hospitalization CasePreviousHospitalization.admissionAndDischargeDate=Date of admission & discharge -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date of admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date of discharge or transfer @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=External ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Active districts districtArchivedDistricts=Archived districts districtAllDistricts=All districts +District=District District.archived=Archived District.epidCode=Epid code District.growthRate=Growth rate @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Home or other place Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker\t\t -HealthConditions.formerSmoker=Former smoker\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease\t +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Active regions regionArchivedRegions=Archived regions regionAllRegions=All regions +Region=Region Region.archived=Archived Region.epidCode=Epid code Region.growthRate=Growth rate @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-api/src/main/resources/captions_no-NO.properties b/sormas-api/src/main/resources/captions_no-NO.properties index ac2e8617a71..4f8e2adc6c2 100644 --- a/sormas-api/src/main/resources/captions_no-NO.properties +++ b/sormas-api/src/main/resources/captions_no-NO.properties @@ -21,12 +21,10 @@ area=Area city=City postcode=Postcode address=Address -community=Community communityName=Community date=Date description=Description disease=Disease -district=District districtName=District edit=Edit epiWeekFrom=From Epi Week @@ -44,10 +42,6 @@ menu=Menu moreActions=More name=Name options=Options -continent=Continent -subcontinent=Subcontinent -country=Country -region=Region regionName=Region system=System to=To @@ -57,8 +51,6 @@ creationDate=Creation date notAvailableShort=NA inaccessibleValue=Confidential numberOfCharacters=Number of characters\: %d / %d -facility=Facility -pointOfEntry=Point of entry remove=Remove reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Cases list caseInfrastructureDataChanged=Infrastructure data has changed -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Case Documents caseEditData=Edit data @@ -608,7 +601,7 @@ caseImportMergeCase=Override existing case with changes from the imported case? # CasePreviousHospitalization CasePreviousHospitalization=Previous hospitalization CasePreviousHospitalization.admissionAndDischargeDate=Date of admission & discharge -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date of admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date of discharge or transfer @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=External ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Active districts districtArchivedDistricts=Archived districts districtAllDistricts=All districts +District=District District.archived=Archived District.epidCode=Epid code District.growthRate=Growth rate @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Home or other place Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker\t\t -HealthConditions.formerSmoker=Former smoker\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease\t +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Active regions regionArchivedRegions=Archived regions regionAllRegions=All regions +Region=Region Region.archived=Archived Region.epidCode=Epid code Region.growthRate=Growth rate @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-api/src/main/resources/captions_pl-PL.properties b/sormas-api/src/main/resources/captions_pl-PL.properties index ac2e8617a71..4f8e2adc6c2 100644 --- a/sormas-api/src/main/resources/captions_pl-PL.properties +++ b/sormas-api/src/main/resources/captions_pl-PL.properties @@ -21,12 +21,10 @@ area=Area city=City postcode=Postcode address=Address -community=Community communityName=Community date=Date description=Description disease=Disease -district=District districtName=District edit=Edit epiWeekFrom=From Epi Week @@ -44,10 +42,6 @@ menu=Menu moreActions=More name=Name options=Options -continent=Continent -subcontinent=Subcontinent -country=Country -region=Region regionName=Region system=System to=To @@ -57,8 +51,6 @@ creationDate=Creation date notAvailableShort=NA inaccessibleValue=Confidential numberOfCharacters=Number of characters\: %d / %d -facility=Facility -pointOfEntry=Point of entry remove=Remove reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Cases list caseInfrastructureDataChanged=Infrastructure data has changed -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Case Documents caseEditData=Edit data @@ -608,7 +601,7 @@ caseImportMergeCase=Override existing case with changes from the imported case? # CasePreviousHospitalization CasePreviousHospitalization=Previous hospitalization CasePreviousHospitalization.admissionAndDischargeDate=Date of admission & discharge -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date of admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date of discharge or transfer @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=External ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Active districts districtArchivedDistricts=Archived districts districtAllDistricts=All districts +District=District District.archived=Archived District.epidCode=Epid code District.growthRate=Growth rate @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Home or other place Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker\t\t -HealthConditions.formerSmoker=Former smoker\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease\t +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Active regions regionArchivedRegions=Archived regions regionAllRegions=All regions +Region=Region Region.archived=Archived Region.epidCode=Epid code Region.growthRate=Growth rate @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-api/src/main/resources/captions_ps-AF.properties b/sormas-api/src/main/resources/captions_ps-AF.properties index 6f981d59bc3..ce5cdfbfb6c 100644 --- a/sormas-api/src/main/resources/captions_ps-AF.properties +++ b/sormas-api/src/main/resources/captions_ps-AF.properties @@ -21,12 +21,10 @@ area=Area city=ښار postcode=پوسټ کوډ address=پته -community=ټولنه communityName=ټولنه date=نېټه description=څرګندونه disease=ناروغی -district=ولسوالی districtName=ولسوالي edit=Edit epiWeekFrom=د کتلوی معافیت د اونې څخه @@ -44,10 +42,6 @@ menu=نوملړ moreActions=نوری کړنی name=نوم options=اختیارات -continent=Continent -subcontinent=Subcontinent -country=Country -region=حوزه regionName=حوزه system=سیستم to=ته @@ -57,8 +51,6 @@ creationDate=د جوړولو نیټه notAvailableShort=موجود نه دی\nد دسترسي وړ نه دی inaccessibleValue=محرم numberOfCharacters=د ځانګړنو شمیر -facility=روغتیایی مرکز -pointOfEntry=د ننوتلو ځای remove=لری کول reportingUser=راپور ورکونکی notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=تصحیح # CaseData caseCasesList=د پیښو لیست caseInfrastructureDataChanged=د زیربناو ارقام تغیر شوی -caseCloneCaseWithNewDisease=د نوي پېښی اماده کول +caseCloneCaseWithNewDisease=Generate new case for caseContacts=قراردادونه caseDocuments=د پیښې سندونه caseEditData=د ارقامو تصحیح کول @@ -608,7 +601,7 @@ caseImportMergeCase=ایا د ظاهر شوي پیښې په تغیر سره مو # CasePreviousHospitalization CasePreviousHospitalization=د بستر پخوانۍ تاریخچه CasePreviousHospitalization.admissionAndDischargeDate=د بستر کیدو او خارجیدو نېټه -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=د بستر کیدو نېټه CasePreviousHospitalization.description=څرګندونه CasePreviousHospitalization.dischargeDate=د خارج کیدو یا انتقال نېټه @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=ارشیف شوی Community.externalID=بهرنی هویت @@ -1024,6 +1018,7 @@ districtActiveDistricts=فعالی ولسوالۍ districtArchivedDistricts=له منځه تللی ولسوالۍ districtAllDistricts=ټولی ولسوالۍ +District=District District.archived=ارشیف شوی District.epidCode=ای پی کوډ District.growthRate=د ودی اندازه @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=منظم شوی روغتیایی مرکز Facility.NO_FACILITY=د روغتیایی مرکز نه شتون Facility.OTHER_FACILITY=نور روغتیایی مرکزونه +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=ارشیف شوی Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker\t\t -HealthConditions.formerSmoker=Former smoker\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease\t +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=فعال هیوادونه countryArchivedCountries=Archived countries countryAllCountries=ټول هیوادونه +Country=Country Country.archived=ارشیف شوی Country.externalId=بهرنی هویت Country.defaultName=معمول نوم @@ -1841,6 +1845,7 @@ regionActiveRegions=فعالی حوزي regionArchivedRegions=آرشیف شوی حوزي regionAllRegions=ټولی حوزي +Region=Region Region.archived=آرشیف شوی Region.epidCode=د epid کوډ Region.growthRate=د ودي اندازه @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-api/src/main/resources/captions_pt-PT.properties b/sormas-api/src/main/resources/captions_pt-PT.properties index c5a15cf0811..ae9ce71d717 100644 --- a/sormas-api/src/main/resources/captions_pt-PT.properties +++ b/sormas-api/src/main/resources/captions_pt-PT.properties @@ -21,12 +21,10 @@ area=Area city=Cidade postcode=Postcode address=Address -community=Comunidade communityName=Comunidade date=Date description=Description disease=Doença -district=Distrito districtName=Distrito edit=Edit epiWeekFrom=From Epi Week @@ -44,10 +42,6 @@ menu=Menu moreActions=Mais name=Nome options=Options -continent=Continent -subcontinent=Subcontinent -country=Country -region=Region regionName=Region system=System to=To @@ -57,8 +51,6 @@ creationDate=Creation date notAvailableShort=NA inaccessibleValue=Confidential numberOfCharacters=Number of characters\: %d / %d -facility=Facility -pointOfEntry=Point of entry remove=Remove reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Cases list caseInfrastructureDataChanged=Infrastructure data has changed -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Case Documents caseEditData=Edit data @@ -608,7 +601,7 @@ caseImportMergeCase=Override existing case with changes from the imported case? # CasePreviousHospitalization CasePreviousHospitalization=Previous hospitalization CasePreviousHospitalization.admissionAndDischargeDate=Date of admission & discharge -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date of admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date of discharge or transfer @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=External ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Active districts districtArchivedDistricts=Archived districts districtAllDistricts=All districts +District=District District.archived=Archived District.epidCode=Epid code District.growthRate=Growth rate @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Home or other place Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker\t\t -HealthConditions.formerSmoker=Former smoker\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease\t +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Active regions regionArchivedRegions=Archived regions regionAllRegions=All regions +Region=Region Region.archived=Archived Region.epidCode=Epid code Region.growthRate=Growth rate @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-api/src/main/resources/captions_ro-RO.properties b/sormas-api/src/main/resources/captions_ro-RO.properties index ac2e8617a71..4f8e2adc6c2 100644 --- a/sormas-api/src/main/resources/captions_ro-RO.properties +++ b/sormas-api/src/main/resources/captions_ro-RO.properties @@ -21,12 +21,10 @@ area=Area city=City postcode=Postcode address=Address -community=Community communityName=Community date=Date description=Description disease=Disease -district=District districtName=District edit=Edit epiWeekFrom=From Epi Week @@ -44,10 +42,6 @@ menu=Menu moreActions=More name=Name options=Options -continent=Continent -subcontinent=Subcontinent -country=Country -region=Region regionName=Region system=System to=To @@ -57,8 +51,6 @@ creationDate=Creation date notAvailableShort=NA inaccessibleValue=Confidential numberOfCharacters=Number of characters\: %d / %d -facility=Facility -pointOfEntry=Point of entry remove=Remove reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Cases list caseInfrastructureDataChanged=Infrastructure data has changed -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Case Documents caseEditData=Edit data @@ -608,7 +601,7 @@ caseImportMergeCase=Override existing case with changes from the imported case? # CasePreviousHospitalization CasePreviousHospitalization=Previous hospitalization CasePreviousHospitalization.admissionAndDischargeDate=Date of admission & discharge -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date of admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date of discharge or transfer @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=External ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Active districts districtArchivedDistricts=Archived districts districtAllDistricts=All districts +District=District District.archived=Archived District.epidCode=Epid code District.growthRate=Growth rate @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Home or other place Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker\t\t -HealthConditions.formerSmoker=Former smoker\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease\t +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Active regions regionArchivedRegions=Archived regions regionAllRegions=All regions +Region=Region Region.archived=Archived Region.epidCode=Epid code Region.growthRate=Growth rate @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-api/src/main/resources/captions_ru-RU.properties b/sormas-api/src/main/resources/captions_ru-RU.properties index 4eb80a5b3d2..c1f69a1abfe 100644 --- a/sormas-api/src/main/resources/captions_ru-RU.properties +++ b/sormas-api/src/main/resources/captions_ru-RU.properties @@ -21,12 +21,10 @@ area=Район city=Город postcode=Индекс address=Адрес -community=Община communityName=Община date=Дата description=Описание disease=Болезнь -district=Административный район districtName=Название района edit=Редактировать epiWeekFrom=Эпидемиологическая неделя с @@ -44,10 +42,6 @@ menu=Меню moreActions=Подробнее name=Имя options=Опции -continent=Континент -subcontinent=Субконтинент -country=Страна -region=Регион regionName=Регион system=Система to=по @@ -57,8 +51,6 @@ creationDate=Дата создания notAvailableShort=не применимо inaccessibleValue=Конфиденциально numberOfCharacters=Количество символов\: %d / %d -facility=Учреждение -pointOfEntry=Пункты въезда remove=Удалить reportingUser=Должностное лицо notTestedYet=Тест пока не осуществлён @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Cases list caseInfrastructureDataChanged=Infrastructure data has changed -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Case Documents caseEditData=Edit data @@ -608,7 +601,7 @@ caseImportMergeCase=Override existing case with changes from the imported case? # CasePreviousHospitalization CasePreviousHospitalization=Previous hospitalization CasePreviousHospitalization.admissionAndDischargeDate=Date of admission & discharge -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date of admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date of discharge or transfer @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=External ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Active districts districtArchivedDistricts=Archived districts districtAllDistricts=All districts +District=District District.archived=Archived District.epidCode=Epid code District.growthRate=Growth rate @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Home or other place Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker\t\t -HealthConditions.formerSmoker=Former smoker\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease\t +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Active regions regionArchivedRegions=Archived regions regionAllRegions=All regions +Region=Region Region.archived=Archived Region.epidCode=Epid code Region.growthRate=Growth rate @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-api/src/main/resources/captions_sv-SE.properties b/sormas-api/src/main/resources/captions_sv-SE.properties index ac2e8617a71..4f8e2adc6c2 100644 --- a/sormas-api/src/main/resources/captions_sv-SE.properties +++ b/sormas-api/src/main/resources/captions_sv-SE.properties @@ -21,12 +21,10 @@ area=Area city=City postcode=Postcode address=Address -community=Community communityName=Community date=Date description=Description disease=Disease -district=District districtName=District edit=Edit epiWeekFrom=From Epi Week @@ -44,10 +42,6 @@ menu=Menu moreActions=More name=Name options=Options -continent=Continent -subcontinent=Subcontinent -country=Country -region=Region regionName=Region system=System to=To @@ -57,8 +51,6 @@ creationDate=Creation date notAvailableShort=NA inaccessibleValue=Confidential numberOfCharacters=Number of characters\: %d / %d -facility=Facility -pointOfEntry=Point of entry remove=Remove reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Cases list caseInfrastructureDataChanged=Infrastructure data has changed -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Case Documents caseEditData=Edit data @@ -608,7 +601,7 @@ caseImportMergeCase=Override existing case with changes from the imported case? # CasePreviousHospitalization CasePreviousHospitalization=Previous hospitalization CasePreviousHospitalization.admissionAndDischargeDate=Date of admission & discharge -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date of admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date of discharge or transfer @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=External ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Active districts districtArchivedDistricts=Archived districts districtAllDistricts=All districts +District=District District.archived=Archived District.epidCode=Epid code District.growthRate=Growth rate @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Home or other place Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker\t\t -HealthConditions.formerSmoker=Former smoker\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease\t +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Active regions regionArchivedRegions=Archived regions regionAllRegions=All regions +Region=Region Region.archived=Archived Region.epidCode=Epid code Region.growthRate=Growth rate @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-api/src/main/resources/captions_sw-KE.properties b/sormas-api/src/main/resources/captions_sw-KE.properties index ac2e8617a71..4f8e2adc6c2 100644 --- a/sormas-api/src/main/resources/captions_sw-KE.properties +++ b/sormas-api/src/main/resources/captions_sw-KE.properties @@ -21,12 +21,10 @@ area=Area city=City postcode=Postcode address=Address -community=Community communityName=Community date=Date description=Description disease=Disease -district=District districtName=District edit=Edit epiWeekFrom=From Epi Week @@ -44,10 +42,6 @@ menu=Menu moreActions=More name=Name options=Options -continent=Continent -subcontinent=Subcontinent -country=Country -region=Region regionName=Region system=System to=To @@ -57,8 +51,6 @@ creationDate=Creation date notAvailableShort=NA inaccessibleValue=Confidential numberOfCharacters=Number of characters\: %d / %d -facility=Facility -pointOfEntry=Point of entry remove=Remove reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Cases list caseInfrastructureDataChanged=Infrastructure data has changed -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Case Documents caseEditData=Edit data @@ -608,7 +601,7 @@ caseImportMergeCase=Override existing case with changes from the imported case? # CasePreviousHospitalization CasePreviousHospitalization=Previous hospitalization CasePreviousHospitalization.admissionAndDischargeDate=Date of admission & discharge -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date of admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date of discharge or transfer @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=External ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Active districts districtArchivedDistricts=Archived districts districtAllDistricts=All districts +District=District District.archived=Archived District.epidCode=Epid code District.growthRate=Growth rate @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Home or other place Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker\t\t -HealthConditions.formerSmoker=Former smoker\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease\t +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Active regions regionArchivedRegions=Archived regions regionAllRegions=All regions +Region=Region Region.archived=Archived Region.epidCode=Epid code Region.growthRate=Growth rate @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-api/src/main/resources/captions_tr-TR.properties b/sormas-api/src/main/resources/captions_tr-TR.properties index ac2e8617a71..4f8e2adc6c2 100644 --- a/sormas-api/src/main/resources/captions_tr-TR.properties +++ b/sormas-api/src/main/resources/captions_tr-TR.properties @@ -21,12 +21,10 @@ area=Area city=City postcode=Postcode address=Address -community=Community communityName=Community date=Date description=Description disease=Disease -district=District districtName=District edit=Edit epiWeekFrom=From Epi Week @@ -44,10 +42,6 @@ menu=Menu moreActions=More name=Name options=Options -continent=Continent -subcontinent=Subcontinent -country=Country -region=Region regionName=Region system=System to=To @@ -57,8 +51,6 @@ creationDate=Creation date notAvailableShort=NA inaccessibleValue=Confidential numberOfCharacters=Number of characters\: %d / %d -facility=Facility -pointOfEntry=Point of entry remove=Remove reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Cases list caseInfrastructureDataChanged=Infrastructure data has changed -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Case Documents caseEditData=Edit data @@ -608,7 +601,7 @@ caseImportMergeCase=Override existing case with changes from the imported case? # CasePreviousHospitalization CasePreviousHospitalization=Previous hospitalization CasePreviousHospitalization.admissionAndDischargeDate=Date of admission & discharge -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date of admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date of discharge or transfer @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=External ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Active districts districtArchivedDistricts=Archived districts districtAllDistricts=All districts +District=District District.archived=Archived District.epidCode=Epid code District.growthRate=Growth rate @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Home or other place Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker\t\t -HealthConditions.formerSmoker=Former smoker\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease\t +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Active regions regionArchivedRegions=Archived regions regionAllRegions=All regions +Region=Region Region.archived=Archived Region.epidCode=Epid code Region.growthRate=Growth rate @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-api/src/main/resources/captions_uk-UA.properties b/sormas-api/src/main/resources/captions_uk-UA.properties index ac2e8617a71..4f8e2adc6c2 100644 --- a/sormas-api/src/main/resources/captions_uk-UA.properties +++ b/sormas-api/src/main/resources/captions_uk-UA.properties @@ -21,12 +21,10 @@ area=Area city=City postcode=Postcode address=Address -community=Community communityName=Community date=Date description=Description disease=Disease -district=District districtName=District edit=Edit epiWeekFrom=From Epi Week @@ -44,10 +42,6 @@ menu=Menu moreActions=More name=Name options=Options -continent=Continent -subcontinent=Subcontinent -country=Country -region=Region regionName=Region system=System to=To @@ -57,8 +51,6 @@ creationDate=Creation date notAvailableShort=NA inaccessibleValue=Confidential numberOfCharacters=Number of characters\: %d / %d -facility=Facility -pointOfEntry=Point of entry remove=Remove reportingUser=Reporting user notTestedYet=Not tested yet @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=Flight number +ActivityAsCase=Activity as case ActivityAsCase.startDate=Start of activity ActivityAsCase.endDate=End of activity ActivityAsCase.activityAsCaseDate=Activity date @@ -322,7 +315,7 @@ CampaignFormData.edit=Edit # CaseData caseCasesList=Cases list caseInfrastructureDataChanged=Infrastructure data has changed -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Generate new case for caseContacts=Contacts caseDocuments=Case Documents caseEditData=Edit data @@ -608,7 +601,7 @@ caseImportMergeCase=Override existing case with changes from the imported case? # CasePreviousHospitalization CasePreviousHospitalization=Previous hospitalization CasePreviousHospitalization.admissionAndDischargeDate=Date of admission & discharge -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date of admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date of discharge or transfer @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=External ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Active districts districtArchivedDistricts=Archived districts districtAllDistricts=All districts +District=District District.archived=Archived District.epidCode=Epid code District.growthRate=Growth rate @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Home or other place Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker\t\t -HealthConditions.formerSmoker=Former smoker\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease\t +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Active regions regionArchivedRegions=Archived regions regionAllRegions=All regions +Region=Region Region.archived=Archived Region.epidCode=Epid code Region.growthRate=Growth rate @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-api/src/main/resources/captions_ur-PK.properties b/sormas-api/src/main/resources/captions_ur-PK.properties index f34ad2cd442..dda07133bc0 100644 --- a/sormas-api/src/main/resources/captions_ur-PK.properties +++ b/sormas-api/src/main/resources/captions_ur-PK.properties @@ -21,12 +21,10 @@ area=خطہ city=شہر postcode=پوسٹ کوڈ address=پتہ -community=کمیونیٹی communityName=کمیونیٹی date=تاریخ description=تفصیل disease=بیماری -district=ضلع districtName=ضلع edit=ترمیم epiWeekFrom=EPI ویک سے @@ -44,10 +42,6 @@ menu=مینیو moreActions=مزید name=نام options=اختیارات -continent=براعظم -subcontinent=برصغیر -country=ملک -region=علاقہ regionName=علاقہ system=سسٹم to=کے لیے @@ -182,6 +176,7 @@ actionDiscardAndContinue=رد کر دیں اور جاری رکھیں activityAsCaseFlightNumber=پرواز نمبر +ActivityAsCase=Activity as case ActivityAsCase.startDate=سرگرمی کا آغاز ActivityAsCase.endDate=سرگرمی کا اختتام ActivityAsCase.activityAsCaseDate=سرگرمی کی تاریخ @@ -322,7 +317,7 @@ CampaignFormData.edit=ترمیم کریں # CaseData caseCasesList=کیسز کی فہرست caseInfrastructureDataChanged=انفراسٹرکچر کا ڈیٹا بدل گیا ہے -caseCloneCaseWithNewDisease=کے لیے نیا کیس بنائیں +caseCloneCaseWithNewDisease=Generate new case for caseContacts=روابط caseDocuments=کیس کے دستاویزات caseEditData=ڈیٹا میں ترمیم کریں @@ -608,7 +603,7 @@ caseImportMergeCase=موجودہ کیس کو، امپورٹ شدہ کیس کی # CasePreviousHospitalization CasePreviousHospitalization=گزشتہ ہسپتال میں داخلہ CasePreviousHospitalization.admissionAndDischargeDate=داخلہ اور چھٹی کی تاریخ -CasePreviousHospitalization.admittedToHealthFacility =کیا مریض کو، داخلی مریض کے طور پر سہولت گاہ میں داخل کیا گیا تھا؟ +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=داخلے کی تاریخ CasePreviousHospitalization.description=تفصیل CasePreviousHospitalization.dischargeDate=چھٹی یا منتقلی کی تاریخ @@ -647,6 +642,7 @@ columnVaccineManufacturer=ویکسین بنانے والا # Community +Community=Community Community.archived=آرکائیوڈ Community.externalID=بیرونی شناخت @@ -1024,6 +1020,7 @@ districtActiveDistricts=فعال اضلاع districtArchivedDistricts=آرکائیو شدہ اضلاع districtAllDistricts=تمام اضلاع +District=District District.archived=آرکائیوڈ District.epidCode=Epid کوڈ District.growthRate=اضافے کی شرح @@ -1088,7 +1085,7 @@ eventSearchEvent=تقریب تلاش کریں eventSearchSpecificEvent=مخصوص تقریب تلاش کریں linkEvent=تقریب سے مںسلک کریں linkEventGroup=تقریب کے گروپ کو لنک کریں -eventSelect=تقریب کا انتخاب کریں +eventSelect=Select event eventSelectGroup=تقریب کے گروپ انتخاب کریں eventDefaultView=تقریبات eventActionsView=اعمال @@ -1293,6 +1290,7 @@ exposureFlightNumber=پرواز نمبر exposureTimePeriod=وقت کی مدت exposureSourceCaseName=سورس کیس کا نام +Exposure=Exposure Exposure.probableInfectionEnvironment= ممکنہ انفیکشن ماحول Exposure.startDate=سامنے کی شروعات Exposure.endDate=سامنے کا اختتام @@ -1355,6 +1353,7 @@ Facility.CONFIGURED_FACILITY=کنفیگرڈ سہولت گاہ Facility.NO_FACILITY=گھر یا دوسری جگہ Facility.OTHER_FACILITY=دوسری سہولت گاہ +Facility=Facility Facility.additionalInformation=اضافی معلومات Facility.archived=آرکائیوڈ Facility.areaType=خطے کی قسم (شہری/دیہی) @@ -1412,10 +1411,10 @@ HealthConditions.otherConditions=اضافی متعلقہ، پہلے سے موج HealthConditions.immunodeficiencyOtherThanHiv=ایچ آئی وی کے علاوہ امیونو کی کمی HealthConditions.cardiovascularDiseaseIncludingHypertension=ہائپر ٹینشن سمیت دل کی بیماری HealthConditions.obesity=موٹاپا -HealthConditions.currentSmoker=موجودہ سگریٹ نوش \t\t -HealthConditions.formerSmoker=سابقہ سگریٹ نوش\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=دمہ -HealthConditions.sickleCellDisease=سکل سیل کی بیماری +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=ایچ آئی وی سمیت امیونو کی کمی # Import @@ -1727,6 +1726,7 @@ personContactDetailOwnerName = مالک کا نام personContactDetailThisPerson = یہ شخص personContactDetailThirdParty = کسی دوسرے شخص یا سہولت گاہ کے رابطے کی تفصیلات جمع کریں +PersonContactDetail = Person contact detail PersonContactDetail.person = شخص PersonContactDetail.primaryContact = ابتدائی رابطے کی تفصیلات PersonContactDetail.personContactDetailType = رابطے قسم کی تفصیلات @@ -1746,6 +1746,8 @@ PointOfEntry.OTHER_AIRPORT=دوسرا ہوائی اڈہ PointOfEntry.OTHER_SEAPORT=دوسری بندرگاہ PointOfEntry.OTHER_GROUND_CROSSING=دوسری گراؤنڈ کراسنگ PointOfEntry.OTHER_POE=داخلے کی دیگر جگہيں + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=داخلے کی جگہ کی قسم PointOfEntry.active=فعال؟ PointOfEntry.latitude=عرض بلد @@ -1783,6 +1785,7 @@ PortHealthInfo.details=داخلے کی جگہ کی تفصیلات # Prescription prescriptionNewPrescription=نیا نسخہ +Prescription=Prescription Prescription.additionalNotes=اضافی نوٹس Prescription.dose=خوراک Prescription.drugIntakeDetails=دوا کا نام @@ -1807,6 +1810,7 @@ continentActiveContinents=فعال براعظموں continentArchivedContinents=آرکائیوڈ براعظم continentAllContinents=تمام براعظم +Continent=Continent Continent.archived=آرکائیوڈ Continent.externalId=بیرونی شناخت Continent.defaultName=پہلے سے طے شدہ نام @@ -1817,6 +1821,7 @@ subcontinentActiveSubcontinents=فعال برصغیر subcontinentArchivedSubcontinents=آرکائیوڈ برصغیر subcontinentAllSubcontinents=تمام برصغیر +Subcontinent=Subcontinent Subcontinent.archived=آرکائیوڈ Subcontinent.externalId=بیرونی شناخت Subcontinent.defaultName=پہلے سے طے شدہ نام @@ -1828,6 +1833,7 @@ countryActiveCountries=فعال ممالک countryArchivedCountries=آرکائیوڈ شدہ ممالک countryAllCountries=تمام ممالک +Country=Country Country.archived=آرکائیوڈ Country.externalId=بیرونی شناخت Country.defaultName=پہلے سے طے شدہ نام @@ -1841,6 +1847,7 @@ regionActiveRegions=فعال علاقے regionArchivedRegions=آرکائیوڈ علاقے regionAllRegions=تمام علاقے +Region=Region Region.archived=آرکائیوڈ Region.epidCode=Epid کوڈ Region.growthRate=اضافے کی شرح @@ -2294,6 +2301,7 @@ Task.taskPriority=کام کی ترجیح Task.travelEntry=سفری اندراج # TestReport +TestReport=Test report TestReport.testDateTime=نتیجہ کی تاریخ اور وقت TestReport.testLabCity=لیبارٹری کا شہر TestReport.testLabExternalId=لیب کی بیرونی شناخت @@ -2308,7 +2316,7 @@ travelEntryOnlyRecoveredEntries=صرف بازیافت شدہ اندراجات travelEntryOnlyVaccinatedEntries=صرف ویکسین شدہ اندراجات travelEntryOnlyEntriesTestedNegative=صرف وہ اندراجات, جن کا ٹیسٹ منفی آیا travelEntryOnlyEntriesConvertedToCase=صر فوہ اندراجات، جن کو کیس میں تبدیل کیا گیا -travelEntryOpenResultingCase=اس ٹریول انٹری کے لۓ کیس اوپن کیس +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=فعال سفری اندراجات travelEntryArchivedTravelEntries=آرکائیوڈ سفری اندراجات travelEntryAllTravelEntries=تمام سفری اندراجات @@ -2359,6 +2367,7 @@ treatmentCreateTreatment=علاج کا انداج کریں treatmentNewTreatment=نیا علاج treatmentOpenPrescription=نسخہ کھولیں +Treatment=Treatment Treatment.additionalNotes=اضافی نوٹس Treatment.dose=خوراک Treatment.drugIntakeDetails=دوا کا نام diff --git a/sormas-api/src/main/resources/captions_zh-CN.properties b/sormas-api/src/main/resources/captions_zh-CN.properties index 9434b2ea3bb..3e7729c6763 100644 --- a/sormas-api/src/main/resources/captions_zh-CN.properties +++ b/sormas-api/src/main/resources/captions_zh-CN.properties @@ -21,12 +21,10 @@ area=地区 city=城市 postcode=邮政编码 address=地址 -community=社区 communityName=社区 date=日期 description=描述 disease=疾病 -district=区 districtName=区 edit=编辑 epiWeekFrom=从Epi周 @@ -44,10 +42,6 @@ menu=菜单 moreActions=更多 name=名 options=选项 -continent=大陆 -subcontinent=次大陆区域 -country=国家/地区 -region=地区 regionName=地区 system=系统 to=至 @@ -57,8 +51,6 @@ creationDate=创建日期 notAvailableShort=不可用 inaccessibleValue=保密 numberOfCharacters=字符数: %d / %d -facility=设施 -pointOfEntry=入口点 remove=移除 reportingUser=报告用户 notTestedYet=尚未测试。 @@ -182,6 +174,7 @@ actionDiscardAndContinue=Discard and continue activityAsCaseFlightNumber=航班号 +ActivityAsCase=Activity as case ActivityAsCase.startDate=活动开始 ActivityAsCase.endDate=活动结束 ActivityAsCase.activityAsCaseDate=活动日期 @@ -322,7 +315,7 @@ CampaignFormData.edit=编辑 # CaseData caseCasesList=病例列表 caseInfrastructureDataChanged=基础设施数据已更改 -caseCloneCaseWithNewDisease=为 生成新案例 +caseCloneCaseWithNewDisease=Generate new case for caseContacts=联系人 caseDocuments=案例文档 caseEditData=编辑数据 @@ -608,7 +601,7 @@ caseImportMergeCase=Override existing case with changes from the imported case? # CasePreviousHospitalization CasePreviousHospitalization=Previous hospitalization CasePreviousHospitalization.admissionAndDischargeDate=Date of admission & discharge -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? CasePreviousHospitalization.admissionDate=Date of admission CasePreviousHospitalization.description=Description CasePreviousHospitalization.dischargeDate=Date of discharge or transfer @@ -647,6 +640,7 @@ columnVaccineManufacturer=Vaccine manufacturer # Community +Community=Community Community.archived=Archived Community.externalID=External ID @@ -1024,6 +1018,7 @@ districtActiveDistricts=Active districts districtArchivedDistricts=Archived districts districtAllDistricts=All districts +District=District District.archived=Archived District.epidCode=Epid code District.growthRate=Growth rate @@ -1088,7 +1083,7 @@ eventSearchEvent=Search event eventSearchSpecificEvent=Search specific Event linkEvent=Link event linkEventGroup=Link event group -eventSelect=Select event +eventSelect=Select event eventSelectGroup=Select event group eventDefaultView=Events eventActionsView=Actions @@ -1293,6 +1288,7 @@ exposureFlightNumber=Flight number exposureTimePeriod=Time period exposureSourceCaseName=Name of source case +Exposure=Exposure Exposure.probableInfectionEnvironment= Probable infection environment Exposure.startDate=Start of exposure Exposure.endDate=End of exposure @@ -1355,6 +1351,7 @@ Facility.CONFIGURED_FACILITY=Configured facility Facility.NO_FACILITY=Home or other place Facility.OTHER_FACILITY=Other facility +Facility=Facility Facility.additionalInformation=Additional information Facility.archived=Archived Facility.areaType=Area type (urban/rural) @@ -1412,10 +1409,10 @@ HealthConditions.otherConditions=Additional relevant pre-existing conditions HealthConditions.immunodeficiencyOtherThanHiv=Immunodeficiency other than HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Cardiovascular disease including hypertension HealthConditions.obesity=Obesity -HealthConditions.currentSmoker=Current smoker\t\t -HealthConditions.formerSmoker=Former smoker\t\t +HealthConditions.currentSmoker=Current smoker +HealthConditions.formerSmoker=Former smoker HealthConditions.asthma=Asthma -HealthConditions.sickleCellDisease=Sickle cell disease\t +HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunodeficiency including HIV # Import @@ -1727,6 +1724,7 @@ personContactDetailOwnerName = Owner name personContactDetailThisPerson = This person personContactDetailThirdParty = Collect contact details of another person or facility +PersonContactDetail = Person contact detail PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primary contact details PersonContactDetail.personContactDetailType = Type of contact details @@ -1746,6 +1744,8 @@ PointOfEntry.OTHER_AIRPORT=Other airport PointOfEntry.OTHER_SEAPORT=Other seaport PointOfEntry.OTHER_GROUND_CROSSING=Other ground crossing PointOfEntry.OTHER_POE=Other point of entry + +PointOfEntry=Point of entry PointOfEntry.pointOfEntryType=Point of entry type PointOfEntry.active=Active? PointOfEntry.latitude=Latitude @@ -1783,6 +1783,7 @@ PortHealthInfo.details=Point of entry details # Prescription prescriptionNewPrescription=New prescription +Prescription=Prescription Prescription.additionalNotes=Additional notes Prescription.dose=Dose Prescription.drugIntakeDetails=Drug name @@ -1807,6 +1808,7 @@ continentActiveContinents=Active continents continentArchivedContinents=Archived continents continentAllContinents=All continents +Continent=Continent Continent.archived=Archived Continent.externalId=External ID Continent.defaultName=Default name @@ -1817,6 +1819,7 @@ subcontinentActiveSubcontinents=Active subcontinents subcontinentArchivedSubcontinents=Archived subcontinents subcontinentAllSubcontinents=All subcontinents +Subcontinent=Subcontinent Subcontinent.archived=Archived Subcontinent.externalId=External ID Subcontinent.defaultName=Default name @@ -1828,6 +1831,7 @@ countryActiveCountries=Active countries countryArchivedCountries=Archived countries countryAllCountries=All countries +Country=Country Country.archived=Archived Country.externalId=External ID Country.defaultName=Default name @@ -1841,6 +1845,7 @@ regionActiveRegions=Active regions regionArchivedRegions=Archived regions regionAllRegions=All regions +Region=Region Region.archived=Archived Region.epidCode=Epid code Region.growthRate=Growth rate @@ -2294,6 +2299,7 @@ Task.taskPriority=Task priority Task.travelEntry=Travel entry # TestReport +TestReport=Test report TestReport.testDateTime=Date and time of result TestReport.testLabCity=Lab city TestReport.testLabExternalId=Lab external ID @@ -2308,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Only recovered entries travelEntryOnlyVaccinatedEntries=Only vaccinated entries travelEntryOnlyEntriesTestedNegative=Only entries tested negative travelEntryOnlyEntriesConvertedToCase=Only entries converted to case -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Open case of this travel entry travelEntryActiveTravelEntries=Active travel entries travelEntryArchivedTravelEntries=Archived travel entries travelEntryAllTravelEntries=All travel entries @@ -2359,6 +2365,7 @@ treatmentCreateTreatment=Create treatment treatmentNewTreatment=New treatment treatmentOpenPrescription=Open prescription +Treatment=Treatment Treatment.additionalNotes=Additional notes Treatment.dose=Dose Treatment.drugIntakeDetails=Drug name diff --git a/sormas-api/src/main/resources/enum_fr-FR.properties b/sormas-api/src/main/resources/enum_fr-FR.properties index 889ee1b150a..253aeccf1a5 100644 --- a/sormas-api/src/main/resources/enum_fr-FR.properties +++ b/sormas-api/src/main/resources/enum_fr-FR.properties @@ -801,7 +801,7 @@ MessageSubject.LAB_SAMPLE_SHIPPED = Échantillon de laboratoire expédié MessageSubject.CONTACT_SYMPTOMATIC = Le contact est devenu symptomatique MessageSubject.TASK_START = Tâche à démarrer MessageSubject.TASK_DUE = Tâche en retard -MessageSubject.TASK_UPDATED_ASSIGNEE = Updated task assignee +MessageSubject.TASK_UPDATED_ASSIGNEE = Responsable de tâche mis à jour MessageSubject.VISIT_COMPLETED = Visite de suivi terminée MessageSubject.DISEASE_CHANGED = Maladie de cas modifiée MessageSubject.EVENT_GROUP_CREATED = Groupe d'événements créé @@ -1785,7 +1785,7 @@ MeansOfImmunization.VACCINATION_RECOVERY = Vaccination/Recovery MeansOfImmunization.OTHER = Autres #EntityColumn -EntityColumn.FIELD_ID = Field ID +EntityColumn.FIELD_ID = ID du champ EntityColumn.FIELD = Champ EntityColumn.TYPE = Type EntityColumn.DATA_PROTECTION = Protection des données diff --git a/sormas-api/src/main/resources/strings_cs-CZ.properties b/sormas-api/src/main/resources/strings_cs-CZ.properties index 92ad6e0091f..85e860de3aa 100644 --- a/sormas-api/src/main/resources/strings_cs-CZ.properties +++ b/sormas-api/src/main/resources/strings_cs-CZ.properties @@ -342,11 +342,11 @@ errorWritingTemplate = Soubor šablony nelze zapsat. errorCampaignDiagramTotalsCalculationError=Alespoň část procentních hodnot pro diagram '%s' nelze spočítat. Zkontrolujte prosím definice chyb v grafu. errorNoPopulationDataLocations=Nebyla nalezena žádná populační data pro následující umístění\: %s errorNoPopulationDataFound=Nejsou k dispozici žádná populační data. Přepněte do absolutního zobrazení dat -errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set +errorFormIdPopulationAgeGroup=Obě možnosti "Id formuláře" a "Věková skupina obyvatel" jsou nastaveny errorExternalSurveillanceToolNonCoronavirusCase=Vybrané případy nelze odeslat na nástroj hlášení, protože případ %s není případ %s. -errorExternalSurveillanceToolCasesNotSharable=%d z vybraných případů nelze odeslat do externího nástroje hlášení.
    Ujistěte se, že všechny [%s] jsou vlastněny a mohou být sdíleny s externím nástrojem pro podávání zpráv. Pak zkuste přeposlat nebo odeslat pouze ty, které mohou být odeslány. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Vybrané události nelze odeslat do nástroje hlášení, protože událost %s není klastrem %s. -errorExternalSurveillanceToolEventNotOwned=%d z vybraných událostí nelze odeslat do externího nástroje hlášení.
    Ujistěte se, že všech [%s] je vlastněno. Potom zkuste znovu poslat nebo poslat pouze ty, které mohou být odeslány. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = Událost souvisí s jurisdikcí, ke které nemáte přístup errorEventUnlinkEventGroupFromAnotherJurisdiction = Skupina událostí má událost související s jurisdikcí, ke které nemáte přístup errorCaseNotEditable = Tento případ již není upravitelný @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = Níže uvedený seznam obsahuje všechny existuj infoPickOrCreateEventForContact = Níže uvedený seznam obsahuje všechny existující události, které mají stejnou chorobu jako aktuální kontakt. Zkontrolujte, zda událost patří k tomuto kontaktu již v tomto seznamu, nebo vytvořte novou, pokud tam není. infoPickOrCreateEventForContacts = Níže uvedený seznam obsahuje všechny existující události, které mají stejnou nemoc jako vybrané kontakty. Zkontrolujte, zda událost, ke které tyto kontakty patří, již v tomto seznamu je, nebo vytvořte novou, pokud není. infoPickOrCreateEventForLabMessage = Níže uvedený seznam obsahuje všechny existující události, které mají stejnou chorobu jako lab zpráva. Zkontrolujte, zda událost, ke které nový účastník události patří, již je na tomto seznamu, nebo vytvořte novou, pokud není. -infoPickOrCreateSuperordinateEventForEvent = Níže uvedený seznam obsahuje všechny existující události, které mají stejnou chorobu jako aktuální událost. Zkontrolujte, zda je událost hlavní nadřazenou pro tuto událost již na tomto seznamu, nebo vytvořte novou, pokud není. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = Seznam níže obsahuje všechny existující skupiny událostí. Zkontrolujte, zda tato událost patří do tohoto seznamu, nebo vytvořte novou, pokud není. infoSelectOrCreatePersonForCase = Databáze již obsahuje alespoň jednu osobu, která se zdá být velmi podobná osobním údajům vytvořeného případu.

    Prohlédněte si prosím seznam osob. Pokud se domníváte, že jedna z těchto osob odpovídá vašemu případu, vyberte je a klikněte na tlačítko Uložit. V opačném případě klikněte na Vytvořit novou osobu pro vytvoření nové osoby pro váš případ.

    Pokud si nejste jisti, můžete toto okno zrušit a zrušit proces vytváření případů. infoSearchPerson = Pomocí níže uvedených filtrů můžete vyhledávat všechny osoby v systému, ke kterému máte přístup. Až budete hotovi, klikněte na "Hledat" a uvidíte seznam osob, které odpovídají textu, který jste zadali. Vyberte osobu v seznamu a klikněte na "Potvrdit" pro výběr vybrané osoby. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Vyberte prosím nemocnici jako místo pobytu. Pokud infoMoreDetailsAboutHospitalization = Chcete-li přidat další podrobnosti o hospitalizaci, přejděte na záložku hospitalizace. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Změna země není povolena, protože alespoň jeden účastník této události nemá nastavený odpovědný region a/nebo odpovědný okres. infoContactAlreadyConvertedToCase = Tento kontakt již byl převeden na případ. Prosím, přidejte nové návštěvy k případu. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Účet musí být aktivován diff --git a/sormas-api/src/main/resources/strings_de-CH.properties b/sormas-api/src/main/resources/strings_de-CH.properties index 22fea867a70..c464194e011 100644 --- a/sormas-api/src/main/resources/strings_de-CH.properties +++ b/sormas-api/src/main/resources/strings_de-CH.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=Für die folgenden Standorte wurden keine Bevölk errorNoPopulationDataFound=Es sind keine Bevölkerungsdaten verfügbar. Wechseln zur absoluten Datenansicht errorFormIdPopulationAgeGroup=Die Optionen "Formular-ID" und "Bevölkerungs-Altersgruppe" sind festgelegt errorExternalSurveillanceToolNonCoronavirusCase=Die ausgewählten Fälle konnten nicht an die Meldesoftware gesendet werden, da der Fall %s kein %s Fall ist. -errorExternalSurveillanceToolCasesNotSharable=%d der ausgewählten Fälle können nicht an die Meldesoftware gesendet werden.
    Bitte stellen Sie sicher, dass alle [%s] im Besitz sind und mit der Meldesoftware geteilt werden dürfen. Versuchen Sie das Senden danach erneut oder senden Sie nur diejenigen, die gesendet werden können. +errorExternalSurveillanceToolCasesNotSharable=%d der ausgewählten Fälle können nicht an die Meldesoftware gesendet werden.
    Bitte stellen Sie sicher, dass alle untenstehenden Fälle im Besitz sind und mit der Meldesoftware geteilt werden dürfen. Versuchen Sie das Senden danach erneut oder senden Sie nur diejenigen, die gesendet werden können. errorExternalSurveillanceToolNonClusterEvent=Die ausgewählten Ereignisse konnten nicht an die Meldesoftware gesendet werden, da das Ereignis %s kein %s Cluster ist. -errorExternalSurveillanceToolEventNotOwned=%d der ausgewählten Ereignisse können nicht an die Meldesoftware gesendet werden.
    Bitte stellen Sie sicher, dass alle [%s] im Besitz sind. Versuchen Sie das Senden danach erneut oder senden Sie nur diejenigen, die gesendet werden können. +errorExternalSurveillanceToolEventNotOwned=%d der ausgewählten Ereignisse können nicht an die Meldesoftware gesendet werden.
    Bitte stellen Sie sicher, dass alle untenstehenden Ereignisse im Besitz sind und mit der Meldesoftware geteilt werden dürfen. Versuchen Sie das Senden danach erneut oder senden Sie nur diejenigen, die gesendet werden können. errorEventFromAnotherJurisdiction = Das Ereignis liegt in einem Zuständigkeitsbereich, auf den Sie keinen Zugriff haben errorEventUnlinkEventGroupFromAnotherJurisdiction = Die Ereignisgruppe hat ein Ereignis in einem Zuständigkeitsbereich, auf den Sie keinen Zugriff haben errorCaseNotEditable = Dieser Fall kann nicht mehr bearbeitet werden @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = Die folgende Liste enthält alle Ereignisse, die infoPickOrCreateEventForContact = Die folgende Liste enthält alle Ereignisse, die die gleiche Krankheit haben wie der aktuelle Kontakt. Bitte prüfen Sie, ob das Ereignis, zu dem dieser Kontakt gehört, bereits in dieser Liste ist oder erstellen Sie eine neue wenn es nicht ist. infoPickOrCreateEventForContacts = Die folgende Liste enthält alle Ereignisse, die die gleiche Krankheit haben wie die ausgewählten Kontakte. Bitte überprüfen Sie, ob das Ereignis, zu dem diese Kontakte gehören, bereits in dieser Liste ist oder erstellen Sie eine neues wenn nicht. infoPickOrCreateEventForLabMessage = Die folgende Liste enthält alle Ereignisse, die der gleichen Krankheit zugeordnet sind wie die Labormeldung. Bitte prüfen Sie, ob das Ereignis, zu dem der neue Ereignisteilnehmer gehört, bereits auf dieser Liste ist oder erstellen Sie ein neues, wenn nicht. -infoPickOrCreateSuperordinateEventForEvent = Die folgende Liste enthält alle Ereignisse, die die gleiche Krankheit haben wie das aktuelle Ereignis. Bitte prüfen Sie, ob das übergeordnete Ereignis für dieses Ereignis bereits auf dieser Liste ist, oder erstellen Sie ein neues, wenn nicht. +infoPickOrCreateSuperordinateEventForEvent = Die folgende Liste enthält alle Ereignisse mit Ereignisdatum, die die gleiche Krankheit haben wie das aktuelle Ereignis. Bitte prüfen Sie, ob das übergeordnete Ereignis für dieses Ereignis bereits auf dieser Liste ist, oder erstellen Sie ein neues, wenn nicht. infoPickOrCreateEventGroupForEvent = Die folgende Liste enthält alle vorhandenen Ereignisgruppen. Bitte prüfen Sie, ob die Ereignisgruppe, zu der dieses Ereignis gehört, bereits auf dieser Liste ist oder erstellen Sie eine neue. infoSelectOrCreatePersonForCase = Die Datenbank enthält bereits mindestens eine Person, die dem erstellten Fall sehr ähnlich zu sein scheint.

    Bitte prüfen Sie die Liste der Personen. Wenn Sie sich sicher sind, dass eine dieser Personen mit Ihrer Fallperson übereinstimmt, wählen Sie sie aus und klicken Sie auf Speichern. Ansonsten klicken Sie auf Neue Person erstellen, um eine neue Person für Ihren Fall zu erstellen.

    Wenn Sie sich unsicher sind, können Sie dieses Fenster schließen und die Fallerstellung abbrechen. infoSearchPerson = Verwenden Sie die folgenden Filter, um nach Personen im System zu suchen, auf die Sie Zugriff haben. Wenn Sie fertig sind, klicken Sie auf "Suchen", um eine Liste von Personen zu sehen, die mit dem eingegebenen Text übereinstimmen. Wählen Sie die Person in der Liste aus und klicken Sie auf "Bestätigen", um die ausgewählte Person auszuwählen. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Bitte wählen Sie ein Krankenhaus als Aufenthaltsort infoMoreDetailsAboutHospitalization = Um weitere Details zum Krankenhausaufenthalt hinzuzufügen, gehen Sie zum Reiter Krankenhausaufenthalt. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Eine Änderung des Landes ist nicht zulässig, da mindestens ein Ereignisteilnehmer dieses Ereignisses keinen zuständigen Kanton und/oder zuständigen Bezirk hat. infoContactAlreadyConvertedToCase = Dieser Kontakt wurde bereits in einen Fall konvertiert. Bitte fügen Sie stattdessen dem Fall neue Anrufe hinzu. +infoSearchPersonOnDependentForm = Nach einer anderen Person suchen # Messages messageActivateAccount = Konto muss aktiviert werden diff --git a/sormas-api/src/main/resources/strings_de-DE.properties b/sormas-api/src/main/resources/strings_de-DE.properties index a32a05bf4ca..8423dc6d79e 100644 --- a/sormas-api/src/main/resources/strings_de-DE.properties +++ b/sormas-api/src/main/resources/strings_de-DE.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=Für die folgenden Standorte wurden keine Bevölk errorNoPopulationDataFound=Es sind keine Bevölkerungsdaten verfügbar. Wechseln zur absoluten Datenansicht errorFormIdPopulationAgeGroup=Die Optionen "Formular-ID" und "Bevölkerungs-Altersgruppe" sind festgelegt errorExternalSurveillanceToolNonCoronavirusCase=Die ausgewählten Fälle konnten nicht an die Meldesoftware gesendet werden, da der Fall %s kein %s Fall ist. -errorExternalSurveillanceToolCasesNotSharable=%d der ausgewählten Fälle können nicht an die Meldesoftware gesendet werden.
    Bitte stellen Sie sicher, dass alle [%s] im Besitz sind und mit der Meldesoftware geteilt werden dürfen. Versuchen Sie das Senden danach erneut oder senden Sie nur diejenigen, die gesendet werden können. +errorExternalSurveillanceToolCasesNotSharable=%d der ausgewählten Fälle können nicht an die Meldesoftware gesendet werden.
    Bitte stellen Sie sicher, dass alle untenstehenden Fälle im Besitz sind und mit der Meldesoftware geteilt werden dürfen. Versuchen Sie das Senden danach erneut oder senden Sie nur diejenigen, die gesendet werden können. errorExternalSurveillanceToolNonClusterEvent=Die ausgewählten Ereignisse konnten nicht an die Meldesoftware gesendet werden, da das Ereignis %s kein %s Cluster ist. -errorExternalSurveillanceToolEventNotOwned=%d der ausgewählten Ereignisse können nicht an die Meldesoftware gesendet werden.
    Bitte stellen Sie sicher, dass alle [%s] im Besitz sind. Versuchen Sie das Senden danach erneut oder senden Sie nur diejenigen, die gesendet werden können. +errorExternalSurveillanceToolEventNotOwned=%d der ausgewählten Ereignisse können nicht an die Meldesoftware gesendet werden.
    Bitte stellen Sie sicher, dass alle untenstehenden Ereignisse im Besitz sind und mit der Meldesoftware geteilt werden dürfen. Versuchen Sie das Senden danach erneut oder senden Sie nur diejenigen, die gesendet werden können. errorEventFromAnotherJurisdiction = Das Ereignis liegt in einem Zuständigkeitsbereich, auf den Sie keinen Zugriff haben errorEventUnlinkEventGroupFromAnotherJurisdiction = Die Ereignisgruppe hat ein Ereignis in einem Zuständigkeitsbereich, auf den Sie keinen Zugriff haben errorCaseNotEditable = Dieser Fall kann nicht mehr bearbeitet werden @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = Die folgende Liste enthält alle Ereignisse, die infoPickOrCreateEventForContact = Die folgende Liste enthält alle Ereignisse, die die gleiche Krankheit haben wie der aktuelle Kontakt. Bitte prüfen Sie, ob das Ereignis, zu dem dieser Kontakt gehört, bereits in dieser Liste ist oder erstellen Sie ein neues wenn nicht. infoPickOrCreateEventForContacts = Die folgende Liste enthält alle Ereignisse, die die gleiche Krankheit haben wie die ausgewählten Kontakte. Bitte überprüfen Sie, ob das Ereignis, zu dem diese Kontakte gehören, bereits in dieser Liste ist oder erstellen Sie eine neues wenn nicht. infoPickOrCreateEventForLabMessage = Die folgende Liste enthält alle Ereignisse, die der gleichen Krankheit zugeordnet sind wie die Labormeldung. Bitte prüfen Sie, ob das Ereignis, zu dem der neue Ereignisteilnehmer gehört, bereits auf dieser Liste ist oder erstellen Sie ein neues, wenn nicht. -infoPickOrCreateSuperordinateEventForEvent = Die folgende Liste enthält alle Ereignisse, die die gleiche Krankheit haben wie das aktuelle Ereignis. Bitte prüfen Sie, ob das übergeordnete Ereignis für dieses Ereignis bereits auf dieser Liste ist, oder erstellen Sie ein neues, wenn nicht. +infoPickOrCreateSuperordinateEventForEvent = Die folgende Liste enthält alle Ereignisse mit Ereignisdatum, die die gleiche Krankheit haben wie das aktuelle Ereignis. Bitte prüfen Sie, ob das übergeordnete Ereignis für dieses Ereignis bereits auf dieser Liste ist, oder erstellen Sie ein neues, wenn nicht. infoPickOrCreateEventGroupForEvent = Die folgende Liste enthält alle vorhandenen Ereignisgruppen. Bitte prüfen Sie, ob die Ereignisgruppe, zu der dieses Ereignis gehört, bereits auf dieser Liste ist oder erstellen Sie eine neue. infoSelectOrCreatePersonForCase = Die Datenbank enthält bereits mindestens eine Person, die dem erstellten Fall sehr ähnlich zu sein scheint.

    Bitte schauen Sie sich die Liste der Personen an. Wenn Sie sicher sind, dass eine dieser Personen mit Ihrer Fallperson übereinstimmt, wählen Sie sie aus und klicken Sie auf Speichern. Ansonsten klicken Sie auf Neue Person erstellen, um eine neue Person für Ihren Fall zu erstellen.

    Wenn Sie sich unsicher sind, können Sie dieses Fenster schließen und die Fallerstellung abbrechen. infoSearchPerson = Verwenden Sie die folgenden Filter, um nach Personen im System zu suchen, auf die Sie Zugriff haben. Wenn Sie fertig sind, klicken Sie auf "Suchen", um eine Liste von Personen zu sehen, die mit dem eingegebenen Text übereinstimmen. Wählen Sie die Person in der Liste aus und klicken Sie auf "Bestätigen", um die ausgewählte Person auszuwählen. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Bitte wählen Sie ein Krankenhaus als Aufenthaltsort infoMoreDetailsAboutHospitalization = Um weitere Details zum Krankenhausaufenthalt hinzuzufügen, gehen Sie zum Reiter Krankenhausaufenthalt. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Eine Änderung des Landes ist nicht zulässig, da mindestens ein Ereignisteilnehmer dieses Ereignisses kein zuständiges Bundesland und/oder zuständige/n Landkreis/Kreisfreie Stadt hat. infoContactAlreadyConvertedToCase = Dieser Kontakt wurde bereits in einen Fall konvertiert. Bitte fügen Sie stattdessen dem Fall neue Anrufe hinzu. +infoSearchPersonOnDependentForm = Nach einer anderen Person suchen # Messages messageActivateAccount = Konto muss aktiviert werden diff --git a/sormas-api/src/main/resources/strings_en-AF.properties b/sormas-api/src/main/resources/strings_en-AF.properties index f5da9073b0a..ea447d4b31b 100644 --- a/sormas-api/src/main/resources/strings_en-AF.properties +++ b/sormas-api/src/main/resources/strings_en-AF.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_en-GH.properties b/sormas-api/src/main/resources/strings_en-GH.properties index 0acb619c5b6..2e09eb76ada 100644 --- a/sormas-api/src/main/resources/strings_en-GH.properties +++ b/sormas-api/src/main/resources/strings_en-GH.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_en-NG.properties b/sormas-api/src/main/resources/strings_en-NG.properties index b2b8266bc37..6ada606fc38 100644 --- a/sormas-api/src/main/resources/strings_en-NG.properties +++ b/sormas-api/src/main/resources/strings_en-NG.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_es-CU.properties b/sormas-api/src/main/resources/strings_es-CU.properties index 9548da4d9c1..8395037d821 100644 --- a/sormas-api/src/main/resources/strings_es-CU.properties +++ b/sormas-api/src/main/resources/strings_es-CU.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No se encontraron datos de población para las si errorNoPopulationDataFound=No hay datos de población disponibles. Cambiando a vista de datos absolutos errorFormIdPopulationAgeGroup=Están especificadas las opciones "ID de formulario" y "Grupo de edad de población" errorExternalSurveillanceToolNonCoronavirusCase=No fue posible enviar los casos seleccionados a la herramienta de reporte porque el caso %s no es un caso %s. -errorExternalSurveillanceToolCasesNotSharable=%d de los casos seleccionados no pueden ser enviados a la herramienta externa de informes.
    Por favor, asegúrese de ser responsable de todo [%s] y que puede compartirlo con la herramienta externa de informes; entonces vuelva a intentar el envío, o envíe solo los que puedan ser enviados. +errorExternalSurveillanceToolCasesNotSharable=%d de los casos seleccionados no pueden ser enviados a la herramienta externa de informes.
    Por favor, asegúrese de ser responsable de los casos siguientes y que puede compartirlos con la herramienta externa de informes; entonces vuelva a intentar el envío, o envíe solo los que puedan ser enviados. errorExternalSurveillanceToolNonClusterEvent=No fue posible enviar los eventos seleccionados a la herramienta de reporte porque el evento %s no es una agrupación %s. -errorExternalSurveillanceToolEventNotOwned=%d de los eventos seleccionados no pueden ser enviados a la herramienta externa de informes.
    Por favor, asegúrese de ser responsable de todo [%s]; entonces vuelva a intentar el envío, o envíe solo los que puedan ser enviados. +errorExternalSurveillanceToolEventNotOwned=%d de los eventos seleccionados no pueden ser enviados a la herramienta externa de informes.
    Por favor, asegúrese de ser responsable de todos los eventos siguientes; entonces vuelva a intentar el envío, o envíe solo los que puedan ser enviados. errorEventFromAnotherJurisdiction = El evento está relacionado con una jurisdicción a la que no tiene acceso errorEventUnlinkEventGroupFromAnotherJurisdiction = El grupo de eventos tiene un evento relacionado con una jurisdicción a la que no tiene acceso errorCaseNotEditable = Este caso ya no es editable @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = La siguiente lista contiene todos los eventos ex infoPickOrCreateEventForContact = La siguiente lista contiene todos los eventos existentes que tienen la misma enfermedad que el contacto actual. Por favor, compruebe si el evento al que pertenece este contacto ya está en esta lista o cree uno nuevo si no lo está. infoPickOrCreateEventForContacts = La siguiente lista contiene todos los eventos existentes que tienen la misma enfermedad que los contactos seleccionados. Por favor, compruebe si el evento al que pertenecen estos contactos ya está en esta lista o cree uno nuevo si no lo está. infoPickOrCreateEventForLabMessage = La siguiente lista contiene todos los eventos existentes que tienen la misma enfermedad que el mensaje de laboratorio. Por favor, compruebe si el evento al que pertenece el nuevo participante de evento ya está en esta lista o cree uno nuevo si no lo está. -infoPickOrCreateSuperordinateEventForEvent = La lista siguiente contiene todos los eventos existentes que tienen la misma enfermedad que el evento actual. Por favor, compruebe si el evento superior de este evento ya está en esta lista, o cree uno nuevo si no lo está. +infoPickOrCreateSuperordinateEventForEvent = La lista siguiente contiene todos los eventos existentes que tienen una fecha de evento y la misma enfermedad que el evento actual. Por favor, compruebe si el evento superior de este evento ya está en esta lista, o cree uno nuevo si no lo está. infoPickOrCreateEventGroupForEvent = La siguiente lista contiene todos los grupos de eventos existentes. Por favor, compruebe si el grupo de eventos al que pertenece este evento ya está en esta lista o cree uno nuevo si no lo está. infoSelectOrCreatePersonForCase = La base de datos ya contiene al menos una persona que parece muy similar a los datos personales del caso creado.

    Por favor, revise la lista de personas. Si está seguro de que una de esas personas coincide con su persona de caso, selecciónela y haga clic en el botón Guardar. De lo contrario, haga clic en Crear nueva persona para crear una nueva persona para su caso.

    Si no está seguro, puede descartar esta ventana y cancelar el proceso de creación de caso. infoSearchPerson = Use los filtros siguientes para buscar a cualquier persona en el sistema a la que tenga acceso. Cuando termine haga clic en "Buscar" para ver una lista de personas que coinciden con el texto que ha ingresado. Seleccione una persona en la lista y haga clic en "Confirmar" para escoger la persona seleccionada. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Por favor seleccione un hospital como lugar de estan infoMoreDetailsAboutHospitalization = Para agregar más detalles sobre la hospitalización, vaya a la pestaña de hospitalización. infoCountryNotEditableEventParticipantsWithoutJurisdiction = No se permite cambiar el país porque al menos un participante de este evento no tiene especificada una provincia responsable y/o municipio responsable. infoContactAlreadyConvertedToCase = Este contacto ya fue convertido en un caso. Añada nuevas visitas al caso en su lugar. +infoSearchPersonOnDependentForm = Buscar otra persona # Messages messageActivateAccount = La cuenta debe ser activada diff --git a/sormas-api/src/main/resources/strings_es-EC.properties b/sormas-api/src/main/resources/strings_es-EC.properties index 584ce105e68..389d43f8e04 100644 --- a/sormas-api/src/main/resources/strings_es-EC.properties +++ b/sormas-api/src/main/resources/strings_es-EC.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_es-ES.properties b/sormas-api/src/main/resources/strings_es-ES.properties index d393dec7300..395653a1f96 100644 --- a/sormas-api/src/main/resources/strings_es-ES.properties +++ b/sormas-api/src/main/resources/strings_es-ES.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_fa-AF.properties b/sormas-api/src/main/resources/strings_fa-AF.properties index d393dec7300..395653a1f96 100644 --- a/sormas-api/src/main/resources/strings_fa-AF.properties +++ b/sormas-api/src/main/resources/strings_fa-AF.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_fi-FI.properties b/sormas-api/src/main/resources/strings_fi-FI.properties index 89d75268e5f..c3b8cf2da22 100644 --- a/sormas-api/src/main/resources/strings_fi-FI.properties +++ b/sormas-api/src/main/resources/strings_fi-FI.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_fil-PH.properties b/sormas-api/src/main/resources/strings_fil-PH.properties index d393dec7300..395653a1f96 100644 --- a/sormas-api/src/main/resources/strings_fil-PH.properties +++ b/sormas-api/src/main/resources/strings_fil-PH.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_fj-FJ.properties b/sormas-api/src/main/resources/strings_fj-FJ.properties index d393dec7300..395653a1f96 100644 --- a/sormas-api/src/main/resources/strings_fj-FJ.properties +++ b/sormas-api/src/main/resources/strings_fj-FJ.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_fr-CH.properties b/sormas-api/src/main/resources/strings_fr-CH.properties index b5683fe6f73..27ef8bae807 100644 --- a/sormas-api/src/main/resources/strings_fr-CH.properties +++ b/sormas-api/src/main/resources/strings_fr-CH.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = La liste ci-dessous contient tous les événements existants ayant la même maladie que le cas actuel. Veuillez vérifier si l'événement auquel il appartient est déjà dans cette liste. Créez en un nouveau le cas écheant. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = La base de données contient déjà au moins une personne qui semble être très similaire aux données personnelles du cas créé.

    Veuillez consulter la liste de personnes. Si vous êtes sûr qu'une de ces personnes corresponde à la personne de votre cas, sélectionnez-les et cliquez sur le bouton Sauvegarder. Sinon, cliquez sur Créer une nouvelle personne pour créer une nouvelle personne pour votre cas.

    Si vous n'êtes pas sûr, vous pouvez fermer cette fenêtre et annuler le processus de création du cas. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Le compte doit être activé diff --git a/sormas-api/src/main/resources/strings_fr-FR.properties b/sormas-api/src/main/resources/strings_fr-FR.properties index dac7037cc9b..5beae6c7337 100644 --- a/sormas-api/src/main/resources/strings_fr-FR.properties +++ b/sormas-api/src/main/resources/strings_fr-FR.properties @@ -331,7 +331,7 @@ errorCreatingTemplateDirectory = Impossible de créer le répertoire des modèle errorDeletingDocumentTemplate = Error deleting document template errorDeletingDocument = Une erreur s'est produite lors de la suppression du document errorDocumentGeneration = Error while generating document\: %s -errorDocumentGenerationMultipleDiseasses = The selected entries has different diseases. +errorDocumentGenerationMultipleDiseasses = Les entrées sélectionnées ont différentes maladies. errorIllegalFilename = Illegal file name\: %s errorFileNotFound = File '%s' not found errorReadingTemplate = Error reading template '%s' @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=Aucune donnée de population n'a été trouvée p errorNoPopulationDataFound=Il n'y a pas de données de population disponibles. Passage à la vue des données absolues errorFormIdPopulationAgeGroup=Les options « ID de formulaire » et « Groupe d'âge de la population » sont définies errorExternalSurveillanceToolNonCoronavirusCase=Impossible d'envoyer les cas sélectionnés à l'outil de signalement car le cas %s n'est pas un cas %s. -errorExternalSurveillanceToolCasesNotSharable=%d des cas sélectionnés ne peuvent pas être envoyés à l'outil de rapport externe.
    Veuillez vous assurer que tous les [%s] sont détenus et autorisés à être partagés avec l'outil de reporting externe. Ensuite, essayez à nouveau d'envoyer ou seulement d'envoyer ceux qui peuvent être envoyés. +errorExternalSurveillanceToolCasesNotSharable=%d des cas sélectionnés ne peuvent pas être envoyés à l'outil de rapport externe.
    Veuillez vous assurer que tous les cas ci-dessous sont détenus et autorisés à être partagés avec l'outil de reporting externe. Ensuite, essayez à nouveau d'envoyer ou seulement d'envoyer ceux qui peuvent être envoyés. errorExternalSurveillanceToolNonClusterEvent=Impossible d'envoyer les événements sélectionnés à l'outil de rapport car l'événement %s n'est pas un cluster de %s. -errorExternalSurveillanceToolEventNotOwned=%d des événements sélectionnés ne peuvent pas être envoyés à l'outil de rapport externe.
    Veuillez vous assurer que tous les [%s] sont disponibles. Ensuite, essayez à nouveau d'envoyer ou seulement d'envoyer ceux qui peuvent être envoyés. +errorExternalSurveillanceToolEventNotOwned=%d des événements sélectionnés ne peuvent pas être envoyés à l'outil de rapport externe.
    Veuillez vous assurer que tous les événements ci-dessous sont disponibles . Ensuite, essayez à nouveau d'envoyer ou d'envoyer uniquement ceux qui peuvent être envoyés. errorEventFromAnotherJurisdiction = L'événement est lié à une juridiction à laquelle vous n'avez pas accès errorEventUnlinkEventGroupFromAnotherJurisdiction = Le groupe d'événements a un événement lié à une juridiction dans laquelle vous n'avez pas accès errorCaseNotEditable = Ce cas n'est plus modifiable @@ -546,7 +546,7 @@ headingPersonInformation = Informations de la personne headingPersonOccupation = Occupation & éducation headingPickOrCreateCase = Choisir ou créer un cas headingPickOrCreatePerson = Choisir ou créer une personne -headingSelectPerson = Select person +headingSelectPerson = Sélectionner une personne headingPickOrCreateEvent = Choisir ou créer un événement headingPickOrCreateEventGroup = Choisir ou créer un groupe d'événements headingPickOrCreateEntry = Choisir ou créer une entrée @@ -837,10 +837,10 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = La liste ci-dessous contient tous les événements existants ayant la même maladie que le cas actuel. Veuillez vérifier si l'événement auquel appartient ce cas est déjà dans cette liste ou en créer un nouveau s'il ne l'est pas. -infoPickOrCreateSuperordinateEventForEvent = La liste ci-dessous contient tous les événements existants ayant la même maladie que l'événement actuel. Veuillez vérifier si l'événement superordonné pour cet événement est déjà dans cette liste ou en créer un nouveau s'il ne l'est pas. +infoPickOrCreateSuperordinateEventForEvent = La liste ci-dessous contient tous les événements existants avec une date d'événement et la même maladie que l'événement en cours. Veuillez vérifier si l'événement superordonné pour cet événement est déjà dans cette liste ou en créer un nouveau s'il ne l'est pas. infoPickOrCreateEventGroupForEvent = La liste ci-dessous contient tous les groupes d'événements existants. Veuillez vérifier si le groupe d'événements auquel appartient cet événement est déjà dans cette liste ou en créer un nouveau s'il ne l'est pas. infoSelectOrCreatePersonForCase = La base de données contient déjà au moins une personne qui semble être très similaire aux données personnelles du cas créé.

    Veuillez consulter la liste des personnes. Si vous êtes certain qu'une de ces personnes correspond à la personne de votre cas, sélectionnez-les et cliquez sur le bouton Sauvegarder. Sinon, cliquez sur Créer une nouvelle personne pour créer une nouvelle personne pour votre cas.

    Si vous n'êtes pas sûr, vous pouvez fermer cette fenêtre et annuler le processus de création du cas. -infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. +infoSearchPerson = Utilisez les filtres ci-dessous pour rechercher toute personne dans le système auquel vous avez accès. Lorsque vous avez terminé, cliquez sur "Rechercher" pour voir une liste de personnes qui correspondent au texte que vous avez saisi. Sélectionnez la personne dans la liste et cliquez sur "Confirmer" pour choisir la personne sélectionnée. infoContactsViewRegionDistrictFilter = Lorsque vous sélectionnez un filtre de région et/ou de district, l'annuaire des contacts est principalement filtré par la région et le district responsables des contacts. Si elles ne sont pas remplies, la région et le district du cas source du contact sont utilisés à la place. infoDeveloperOptions = Vous pouvez utiliser les commandes ci-dessous pour générer des cas factices et des contacts en fonction des contraintes sélectionnées. Veuillez noter que la génération de nombreuses données à la fois peut prendre un certain temps.
    Les données générées ne sont ni totalement déterministes, ni entièrement aléatoires, et ne sont destinées qu'à des fins de test et de démonstration. infoDeveloperOptionsContactGeneration = Lors de la génération de contacts, le générateur choisira des cas existants aléatoirement comme source. Veuillez vous assurer que la base de données de cas n'est pas vide avant de générer des contacts. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Veuillez sélectionner un hôpital comme lieu de sé infoMoreDetailsAboutHospitalization = Pour plus de détails sur l'hospitalisation, allez dans l'onglet hospitalisation. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Le changement de pays n'est pas autorisé car au moins un participant à cet événement n'a pas de région responsable et/ou de district responsable. infoContactAlreadyConvertedToCase = Ce contact a déjà été converti en un cas. Veuillez ajouter de nouvelles visites à la place. +infoSearchPersonOnDependentForm = Rechercher une autre personne # Messages messageActivateAccount = Le compte doit être activé @@ -1206,10 +1207,10 @@ notificationTaskAssociatedCaseLink = Lien vers le cas associé \: %s notificationTaskAssociatedContactLink = Lien vers le contact associé \: %s notificationTaskAssociatedEventLink = Lien vers l'événement associé \: %s notificationTaskAssociatedTravelEntryLink = Lien vers l'entrée de voyage associée \: %s -notificationTaskGeneralUpdatedAssigneeUserSource = Your %s task has been assigned to another user. You are no longer in charge of this task. -notificationTaskGeneralUpdatedAssigneeUserTarget = A(n) %s task has been assigned to you. -notificationTaskSpecificUpdatedAssigneeUserSource = Your %s task for %s has been assigned to another user. You are no longer in charge of this task. -notificationTaskSpecificUpdatedAssigneeUserTarget = A(n) %s task for %s has been assigned to you. +notificationTaskGeneralUpdatedAssigneeUserSource = Votre tâche %s a été assignée à un autre utilisateur. Vous n'êtes plus responsable de cette tâche. +notificationTaskGeneralUpdatedAssigneeUserTarget = La tâche A (n) %s vous a été assignée. +notificationTaskSpecificUpdatedAssigneeUserSource = Votre tâche %s pour %s a été assignée à un autre utilisateur. Vous n'êtes plus en charge de cette tâche. +notificationTaskSpecificUpdatedAssigneeUserTarget = A(n) %s tâche pour %s vous a été assignée. notificationVisitCompleted = Une visite de suivi pour le contact %s assignée à l'utilisateur %s a été terminée. notificationEventParticipantRelatedToOtherEvents = La personne %s nouvellement ajoutée en tant que participant %s à l'événement %s (utilisateur responsable \: %s) par %s est également liée à ces événements \:\n%s notificationEventWithResponsibleUserLine = Événement %s (utilisateur responsable\: %s) diff --git a/sormas-api/src/main/resources/strings_hi-IN.properties b/sormas-api/src/main/resources/strings_hi-IN.properties index d393dec7300..395653a1f96 100644 --- a/sormas-api/src/main/resources/strings_hi-IN.properties +++ b/sormas-api/src/main/resources/strings_hi-IN.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_hr-HR.properties b/sormas-api/src/main/resources/strings_hr-HR.properties index d393dec7300..395653a1f96 100644 --- a/sormas-api/src/main/resources/strings_hr-HR.properties +++ b/sormas-api/src/main/resources/strings_hr-HR.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_it-CH.properties b/sormas-api/src/main/resources/strings_it-CH.properties index 45d75b6e7af..ba6b04faaf8 100644 --- a/sormas-api/src/main/resources/strings_it-CH.properties +++ b/sormas-api/src/main/resources/strings_it-CH.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = La banca dati contiene già almeno una persona che sembra essere molto simile ai dettagli personali del contatto creato.

    Consulta l'elenco delle persone. Se ti senti sicuro che una di queste persone corrisponde al tuo contatto, selezionala e clicca sul pulsante Salva. Altrimenti, clicca su Crea nuova persona per creare una nuova persona per il tuo contatto.

    Se non sei sicuro, puoi scartare questa finestra e annullare il processo di creazione del contatto. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = L'account deve essere attivato diff --git a/sormas-api/src/main/resources/strings_it-IT.properties b/sormas-api/src/main/resources/strings_it-IT.properties index 88917c494c3..4118e481c42 100644 --- a/sormas-api/src/main/resources/strings_it-IT.properties +++ b/sormas-api/src/main/resources/strings_it-IT.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = La banca dati contiene già almeno una persona che sembra essere molto simile ai dettagli personali del contatto creato.

    Consulta l'elenco delle persone. Se ti senti sicuro che una di queste persone corrisponde al tuo contatto, selezionala e clicca sul pulsante Salva. Altrimenti, clicca su Crea nuova persona per creare una nuova persona per il tuo contatto.

    Se non sei sicuro, puoi scartare questa finestra e annullare il processo di creazione del contatto. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_ja-JP.properties b/sormas-api/src/main/resources/strings_ja-JP.properties index d393dec7300..395653a1f96 100644 --- a/sormas-api/src/main/resources/strings_ja-JP.properties +++ b/sormas-api/src/main/resources/strings_ja-JP.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_nl-NL.properties b/sormas-api/src/main/resources/strings_nl-NL.properties index d393dec7300..395653a1f96 100644 --- a/sormas-api/src/main/resources/strings_nl-NL.properties +++ b/sormas-api/src/main/resources/strings_nl-NL.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_no-NO.properties b/sormas-api/src/main/resources/strings_no-NO.properties index d393dec7300..395653a1f96 100644 --- a/sormas-api/src/main/resources/strings_no-NO.properties +++ b/sormas-api/src/main/resources/strings_no-NO.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_pl-PL.properties b/sormas-api/src/main/resources/strings_pl-PL.properties index d393dec7300..395653a1f96 100644 --- a/sormas-api/src/main/resources/strings_pl-PL.properties +++ b/sormas-api/src/main/resources/strings_pl-PL.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_ps-AF.properties b/sormas-api/src/main/resources/strings_ps-AF.properties index 6f857abfd6f..de8ad9df933 100644 --- a/sormas-api/src/main/resources/strings_ps-AF.properties +++ b/sormas-api/src/main/resources/strings_ps-AF.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_pt-PT.properties b/sormas-api/src/main/resources/strings_pt-PT.properties index d393dec7300..395653a1f96 100644 --- a/sormas-api/src/main/resources/strings_pt-PT.properties +++ b/sormas-api/src/main/resources/strings_pt-PT.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_ro-RO.properties b/sormas-api/src/main/resources/strings_ro-RO.properties index d393dec7300..395653a1f96 100644 --- a/sormas-api/src/main/resources/strings_ro-RO.properties +++ b/sormas-api/src/main/resources/strings_ro-RO.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_ru-RU.properties b/sormas-api/src/main/resources/strings_ru-RU.properties index dfe691a980c..82595eb150e 100644 --- a/sormas-api/src/main/resources/strings_ru-RU.properties +++ b/sormas-api/src/main/resources/strings_ru-RU.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_sv-SE.properties b/sormas-api/src/main/resources/strings_sv-SE.properties index d393dec7300..395653a1f96 100644 --- a/sormas-api/src/main/resources/strings_sv-SE.properties +++ b/sormas-api/src/main/resources/strings_sv-SE.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_sw-KE.properties b/sormas-api/src/main/resources/strings_sw-KE.properties index d393dec7300..395653a1f96 100644 --- a/sormas-api/src/main/resources/strings_sw-KE.properties +++ b/sormas-api/src/main/resources/strings_sw-KE.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_tr-TR.properties b/sormas-api/src/main/resources/strings_tr-TR.properties index d393dec7300..395653a1f96 100644 --- a/sormas-api/src/main/resources/strings_tr-TR.properties +++ b/sormas-api/src/main/resources/strings_tr-TR.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_uk-UA.properties b/sormas-api/src/main/resources/strings_uk-UA.properties index d393dec7300..395653a1f96 100644 --- a/sormas-api/src/main/resources/strings_uk-UA.properties +++ b/sormas-api/src/main/resources/strings_uk-UA.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = Please select a hospital as the place of stay. If th infoMoreDetailsAboutHospitalization = For adding more details about the hospitalization, go to the hospitalization tab. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/strings_ur-PK.properties b/sormas-api/src/main/resources/strings_ur-PK.properties index 91cd4814b03..be76f408a05 100644 --- a/sormas-api/src/main/resources/strings_ur-PK.properties +++ b/sormas-api/src/main/resources/strings_ur-PK.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=درج ذیل مقامات کے لیے آبادی errorNoPopulationDataFound=آبادی کا کوئی ڈیٹا دستیاب نہیں ہے۔ مطلق ڈیٹا ویو پر سوئچ کر رہے ہيں errorFormIdPopulationAgeGroup="فارم کی شناخت" اور "آبادی کی عمر گروپ" دونوں آپشن سیٹ ہیں errorExternalSurveillanceToolNonCoronavirusCase=رپورٹنگ ٹول کو منتخب کیسز نہیں بھیجے جا سکے کیونکہ کیس %s کیس %s نہیں ہے۔ -errorExternalSurveillanceToolCasesNotSharable=منتخب کردہ کیسز میں سے %d بیرونی رپورٹنگ ٹول کو نہیں بھیجے جا سکتے۔
    براہ کرم یقینی بنائیں کہ تمام [%s] کی ملکیت ہے اور بیرونی رپورٹنگ ٹول کے ساتھ شیئر کرنے کی اجازت ہے۔ پھر، دوبارہ بھیجنے کی کوشش کریں یا صرف وہی بھیجیں جو بھیجا جا سکتا ہے۔ +errorExternalSurveillanceToolCasesNotSharable=%d منتخب کیسز میں سے بیرونی رپورٹنگ ٹول کو نہیں بھیجا جا سکتا۔
    براہ کرم یقینی بنائیں کہ نیچے دیے گئے تمام کیسز ملکیت میں ہیں اور انہیں بیرونی رپورٹنگ ٹول کے ساتھ شیئر کرنے کی اجازت ہے۔ پھر، دوبارہ بھیجنے کی کوشش کریں یا صرف وہی بھیجیں جو بھیجا جا سکتے ہیں۔ errorExternalSurveillanceToolNonClusterEvent=رپورٹنگ ٹول میں منتخب تقریبات کو نہیں بھیجا جا سکا کیونکہ تقریب %s %s کلسٹر نہیں ہے۔ -errorExternalSurveillanceToolEventNotOwned=منتخب کردہ تقریبات میں سے %d بیرونی رپورٹنگ ٹول کو نہیں بھیجے جا سکتے۔
    براہ کرم یقینی بنائیں کہ تمام [%s] کی ملکیت ہے۔ پھر، دوبارہ بھیجنے کی کوشش کریں یا صرف وہی بھیجیں جو بھیجا جا سکتا ہے۔ +errorExternalSurveillanceToolEventNotOwned=منتخب کردہ واتقریباتقعات میں سے %d بیرونی رپورٹنگ ٹول کو نہیں بھیجے جا سکتے۔
    براہ کرم یقینی بنائیں کہ نیچے دیے گئے تمام تقریبات کی ملکیت میں ہیں۔ پھر، دوبارہ بھیجنے کی کوشش کریں یا صرف وہی بھیجیں جو بھیجا جا سکتے ہیں۔ errorEventFromAnotherJurisdiction = تقریب ایک ایسے دائرہ اختیار سے متعلق ہے جس تک آپ کی رسائی نہیں ہے۔ errorEventUnlinkEventGroupFromAnotherJurisdiction = تقریبی گروپ کے پاس کسی ایسے دائرہ اختیار سے متعلق ایک تقریب ہے جس تک آپ کی رسائی نہیں ہے۔ errorCaseNotEditable = یہ کیس مزید قابل ترمیم نہیں ہے @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = نیچے دی گئی فہرست میں تمام infoPickOrCreateEventForContact = ذیل کی فہرست میں تمام موجودہ تقریبات شامل ہیں جن میں موجودہ رابطہ جیسی بیماری ہے۔ براہ کرم چیک کریں کہ آیا یہ رابطے جس تقریب سے تعلق رکھتے ہیں، اس فہرست میں پہلے سے موجود ہے یا اگر نہیں ہے تو نیا بنائیں۔ infoPickOrCreateEventForContacts = نیچے دی گئی فہرست میں تمام موجودہ تقریبات شامل ہیں جن میں وہی بیماری ہے جو منتخب شدہ روابط کی طرح ہے۔ براہ کرم چیک کریں کہ آیا یہ روابط جس تقریب سے تعلق رکھتے ہیں اس فہرست میں پہلے سے موجود ہے یا اگر نہیں ہے تو نیا بنائیں۔ infoPickOrCreateEventForLabMessage = نیچے دی گئی فہرست میں تمام موجودہ تقریبات شامل ہیں جن میں لیبارٹری پیغام جیسی بیماری ہے۔ براہ کرم چیک کریں کہ آیا تقریب کا نیا حصہ لینے والا جس تقریب سے تعلق رکھتا ہے اس فہرست میں پہلے سے موجود ہے یا اگر نہیں ہے تو نیا بنائیں۔ -infoPickOrCreateSuperordinateEventForEvent = ذیل کی فہرست میں تمام موجودہ تقریبات شامل ہیں جن میں موجودہ تقریب جیسی بیماری ہے۔ براہ کرم چیک کریں کہ آیا اس تقریب کا اعلیٰ ترین تقریب اس فہرست میں پہلے سے موجود ہے یا اگر نہیں ہے تو نیا بنائیں۔ +infoPickOrCreateSuperordinateEventForEvent = نیچے دی گئی فہرست میں تمام موجودہ تقریبات شامل ہیں جن میں تقریب کی تاریخ ہے اور موجودہ تقریب جیسی بیماری ہے۔ براہ کرم چیک کریں کہ آیا اس تقریب کی اعلیٰ ترین تقریب اس فہرست میں پہلے سے موجود ہے یا اگر نہیں ہے تو نئ بنائیں۔ infoPickOrCreateEventGroupForEvent = ذیل کی فہرست میں تمام موجودہ تقریبی گروہ شامل ہیں۔ براہ کرم چیک کریں کہ آیا یہ تقریب جس تقریبی گروہ سے تعلق رکھتا ہے اس فہرست میں پہلے سے موجود ہے یا اگر نہیں ہے تو ایک نیا بنائیں۔ infoSelectOrCreatePersonForCase = ڈیٹا بیس میں پہلے سے ہی کم از کم ایک شخص موجود ہے جو بظاہر بنائے گئے کیس کی ذاتی تفصیلات سے بہت ملتا جلتا ہے۔

    براہ کرم افراد کی فہرست کو دیکھیں۔ اگر آپ کو یقین ہے کہ ان افراد میں سے ایک آپ کے کیس والے سے میل کھاتا ہے، تو انہیں منتخب کریں اور محفوظ کریں بٹن پر کلک کریں۔ بصورت دیگر، اپنے کیس کے لیے نیا فرد بنانے کے لیے نیا فرد بنائیں پر کلک کریں۔

    اگر آپ کو یقین نہیں ہے، تو آپ اس ونڈو کو رد کر سکتے ہیں اور کیس بنانے کے عمل کو منسوخ کر سکتے ہیں۔ infoSearchPerson = اس سسٹم میں کسی بھی شخص کو تلاش کرنے کے لیے نیچے دیے گئے فلٹرز کا استعمال کریں جس تک آپ کی رسائی ہے۔ جب آپ يہ کر لیں تو ان افراد کی فہرست دیکھنے کے لیے "تلاش" پر کلک کریں جو آپ کے درج کردہ ٹیکسٹ سے میل کھاتے ہیں۔ فہرست میں فرد کو منتخب کریں اور منتخب شخص کو منتخب کرنے کے لیے "تصدیق" پر کلک کریں۔ @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = براہ کرم قیام کی جگہ کے طور پ infoMoreDetailsAboutHospitalization = ہسپتال میں داخل ہونے کے بارے میں مزید تفصیلات شامل کرنے کے لیے، ہسپتال میں داخل ہونے والے ٹیب پر جائیں۔ infoCountryNotEditableEventParticipantsWithoutJurisdiction = ملک کو تبدیل کرنے کی اجازت نہیں ہے کیونکہ اس تقریب میں کم از کم ایک شرکت کرنے والے کے پاس ذمہ دار علاقہ اور/یا ذمہ دار ضلع سیٹ نہیں ہے۔ infoContactAlreadyConvertedToCase = یہ رابطہ پہلے ہی کیس میں تبدیل ہو چکا ہے۔ اس کے بجائے براہ کرم کیس میں نئے دورے شامل کریں۔ +infoSearchPersonOnDependentForm = کسی دوسرے شخص کو تلاش کریں # Messages messageActivateAccount = اکاؤنٹ ایکٹیویٹ کرنا ہوگا diff --git a/sormas-api/src/main/resources/strings_zh-CN.properties b/sormas-api/src/main/resources/strings_zh-CN.properties index 014dce5b149..841425d99aa 100644 --- a/sormas-api/src/main/resources/strings_zh-CN.properties +++ b/sormas-api/src/main/resources/strings_zh-CN.properties @@ -344,9 +344,9 @@ errorNoPopulationDataLocations=No population data was found for the following lo errorNoPopulationDataFound=There is no population data available. Switching to absolute data view errorFormIdPopulationAgeGroup=Both "Form Id" and "Population Age Group" options are set errorExternalSurveillanceToolNonCoronavirusCase=Could not send the selected cases to the reporting tool because the case %s is not a %s case. -errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolCasesNotSharable=%d of the selected cases can not be sent to the external reporting tool.
    Please make sure that all of the cases below are owned and allowed to be shared with the external reporting tool. Then, re-try sending or only send the ones that can be sent. errorExternalSurveillanceToolNonClusterEvent=Could not send the selected events to the reporting tool because the event %s is not a %s cluster. -errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of [%s] is owned. Then, re-try sending or only send the ones that can be sent. +errorExternalSurveillanceToolEventNotOwned=%d of the selected events can not be sent to the external reporting tool.
    Please make sure that all of the events below are owned. Then, re-try sending or only send the ones that can be sent. errorEventFromAnotherJurisdiction = The event is related to a jurisdiction you don't have access to errorEventUnlinkEventGroupFromAnotherJurisdiction = The event group has an event related to a jurisdiction you don't have access to errorCaseNotEditable = This case is not editable any more @@ -837,7 +837,7 @@ infoPickOrCreateEventForCases = The list below contains all existing events havi infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForContacts = The list below contains all existing events having the same disease as the selected contacts. Please check whether the event these contacts belongs to is already on this list or create a new one if it isn't. infoPickOrCreateEventForLabMessage = The list below contains all existing events having the same disease as the lab message. Please check whether the event the new event participant belongs to is already on this list or create a new one if it isn't. -infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events having the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. +infoPickOrCreateSuperordinateEventForEvent = The list below contains all existing events with an event date and the same disease as the current event. Please check whether the superordinate event for this event is already on this list or create a new one if it isn't. infoPickOrCreateEventGroupForEvent = The list below contains all existing event groups. Please check whether the event group this event belongs to is already on this list or create a new one if it isn't. infoSelectOrCreatePersonForCase = The database already contains at least one person that seems to be very similar to the personal details of the created case.

    Please look through the list of persons. If you feel certain that one of those persons matches your case person, select them and click on the Save button. Otherwise, click on Create New Person to create a new person for your case.

    If you are unsure, you can discard this window and cancel the case creation process. infoSearchPerson = Use the filters below to search for any person in the system you have access to. When you're done click on "Search" to see a list of persons that match the text that you have entered. Select person in the list and click on "Confirm" to choose the selected person. @@ -871,6 +871,7 @@ infoPlaceOfStayInHospital = 请选择医院作为停留地点。 如果病人目 infoMoreDetailsAboutHospitalization = 为了提供更多有关住院的详细信息,请到医院的选项卡。 infoCountryNotEditableEventParticipantsWithoutJurisdiction = Changing the country is not permitted because at least one event participant in this event does not have a responsible region and/or responsible district set. infoContactAlreadyConvertedToCase = This contact has already been converted to a case. Please add new visits to the case instead. +infoSearchPersonOnDependentForm = Search for another person # Messages messageActivateAccount = Account has to be activated diff --git a/sormas-api/src/main/resources/validations_cs-CZ.properties b/sormas-api/src/main/resources/validations_cs-CZ.properties index d4a3284fc5d..1f7b067a109 100644 --- a/sormas-api/src/main/resources/validations_cs-CZ.properties +++ b/sormas-api/src/main/resources/validations_cs-CZ.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = Osoba má více primárních telefonních č personMultiplePrimaryEmailAddresses = Osoba má více primárních e-mailových adres. Povolena je pouze jedna primární e-mailová adresa. birthDateInFuture = Datum narození nesmí být v budoucnu birthDateInvalid = Zadané datum narození není platné -nameOrAnyOtherFieldShouldBeFilled=Alespoň název nebo jiné pole by mělo být vyplněno +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Typ zařízení %s nelze použít pro místo pobytu fileTooBig = Soubor je příliš velký. Maximální povolená velikost souboru je %dMB infrastructureDataLocked = Údaje o infrastruktuře jsou uzamčeny a nelze je aktualizovat diff --git a/sormas-api/src/main/resources/validations_de-CH.properties b/sormas-api/src/main/resources/validations_de-CH.properties index cd63c734097..42c9c94852c 100644 --- a/sormas-api/src/main/resources/validations_de-CH.properties +++ b/sormas-api/src/main/resources/validations_de-CH.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = Die Person hat mehrere primäre Telefonnumme personMultiplePrimaryEmailAddresses = Die Person hat mehrere primäre E-Mail-Adressen. Es ist nur eine primäre E-Mail-Adresse erlaubt. birthDateInFuture = Geburtsdatum darf nicht in der Zukunft liegen birthDateInvalid = Das angegebene Geburtsdatum ist kein gültiges Datum -nameOrAnyOtherFieldShouldBeFilled=Mindestens der Name oder ein anderes Feld sollte ausgefüllt werden +nameOrAnyOtherFieldShouldBeFilled=Mindestens ein Namensfeld oder ein anderes Feld sollte ausgefüllt werden notAccomodationFacilityType = Einrichtungstyp %s kann nicht für den Aufenthaltsort verwendet werden fileTooBig = Die Datei ist zu groß. Die maximal erlaubte Dateigröße beträgt %dMB infrastructureDataLocked = Infrastrukturdaten sind gesperrt und können nicht aktualisiert werden diff --git a/sormas-api/src/main/resources/validations_de-DE.properties b/sormas-api/src/main/resources/validations_de-DE.properties index 3aac3700888..d6d2f0c0aec 100644 --- a/sormas-api/src/main/resources/validations_de-DE.properties +++ b/sormas-api/src/main/resources/validations_de-DE.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = Die Person hat mehrere primäre Telefonnumme personMultiplePrimaryEmailAddresses = Die Person hat mehrere primäre E-Mail-Adressen. Es ist nur eine primäre E-Mail-Adresse erlaubt. birthDateInFuture = Geburtsdatum darf nicht in der Zukunft liegen birthDateInvalid = Das angegebene Geburtsdatum ist kein gültiges Datum -nameOrAnyOtherFieldShouldBeFilled=Mindestens der Name oder ein anderes Feld sollte ausgefüllt werden +nameOrAnyOtherFieldShouldBeFilled=Mindestens ein Namensfeld oder ein anderes Feld sollte ausgefüllt werden notAccomodationFacilityType = Einrichtungsart %s kann nicht für den Aufenthaltsort verwendet werden fileTooBig = Die Datei ist zu groß. Die maximal erlaubte Dateigröße beträgt %dMB infrastructureDataLocked = Infrastrukturdaten sind gesperrt und können nicht aktualisiert werden diff --git a/sormas-api/src/main/resources/validations_en-AF.properties b/sormas-api/src/main/resources/validations_en-AF.properties index c8165b0169b..f15fe93e5c7 100644 --- a/sormas-api/src/main/resources/validations_en-AF.properties +++ b/sormas-api/src/main/resources/validations_en-AF.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_en-GH.properties b/sormas-api/src/main/resources/validations_en-GH.properties index bb1349cb232..263bcedfda9 100644 --- a/sormas-api/src/main/resources/validations_en-GH.properties +++ b/sormas-api/src/main/resources/validations_en-GH.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_en-NG.properties b/sormas-api/src/main/resources/validations_en-NG.properties index 9b6052d6a6c..de2e48755de 100644 --- a/sormas-api/src/main/resources/validations_en-NG.properties +++ b/sormas-api/src/main/resources/validations_en-NG.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_es-CU.properties b/sormas-api/src/main/resources/validations_es-CU.properties index 346e44c9b77..8db87eee85a 100644 --- a/sormas-api/src/main/resources/validations_es-CU.properties +++ b/sormas-api/src/main/resources/validations_es-CU.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = La persona tiene varios números telefónico personMultiplePrimaryEmailAddresses = La persona tiene varias direcciones de correo electrónico principales. Sólo se permite una dirección de correo electrónico principal. birthDateInFuture = La fecha de nacimiento no puede ser en el futuro birthDateInvalid = La fecha de nacimiento especificada no es una fecha válida -nameOrAnyOtherFieldShouldBeFilled=Debe ser rellenado al menos el campo de nombre o algún otro campo +nameOrAnyOtherFieldShouldBeFilled=Debe rellenarse al menos un campo de nombre u otro campo notAccomodationFacilityType = El tipo de instalación %s no puede ser usado como lugar de estancia fileTooBig = Archivo demasiado grande. El tamaño máximo permitido es %dMB infrastructureDataLocked = Los datos de infraestructura están bloqueados y no se pueden actualizar diff --git a/sormas-api/src/main/resources/validations_es-EC.properties b/sormas-api/src/main/resources/validations_es-EC.properties index ef7dc38a3c6..02111635fd2 100644 --- a/sormas-api/src/main/resources/validations_es-EC.properties +++ b/sormas-api/src/main/resources/validations_es-EC.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_es-ES.properties b/sormas-api/src/main/resources/validations_es-ES.properties index 9b6052d6a6c..de2e48755de 100644 --- a/sormas-api/src/main/resources/validations_es-ES.properties +++ b/sormas-api/src/main/resources/validations_es-ES.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_fa-AF.properties b/sormas-api/src/main/resources/validations_fa-AF.properties index 9b6052d6a6c..de2e48755de 100644 --- a/sormas-api/src/main/resources/validations_fa-AF.properties +++ b/sormas-api/src/main/resources/validations_fa-AF.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_fi-FI.properties b/sormas-api/src/main/resources/validations_fi-FI.properties index 2cf7dddd4c4..00cac77a4af 100644 --- a/sormas-api/src/main/resources/validations_fi-FI.properties +++ b/sormas-api/src/main/resources/validations_fi-FI.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_fil-PH.properties b/sormas-api/src/main/resources/validations_fil-PH.properties index 9b6052d6a6c..de2e48755de 100644 --- a/sormas-api/src/main/resources/validations_fil-PH.properties +++ b/sormas-api/src/main/resources/validations_fil-PH.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_fj-FJ.properties b/sormas-api/src/main/resources/validations_fj-FJ.properties index 9b6052d6a6c..de2e48755de 100644 --- a/sormas-api/src/main/resources/validations_fj-FJ.properties +++ b/sormas-api/src/main/resources/validations_fj-FJ.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_fr-CH.properties b/sormas-api/src/main/resources/validations_fr-CH.properties index 08efb644e57..a6b6c1f2228 100644 --- a/sormas-api/src/main/resources/validations_fr-CH.properties +++ b/sormas-api/src/main/resources/validations_fr-CH.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_fr-FR.properties b/sormas-api/src/main/resources/validations_fr-FR.properties index 9c19c4258ea..6fcc2180054 100644 --- a/sormas-api/src/main/resources/validations_fr-FR.properties +++ b/sormas-api/src/main/resources/validations_fr-FR.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = La personne a plusieurs numéros de téléph personMultiplePrimaryEmailAddresses = La personne a plusieurs adresses e-mail principales. Une seule adresse e-mail principale est autorisée. birthDateInFuture = La date de naissance ne doit pas être dans le futur birthDateInvalid = La date de naissance spécifiée n'est pas une date valide -nameOrAnyOtherFieldShouldBeFilled=Au moins le nom ou un autre champ doit être rempli +nameOrAnyOtherFieldShouldBeFilled=Au moins un champ de nom ou un autre champ doit être rempli notAccomodationFacilityType = Le type d'établissement %s ne peut pas être utilisé pour le lieu de séjour fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Les données d'infrastructure sont verrouillées et ne peuvent pas être mises à jour diff --git a/sormas-api/src/main/resources/validations_hi-IN.properties b/sormas-api/src/main/resources/validations_hi-IN.properties index 9b6052d6a6c..de2e48755de 100644 --- a/sormas-api/src/main/resources/validations_hi-IN.properties +++ b/sormas-api/src/main/resources/validations_hi-IN.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_hr-HR.properties b/sormas-api/src/main/resources/validations_hr-HR.properties index 9b6052d6a6c..de2e48755de 100644 --- a/sormas-api/src/main/resources/validations_hr-HR.properties +++ b/sormas-api/src/main/resources/validations_hr-HR.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_it-CH.properties b/sormas-api/src/main/resources/validations_it-CH.properties index ac44c49a35d..ef7d1e9f4e5 100644 --- a/sormas-api/src/main/resources/validations_it-CH.properties +++ b/sormas-api/src/main/resources/validations_it-CH.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_it-IT.properties b/sormas-api/src/main/resources/validations_it-IT.properties index 80402b22363..a47b4bc5915 100644 --- a/sormas-api/src/main/resources/validations_it-IT.properties +++ b/sormas-api/src/main/resources/validations_it-IT.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_ja-JP.properties b/sormas-api/src/main/resources/validations_ja-JP.properties index 9b6052d6a6c..de2e48755de 100644 --- a/sormas-api/src/main/resources/validations_ja-JP.properties +++ b/sormas-api/src/main/resources/validations_ja-JP.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_nl-NL.properties b/sormas-api/src/main/resources/validations_nl-NL.properties index 9b6052d6a6c..de2e48755de 100644 --- a/sormas-api/src/main/resources/validations_nl-NL.properties +++ b/sormas-api/src/main/resources/validations_nl-NL.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_no-NO.properties b/sormas-api/src/main/resources/validations_no-NO.properties index 9b6052d6a6c..de2e48755de 100644 --- a/sormas-api/src/main/resources/validations_no-NO.properties +++ b/sormas-api/src/main/resources/validations_no-NO.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_pl-PL.properties b/sormas-api/src/main/resources/validations_pl-PL.properties index 9b6052d6a6c..de2e48755de 100644 --- a/sormas-api/src/main/resources/validations_pl-PL.properties +++ b/sormas-api/src/main/resources/validations_pl-PL.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_ps-AF.properties b/sormas-api/src/main/resources/validations_ps-AF.properties index 9b6052d6a6c..de2e48755de 100644 --- a/sormas-api/src/main/resources/validations_ps-AF.properties +++ b/sormas-api/src/main/resources/validations_ps-AF.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_pt-PT.properties b/sormas-api/src/main/resources/validations_pt-PT.properties index 9b6052d6a6c..de2e48755de 100644 --- a/sormas-api/src/main/resources/validations_pt-PT.properties +++ b/sormas-api/src/main/resources/validations_pt-PT.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_ro-RO.properties b/sormas-api/src/main/resources/validations_ro-RO.properties index 9b6052d6a6c..de2e48755de 100644 --- a/sormas-api/src/main/resources/validations_ro-RO.properties +++ b/sormas-api/src/main/resources/validations_ro-RO.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_ru-RU.properties b/sormas-api/src/main/resources/validations_ru-RU.properties index c283f9eaa6c..8a6c3d393e9 100644 --- a/sormas-api/src/main/resources/validations_ru-RU.properties +++ b/sormas-api/src/main/resources/validations_ru-RU.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_sv-SE.properties b/sormas-api/src/main/resources/validations_sv-SE.properties index 9b6052d6a6c..de2e48755de 100644 --- a/sormas-api/src/main/resources/validations_sv-SE.properties +++ b/sormas-api/src/main/resources/validations_sv-SE.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_sw-KE.properties b/sormas-api/src/main/resources/validations_sw-KE.properties index 9b6052d6a6c..de2e48755de 100644 --- a/sormas-api/src/main/resources/validations_sw-KE.properties +++ b/sormas-api/src/main/resources/validations_sw-KE.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_tr-TR.properties b/sormas-api/src/main/resources/validations_tr-TR.properties index 9b6052d6a6c..de2e48755de 100644 --- a/sormas-api/src/main/resources/validations_tr-TR.properties +++ b/sormas-api/src/main/resources/validations_tr-TR.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_uk-UA.properties b/sormas-api/src/main/resources/validations_uk-UA.properties index 9b6052d6a6c..de2e48755de 100644 --- a/sormas-api/src/main/resources/validations_uk-UA.properties +++ b/sormas-api/src/main/resources/validations_uk-UA.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated diff --git a/sormas-api/src/main/resources/validations_ur-PK.properties b/sormas-api/src/main/resources/validations_ur-PK.properties index 3a34a6f3fa1..9d3caeb4150 100644 --- a/sormas-api/src/main/resources/validations_ur-PK.properties +++ b/sormas-api/src/main/resources/validations_ur-PK.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = اس شخص کے پاس متعدد بنیا personMultiplePrimaryEmailAddresses = اس شخص کے پاس متعدد بنیادی ای میل پتے ہیں۔ صرف ایک بنیادی ای میل پتے کی اجازت ہے۔ birthDateInFuture = تاریخ پیدائش مستقبل میں نہیں ہونی چاہیے birthDateInvalid = دی گئ تاریخ پیدائش ایک درست تاریخ نہیں ہے -nameOrAnyOtherFieldShouldBeFilled=کم از کم نام یا کوئی اور فیلڈ بھری جائے +nameOrAnyOtherFieldShouldBeFilled=کم از کم ایک نام کی فیلڈ یا کوئی دوسرا فیلڈ بھرنا چاہیے notAccomodationFacilityType = سہولت گاہ کی قسم %s کو قیام کی جگہ کے لیے استعمال نہیں کیا جا سکتی fileTooBig = فائل بہت بڑی ہے۔ زیادہ سے زیادہ فائل سائز کی اجازت MB %d ہے infrastructureDataLocked = انفراسٹرکچر ڈیٹا مقفل ہے اور اسے اپ ڈیٹ نہیں کیا جا سکتا diff --git a/sormas-api/src/main/resources/validations_zh-CN.properties b/sormas-api/src/main/resources/validations_zh-CN.properties index 8c9704f8466..75e6b422e63 100644 --- a/sormas-api/src/main/resources/validations_zh-CN.properties +++ b/sormas-api/src/main/resources/validations_zh-CN.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = The person has multiple primary phone number personMultiplePrimaryEmailAddresses = The person has multiple primary email addresses. Only one primary email address is allowed. birthDateInFuture = Birth date must not be in the future birthDateInvalid = The specified birth date is not a valid date -nameOrAnyOtherFieldShouldBeFilled=At least name or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled notAccomodationFacilityType = Facility type %s can not be used for place of stay fileTooBig = File too big. The maximum file size allowed is %dMB infrastructureDataLocked = Infrastructure data is locked and cannot be updated From 4a3987e9072214922291612a925bdc44ca184126 Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Wed, 16 Feb 2022 14:25:30 +0200 Subject: [PATCH 090/253] #7747-Fix-Allure-Report : applied major refactoring --- sormas-e2e-tests/gradle.properties | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../scripts/runCreatePerformanceData.sh | 4 +- .../scripts/runPagesMeasurements.sh | 4 +- sormas-e2e-tests/scripts/runTests.sh | 2 +- .../e2etests/common/CommonInjectorSource.java | 2 +- .../sormas/e2etests/common/CommonModule.java | 24 +++++------ .../sormas/e2etests/common/MoreResources.java | 2 +- .../e2etests/common/PropertiesModule.java | 2 +- .../org/sormas/e2etests/common/TimerLite.java | 2 +- .../e2etests/constants/api/Endpoints.java | 2 +- .../e2etests/enums/APITestData/Disease.java | 2 +- .../enums/APITestData/FacilityType.java | 2 +- .../APITestData/POSTCase_ErrorMessages.java | 2 +- .../sormas/e2etests/enums/ActivityTypes.java | 2 +- .../sormas/e2etests/enums/AreaTypeValues.java | 2 +- .../enums/AvailableAndCooperative.java | 2 +- .../e2etests/enums/CaseClassification.java | 4 +- .../sormas/e2etests/enums/CaseOutcome.java | 2 +- .../e2etests/enums/CommunityValues.java | 2 +- .../sormas/e2etests/enums/ContactOutcome.java | 2 +- .../sormas/e2etests/enums/ContinentUUIDs.java | 2 +- .../sormas/e2etests/enums/CountryUUIDs.java | 2 +- .../sormas/e2etests/enums/DiseasesValues.java | 2 +- .../e2etests/enums/DistrictsValues.java | 2 +- .../e2etests/enums/FacilityCategory.java | 2 +- .../sormas/e2etests/enums/FacilityType.java | 2 +- .../sormas/e2etests/enums/FacilityUUIDs.java | 2 +- .../sormas/e2etests/enums/FollowUpStatus.java | 2 +- .../sormas/e2etests/enums/GenderValues.java | 2 +- .../e2etests/enums/LaboratoryValues.java | 2 +- .../e2etests/enums/OperatingSystems.java | 2 +- .../e2etests/enums/PathogenTestResults.java | 2 +- .../e2etests/enums/PresentCondition.java | 2 +- .../sormas/e2etests/enums/RegionsValues.java | 2 +- .../sormas/e2etests/enums/RolesValues.java | 2 +- .../e2etests/enums/SourceOfTemperature.java | 2 +- .../e2etests/enums/SpecimenConditions.java | 2 +- .../e2etests/enums/SubcontinentUUIDs.java | 2 +- .../sormas/e2etests/enums/TestDataUser.java | 2 +- .../e2etests/enums/YesNoUnknownOptions.java | 2 +- .../ImmunizationManagementStatusValues.java | 2 +- .../MeansOfImmunizationValues.java | 2 +- .../enums/immunizations/StatusValues.java | 2 +- .../configprovider/ConfigFileReader.java | 2 +- .../e2etests/envconfig/dto/EnvUser.java | 2 +- .../e2etests/envconfig/dto/Environment.java | 2 +- .../e2etests/envconfig/dto/Environments.java | 2 +- .../envconfig/manager/EnvironmentManager.java | 2 +- .../e2etests/pages/application/LoginPage.java | 2 +- .../pages/application/NavBarPage.java | 2 +- .../actions/CreateNewActionPage.java | 2 +- .../application/actions/EditActionPage.java | 2 +- .../application/cases/CaseDirectoryPage.java | 2 +- .../application/cases/CreateNewCasePage.java | 2 +- .../pages/application/cases/EditCasePage.java | 2 +- .../application/cases/EditCasePersonPage.java | 2 +- .../application/cases/EditContactsPage.java | 2 +- .../cases/EpidemiologicalDataCasePage.java | 2 +- .../application/cases/FollowUpTabPage.java | 2 +- .../cases/HospitalizationTabPage.java | 2 +- .../cases/PreviousHospitalizationPage.java | 2 +- .../application/cases/SymptomsTabPage.java | 2 +- .../configuration/ConfigurationTabsPage.java | 2 +- .../configuration/DocumentTemplatesPage.java | 2 +- .../contacts/ContactDirectoryPage.java | 2 +- .../contacts/ContactsLineListingPage.java | 2 +- .../contacts/CreateNewContactPage.java | 2 +- .../contacts/CreateNewVisitPage.java | 2 +- .../application/contacts/EditContactPage.java | 2 +- .../contacts/EditContactPersonPage.java | 2 +- .../EditPersonContactDetailsPage.java | 2 +- .../contacts/FollowUpVisitsTabPage.java | 2 +- .../contacts/PersonContactDetailsPage.java | 2 +- .../Contacts/ContactsDashboardPage.java | 2 +- .../SurveillanceDashboardPage.java | 2 +- .../events/CreateNewEventPage.java | 2 +- .../application/events/EditEventPage.java | 2 +- .../application/events/EventActionsPage.java | 2 +- .../events/EventDirectoryPage.java | 2 +- .../events/EventParticipantsPage.java | 2 +- .../ImmunizationsDirectoryPage.java | 2 +- .../application/persons/EditPersonPage.java | 2 +- .../persons/PersonDirectoryPage.java | 2 +- .../reports/WeeklyReportsPage.java | 2 +- .../samples/CreateNewSamplePage.java | 2 +- .../application/samples/EditSamplePage.java | 2 +- .../samples/SamplesDirectoryPage.java | 2 +- .../application/tasks/CreateNewTaskPage.java | 2 +- .../application/tasks/TaskManagementPage.java | 2 +- .../application/users/CreateNewUserPage.java | 2 +- .../pages/application/users/EditUserPage.java | 2 +- .../application/users/UserManagementPage.java | 2 +- .../webdriver/ChromeDriverFactory.java | 2 +- .../e2etests/webdriver/DriverFactory.java | 2 +- .../e2etests/webdriver/DriverManager.java | 2 +- .../e2etests/webdriver/DriverMetaData.java | 2 +- .../e2etests/webdriver/DriverModule.java | 2 +- .../webdriver/RemoteDriverFactory.java | 2 +- .../src/main/java/recorders/StepsLogger.java | 2 +- .../properties/common.properties | 4 +- .../environment/test-performance.properties | 2 +- .../src/main/resources/cucumber.properties | 2 +- .../src/main/resources/enum.properties | 2 +- .../src/main/resources/logback.xml | 6 +-- .../sormas/e2etests/entities}/pojo/User.java | 4 +- .../entities}/pojo/api/AssigneeUser.java | 4 +- .../entities}/pojo/api/AssociatedCase.java | 4 +- .../e2etests/entities}/pojo/api/Case.java | 4 +- .../entities}/pojo/api/ClinicalCourse.java | 4 +- .../entities}/pojo/api/Community.java | 4 +- .../e2etests/entities}/pojo/api/Contact.java | 4 +- .../e2etests/entities}/pojo/api/District.java | 4 +- .../e2etests/entities}/pojo/api/EpiData.java | 4 +- .../e2etests/entities}/pojo/api/Event.java | 4 +- .../entities}/pojo/api/EventLocation.java | 4 +- .../entities}/pojo/api/HealthConditions.java | 4 +- .../entities}/pojo/api/HealthFacility.java | 4 +- .../entities}/pojo/api/Hospitalization.java | 4 +- .../entities}/pojo/api/Immunization.java | 4 +- .../e2etests/entities}/pojo/api/Lab.java | 4 +- .../entities}/pojo/api/MaternalHistory.java | 4 +- .../e2etests/entities}/pojo/api/Person.java | 6 +-- .../entities}/pojo/api/PortHealthInfo.java | 4 +- .../e2etests/entities}/pojo/api/Region.java | 4 +- .../entities}/pojo/api/ReportingUser.java | 4 +- .../e2etests/entities}/pojo/api/Request.java | 4 +- .../e2etests/entities}/pojo/api/Sample.java | 4 +- .../pojo/api/SurveillanceOfficer.java | 4 +- .../e2etests/entities}/pojo/api/Symptoms.java | 4 +- .../e2etests/entities}/pojo/api/Task.java | 4 +- .../e2etests/entities}/pojo/api/Therapy.java | 4 +- .../entities}/pojo/api/chunks/Address.java | 4 +- .../entities}/pojo/api/chunks/Country.java | 4 +- .../pojo/api/chunks/PersonContactDetails.java | 6 +-- .../pojo/helpers/ComparisonHelper.java | 4 +- .../e2etests/entities}/pojo/web/Action.java | 4 +- .../e2etests/entities}/pojo/web/Address.java | 4 +- .../e2etests/entities}/pojo/web/Case.java | 4 +- .../e2etests/entities}/pojo/web/Contact.java | 4 +- .../pojo/web/ContactsLineListing.java | 4 +- .../pojo/web/EpidemiologicalData.java | 8 ++-- .../e2etests/entities}/pojo/web/Event.java | 4 +- .../pojo/web/EventActionTableEntry.java | 4 +- .../entities}/pojo/web/EventGroup.java | 4 +- .../entities}/pojo/web/EventHandout.java | 4 +- .../entities}/pojo/web/EventParticipant.java | 2 +- .../entities}/pojo/web/ExposureDetails.java | 2 +- .../pojo/web/ExposureInvestigation.java | 2 +- .../entities}/pojo/web/FollowUpVisit.java | 4 +- .../entities}/pojo/web/Hospitalization.java | 2 +- .../entities}/pojo/web/Immunization.java | 2 +- .../e2etests/entities}/pojo/web/Person.java | 4 +- .../pojo/web/PreviousHospitalization.java | 2 +- .../entities}/pojo/web/QuarantineOrder.java | 4 +- .../e2etests/entities}/pojo/web/Sample.java | 4 +- .../e2etests/entities}/pojo/web/Symptoms.java | 4 +- .../e2etests/entities}/pojo/web/Task.java | 4 +- .../e2etests/entities}/pojo/web/Therapy.java | 2 +- .../e2etests/entities}/pojo/web/Visit.java | 4 +- .../web/epidemiologicalData/Activity.java | 2 +- .../web/epidemiologicalData/Exposure.java | 2 +- .../entities}/services/ActionService.java | 6 +-- .../services/CaseDocumentService.java | 7 ++-- .../entities}/services/CaseService.java | 6 +-- .../services/ClinicalCourseVisitService.java | 4 +- .../services/ContactDocumentService.java | 6 +-- .../entities}/services/ContactService.java | 8 ++-- .../services/ContactsLineListingService.java | 6 +-- .../services/EpidemiologicalDataService.java | 10 ++--- .../services/EventDocumentService.java | 6 +-- .../entities}/services/EventGroupService.java | 6 +-- .../services/EventParticipantService.java | 4 +- .../entities}/services/EventService.java | 6 +-- .../services/ExposureDetailsService.java | 4 +- .../ExposureInvestigationService.java | 4 +- .../services/FollowUpVisitService.java | 8 ++-- .../services/HospitalizationService.java | 4 +- .../services/ImmunizationService.java | 4 +- .../entities}/services/PersonService.java | 6 +-- .../PreviousHospitalizationService.java | 4 +- .../entities}/services/SampleService.java | 6 +-- .../entities}/services/SymptomService.java | 6 +-- .../entities}/services/TaskService.java | 6 +-- .../entities}/services/TherapyService.java | 4 +- .../entities}/services/UserService.java | 6 +-- .../services/api/CaseApiService.java | 40 +++++++++++++++---- .../services/api/ContactApiService.java | 33 +++++++++++---- .../services/api/EventApiService.java | 8 ++-- .../services/api/ImmunizationApiService.java | 20 ++++++---- .../services/api/PersonApiService.java | 12 +++--- .../services/api/SampleApiService.java | 10 +++-- .../services/api/TaskApiService.java | 7 ++-- .../e2etests/helpers/AssertHelpers.java | 2 +- .../e2etests/helpers/RestAssuredClient.java | 31 ++++++++------ .../e2etests/helpers/WebDriverHelpers.java | 2 +- .../e2etests/helpers/api/CaseHelper.java | 6 +-- .../e2etests/helpers/api/ContactHelper.java | 6 +-- .../e2etests/helpers/api/EventHelper.java | 6 +-- .../e2etests/helpers/api/FacilityHelper.java | 2 +- .../helpers/api/ImmunizationHelper.java | 6 +-- .../e2etests/helpers/api/PersonsHelper.java | 6 +-- .../e2etests/helpers/api/SampleHelper.java | 6 +-- .../e2etests/helpers/api/TaskHelper.java | 6 +-- .../e2etests/runner/CucumberTestRunner.java | 2 +- .../org/sormas/e2etests/state/ApiState.java | 18 ++++----- .../org/sormas/e2etests/steps/BaseSteps.java | 2 +- .../e2etests/steps/api/BusinessFlows.java | 16 ++++---- .../sormas/e2etests/steps/api/CaseSteps.java | 6 +-- .../e2etests/steps/api/ContactSteps.java | 12 +++--- .../sormas/e2etests/steps/api/EventSteps.java | 6 +-- .../e2etests/steps/api/ImmunizationSteps.java | 8 ++-- .../e2etests/steps/api/PersonSteps.java | 6 +-- .../e2etests/steps/api/SamplesSteps.java | 6 +-- .../sormas/e2etests/steps/api/TasksSteps.java | 8 ++-- .../api/commonSteps/ResponseChecksSteps.java | 2 +- .../UploadDocumentTemplatesSteps.java | 8 +--- .../steps/web/application/LoginSteps.java | 7 +--- .../steps/web/application/NavBarSteps.java | 2 +- .../actions/CreateNewActionSteps.java | 6 +-- .../application/actions/EditActionSteps.java | 6 +-- .../cases/CaseDetailedTableViewSteps.java | 8 ++-- .../application/cases/CaseDirectorySteps.java | 2 +- .../cases/CaseLineListingSteps.java | 4 +- .../cases/ClinicalCourseTabCaseSteps.java | 8 ++-- .../application/cases/CreateNewCaseSteps.java | 6 +-- .../cases/EditCasePersonSteps.java | 8 ++-- .../web/application/cases/EditCaseSteps.java | 23 ++++++----- .../application/cases/EditContactsSteps.java | 15 +++---- .../application/cases/EditTherapySteps.java | 12 ++---- .../cases/EpidemiologicalDataCaseSteps.java | 19 +++++---- .../web/application/cases/FollowUpStep.java | 10 ++--- .../cases/HospitalizationTabSteps.java | 16 +++++--- .../cases/PreviousHospitalizationSteps.java | 6 +-- .../application/cases/SymptomsTabSteps.java | 16 ++++---- .../contacts/ChooseSourceCaseSteps.java | 2 +- .../contacts/ContactDirectorySteps.java | 17 ++++---- .../ContactsDetailedTableViewSteps.java | 8 ++-- .../contacts/ContactsLineListingSteps.java | 6 +-- .../contacts/CreateNewContactSteps.java | 6 +-- .../contacts/CreateNewVisitSteps.java | 8 ++-- .../contacts/EditContactPersonSteps.java | 8 ++-- .../contacts/EditContactSteps.java | 12 +++--- .../EditPersonContactDetailsSteps.java | 4 +- .../ExposureInContactEpiDataSteps.java | 17 ++++---- .../contacts/FollowUpVisitsTabSteps.java | 11 +++-- .../contacts/PersonContactDetailsSteps.java | 4 +- .../contacts/ContactsDashboardSteps.java | 2 +- .../SurveillanceDashboardSteps.java | 2 +- .../events/CreateNewEventSteps.java | 6 +-- .../application/events/EditEventSteps.java | 31 +++++++------- .../application/events/EventActionsSteps.java | 8 ++-- .../events/EventActionsTableSteps.java | 4 +- .../events/EventDirectorySteps.java | 10 +++-- .../CreateNewImmunizationSteps.java | 4 +- .../EditImmunizationPersonSteps.java | 4 +- .../immunizations/EditImmunizationSteps.java | 11 ++--- .../application/persons/EditPersonSteps.java | 17 ++++---- .../persons/PersonDirectorySteps.java | 13 +++--- .../reports/WeeklyReportsSteps.java | 2 +- .../samples/CreateNewSampleSteps.java | 8 ++-- .../application/samples/EditSampleSteps.java | 15 +++---- .../samples/SamplesDirectorySteps.java | 9 +++-- .../application/tasks/CreateNewTaskSteps.java | 8 ++-- .../tasks/TaskManagementSteps.java | 6 +-- .../application/users/CreateNewUserSteps.java | 6 +-- .../web/application/users/EditUserSteps.java | 6 +-- .../users/UserManagementSteps.java | 2 +- .../src/test/resources/allure.properties | 2 +- .../allurefiles/environment.properties | 2 +- .../resources/features/sanity/api/Api.feature | 8 ++++ .../sanity/api/EntitiesCreation.feature | 4 +- .../PagesLoadMeasurements.feature | 9 +++++ .../features/sanity/web/Case.feature | 23 ++++++----- .../sanity/web/CaseClasification.feature | 2 + .../features/sanity/web/CaseFilters.feature | 15 +++---- .../sanity/web/CaseFollowUpVisit.feature | 3 +- .../sanity/web/CaseHospitalization.feature | 1 + .../features/sanity/web/CaseSymptoms.feature | 4 +- .../features/sanity/web/CaseViews.feature | 1 + .../sanity/web/ContactFilters.feature | 12 ++---- .../features/sanity/web/Contacts.feature | 20 ++++++---- .../features/sanity/web/Dashboard.feature | 2 + .../sanity/web/DocumentTemplate.feature | 10 ++--- .../features/sanity/web/EpiData.feature | 23 ++++++----- .../web/EpidemiologicalDataCase.feature | 3 +- .../features/sanity/web/Event.feature | 22 ++++++---- .../features/sanity/web/Immunization.feature | 1 + .../features/sanity/web/LineListing.feature | 2 + .../features/sanity/web/Pathogen.feature | 14 +++---- .../features/sanity/web/Persons.feature | 4 +- .../features/sanity/web/Reports.feature | 2 + .../features/sanity/web/Sample.feature | 10 +++-- .../features/sanity/web/SampleFilters.feature | 3 +- .../features/sanity/web/Task.feature | 4 +- .../sanity/web/TaskManagementFilter.feature | 4 +- .../features/sanity/web/User.feature | 4 +- 297 files changed, 848 insertions(+), 725 deletions(-) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/User.java (93%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/AssigneeUser.java (91%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/AssociatedCase.java (90%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/Case.java (95%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/ClinicalCourse.java (91%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/Community.java (90%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/Contact.java (94%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/District.java (90%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/EpiData.java (91%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/Event.java (92%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/EventLocation.java (90%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/HealthConditions.java (91%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/HealthFacility.java (90%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/Hospitalization.java (90%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/Immunization.java (92%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/Lab.java (90%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/MaternalHistory.java (91%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/Person.java (88%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/PortHealthInfo.java (90%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/Region.java (91%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/ReportingUser.java (91%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/Request.java (90%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/Sample.java (92%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/SurveillanceOfficer.java (91%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/Symptoms.java (91%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/Task.java (92%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/Therapy.java (90%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/chunks/Address.java (92%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/chunks/Country.java (90%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/api/chunks/PersonContactDetails.java (87%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/helpers/ComparisonHelper.java (97%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/Action.java (90%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/Address.java (90%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/Case.java (96%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/Contact.java (95%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/ContactsLineListing.java (91%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/EpidemiologicalData.java (83%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/Event.java (92%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/EventActionTableEntry.java (91%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/EventGroup.java (89%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/EventHandout.java (89%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/EventParticipant.java (87%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/ExposureDetails.java (95%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/ExposureInvestigation.java (87%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/FollowUpVisit.java (94%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/Hospitalization.java (93%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/Immunization.java (94%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/Person.java (94%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/PreviousHospitalization.java (92%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/QuarantineOrder.java (90%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/Sample.java (93%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/Symptoms.java (93%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/Task.java (92%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/Therapy.java (94%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/Visit.java (92%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/epidemiologicalData/Activity.java (93%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/pojo/web/epidemiologicalData/Exposure.java (95%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/ActionService.java (89%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/CaseDocumentService.java (87%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/CaseService.java (97%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/ClinicalCourseVisitService.java (89%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/ContactDocumentService.java (88%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/ContactService.java (96%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/ContactsLineListingService.java (92%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/EpidemiologicalDataService.java (91%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/EventDocumentService.java (87%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/EventGroupService.java (86%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/EventParticipantService.java (88%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/EventService.java (93%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/ExposureDetailsService.java (95%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/ExposureInvestigationService.java (78%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/FollowUpVisitService.java (95%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/HospitalizationService.java (91%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/ImmunizationService.java (95%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/PersonService.java (95%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/PreviousHospitalizationService.java (92%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/SampleService.java (96%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/SymptomService.java (92%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/TaskService.java (94%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/TherapyService.java (96%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/UserService.java (96%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/api/CaseApiService.java (75%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/api/ContactApiService.java (74%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/api/EventApiService.java (86%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/api/ImmunizationApiService.java (78%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/api/PersonApiService.java (93%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/api/SampleApiService.java (80%) rename sormas-e2e-tests/src/{main/java/org/sormas/e2etests => test/java/org/sormas/e2etests/entities}/services/api/TaskApiService.java (88%) diff --git a/sormas-e2e-tests/gradle.properties b/sormas-e2e-tests/gradle.properties index 0e3a4ea968c..c26cfd58add 100644 --- a/sormas-e2e-tests/gradle.properties +++ b/sormas-e2e-tests/gradle.properties @@ -1,6 +1,6 @@ # # SORMAS® - Surveillance Outbreak Response Management & Analysis System -# Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) +# Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/gradle/wrapper/gradle-wrapper.properties b/sormas-e2e-tests/gradle/wrapper/gradle-wrapper.properties index f72a5eff76d..a1b8bf77904 100644 --- a/sormas-e2e-tests/gradle/wrapper/gradle-wrapper.properties +++ b/sormas-e2e-tests/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ # # SORMAS® - Surveillance Outbreak Response Management & Analysis System -# Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) +# Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/scripts/runCreatePerformanceData.sh b/sormas-e2e-tests/scripts/runCreatePerformanceData.sh index c51b86a07cd..64d04820868 100644 --- a/sormas-e2e-tests/scripts/runCreatePerformanceData.sh +++ b/sormas-e2e-tests/scripts/runCreatePerformanceData.sh @@ -1,7 +1,7 @@ #!/bin/sh # # SORMAS® - Surveillance Outbreak Response Management & Analysis System -# Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) +# Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -32,7 +32,7 @@ for ((i = 1; i <= $1; ++i)); do echo "Run: $i " echo "Started at:" date +"%T" - ./gradlew startTests -Dcucumber.tags="@PersonsAndImmunizations" -Dheadless=true -Dcourgette.threads=9 + ./gradlew startTests -Dcucumber.tags="@PersonsAndImmunizations" -Dheadless=true -Dcourgette.threads=9 -DenvConfig=........./data.json echo "Finished at:" date +"%T" done diff --git a/sormas-e2e-tests/scripts/runPagesMeasurements.sh b/sormas-e2e-tests/scripts/runPagesMeasurements.sh index 6ffa6d90f3b..3b44a206dab 100644 --- a/sormas-e2e-tests/scripts/runPagesMeasurements.sh +++ b/sormas-e2e-tests/scripts/runPagesMeasurements.sh @@ -1,7 +1,7 @@ #!/bin/sh # # SORMAS® - Surveillance Outbreak Response Management & Analysis System -# Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) +# Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -33,4 +33,4 @@ cat /dev/null > ./customReports/data/results.txt echo "Executing gradle clean..." ./gradlew clean goJF echo "Starting all BDD tests under @PagesMeasurements tag..." -./gradlew startTests -Dcucumber.tags="@PagesMeasurements" -Dheadless=true -Dcourgette.threads=9 \ No newline at end of file +./gradlew startTests -Dcucumber.tags="@PagesMeasurements" -Dheadless=true -Dcourgette.threads=9 -DenvConfig=........../data.json \ No newline at end of file diff --git a/sormas-e2e-tests/scripts/runTests.sh b/sormas-e2e-tests/scripts/runTests.sh index 6963aefed88..fa7f7eacb70 100644 --- a/sormas-e2e-tests/scripts/runTests.sh +++ b/sormas-e2e-tests/scripts/runTests.sh @@ -1,7 +1,7 @@ #!/bin/sh # # SORMAS® - Surveillance Outbreak Response Management & Analysis System -# Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) +# Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/CommonInjectorSource.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/CommonInjectorSource.java index 22798e51794..b9b1d0394c8 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/CommonInjectorSource.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/CommonInjectorSource.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/CommonModule.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/CommonModule.java index 5cd45bafab6..04fae7be8a6 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/CommonModule.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/CommonModule.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,15 +25,12 @@ import com.google.inject.Exposed; import com.google.inject.PrivateModule; import com.google.inject.Provides; -import io.restassured.RestAssured; -import io.restassured.specification.RequestSpecification; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.Locale; import java.util.Properties; import javax.inject.Singleton; import lombok.SneakyThrows; -import org.sormas.e2etests.enums.TestDataUser; import org.sormas.e2etests.envconfig.manager.EnvironmentManager; import org.sormas.e2etests.webdriver.DriverManager; import org.testng.asserts.SoftAssert; @@ -95,13 +92,14 @@ ObjectMapper provideObjectMapper() { return objectMapper; } - @Provides - @Exposed - RequestSpecification provideRestAssured() { - return RestAssured.given() - .auth() - .preemptive() - .basic( - TestDataUser.REST_AUTOMATION.getUsername(), TestDataUser.REST_AUTOMATION.getPassword()); - } + // @Provides + // @Exposed + // RequestSpecification provideRestAssured() { + // return RestAssured.given() + // .auth() + // .preemptive() + // .basic( + // TestDataUser.REST_AUTOMATION.getUsername(), + // TestDataUser.REST_AUTOMATION.getPassword()); + // } } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/MoreResources.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/MoreResources.java index 241d8e95ff6..da824c6ded2 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/MoreResources.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/MoreResources.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/PropertiesModule.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/PropertiesModule.java index d41291c6ee8..ac581c99283 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/PropertiesModule.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/PropertiesModule.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/TimerLite.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/TimerLite.java index be432043674..015b96426b2 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/TimerLite.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/TimerLite.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/constants/api/Endpoints.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/constants/api/Endpoints.java index a0daf6a5c52..3ee759aebae 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/constants/api/Endpoints.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/constants/api/Endpoints.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/APITestData/Disease.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/APITestData/Disease.java index 493dbb2f3cb..037a9a46956 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/APITestData/Disease.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/APITestData/Disease.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/APITestData/FacilityType.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/APITestData/FacilityType.java index 30941470c1a..35a64cb6162 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/APITestData/FacilityType.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/APITestData/FacilityType.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/APITestData/POSTCase_ErrorMessages.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/APITestData/POSTCase_ErrorMessages.java index a0ae7b0d0a9..54b2eb18269 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/APITestData/POSTCase_ErrorMessages.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/APITestData/POSTCase_ErrorMessages.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/ActivityTypes.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/ActivityTypes.java index 5e5821847d9..bc3f8982502 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/ActivityTypes.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/ActivityTypes.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/AreaTypeValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/AreaTypeValues.java index 1df91f85374..56694369974 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/AreaTypeValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/AreaTypeValues.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/AvailableAndCooperative.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/AvailableAndCooperative.java index 310e4abe263..2189fe728a1 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/AvailableAndCooperative.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/AvailableAndCooperative.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CaseClassification.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CaseClassification.java index 6e445fb7cb5..208f617fe6d 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CaseClassification.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CaseClassification.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -44,7 +44,7 @@ public enum CaseClassification { public static String getUIValueFor(String option) { CaseClassification[] classifications = CaseClassification.values(); for (CaseClassification value : classifications) { - if (value.getClassificationAPIvalue().equalsIgnoreCase(option)) + if (value.getClassificationUIvalue().equalsIgnoreCase(option)) return value.getClassificationUIvalue(); } throw new Exception("Unable to find " + option + " value in CaseClassification Enum"); diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CaseOutcome.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CaseOutcome.java index 8be834229b7..5862dc56587 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CaseOutcome.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CaseOutcome.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CommunityValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CommunityValues.java index 170e61942d4..9d77df82f96 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CommunityValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CommunityValues.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/ContactOutcome.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/ContactOutcome.java index 8a567f975c4..5a29f1cee3c 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/ContactOutcome.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/ContactOutcome.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/ContinentUUIDs.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/ContinentUUIDs.java index f18a315fc14..fa583f65335 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/ContinentUUIDs.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/ContinentUUIDs.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CountryUUIDs.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CountryUUIDs.java index 6602800d1dd..0066756d54c 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CountryUUIDs.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CountryUUIDs.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DiseasesValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DiseasesValues.java index bfb24366169..d67dda9a3e4 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DiseasesValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DiseasesValues.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java index 686aa100e0b..67885e2b8d6 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/FacilityCategory.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/FacilityCategory.java index 1327057e347..5a35a8cba6f 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/FacilityCategory.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/FacilityCategory.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/FacilityType.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/FacilityType.java index 3dd623500cd..3bf9cc86028 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/FacilityType.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/FacilityType.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/FacilityUUIDs.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/FacilityUUIDs.java index bd09a4f5aab..fd65bfc13f7 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/FacilityUUIDs.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/FacilityUUIDs.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/FollowUpStatus.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/FollowUpStatus.java index 2b4c20d41dc..9768f896e60 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/FollowUpStatus.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/FollowUpStatus.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValues.java index d4c21b3d4d8..2c94ee41f3d 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValues.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/LaboratoryValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/LaboratoryValues.java index 4ad78c7e558..2e41c50e86a 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/LaboratoryValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/LaboratoryValues.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/OperatingSystems.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/OperatingSystems.java index c3778eef775..6eefc0cab04 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/OperatingSystems.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/OperatingSystems.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PathogenTestResults.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PathogenTestResults.java index 8eda3830839..d2098e14c27 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PathogenTestResults.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PathogenTestResults.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PresentCondition.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PresentCondition.java index dfaa6b87608..16792a7b16e 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PresentCondition.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PresentCondition.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RegionsValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RegionsValues.java index 51206d98035..c0d85b1d32c 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RegionsValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RegionsValues.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RolesValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RolesValues.java index c9a59a9be3d..6ef5363a80a 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RolesValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/RolesValues.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SourceOfTemperature.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SourceOfTemperature.java index 6ff3e824b1e..500dab8d7b4 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SourceOfTemperature.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SourceOfTemperature.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java index 60e9f8cab45..77d02d6af9f 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SpecimenConditions.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SubcontinentUUIDs.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SubcontinentUUIDs.java index ac3e1daf3ad..b29fc4db75d 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SubcontinentUUIDs.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/SubcontinentUUIDs.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/TestDataUser.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/TestDataUser.java index baf5dbda092..7dc55a3dcd7 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/TestDataUser.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/TestDataUser.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/YesNoUnknownOptions.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/YesNoUnknownOptions.java index cb07575a877..4701b5df31c 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/YesNoUnknownOptions.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/YesNoUnknownOptions.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/immunizations/ImmunizationManagementStatusValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/immunizations/ImmunizationManagementStatusValues.java index 6be3d92ef9c..92dd02960d1 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/immunizations/ImmunizationManagementStatusValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/immunizations/ImmunizationManagementStatusValues.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/immunizations/MeansOfImmunizationValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/immunizations/MeansOfImmunizationValues.java index e01ad73d34c..e1fe864ae2a 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/immunizations/MeansOfImmunizationValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/immunizations/MeansOfImmunizationValues.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/immunizations/StatusValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/immunizations/StatusValues.java index 6d708f4c822..c0c4169d2a5 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/immunizations/StatusValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/immunizations/StatusValues.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/configprovider/ConfigFileReader.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/configprovider/ConfigFileReader.java index b270aacb8ba..08ba991267a 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/configprovider/ConfigFileReader.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/configprovider/ConfigFileReader.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/EnvUser.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/EnvUser.java index e0a21a0571f..d6dd8c491d0 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/EnvUser.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/EnvUser.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environment.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environment.java index 07088ebf6d4..dbc152743a7 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environment.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environment.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environments.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environments.java index dcbd83847d9..06ef9f8009c 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environments.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environments.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/manager/EnvironmentManager.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/manager/EnvironmentManager.java index 79bf5d063ce..d8eafd5a715 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/manager/EnvironmentManager.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/manager/EnvironmentManager.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/LoginPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/LoginPage.java index 267d2692be3..4d140a43013 100755 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/LoginPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/LoginPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/NavBarPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/NavBarPage.java index 2acd2b01293..1c98f095c7e 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/NavBarPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/NavBarPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/actions/CreateNewActionPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/actions/CreateNewActionPage.java index f97e5359ef1..ea77c549042 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/actions/CreateNewActionPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/actions/CreateNewActionPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/actions/EditActionPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/actions/EditActionPage.java index 72061992a2f..d25127f7f6d 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/actions/EditActionPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/actions/EditActionPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java index a34e0de445d..7124194cf0f 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CreateNewCasePage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CreateNewCasePage.java index 48ffb2d1287..bdbf9e4b7a6 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CreateNewCasePage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CreateNewCasePage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EditCasePage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EditCasePage.java index 4e06293df46..3df16ac6acd 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EditCasePage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EditCasePage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EditCasePersonPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EditCasePersonPage.java index f1e71d36e1d..420390e8903 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EditCasePersonPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EditCasePersonPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EditContactsPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EditContactsPage.java index cafa1742a34..a81b885c8d2 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EditContactsPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EditContactsPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EpidemiologicalDataCasePage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EpidemiologicalDataCasePage.java index 8a09e548d28..c03bcbd763b 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EpidemiologicalDataCasePage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EpidemiologicalDataCasePage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/FollowUpTabPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/FollowUpTabPage.java index 0486ee351aa..0249b41c7f3 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/FollowUpTabPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/FollowUpTabPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/HospitalizationTabPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/HospitalizationTabPage.java index e209fc1de2c..920a4db5f36 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/HospitalizationTabPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/HospitalizationTabPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/PreviousHospitalizationPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/PreviousHospitalizationPage.java index cb9616eeec7..0a847b37d84 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/PreviousHospitalizationPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/PreviousHospitalizationPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/SymptomsTabPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/SymptomsTabPage.java index 9444dc1a354..fd672c438fb 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/SymptomsTabPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/SymptomsTabPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/configuration/ConfigurationTabsPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/configuration/ConfigurationTabsPage.java index e6d6b4cac1f..81aa5b29487 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/configuration/ConfigurationTabsPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/configuration/ConfigurationTabsPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/configuration/DocumentTemplatesPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/configuration/DocumentTemplatesPage.java index e1977cd60d6..ac2d03a3cc8 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/configuration/DocumentTemplatesPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/configuration/DocumentTemplatesPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/ContactDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/ContactDirectoryPage.java index 7d083025ce0..2b238f42a8b 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/ContactDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/ContactDirectoryPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/ContactsLineListingPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/ContactsLineListingPage.java index 0266ca46336..e3f8dce9d5f 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/ContactsLineListingPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/ContactsLineListingPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/CreateNewContactPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/CreateNewContactPage.java index 9c5590af57b..f9b1670957b 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/CreateNewContactPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/CreateNewContactPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/CreateNewVisitPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/CreateNewVisitPage.java index 49e0118f681..c5eacdb8712 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/CreateNewVisitPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/CreateNewVisitPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/EditContactPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/EditContactPage.java index 9b9f39d7812..a53f1f4d7e8 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/EditContactPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/EditContactPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/EditContactPersonPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/EditContactPersonPage.java index 0a5933c6df6..63318b08653 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/EditContactPersonPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/EditContactPersonPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/EditPersonContactDetailsPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/EditPersonContactDetailsPage.java index 40e476ee16c..f6b9b4dc4f8 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/EditPersonContactDetailsPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/EditPersonContactDetailsPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/FollowUpVisitsTabPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/FollowUpVisitsTabPage.java index b2ebf04c192..a7735212fc5 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/FollowUpVisitsTabPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/FollowUpVisitsTabPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/PersonContactDetailsPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/PersonContactDetailsPage.java index eb71e966c61..cc0146da449 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/PersonContactDetailsPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/PersonContactDetailsPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/dashboard/Contacts/ContactsDashboardPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/dashboard/Contacts/ContactsDashboardPage.java index eb9bbfaaf9e..b0ce2007c90 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/dashboard/Contacts/ContactsDashboardPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/dashboard/Contacts/ContactsDashboardPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/dashboard/Surveillance/SurveillanceDashboardPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/dashboard/Surveillance/SurveillanceDashboardPage.java index e28f21dfa2a..cd7137ba3cd 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/dashboard/Surveillance/SurveillanceDashboardPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/dashboard/Surveillance/SurveillanceDashboardPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/CreateNewEventPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/CreateNewEventPage.java index f090542f0cd..105f8d1732c 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/CreateNewEventPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/CreateNewEventPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EditEventPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EditEventPage.java index 264dcdb1d96..926171a5b27 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EditEventPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EditEventPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventActionsPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventActionsPage.java index 8fa917c99c7..19270d33106 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventActionsPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventActionsPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java index 5b4c5530647..e44fab1042a 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventParticipantsPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventParticipantsPage.java index 8801e79ffa5..e8fd9ec1399 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventParticipantsPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventParticipantsPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/immunizations/ImmunizationsDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/immunizations/ImmunizationsDirectoryPage.java index e366b5f5464..85b624135de 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/immunizations/ImmunizationsDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/immunizations/ImmunizationsDirectoryPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java index d284684128d..b2d26bf875b 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/PersonDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/PersonDirectoryPage.java index 831a5976f91..9e21b703b1c 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/PersonDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/PersonDirectoryPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/reports/WeeklyReportsPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/reports/WeeklyReportsPage.java index 356595fdbc5..e2e79e7fbfa 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/reports/WeeklyReportsPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/reports/WeeklyReportsPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/CreateNewSamplePage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/CreateNewSamplePage.java index 1b9ae907c5e..11fcd2aae58 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/CreateNewSamplePage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/CreateNewSamplePage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/EditSamplePage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/EditSamplePage.java index d69ee202bb9..d2920635f10 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/EditSamplePage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/EditSamplePage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java index 8c084b171b4..abb6c4fb7ca 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/tasks/CreateNewTaskPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/tasks/CreateNewTaskPage.java index f2d53c4403f..054b0f0e15b 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/tasks/CreateNewTaskPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/tasks/CreateNewTaskPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/tasks/TaskManagementPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/tasks/TaskManagementPage.java index 00cbc4472fa..482ac1a9469 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/tasks/TaskManagementPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/tasks/TaskManagementPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/users/CreateNewUserPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/users/CreateNewUserPage.java index 4688198f4ac..256f3c1ed61 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/users/CreateNewUserPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/users/CreateNewUserPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/users/EditUserPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/users/EditUserPage.java index 6c9d318e19d..da07448747a 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/users/EditUserPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/users/EditUserPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/users/UserManagementPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/users/UserManagementPage.java index 71eca0de4a5..14e4098f55b 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/users/UserManagementPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/users/UserManagementPage.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/ChromeDriverFactory.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/ChromeDriverFactory.java index 2a344c75d4a..215a9661e63 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/ChromeDriverFactory.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/ChromeDriverFactory.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/DriverFactory.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/DriverFactory.java index 4031736a1d4..f4b7abc91a2 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/DriverFactory.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/DriverFactory.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/DriverManager.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/DriverManager.java index 12653a3bebb..ca4ff357748 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/DriverManager.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/DriverManager.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/DriverMetaData.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/DriverMetaData.java index f9729da5c98..7ca2044ff84 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/DriverMetaData.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/DriverMetaData.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/DriverModule.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/DriverModule.java index 452169c5aa6..7530818fde4 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/DriverModule.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/DriverModule.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/RemoteDriverFactory.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/RemoteDriverFactory.java index 88350df2699..dc0e7784b52 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/RemoteDriverFactory.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/RemoteDriverFactory.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java index d12ca8fe46e..4d1a8e316d5 100755 --- a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java +++ b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/resources/configuration/properties/common.properties b/sormas-e2e-tests/src/main/resources/configuration/properties/common.properties index 17ba1910a07..7092796a0a3 100644 --- a/sormas-e2e-tests/src/main/resources/configuration/properties/common.properties +++ b/sormas-e2e-tests/src/main/resources/configuration/properties/common.properties @@ -1,6 +1,6 @@ # # SORMAS® - Surveillance Outbreak Response Management & Analysis System -# Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) +# Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -17,6 +17,6 @@ # BROWSER=chrome -REMOTE_DRIVER=true +REMOTE_DRIVER=false HEADLESS=true LOG_RESTASSURED=false diff --git a/sormas-e2e-tests/src/main/resources/configuration/properties/environment/test-performance.properties b/sormas-e2e-tests/src/main/resources/configuration/properties/environment/test-performance.properties index 39200428885..2ded204d5b5 100644 --- a/sormas-e2e-tests/src/main/resources/configuration/properties/environment/test-performance.properties +++ b/sormas-e2e-tests/src/main/resources/configuration/properties/environment/test-performance.properties @@ -1,6 +1,6 @@ # # SORMAS® - Surveillance Outbreak Response Management & Analysis System -# Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) +# Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/resources/cucumber.properties b/sormas-e2e-tests/src/main/resources/cucumber.properties index 0ea85868e26..2838b0278d5 100644 --- a/sormas-e2e-tests/src/main/resources/cucumber.properties +++ b/sormas-e2e-tests/src/main/resources/cucumber.properties @@ -1,6 +1,6 @@ # # SORMAS® - Surveillance Outbreak Response Management & Analysis System -# Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) +# Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/resources/enum.properties b/sormas-e2e-tests/src/main/resources/enum.properties index ffc4b2ab458..88c190d9993 100644 --- a/sormas-e2e-tests/src/main/resources/enum.properties +++ b/sormas-e2e-tests/src/main/resources/enum.properties @@ -1,6 +1,6 @@ ############################################################################### # SORMAS® - Surveillance Outbreak Response Management & Analysis System -# Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) +# Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/main/resources/logback.xml b/sormas-e2e-tests/src/main/resources/logback.xml index 394bb394214..390cb964041 100755 --- a/sormas-e2e-tests/src/main/resources/logback.xml +++ b/sormas-e2e-tests/src/main/resources/logback.xml @@ -1,7 +1,7 @@ @@ -777,7 +778,7 @@ junit junit - 4.13.1 + 4.13.2 test @@ -794,17 +795,25 @@ 3.17
    + + org.hamcrest + hamcrest + ${hamcrest.version} + test + org.hamcrest hamcrest-core - 1.3 + ${hamcrest.version} test + org.hamcrest hamcrest-library - 1.3 + ${hamcrest.version} test + @@ -817,7 +826,7 @@ org.mockito mockito-inline - 3.5.15 + 4.3.1 test @@ -892,19 +901,18 @@ - + org.hamcrest - hamcrest-core + hamcrest + + junit junit - - org.hamcrest - hamcrest-library - + org.mockito mockito-inline diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/caze/importer/CaseImporterTest.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/caze/importer/CaseImporterTest.java index 742bbd9b8b9..33617d87b59 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/caze/importer/CaseImporterTest.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/caze/importer/CaseImporterTest.java @@ -36,7 +36,7 @@ import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import com.opencsv.exceptions.CsvValidationException; import com.vaadin.ui.UI; diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/dashboard/campaigns/GridTemplateAreaCreatorTest.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/dashboard/campaigns/GridTemplateAreaCreatorTest.java index 61a3d64ba04..895dc37b3d0 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/dashboard/campaigns/GridTemplateAreaCreatorTest.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/dashboard/campaigns/GridTemplateAreaCreatorTest.java @@ -6,7 +6,7 @@ import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import de.symeda.sormas.api.campaign.diagram.CampaignDashboardElement; diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/event/importer/EventImporterTest.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/event/importer/EventImporterTest.java index aebf81d131c..2442f28e95a 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/event/importer/EventImporterTest.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/event/importer/EventImporterTest.java @@ -17,7 +17,7 @@ import org.apache.commons.io.output.StringBuilderWriter; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import com.opencsv.exceptions.CsvValidationException; diff --git a/sormas-ui/src/test/java/de/symeda/sormas/ui/utils/DownloadUtilTest.java b/sormas-ui/src/test/java/de/symeda/sormas/ui/utils/DownloadUtilTest.java index 39eadde9f82..0cd9cc72b1f 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/ui/utils/DownloadUtilTest.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/ui/utils/DownloadUtilTest.java @@ -11,7 +11,7 @@ import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import com.vaadin.server.StreamResource; diff --git a/sormas-ui/src/test/java/travelentry/importer/TravelEntryImporterTest.java b/sormas-ui/src/test/java/travelentry/importer/TravelEntryImporterTest.java index 79766331fef..964c02034d3 100644 --- a/sormas-ui/src/test/java/travelentry/importer/TravelEntryImporterTest.java +++ b/sormas-ui/src/test/java/travelentry/importer/TravelEntryImporterTest.java @@ -32,7 +32,7 @@ import org.apache.commons.io.output.StringBuilderWriter; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import com.opencsv.exceptions.CsvValidationException; From 410fafd9f6433a8e992d97d532126b65a471072a Mon Sep 17 00:00:00 2001 From: Stefan Kock Date: Tue, 15 Feb 2022 07:51:56 +0100 Subject: [PATCH 092/253] #7978: Updated xdocreport - xdocreport 2.0.2 -> 2.0.3 (some breaking changes) - velocity 1.7 -> velocity-engine-core 2.3 - commons-lang 2.6 -> removed --- .../sormas/backend/docgeneration/CleanHtmlReference.java | 5 +++-- .../sormas/backend/docgeneration/NoIncludesEventHandler.java | 3 ++- .../symeda/sormas/backend/docgeneration/TemplateEngine.java | 3 ++- sormas-base/pom.xml | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/CleanHtmlReference.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/CleanHtmlReference.java index ee3d497940b..4a848d2fb9c 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/CleanHtmlReference.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/CleanHtmlReference.java @@ -16,13 +16,14 @@ package de.symeda.sormas.backend.docgeneration; import org.apache.velocity.app.event.ReferenceInsertionEventHandler; +import org.apache.velocity.context.Context; import de.symeda.sormas.api.utils.HtmlHelper; public class CleanHtmlReference implements ReferenceInsertionEventHandler { @Override - public Object referenceInsert(String s, Object o) { - return o == null ? null : HtmlHelper.cleanHtml(o.toString(), HtmlHelper.EVENTACTION_WHITELIST); + public Object referenceInsert(Context context, String reference, Object value) { + return value == null ? null : HtmlHelper.cleanHtml(value.toString(), HtmlHelper.EVENTACTION_WHITELIST); } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/NoIncludesEventHandler.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/NoIncludesEventHandler.java index 8ac33e1e52a..4d5c0a0ff54 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/NoIncludesEventHandler.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/NoIncludesEventHandler.java @@ -16,11 +16,12 @@ package de.symeda.sormas.backend.docgeneration; import org.apache.velocity.app.event.IncludeEventHandler; +import org.apache.velocity.context.Context; public class NoIncludesEventHandler implements IncludeEventHandler { @Override - public String includeEvent(String s, String s1, String s2) { + public String includeEvent(Context context, String includeResourcePath, String currentResourcePath, String directiveName) { return null; } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/TemplateEngine.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/TemplateEngine.java index 74a24b3bc33..ee7591f8397 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/TemplateEngine.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/TemplateEngine.java @@ -222,7 +222,8 @@ private FieldsExtractor getFieldExtractorTxt(Reader templateFile FieldsExtractor extractor = FieldsExtractor.create(); ExtractVariablesVelocityVisitor visitor = new ExtractVariablesVelocityVisitor(extractor); try { - SimpleNode document = RuntimeSingleton.parse(templateFileReader, templateName); + Template template = RuntimeSingleton.getTemplate(templateName); + SimpleNode document = RuntimeSingleton.parse(templateFileReader, template); document.jjtAccept(visitor, null); return extractor; } catch (ParseException e) { diff --git a/sormas-base/pom.xml b/sormas-base/pom.xml index ecf3b580fb0..14f9b971fa5 100644 --- a/sormas-base/pom.xml +++ b/sormas-base/pom.xml @@ -35,7 +35,7 @@ 1.67 16.1.0 3.15.1.Final - 2.0.2 + 2.0.3 8.3.1 0.22.0 2.2 From 3e58c13de2387f80840160219c6a490e9f8e87b2 Mon Sep 17 00:00:00 2001 From: syntakker Date: Tue, 15 Feb 2022 23:21:05 +0100 Subject: [PATCH 093/253] Fix test failure after velocity update #7978 --- .../sormas/backend/docgeneration/TemplateEngine.java | 3 ++- .../resources/docgeneration/eventHandout/EventHandout.cmp | 8 ++++---- .../eventHandout/EventHandoutPreformatting.cmp | 8 ++++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/TemplateEngine.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/TemplateEngine.java index ee7591f8397..ba0c9b07924 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/TemplateEngine.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/TemplateEngine.java @@ -222,7 +222,8 @@ private FieldsExtractor getFieldExtractorTxt(Reader templateFile FieldsExtractor extractor = FieldsExtractor.create(); ExtractVariablesVelocityVisitor visitor = new ExtractVariablesVelocityVisitor(extractor); try { - Template template = RuntimeSingleton.getTemplate(templateName); + Template template = new Template(); + template.setName(templateName); SimpleNode document = RuntimeSingleton.parse(templateFileReader, template); document.jjtAccept(visitor, null); return extractor; diff --git a/sormas-backend/src/test/resources/docgeneration/eventHandout/EventHandout.cmp b/sormas-backend/src/test/resources/docgeneration/eventHandout/EventHandout.cmp index 91e8399f740..fcae8a6b2f1 100644 --- a/sormas-backend/src/test/resources/docgeneration/eventHandout/EventHandout.cmp +++ b/sormas-backend/src/test/resources/docgeneration/eventHandout/EventHandout.cmp @@ -55,10 +55,10 @@ - - - -
    First NameLast NamePhoneContacted
    GeorgesBataille+49 681 8901[ ]
    GuyDebord+49 681 4567[ ]
    IsidoreIsou+49 681 1234[ ]
    + GeorgesBataille+49 681 8901[ ] + GuyDebord+49 681 4567[ ] + IsidoreIsou+49 681 1234[ ] +
    diff --git a/sormas-backend/src/test/resources/docgeneration/eventHandout/EventHandoutPreformatting.cmp b/sormas-backend/src/test/resources/docgeneration/eventHandout/EventHandoutPreformatting.cmp index 95971b7fc5e..948c2d285e3 100644 --- a/sormas-backend/src/test/resources/docgeneration/eventHandout/EventHandoutPreformatting.cmp +++ b/sormas-backend/src/test/resources/docgeneration/eventHandout/EventHandoutPreformatting.cmp @@ -55,10 +55,10 @@ - - - -
    First NameLast NamePhoneContacted
    GeorgesBataille+49 681 8901[ ]
    GuyDebord+49 681 4567[ ]
    IsidoreIsou+49 681 1234[ ]
    + GeorgesBataille+49 681 8901[ ] + GuyDebord+49 681 4567[ ] + IsidoreIsou+49 681 1234[ ] +
    From bcf0d85c8d575bdb11df9a3d8cc35d1e458b95f2 Mon Sep 17 00:00:00 2001 From: Stefan Kock Date: Mon, 14 Feb 2022 15:57:19 +0100 Subject: [PATCH 094/253] #7978: Updated several dependencies - bouncycastle 1.67 -> 1.70 - commons-compress 1.19 -> 1.21 - commons-io 2.8.0 -> 2.11.0 - commons-lang3 3.11 -> 3.12.0 - docx4j 8.3.1 -> 8.3.2 - etcd-java 0.0.18 - 0.0.19 - freemarker 2.3.30 -> 2.3.31 - google-http-client 1.39.2 -> 1.41.4 - google-http-client-gson 1.39.2 -> 1.41.4 - google-oauth-client 1.31.5 -> 1.33.1 - gt-shapefile 24.1 -> 26.2 - guava 30.0 -> 31.0.1 - hibernate-core 5.4.25.Final -> 5.6.5.Final - hibernate-types-52 2.10.0 -> hibernate-types-55 2.14.0 - httpcore 4.4.14 -> 4.4.15 - joda-time 2.10.8 -> 2.10.13 - json-path 2.6.0 -> 2.7.0 - jsoup 1.14.2 -> 1.14.3 - keycloak 16.1.0 -> 16.1.1 - libphonenumber 8.12.14 -> 8.12.43 - logback 1.2.9 -> 1.2.10 - opencsv 5.3 -> 5.5.2 - postgresql 42.2.18 -> 42.3.3 - resteasy 3.15.1.Final -> 3.15.3.Final - slf4j 1.7.30 -> 1.7.36 - swagger 2.1.6 -> 2.1.13 - vaadin 8.14.1 -> 8.14.3 --- sormas-app/app/build.gradle | 10 ++--- sormas-backend/pom.xml | 2 +- sormas-base/dependencies/serverlibs.pom | 6 ++- sormas-base/pom.xml | 60 ++++++++++++++----------- sormas-ui/pom.xml | 2 +- 5 files changed, 45 insertions(+), 35 deletions(-) diff --git a/sormas-app/app/build.gradle b/sormas-app/app/build.gradle index 172a67ac6e0..cbbe61e0832 100644 --- a/sormas-app/app/build.gradle +++ b/sormas-app/app/build.gradle @@ -104,17 +104,17 @@ dependencies { implementation 'com.google.firebase:firebase-config' implementation("de.symeda.sormas:sormas-api:$sormasVersion") { changing = true } implementation 'com.github.mpkorstanje:simmetrics-core:4.1.1' - implementation 'com.google.guava:guava:30.0-jre' - implementation 'com.opencsv:opencsv:5.3' + implementation 'com.google.guava:guava:31.0.1-android' + implementation 'com.opencsv:opencsv:5.5.2' implementation 'commons-beanutils:commons-beanutils:1.9.4' implementation 'commons-codec:commons-codec:1.15' implementation 'commons-collections:commons-collections:3.2.2' implementation 'commons-logging:commons-logging:1.2' - implementation 'joda-time:joda-time:2.10.8' + implementation 'joda-time:joda-time:2.10.13' implementation 'org.apache.commons:commons-collections4:4.4' - implementation 'org.apache.commons:commons-lang3:3.11' + implementation 'org.apache.commons:commons-lang3:3.12.0' implementation 'org.apache.commons:commons-text:1.9' - implementation 'org.jsoup:jsoup:1.14.2' + implementation 'org.jsoup:jsoup:1.14.3' implementation 'com.googlecode:openbeans:1.0' implementation files('libs/MPAndroidChart-v3.0.2.jar') implementation(name: 'CircleProgress-v1.2.1', ext: 'aar') diff --git a/sormas-backend/pom.xml b/sormas-backend/pom.xml index a32f8107f3b..f0a84285dae 100644 --- a/sormas-backend/pom.xml +++ b/sormas-backend/pom.xml @@ -113,7 +113,7 @@ com.vladmihalcea - hibernate-types-52 + hibernate-types-55 diff --git a/sormas-base/dependencies/serverlibs.pom b/sormas-base/dependencies/serverlibs.pom index 7fa1fd8c18e..effd624397b 100644 --- a/sormas-base/dependencies/serverlibs.pom +++ b/sormas-base/dependencies/serverlibs.pom @@ -55,7 +55,7 @@ com.vladmihalcea - hibernate-types-52 + hibernate-types-55 @@ -93,6 +93,10 @@ org.apache.commons commons-collections4 + + org.apache.commons + commons-compress + org.apache.commons commons-lang3 diff --git a/sormas-base/pom.xml b/sormas-base/pom.xml index 14f9b971fa5..98e9b8746f1 100644 --- a/sormas-base/pom.xml +++ b/sormas-base/pom.xml @@ -26,17 +26,17 @@ 2.3.3 - 1.7.30 - 1.2.9 + 1.7.36 + 1.2.10 TODO: Remove bootstrap.js in widgetset - 8.14.1 + 8.14.3 ${vaadin.version} - 2.1.6 - 1.67 - 16.1.0 - 3.15.1.Final + 2.1.13 + 1.70 + 16.1.1 + 3.15.3.Final 2.0.3 - 8.3.1 + 8.3.2 0.22.0 2.2 @@ -349,14 +349,14 @@ com.google.guava guava - 30.0-jre + 31.0.1-jre provided com.opencsv opencsv - 5.3 + 5.5.2 provided @@ -388,7 +388,7 @@ commons-io commons-io - 2.8.0 + 2.11.0 provided @@ -401,7 +401,7 @@ joda-time joda-time - 2.10.8 + 2.10.13 provided @@ -414,7 +414,7 @@ org.apache.httpcomponents httpcore - 4.4.14 + 4.4.15 provided @@ -424,10 +424,16 @@ 4.4 provided + + org.apache.commons + commons-compress + 1.21 + provided + org.apache.commons commons-lang3 - 3.11 + 3.12.0 provided @@ -453,7 +459,7 @@ org.hibernate hibernate-core - 5.4.25.Final + 5.6.5.Final provided @@ -517,8 +523,8 @@ com.vladmihalcea - hibernate-types-52 - 2.10.0 + hibernate-types-55 + 2.14.0 provided @@ -532,14 +538,14 @@ org.jsoup jsoup - 1.14.2 + 1.14.3 provided org.postgresql postgresql - 42.2.18 + 42.3.3 provided @@ -575,13 +581,13 @@ com.googlecode.libphonenumber libphonenumber - 8.12.14 + 8.12.43 com.jayway.jsonpath json-path - 2.6.0 + 2.7.0 @@ -627,13 +633,13 @@ org.freemarker freemarker - 2.3.30 + 2.3.31 org.geotools gt-shapefile - 24.1 + 26.2 @@ -875,24 +881,24 @@ com.ibm.etcd etcd-java - 0.0.18 + 0.0.19 com.google.oauth-client google-oauth-client - 1.31.5 + 1.33.1 com.google.http-client google-http-client - 1.39.2 + 1.41.4 com.google.http-client google-http-client-gson - 1.39.2 + 1.41.4 diff --git a/sormas-ui/pom.xml b/sormas-ui/pom.xml index 2245a5f673d..8b3382d103a 100644 --- a/sormas-ui/pom.xml +++ b/sormas-ui/pom.xml @@ -113,7 +113,7 @@ com.vladmihalcea - hibernate-types-52 + hibernate-types-55 From 98cfdf3f6e35c345a31d6ce775c6aa0157831fa2 Mon Sep 17 00:00:00 2001 From: Stefan Kock Date: Mon, 14 Feb 2022 15:58:40 +0100 Subject: [PATCH 095/253] #7978: Updated jackson version for android app - Overlooked in #4601 --- sormas-app/app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sormas-app/app/build.gradle b/sormas-app/app/build.gradle index cbbe61e0832..312d03275b7 100644 --- a/sormas-app/app/build.gradle +++ b/sormas-app/app/build.gradle @@ -120,8 +120,8 @@ dependencies { implementation(name: 'CircleProgress-v1.2.1', ext: 'aar') implementation 'io.reactivex:rxandroid:1.0.1' implementation 'io.reactivex:rxjava:1.0.14' - implementation 'com.fasterxml.jackson.core:jackson-core:2.10.2' - implementation 'com.fasterxml.jackson.core:jackson-annotations:2.10.2' + implementation 'com.fasterxml.jackson.core:jackson-core:2.12.4' + implementation 'com.fasterxml.jackson.core:jackson-annotations:2.12.4' implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" implementation "androidx.paging:paging-runtime:$paging_version" testImplementation 'junit:junit:4.13.2' From c2db66795ed412a42b984641563601a920b3d47c Mon Sep 17 00:00:00 2001 From: Stefan Kock Date: Tue, 15 Feb 2022 11:32:59 +0100 Subject: [PATCH 096/253] #7978: Documented False positives for etcd-java --- .../dependencies/check-suppressions.xml | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/sormas-base/dependencies/check-suppressions.xml b/sormas-base/dependencies/check-suppressions.xml index 6409fd226a2..04503e85e3c 100644 --- a/sormas-base/dependencies/check-suppressions.xml +++ b/sormas-base/dependencies/check-suppressions.xml @@ -65,6 +65,27 @@ .*\bmaven-ant-tasks.*\.jar CVE-2020-22475 + + + .*\betcd-java.*\.jar + CVE-2020-15106 + + + + .*\betcd-java.*\.jar + CVE-2020-15112 + + + + .*\betcd-java.*\.jar + CVE-2020-15113 + From 2a8a98c6895d65d162c298321933723ed0119400 Mon Sep 17 00:00:00 2001 From: Stefan Kock Date: Tue, 15 Feb 2022 12:14:32 +0100 Subject: [PATCH 097/253] #7978: Integrated dependency-check-maven plugin for maven based scans --- sormas-base/pom.xml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/sormas-base/pom.xml b/sormas-base/pom.xml index 98e9b8746f1..44ad19bc613 100644 --- a/sormas-base/pom.xml +++ b/sormas-base/pom.xml @@ -1188,6 +1188,31 @@ versions-maven-plugin 2.8.1 + + org.owasp + dependency-check-maven + 6.5.3 + + 12 + HTML,XML + target/dependency-check + true + false + false + + dependencies/check-suppressions.xml + + false + + + + + check + + + + + From 932bd285c7a97e699e4a9eed09085902deb4f640 Mon Sep 17 00:00:00 2001 From: sergiupacurariu <62688603+sergiupacurariu@users.noreply.github.com> Date: Wed, 16 Feb 2022 17:36:32 +0200 Subject: [PATCH 098/253] #7247 - CoreAdo: Introduce "end of processing date" --- .../java/de/symeda/sormas/api/CoreFacade.java | 10 +- .../de/symeda/sormas/api/caze/CaseFacade.java | 9 - .../sormas/api/contact/ContactFacade.java | 1 - .../symeda/sormas/api/event/EventFacade.java | 1 - .../de/symeda/sormas/api/i18n/Captions.java | 2 + .../de/symeda/sormas/api/i18n/Strings.java | 13 + .../api/immunization/ImmunizationFacade.java | 1 - .../api/travelentry/TravelEntryFacade.java | 3 +- .../de/symeda/sormas/api/user/UserRight.java | 6 + .../src/main/resources/captions.properties | 2 + .../src/main/resources/strings.properties | 13 + .../backend/campaign/CampaignFacadeEjb.java | 20 +- .../backend/campaign/CampaignService.java | 11 +- .../sormas/backend/caze/CaseFacadeEjb.java | 33 +-- .../sormas/backend/caze/CaseService.java | 75 ++---- .../common/AbstractCoreAdoService.java | 74 ++++++ .../backend/common/AbstractCoreFacadeEjb.java | 43 ++- .../AgregatedChangeDateExpressionBuilder.java | 39 +++ .../backend/common/ChangeDateBuilder.java | 8 + .../common/ChangeDateFilterBuilder.java | 2 +- .../symeda/sormas/backend/common/CoreAdo.java | 36 ++- .../backend/contact/ContactFacadeEjb.java | 11 +- .../backend/contact/ContactService.java | 21 +- .../CoreEntityDeletionService.java | 2 +- .../DeletionConfiguration.java | 4 +- .../backend/epidata/EpiDataService.java | 13 + .../sormas/backend/event/EventFacadeEjb.java | 31 ++- .../event/EventParticipantFacadeEjb.java | 9 +- .../event/EventParticipantService.java | 22 +- .../sormas/backend/event/EventService.java | 22 +- .../immunization/ImmunizationFacadeEjb.java | 9 +- .../immunization/ImmunizationService.java | 36 +-- .../travelentry/TravelEntryFacadeEjb.java | 34 ++- .../services/BaseTravelEntryService.java | 21 ++ .../services/TravelEntryService.java | 5 +- .../src/main/resources/sql/sormas_schema.sql | 45 ++++ .../backend/caze/CaseFacadeEjbTest.java | 6 +- .../backend/contact/ContactFacadeEjbTest.java | 4 +- .../backend/event/EventFacadeEjbTest.java | 6 +- .../backend/person/PersonFacadeEjbTest.java | 8 +- .../backend/sample/SampleFacadeEjbTest.java | 5 +- .../backend/task/TaskFacadeEjbTest.java | 8 +- .../symeda/sormas/ui/ControllerProvider.java | 7 + .../ui/campaign/CampaignController.java | 95 +++---- .../symeda/sormas/ui/caze/CaseController.java | 170 +++++------- .../de/symeda/sormas/ui/caze/CasesView.java | 4 +- .../sormas/ui/contact/ContactController.java | 39 +++ .../sormas/ui/events/EventController.java | 189 +++++-------- .../events/EventParticipantsController.java | 41 +++ .../symeda/sormas/ui/events/EventsView.java | 5 +- .../immunization/ImmunizationController.java | 76 ++---- .../ui/travelentry/TravelEntryController.java | 81 ++---- .../sormas/ui/utils/ArchiveController.java | 250 ++++++++++++++++++ .../symeda/sormas/ui/utils/VaadinUiUtil.java | 37 ++- 54 files changed, 1092 insertions(+), 626 deletions(-) create mode 100644 sormas-backend/src/main/java/de/symeda/sormas/backend/common/AgregatedChangeDateExpressionBuilder.java create mode 100644 sormas-backend/src/main/java/de/symeda/sormas/backend/common/ChangeDateBuilder.java create mode 100644 sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchiveController.java diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/CoreFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/CoreFacade.java index 98646d2e38e..7704abc8325 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/CoreFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/CoreFacade.java @@ -26,10 +26,6 @@ public interface CoreFacade extends BaseFacade { - void archive(String uuid); - - void dearchive(String uuid); - boolean isArchived(String uuid); boolean exists(String uuid); @@ -37,4 +33,10 @@ public interface CoreFacade getAllAfter(Date date, Integer batchSize, String lastSynchronizedUuid); AutomaticDeletionInfoDto getAutomaticDeletionInfo(String uuid); + + void archiveCoreEntities(List entityUuid, Date endOfProcessingDate); + + void dearchiveCoreEntities(List entityUuids, String dearchiveReason); + + Date calculateEndOfProcessingDate(List entityUuids); } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java index b7521ea8a9a..e5108c09029 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseFacade.java @@ -36,7 +36,6 @@ import de.symeda.sormas.api.Language; import de.symeda.sormas.api.common.Page; import de.symeda.sormas.api.contact.ContactReferenceDto; -import de.symeda.sormas.api.deletionconfiguration.AutomaticDeletionInfoDto; import de.symeda.sormas.api.event.EventParticipantReferenceDto; import de.symeda.sormas.api.externaldata.ExternalDataDto; import de.symeda.sormas.api.externaldata.ExternalDataUpdateException; @@ -164,14 +163,6 @@ Long countCasesForMap( void archiveAllArchivableCases(int daysAfterCaseGetsArchived); - /** - * @param caseUuids - * Cases identified by {@code uuid} to be archived or not. - * @param archived - * {@code true} archives the Case, {@code false} unarchives it. - */ - void updateArchived(List caseUuids, boolean archived); - List getRandomCaseReferences(CaseCriteria criteria, int count, Random randomGenerator); FollowUpPeriodDto calculateFollowUpUntilDate(CaseDataDto caseDto, boolean ignoreOverwrite); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java index e774aae41a7..292d4338491 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java @@ -30,7 +30,6 @@ import de.symeda.sormas.api.Language; import de.symeda.sormas.api.common.Page; import de.symeda.sormas.api.dashboard.DashboardContactDto; -import de.symeda.sormas.api.deletionconfiguration.AutomaticDeletionInfoDto; import de.symeda.sormas.api.externaldata.ExternalDataDto; import de.symeda.sormas.api.externaldata.ExternalDataUpdateException; import de.symeda.sormas.api.followup.FollowUpPeriodDto; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java index 2c2c01fe63f..9c6c13db1fe 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventFacade.java @@ -30,7 +30,6 @@ import de.symeda.sormas.api.CoreFacade; import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.common.Page; -import de.symeda.sormas.api.deletionconfiguration.AutomaticDeletionInfoDto; import de.symeda.sormas.api.externaldata.ExternalDataDto; import de.symeda.sormas.api.externaldata.ExternalDataUpdateException; import de.symeda.sormas.api.externalsurveillancetool.ExternalSurveillanceToolException; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java index e1846799623..28fe2f1761d 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java @@ -879,6 +879,7 @@ public interface Captions { String dashboardWeekBefore = "dashboardWeekBefore"; String dashboardYesterday = "dashboardYesterday"; String date = "date"; + String dearchiveReason = "dearchiveReason"; String defaultCommunity = "defaultCommunity"; String defaultDistrict = "defaultDistrict"; String defaultFacility = "defaultFacility"; @@ -978,6 +979,7 @@ public interface Captions { String DocumentTemplate_uploadWorkflowTemplate = "DocumentTemplate.uploadWorkflowTemplate"; String documentUploadDocument = "documentUploadDocument"; String edit = "edit"; + String endOfProcessingDate = "endOfProcessingDate"; String EpiData = "EpiData"; String EpiData_activitiesAsCase = "EpiData.activitiesAsCase"; String EpiData_activityAsCaseDetailsKnown = "EpiData.activityAsCaseDetailsKnown"; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java index 069bf030abb..2034b9a600c 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java @@ -57,6 +57,7 @@ public interface Strings { String confirmationArchiveCases = "confirmationArchiveCases"; String confirmationArchiveCommunities = "confirmationArchiveCommunities"; String confirmationArchiveCommunity = "confirmationArchiveCommunity"; + String confirmationArchiveContact = "confirmationArchiveContact"; String confirmationArchiveContinent = "confirmationArchiveContinent"; String confirmationArchiveContinents = "confirmationArchiveContinents"; String confirmationArchiveCountries = "confirmationArchiveCountries"; @@ -65,6 +66,7 @@ public interface Strings { String confirmationArchiveDistricts = "confirmationArchiveDistricts"; String confirmationArchiveEvent = "confirmationArchiveEvent"; String confirmationArchiveEventGroup = "confirmationArchiveEventGroup"; + String confirmationArchiveEventParticipant = "confirmationArchiveEventParticipant"; String confirmationArchiveEvents = "confirmationArchiveEvents"; String confirmationArchiveFacilities = "confirmationArchiveFacilities"; String confirmationArchiveFacility = "confirmationArchiveFacility"; @@ -91,6 +93,7 @@ public interface Strings { String confirmationDearchiveCases = "confirmationDearchiveCases"; String confirmationDearchiveCommunities = "confirmationDearchiveCommunities"; String confirmationDearchiveCommunity = "confirmationDearchiveCommunity"; + String confirmationDearchiveContact = "confirmationDearchiveContact"; String confirmationDearchiveContinent = "confirmationDearchiveContinent"; String confirmationDearchiveContinents = "confirmationDearchiveContinents"; String confirmationDearchiveCountries = "confirmationDearchiveCountries"; @@ -99,6 +102,7 @@ public interface Strings { String confirmationDearchiveDistricts = "confirmationDearchiveDistricts"; String confirmationDearchiveEvent = "confirmationDearchiveEvent"; String confirmationDearchiveEventGroup = "confirmationDearchiveEventGroup"; + String confirmationDearchiveEventParticipant = "confirmationDearchiveEventParticipant"; String confirmationDearchiveEvents = "confirmationDearchiveEvents"; String confirmationDearchiveFacilities = "confirmationDearchiveFacilities"; String confirmationDearchiveFacility = "confirmationDearchiveFacility"; @@ -340,8 +344,10 @@ public interface Strings { String headingAnimalContacts = "headingAnimalContacts"; String headingArchiveCampaign = "headingArchiveCampaign"; String headingArchiveCase = "headingArchiveCase"; + String headingArchiveContact = "headingArchiveContact"; String headingArchiveEvent = "headingArchiveEvent"; String headingArchiveEventGroup = "headingArchiveEventGroup"; + String headingArchiveEventParticipant = "headingArchiveEventParticipant"; String headingArchiveImmunization = "headingArchiveImmunization"; String headingArchiveTravelEntry = "headingArchiveTravelEntry"; String headingArchivingNotPossible = "headingArchivingNotPossible"; @@ -436,8 +442,10 @@ public interface Strings { String headingDataImport = "headingDataImport"; String headingDearchiveCampaign = "headingDearchiveCampaign"; String headingDearchiveCase = "headingDearchiveCase"; + String headingDearchiveContact = "headingDearchiveContact"; String headingDearchiveEvent = "headingDearchiveEvent"; String headingDearchiveEventGroup = "headingDearchiveEventGroup"; + String headingDearchiveEventParticipant = "headingDearchiveEventParticipant"; String headingDearchiveImmunization = "headingDearchiveImmunization"; String headingDearchiveTravelEntry = "headingDearchiveTravelEntry"; String headingDearchivingNotPossible = "headingDearchivingNotPossible"; @@ -866,6 +874,7 @@ public interface Strings { String messageAllContactsLinkedToEvent = "messageAllContactsLinkedToEvent"; String messageAlreadyEventParticipant = "messageAlreadyEventParticipant"; String messageAnimalContactsHint = "messageAnimalContactsHint"; + String messageArchiveUndoneReasonMandatory = "messageArchiveUndoneReasonMandatory"; String messageAreaArchived = "messageAreaArchived"; String messageAreaArchivingNotPossible = "messageAreaArchivingNotPossible"; String messageAreaDearchived = "messageAreaDearchived"; @@ -919,9 +928,11 @@ public interface Strings { String messageCommunityDearchivingNotPossible = "messageCommunityDearchivingNotPossible"; String messageCompletenessValuesUpdated = "messageCompletenessValuesUpdated"; String messageConfirmCaseAfterPathogenTest = "messageConfirmCaseAfterPathogenTest"; + String messageContactArchived = "messageContactArchived"; String messageContactCaseChanged = "messageContactCaseChanged"; String messageContactCaseRemoved = "messageContactCaseRemoved"; String messageContactCreated = "messageContactCreated"; + String messageContactDearchived = "messageContactDearchived"; String messageContactDuplicateDeleted = "messageContactDuplicateDeleted"; String messageContactExternalTokenWarning = "messageContactExternalTokenWarning"; String messageContactSaved = "messageContactSaved"; @@ -983,7 +994,9 @@ public interface Strings { String messageEventLinkedAsSubordinate = "messageEventLinkedAsSubordinate"; String messageEventLinkedAsSuperordinate = "messageEventLinkedAsSuperordinate"; String messageEventLinkedToGroup = "messageEventLinkedToGroup"; + String messageEventParticipantArchived = "messageEventParticipantArchived"; String messageEventParticipantCreated = "messageEventParticipantCreated"; + String messageEventParticipantDearchived = "messageEventParticipantDearchived"; String messageEventParticipantResponsibleJurisdictionUpdated = "messageEventParticipantResponsibleJurisdictionUpdated"; String messageEventParticipantSaved = "messageEventParticipantSaved"; String messageEventParticipantsDeleted = "messageEventParticipantsDeleted"; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/immunization/ImmunizationFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/immunization/ImmunizationFacade.java index 5aa0ed6d5f6..4a733deb543 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/immunization/ImmunizationFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/immunization/ImmunizationFacade.java @@ -22,7 +22,6 @@ import de.symeda.sormas.api.CoreFacade; import de.symeda.sormas.api.common.Page; -import de.symeda.sormas.api.deletionconfiguration.AutomaticDeletionInfoDto; import de.symeda.sormas.api.utils.SortProperty; @Remote diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/travelentry/TravelEntryFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/travelentry/TravelEntryFacade.java index 25feb20135a..7cd37ea4e7c 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/travelentry/TravelEntryFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/travelentry/TravelEntryFacade.java @@ -6,6 +6,7 @@ import de.symeda.sormas.api.CoreFacade; import de.symeda.sormas.api.common.Page; +import de.symeda.sormas.api.CoreFacade; import de.symeda.sormas.api.deletionconfiguration.AutomaticDeletionInfoDto; import de.symeda.sormas.api.utils.SortProperty; @@ -16,8 +17,6 @@ public interface TravelEntryFacade extends CoreFacadePlease indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -923,6 +932,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -956,6 +967,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java index 9ff5316b6df..1a762530c43 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java @@ -24,8 +24,6 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; -import de.symeda.sormas.api.deletionconfiguration.AutomaticDeletionInfoDto; -import de.symeda.sormas.backend.deletionconfiguration.CoreEntityType; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -36,6 +34,7 @@ import de.symeda.sormas.api.campaign.CampaignReferenceDto; import de.symeda.sormas.api.campaign.diagram.CampaignDashboardElement; import de.symeda.sormas.api.campaign.form.CampaignFormMetaReferenceDto; +import de.symeda.sormas.api.deletionconfiguration.AutomaticDeletionInfoDto; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Strings; import de.symeda.sormas.api.i18n.Validations; @@ -45,8 +44,10 @@ import de.symeda.sormas.api.utils.ValidationRuntimeException; import de.symeda.sormas.backend.campaign.diagram.CampaignDiagramDefinitionFacadeEjb; import de.symeda.sormas.backend.campaign.form.CampaignFormMetaService; +import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; +import de.symeda.sormas.backend.deletionconfiguration.CoreEntityType; import de.symeda.sormas.backend.user.User; import de.symeda.sormas.backend.user.UserFacadeEjb; import de.symeda.sormas.backend.user.UserRoleConfigFacadeEjb.UserRoleConfigFacadeEjbLocal; @@ -56,8 +57,12 @@ import de.symeda.sormas.backend.util.QueryHelper; @Stateless(name = "CampaignFacade") -public class CampaignFacadeEjb extends AbstractCoreFacadeEjb implements CampaignFacade { +public class CampaignFacadeEjb + extends AbstractCoreFacadeEjb + implements CampaignFacade { + @EJB + CampaignService campaignService; @EJB private CampaignFormMetaService campaignFormMetaService; @EJB @@ -73,6 +78,11 @@ public CampaignFacadeEjb(CampaignService service, UserService userService) { super(Campaign.class, CampaignDto.class, service, userService); } + @Override + public AbstractCoreAdoService getEntityService() { + return campaignService; + } + @Override public List getIndexList(CampaignCriteria campaignCriteria, Integer first, Integer max, List sortProperties) { @@ -187,6 +197,10 @@ public Campaign fillOrBuildEntity(@NotNull CampaignDto source, Campaign target, return target; } + @Override + protected void delete(Campaign entity) { + } + public void validate(CampaignReferenceDto campaignReferenceDto) { validate(getByUuid(campaignReferenceDto.getUuid())); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignService.java index e9f85bf5cd5..62ef8596378 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignService.java @@ -15,6 +15,7 @@ import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; +import de.symeda.sormas.backend.common.ChangeDateBuilder; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; @Stateless @@ -47,7 +48,8 @@ public Predicate buildCriteriaFilter(CampaignCriteria campaignCriteria, Criteria cb.between(from.get(Campaign.START_DATE), campaignCriteria.getStartDateAfter(), campaignCriteria.getStartDateBefore())); } if (campaignCriteria.getEndDateAfter() != null || campaignCriteria.getEndDateBefore() != null) { - filter = CriteriaBuilderHelper.and(cb, filter, cb.between(from.get(Campaign.END_DATE), campaignCriteria.getEndDateAfter(), campaignCriteria.getEndDateAfter())); + filter = CriteriaBuilderHelper + .and(cb, filter, cb.between(from.get(Campaign.END_DATE), campaignCriteria.getEndDateAfter(), campaignCriteria.getEndDateAfter())); } if (campaignCriteria.getFreeText() != null) { String[] textFilters = campaignCriteria.getFreeText().split("\\s+"); @@ -57,14 +59,15 @@ public Predicate buildCriteriaFilter(CampaignCriteria campaignCriteria, Criteria } Predicate likeFilters = cb.or( - CriteriaBuilderHelper.unaccentedIlike(cb, from.get(Campaign.NAME), textFilter), - CriteriaBuilderHelper.ilike(cb, from.get(Campaign.UUID), textFilter)); + CriteriaBuilderHelper.unaccentedIlike(cb, from.get(Campaign.NAME), textFilter), + CriteriaBuilderHelper.ilike(cb, from.get(Campaign.UUID), textFilter)); filter = CriteriaBuilderHelper.and(cb, filter, likeFilters); } } if (campaignCriteria.getRelevanceStatus() != null) { if (campaignCriteria.getRelevanceStatus() == EntityRelevanceStatus.ACTIVE) { - filter = CriteriaBuilderHelper.and(cb, filter, cb.or(cb.equal(from.get(Campaign.ARCHIVED), false), cb.isNull(from.get(Campaign.ARCHIVED)))); + filter = CriteriaBuilderHelper + .and(cb, filter, cb.or(cb.equal(from.get(Campaign.ARCHIVED), false), cb.isNull(from.get(Campaign.ARCHIVED)))); } else if (campaignCriteria.getRelevanceStatus() == EntityRelevanceStatus.ARCHIVED) { filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(Campaign.ARCHIVED), true)); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java index a27efbe60dd..3f71e031e63 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java @@ -123,7 +123,6 @@ import de.symeda.sormas.api.contact.ContactCriteria; import de.symeda.sormas.api.contact.ContactDto; import de.symeda.sormas.api.contact.ContactReferenceDto; -import de.symeda.sormas.api.deletionconfiguration.AutomaticDeletionInfoDto; import de.symeda.sormas.api.document.DocumentRelatedEntityType; import de.symeda.sormas.api.epidata.EpiDataDto; import de.symeda.sormas.api.epidata.EpiDataHelper; @@ -210,6 +209,7 @@ import de.symeda.sormas.backend.clinicalcourse.ClinicalVisitFacadeEjb.ClinicalVisitFacadeEjbLocal; import de.symeda.sormas.backend.clinicalcourse.ClinicalVisitService; import de.symeda.sormas.backend.clinicalcourse.HealthConditions; +import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; @@ -330,10 +330,10 @@ public class CaseFacadeEjb extends AbstractCoreFacadeEjb implements CaseFacade { - private static final int ARCHIVE_BATCH_SIZE = 1000; - private final Logger logger = LoggerFactory.getLogger(getClass()); + @EJB + private CaseService caseService; @EJB private CaseClassificationFacadeEjbLocal caseClassificationFacade; @EJB @@ -457,6 +457,11 @@ public CaseFacadeEjb(CaseService service, UserService userService) { super(Case.class, CaseDataDto.class, service, userService); } + @Override + public AbstractCoreAdoService getEntityService() { + return caseService; + } + @Override public List getAllActiveCasesAfter(Date date) { return getAllActiveCasesAfter(date, false); @@ -3412,11 +3417,14 @@ void archiveAllArchivableCases(int daysAfterCaseGetsArchived, LocalDate referenc Root from = cq.from(Case.class); Timestamp notChangedTimestamp = Timestamp.valueOf(notChangedSince.atStartOfDay()); - cq.where(cb.equal(from.get(Case.ARCHIVED), false), cb.not(service.createChangeDateFilter(cb, from, notChangedTimestamp, true))); - cq.select(from.get(Case.UUID)); + cq.where(cb.equal(from.get(Case.ARCHIVED), false), cb.not(caseService.createChangeDateFilter(cb, from, notChangedTimestamp, true))); + cq.select(from.get(Case.UUID)).distinct(true); List caseUuids = em.createQuery(cq).getResultList(); - IterableHelper.executeBatched(caseUuids, ARCHIVE_BATCH_SIZE, batchedCaseUuids -> service.updateArchived(batchedCaseUuids, true)); + if (!caseUuids.isEmpty()) { + archiveCoreEntities(caseUuids, null); + } + logger.debug( "archiveAllArchivableCases() finished. caseCount = {}, daysAfterCaseGetsArchived = {}, {}ms", caseUuids.size(), @@ -3424,19 +3432,6 @@ void archiveAllArchivableCases(int daysAfterCaseGetsArchived, LocalDate referenc DateHelper.durationMillies(startTime)); } - @Override - public void updateArchived(List caseUuids, boolean archived) { - - long startTime = DateHelper.startTime(); - - IterableHelper.executeBatched(caseUuids, ARCHIVE_BATCH_SIZE, batchedCaseUuids -> service.updateArchived(batchedCaseUuids, archived)); - logger.debug( - "updateArchived() finished. caseCount = {}, archived = {}, {}ms", - caseUuids.size(), - archived, - DateHelper.durationMillies(startTime)); - } - @Override public boolean hasPositiveLabResult(String caseUuid) { final CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java index 50ccb941297..edec024ca4a 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java @@ -18,7 +18,6 @@ package de.symeda.sormas.backend.caze; import java.sql.Timestamp; -import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -53,7 +52,6 @@ import javax.transaction.Transactional; import javax.validation.constraints.NotNull; -import de.symeda.sormas.backend.common.AbstractCoreAdoService; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -107,11 +105,12 @@ import de.symeda.sormas.backend.clinicalcourse.ClinicalCourse; import de.symeda.sormas.backend.clinicalcourse.ClinicalVisit; import de.symeda.sormas.backend.clinicalcourse.ClinicalVisitService; -import de.symeda.sormas.backend.common.AbstractDeletableAdoService; +import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; +import de.symeda.sormas.backend.common.ChangeDateBuilder; import de.symeda.sormas.backend.common.ChangeDateFilterBuilder; -import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; +import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.contact.ContactQueryContext; import de.symeda.sormas.backend.contact.ContactService; @@ -956,7 +955,7 @@ public Predicate createChangeDateFilter(CriteriaBuilder cb, From casePa */ public Predicate createChangeDateFilter(CriteriaBuilder cb, From casePath, Timestamp date, boolean includeExtendedChangeDateFilters) { - return addChangeDateFilter(new ChangeDateFilterBuilder(cb, date), casePath, includeExtendedChangeDateFilters).build(); + return addChangeDates(new ChangeDateFilterBuilder(cb, date), casePath, includeExtendedChangeDateFilters).build(); } private Predicate createChangeDateFilter( @@ -966,7 +965,7 @@ private Predicate createChangeDateFilter( boolean includeExtendedChangeDateFilters, String lastSynchronizedUuid) { - return addChangeDateFilter(new ChangeDateFilterBuilder(cb, date, casePath, lastSynchronizedUuid), casePath, includeExtendedChangeDateFilters) + return addChangeDates(new ChangeDateFilterBuilder(cb, date, casePath, lastSynchronizedUuid), casePath, includeExtendedChangeDateFilters) .build(); } @@ -976,41 +975,35 @@ public Predicate createChangeDateFilter( Expression dateExpression, boolean includeExtendedChangeDateFilters) { - return addChangeDateFilter(new ChangeDateFilterBuilder(cb, dateExpression), casePath, includeExtendedChangeDateFilters).build(); + return addChangeDates(new ChangeDateFilterBuilder(cb, dateExpression), casePath, includeExtendedChangeDateFilters).build(); } - private ChangeDateFilterBuilder addChangeDateFilter( - ChangeDateFilterBuilder filterBuilder, - From casePath, - boolean includeExtendedChangeDateFilters) { - - Join hospitalization = casePath.join(Case.HOSPITALIZATION, JoinType.LEFT); - Join clinicalCourse = casePath.join(Case.CLINICAL_COURSE, JoinType.LEFT); + @Override + protected > T addChangeDates(T builder, From caseFrom, boolean includeExtendedChangeDateFilters) { + Join hospitalization = caseFrom.join(Case.HOSPITALIZATION, JoinType.LEFT); + Join clinicalCourse = caseFrom.join(Case.CLINICAL_COURSE, JoinType.LEFT); - filterBuilder = filterBuilder.add(casePath) - .add(casePath, Case.SYMPTOMS) + builder = super.addChangeDates(builder, caseFrom, includeExtendedChangeDateFilters).add(caseFrom, Case.SYMPTOMS) .add(hospitalization) - .add(hospitalization, Hospitalization.PREVIOUS_HOSPITALIZATIONS); - - filterBuilder = epiDataService.addChangeDateFilters(filterBuilder, casePath.join(Contact.EPI_DATA, JoinType.LEFT)); - - filterBuilder = filterBuilder.add(casePath, Case.THERAPY) + .add(hospitalization, Hospitalization.PREVIOUS_HOSPITALIZATIONS) + .add(caseFrom, Case.THERAPY) .add(clinicalCourse) .add(clinicalCourse, ClinicalCourse.HEALTH_CONDITIONS) - .add(casePath, Case.MATERNAL_HISTORY) - .add(casePath, Case.PORT_HEALTH_INFO) - .add(casePath, Case.SORMAS_TO_SORMAS_ORIGIN_INFO) - .add(casePath, Case.SORMAS_TO_SORMAS_SHARES); + .add(caseFrom, Case.MATERNAL_HISTORY) + .add(caseFrom, Case.PORT_HEALTH_INFO) + .add(caseFrom, Case.SORMAS_TO_SORMAS_ORIGIN_INFO) + .add(caseFrom, Case.SORMAS_TO_SORMAS_SHARES); + + builder = epiDataService.addChangeDates(builder, caseFrom.join(Case.EPI_DATA, JoinType.LEFT)); if (includeExtendedChangeDateFilters) { - Join caseSampleJoin = casePath.join(Case.SAMPLES, JoinType.LEFT); - Join casePersonJoin = casePath.join(Case.PERSON, JoinType.LEFT); + Join caseSampleJoin = caseFrom.join(Case.SAMPLES, JoinType.LEFT); + Join casePersonJoin = caseFrom.join(Case.PERSON, JoinType.LEFT); - filterBuilder = - filterBuilder.add(caseSampleJoin).add(caseSampleJoin, Sample.PATHOGENTESTS).add(casePersonJoin).add(casePersonJoin, Person.ADDRESS); + builder = builder.add(caseSampleJoin).add(caseSampleJoin, Sample.PATHOGENTESTS).add(casePersonJoin).add(casePersonJoin, Person.ADDRESS); } - return filterBuilder; + return builder; } @SuppressWarnings("rawtypes") @@ -1292,28 +1285,6 @@ public void updateFollowUpDetails(Case caze, boolean followUpStatusChangedByUser ensurePersisted(caze); } - /** - * @param caseUuids - * {@link Case}s identified by {@code uuid} to be archived or not. - * @param archived - * {@code true} archives the Case, {@code false} unarchives it. - * @see {@link Case#setArchived(boolean)} - */ - @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) - public void updateArchived(List caseUuids, boolean archived) { - - CriteriaBuilder cb = em.getCriteriaBuilder(); - CriteriaUpdate cu = cb.createCriteriaUpdate(Case.class); - Root root = cu.from(Case.class); - - cu.set(Case.CHANGE_DATE, Timestamp.from(Instant.now())); - cu.set(root.get(Case.ARCHIVED), archived); - - cu.where(root.get(Case.UUID).in(caseUuids)); - - em.createQuery(cu).executeUpdate(); - } - public boolean isCaseEditAllowed(Case caze) { if (caze.getSormasToSormasOriginInfo() != null && !caze.getSormasToSormasOriginInfo().isOwnershipHandedOver()) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java index 25c92ed00d3..ace4a384221 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java @@ -15,12 +15,27 @@ package de.symeda.sormas.backend.common; +import java.sql.Timestamp; +import java.time.Instant; +import java.util.Date; +import java.util.List; + +import javax.ejb.TransactionAttribute; +import javax.ejb.TransactionAttributeType; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.CriteriaUpdate; +import javax.persistence.criteria.Expression; +import javax.persistence.criteria.From; import javax.persistence.criteria.Root; +import de.symeda.sormas.backend.caze.Case; +import de.symeda.sormas.backend.util.IterableHelper; + public abstract class AbstractCoreAdoService extends AbstractDeletableAdoService { + private static final int ARCHIVE_BATCH_SIZE = 1000; + protected AbstractCoreAdoService(Class elementClass) { super(elementClass); } @@ -35,4 +50,63 @@ public boolean isArchived(String uuid) { long count = em.createQuery(cq).getSingleResult(); return count > 0; } + + protected > T addChangeDates(T builder, From adoPath, boolean includeExtendedChangeDateFilters){ + return builder.add(adoPath); + } + + public Date calculateCaseEndOfProcessingDate(List entityuuids) { + + if (entityuuids.isEmpty()) { + return null; + } + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(Date.class); + Root from = cq.from(getElementClass()); + + Expression agregatedChangeDateExpression = addChangeDates(new AgregatedChangeDateExpressionBuilder(cb), from, true).build(); + cq.select(cb.max(agregatedChangeDateExpression)); + cq.where(from.get(ADO.UUID).in(entityuuids)); + + return em.createQuery(cq).getSingleResult(); + } + + @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) + public void updateArchivedCoreEntities(List entityUuids, Date endOfProcessingDate) { + + final Date finalEndOfProcessingDate = endOfProcessingDate != null ? endOfProcessingDate : calculateCaseEndOfProcessingDate(entityUuids); + + IterableHelper.executeBatched(entityUuids, ARCHIVE_BATCH_SIZE, batchedUuids -> { + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaUpdate cu = cb.createCriteriaUpdate(getElementClass()); + Root root = cu.from(getElementClass()); + + cu.set(AbstractDomainObject.CHANGE_DATE, Timestamp.from(Instant.now())); + cu.set(root.get(Case.ARCHIVED), true); + cu.set(root.get(CoreAdo.END_OF_PROCESSING_DATE), finalEndOfProcessingDate); + + cu.where(root.get(AbstractDomainObject.UUID).in(batchedUuids)); + + em.createQuery(cu).executeUpdate(); + }); + } + + @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) + public void updateDearchivedCoreEntities(List entityUuids, String dearchiveReason) { + + IterableHelper.executeBatched(entityUuids, ARCHIVE_BATCH_SIZE, batchedUuids -> { + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaUpdate cu = cb.createCriteriaUpdate(getElementClass()); + Root root = cu.from(getElementClass()); + + cu.set(AbstractDomainObject.CHANGE_DATE, Timestamp.from(Instant.now())); + cu.set(root.get(Case.ARCHIVED), false); + cu.set(root.get(CoreAdo.END_OF_PROCESSING_DATE), (Date) null); + cu.set(root.get(CoreAdo.ARCHIVE_UNDONE_REASON), dearchiveReason); + + cu.where(root.get(AbstractDomainObject.UUID).in(batchedUuids)); + + em.createQuery(cu).executeUpdate(); + }); + } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreFacadeEjb.java index ba2376c8796..d013cd5d55a 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreFacadeEjb.java @@ -56,6 +56,8 @@ protected AbstractCoreFacadeEjb(Class adoClass, Class dtoClass, SRV se super(adoClass, dtoClass, service, userService); } + public abstract AbstractCoreAdoService getEntityService(); + @Override public DTO getByUuid(String uuid) { Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); @@ -101,23 +103,6 @@ public boolean exists(String uuid) { return service.exists(uuid); } - @Override - public void archive(String uuid) { - ADO ado = service.getByUuid(uuid); - if (ado != null) { - ado.setArchived(true); - service.ensurePersisted(ado); - } - } - - public void dearchive(String uuid) { - ADO ado = service.getByUuid(uuid); - if (ado != null) { - ado.setArchived(false); - service.ensurePersisted(ado); - } - } - public boolean isArchived(String uuid) { return service.isArchived(uuid); } @@ -161,12 +146,12 @@ protected void delete(ADO entity) { protected String getDeleteReferenceField(DeletionReference deletionReference) { switch (deletionReference) { - case CREATION: - return AbstractDomainObject.CREATION_DATE; - case END: - return AbstractDomainObject.CHANGE_DATE; - default: - throw new IllegalArgumentException("deletion reference " + deletionReference + " not supported in " + getClass().getSimpleName()); + case CREATION: + return AbstractDomainObject.CREATION_DATE; + case END: + return AbstractDomainObject.CHANGE_DATE; + default: + throw new IllegalArgumentException("deletion reference " + deletionReference + " not supported in " + getClass().getSimpleName()); } } @@ -193,4 +178,16 @@ private Object[] getDeletionData(String uuid, DeletionConfiguration entityConfig protected abstract void restorePseudonymizedDto(DTO dto, DTO existingDto, ADO entity, Pseudonymizer pseudonymizer); public abstract void validate(DTO dto) throws ValidationRuntimeException; + + public void archiveCoreEntities(List entityUuids, Date endOfProcessingDate) { + getEntityService().updateArchivedCoreEntities(entityUuids, endOfProcessingDate); + } + + public void dearchiveCoreEntities(List entityUuids, String dearchiveReason) { + getEntityService().updateDearchivedCoreEntities(entityUuids, dearchiveReason); + } + + public Date calculateEndOfProcessingDate(List entityUuids) { + return getEntityService().calculateCaseEndOfProcessingDate(entityUuids); + } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AgregatedChangeDateExpressionBuilder.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AgregatedChangeDateExpressionBuilder.java new file mode 100644 index 00000000000..5dc3c6860b7 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AgregatedChangeDateExpressionBuilder.java @@ -0,0 +1,39 @@ +package de.symeda.sormas.backend.common; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.Expression; +import javax.persistence.criteria.From; +import javax.persistence.criteria.JoinType; + +public class AgregatedChangeDateExpressionBuilder implements ChangeDateBuilder { + + private final CriteriaBuilder cb; + private List> dateExpressions; + + public AgregatedChangeDateExpressionBuilder(CriteriaBuilder cb) { + this.cb = cb; + this.dateExpressions = new ArrayList<>(); + } + + public Expression build() { + return cb.function("greatest", Date.class, dateExpressions.toArray(new Expression[] {})); + } + + public AgregatedChangeDateExpressionBuilder add(From path, String... joinFields) { + dateExpressions.add(changeDateExpression(path, joinFields)); + return this; + } + + private Expression changeDateExpression(From path, String... joinFields) { + From parent = path; + for (String joinField : joinFields) { + parent = parent.join(joinField, JoinType.LEFT); + } + return parent.get(AbstractDomainObject.CHANGE_DATE); + } + +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ChangeDateBuilder.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ChangeDateBuilder.java new file mode 100644 index 00000000000..ac793479d8b --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ChangeDateBuilder.java @@ -0,0 +1,8 @@ +package de.symeda.sormas.backend.common; + +import javax.persistence.criteria.From; + +public interface ChangeDateBuilder { + + T add(From path, String... joinFields); +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ChangeDateFilterBuilder.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ChangeDateFilterBuilder.java index 74565f117cd..f0477cd1472 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ChangeDateFilterBuilder.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ChangeDateFilterBuilder.java @@ -27,7 +27,7 @@ import de.symeda.sormas.api.EntityDto; -public class ChangeDateFilterBuilder { +public class ChangeDateFilterBuilder implements ChangeDateBuilder { private final CriteriaBuilder cb; private final Stream.Builder filters; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CoreAdo.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CoreAdo.java index 8dd425f3c1a..4087ac60aca 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CoreAdo.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CoreAdo.java @@ -15,6 +15,10 @@ package de.symeda.sormas.backend.common; +import static de.symeda.sormas.api.utils.FieldConstraints.CHARACTER_LIMIT_DEFAULT; + +import java.sql.Timestamp; + import javax.persistence.Column; import javax.persistence.MappedSuperclass; @@ -30,15 +34,37 @@ public class CoreAdo extends DeletableAdo { public static final String ARCHIVED = "archived"; + public static final String END_OF_PROCESSING_DATE = "endOfProcessingDate"; + public static final String ARCHIVE_UNDONE_REASON = "archiveUndoneReason"; - private boolean archived; + private boolean archived; + private Timestamp endOfProcessingDate; + private String archiveUndoneReason; - @Column(nullable = false) - public boolean isArchived() { - return archived; - } + @Column(nullable = false) + public boolean isArchived() { + return archived; + } public void setArchived(boolean archived) { this.archived = archived; } + + @Column + public Timestamp getEndOfProcessingDate() { + return endOfProcessingDate; + } + + public void setEndOfProcessingDate(Timestamp endOfProcessingDate) { + this.endOfProcessingDate = endOfProcessingDate; + } + + @Column(length = CHARACTER_LIMIT_DEFAULT) + public String getArchiveUndoneReason() { + return archiveUndoneReason; + } + + public void setArchiveUndoneReason(String archiveUndoneReason) { + this.archiveUndoneReason = archiveUndoneReason; + } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java index f0399ac8e78..cb0d137ebc3 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java @@ -138,6 +138,7 @@ import de.symeda.sormas.backend.caze.CaseFacadeEjb.CaseFacadeEjbLocal; import de.symeda.sormas.backend.caze.CaseService; import de.symeda.sormas.backend.clinicalcourse.ClinicalCourseFacadeEjb; +import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; @@ -203,7 +204,8 @@ import de.symeda.sormas.backend.visit.VisitService; @Stateless(name = "ContactFacade") -public class ContactFacadeEjb extends AbstractCoreFacadeEjb +public class ContactFacadeEjb + extends AbstractCoreFacadeEjb implements ContactFacade { private static final long SECONDS_30_DAYS = TimeUnit.DAYS.toSeconds(30L); @@ -213,6 +215,8 @@ public class ContactFacadeEjb extends AbstractCoreFacadeEjb getEntityService() { + return contactService; + } + @Override protected void selectDtoFields(CriteriaQuery cq, Root root) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java index 2f6bc340da3..82474e9e77e 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java @@ -83,6 +83,7 @@ import de.symeda.sormas.backend.clinicalcourse.HealthConditions; import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; +import de.symeda.sormas.backend.common.ChangeDateBuilder; import de.symeda.sormas.backend.common.ChangeDateFilterBuilder; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.common.DeletableAdo; @@ -210,16 +211,22 @@ public Predicate createChangeDateFilter(CriteriaBuilder cb, From fro } public Predicate createChangeDateFilter(CriteriaBuilder cb, From from, Timestamp date, String lastSynchronizedUuid) { - ChangeDateFilterBuilder changeDateFilterBuilder = new ChangeDateFilterBuilder(cb, date, from, lastSynchronizedUuid); - Join epiData = from.join(Contact.EPI_DATA, JoinType.LEFT); - Join healthCondition = from.join(Contact.HEALTH_CONDITIONS, JoinType.LEFT); + return addChangeDates(changeDateFilterBuilder, from, false).build(); + } + + @Override + protected > T addChangeDates(T builder, From contactFrom, boolean includeExtendedChangeDateFilters) { + Join healthCondition = contactFrom.join(Contact.HEALTH_CONDITIONS, JoinType.LEFT); + Join epiData = contactFrom.join(Contact.EPI_DATA, JoinType.LEFT); + + builder = super.addChangeDates(builder, contactFrom, includeExtendedChangeDateFilters).add(healthCondition) + .add(contactFrom, Contact.SORMAS_TO_SORMAS_ORIGIN_INFO) + .add(contactFrom, Contact.SORMAS_TO_SORMAS_SHARES); - changeDateFilterBuilder.add(from); - epiDataService.addChangeDateFilters(changeDateFilterBuilder, epiData); - changeDateFilterBuilder.add(healthCondition).add(from, Contact.SORMAS_TO_SORMAS_ORIGIN_INFO).add(from, Contact.SORMAS_TO_SORMAS_SHARES); + builder = epiDataService.addChangeDates(builder, epiData); - return changeDateFilterBuilder.build(); + return builder; } public List getAllActiveUuids(User user) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/CoreEntityDeletionService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/CoreEntityDeletionService.java index 4284c1dfa59..3920c2769b4 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/CoreEntityDeletionService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/CoreEntityDeletionService.java @@ -49,7 +49,7 @@ public void executeAutomaticDeletion() { coreEntityFacades.forEach(coreEntityType -> { DeletionConfiguration coreEntityTypeConfig = deletionConfigurationService.getCoreEntityTypeConfig(coreEntityType.coreEntityType); - if (coreEntityTypeConfig.deletionReference != null && coreEntityTypeConfig.deletionPeriod != null) { + if (coreEntityTypeConfig.getDeletionReference() != null && coreEntityTypeConfig.deletionPeriod != null) { coreEntityType.entityFacade.executeAutomaticDeletion(coreEntityTypeConfig); } }); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/DeletionConfiguration.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/DeletionConfiguration.java index 0fe072a3ca7..174423ff05f 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/DeletionConfiguration.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/deletionconfiguration/DeletionConfiguration.java @@ -24,8 +24,8 @@ public class DeletionConfiguration extends AbstractDomainObject { public static final String DELETION_REFERENCE = "deletionReference"; public static final String DELETION_PERIOD = "deletionPeriod"; - CoreEntityType entityType; - DeletionReference deletionReference; + private CoreEntityType entityType; + private DeletionReference deletionReference; @Min(value = 7, message = Validations.numberTooSmall) @Max(value = Integer.MAX_VALUE, message = Validations.numberTooBig) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/epidata/EpiDataService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/epidata/EpiDataService.java index b31de34a569..7741d900f5b 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/epidata/EpiDataService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/epidata/EpiDataService.java @@ -30,6 +30,7 @@ import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.backend.activityascase.ActivityAsCase; import de.symeda.sormas.backend.common.BaseAdoService; +import de.symeda.sormas.backend.common.ChangeDateBuilder; import de.symeda.sormas.backend.common.ChangeDateFilterBuilder; import de.symeda.sormas.backend.exposure.Exposure; @@ -63,4 +64,16 @@ public ChangeDateFilterBuilder addChangeDateFilters(ChangeDateFilterBuilder filt .add(activitiesAsCaseJoin) .add(activitiesAsCaseJoin, ActivityAsCase.LOCATION); } + + public > T addChangeDates(T builder, From epiData) { + + Join exposures = epiData.join(EpiData.EXPOSURES, JoinType.LEFT); + Join activitiesAsCaseJoin = epiData.join(EpiData.ACTIVITIES_AS_CASE, JoinType.LEFT); + + return builder.add(epiData) + .add(exposures) + .add(exposures, Exposure.LOCATION) + .add(activitiesAsCaseJoin) + .add(activitiesAsCaseJoin, ActivityAsCase.LOCATION); + } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java index 8860ebb0674..a7d976997b1 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java @@ -45,7 +45,6 @@ import javax.inject.Inject; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.CriteriaUpdate; import javax.persistence.criteria.Expression; import javax.persistence.criteria.Join; import javax.persistence.criteria.JoinType; @@ -64,7 +63,6 @@ import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.caze.CaseOutcome; import de.symeda.sormas.api.common.Page; -import de.symeda.sormas.api.deletionconfiguration.AutomaticDeletionInfoDto; import de.symeda.sormas.api.event.EventCriteria; import de.symeda.sormas.api.event.EventDetailedReferenceDto; import de.symeda.sormas.api.event.EventDto; @@ -92,6 +90,7 @@ import de.symeda.sormas.api.utils.SortProperty; import de.symeda.sormas.api.utils.ValidationRuntimeException; import de.symeda.sormas.backend.caze.Case; +import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; @@ -132,6 +131,10 @@ public class EventFacadeEjb extends AbstractCoreFacadeEjb getEntityService() { + return eventService; + } + @Override public List getAllActiveUuids() { @@ -1187,20 +1195,12 @@ void archiveAllArchivableEvents(int daysAfterEventGetsArchived, @NotNull LocalDa Root from = cq.from(Event.class); Timestamp notChangedTimestamp = Timestamp.valueOf(notChangedSince.atStartOfDay()); - cq.where(cb.equal(from.get(Event.ARCHIVED), false), cb.not(service.createChangeDateFilter(cb, from, notChangedTimestamp))); - cq.select(from.get(Event.UUID)); - List uuids = em.createQuery(cq).getResultList(); - - if (!uuids.isEmpty()) { - - CriteriaUpdate cu = cb.createCriteriaUpdate(Event.class); - Root root = cu.from(Event.class); - - cu.set(root.get(Event.ARCHIVED), true); - - cu.where(root.get(Event.UUID).in(uuids)); + cq.where(cb.equal(from.get(Event.ARCHIVED), false), cb.not(eventService.createChangeDateFilter(cb, from, notChangedTimestamp))); + cq.select(from.get(Event.UUID)).distinct(true); + List eventUuids = em.createQuery(cq).getResultList(); - em.createQuery(cu).executeUpdate(); + if (!eventUuids.isEmpty()) { + archiveCoreEntities(eventUuids, null); } } @@ -1296,7 +1296,6 @@ protected CoreEntityType getCoreEntityType() { public static class EventFacadeEjbLocal extends EventFacadeEjb { public EventFacadeEjbLocal() { - super(); } @Inject diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java index 4abaad61ffc..300180bd1ff 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java @@ -57,7 +57,6 @@ import de.symeda.sormas.api.caze.CaseExportDto; import de.symeda.sormas.api.caze.EmbeddedSampleExportDto; import de.symeda.sormas.api.common.Page; -import de.symeda.sormas.api.deletionconfiguration.AutomaticDeletionInfoDto; import de.symeda.sormas.api.event.EventDto; import de.symeda.sormas.api.event.EventParticipantCriteria; import de.symeda.sormas.api.event.EventParticipantDto; @@ -89,6 +88,7 @@ import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.caze.CaseFacadeEjb; import de.symeda.sormas.backend.caze.CaseService; +import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; @@ -140,6 +140,8 @@ public class EventParticipantFacadeEjb private final Logger logger = LoggerFactory.getLogger(getClass()); + @EJB + private EventParticipantService eventParticipantService; @EJB private EventService eventService; @EJB @@ -182,6 +184,11 @@ public static EventParticipantReferenceDto toReferenceDto(EventParticipant entit return new EventParticipantReferenceDto(entity.getUuid(), person.getFirstName(), person.getFirstName()); } + @Override + public AbstractCoreAdoService getEntityService() { + return eventParticipantService; + } + @Override public List getAllEventParticipantsByEventAfter(Date date, String eventUuid) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java index d3c7eb8f24a..aeaf5c165a5 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java @@ -39,7 +39,7 @@ import javax.persistence.criteria.Root; import javax.persistence.criteria.Subquery; -import de.symeda.sormas.backend.common.AbstractCoreAdoService; +import de.symeda.sormas.backend.common.ChangeDateFilterBuilder; import org.apache.commons.collections.CollectionUtils; import de.symeda.sormas.api.Disease; @@ -48,7 +48,9 @@ import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.backend.caze.Case; +import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; +import de.symeda.sormas.backend.common.ChangeDateBuilder; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.contact.ContactQueryContext; @@ -78,7 +80,6 @@ public EventParticipantService() { super(EventParticipant.class); } - public List getAllAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { return getAllAfter(date, null, batchSize, lastSynchronizedUuid); } @@ -406,14 +407,23 @@ public List getByEventUuids(List eventUuids) { @Override public Predicate createChangeDateFilter(CriteriaBuilder cb, From from, Timestamp date) { - Predicate dateFilter = super.createChangeDateFilter(cb, from, date); - dateFilter = cb.or(dateFilter, changeDateFilter(cb, date, from, EventParticipant.SORMAS_TO_SORMAS_ORIGIN_INFO)); - dateFilter = cb.or(dateFilter, changeDateFilter(cb, date, from, EventParticipant.SORMAS_TO_SORMAS_SHARES)); + ChangeDateFilterBuilder changeDateFilterBuilder = new ChangeDateFilterBuilder(cb, date, from, null); - return dateFilter; + return addChangeDates(changeDateFilterBuilder, from, false).build(); } + @Override + protected > T addChangeDates( + T builder, + From eventParticipantFrom, + boolean includeExtendedChangeDateFilters) { + + return super.addChangeDates(builder, eventParticipantFrom, includeExtendedChangeDateFilters) + .add(eventParticipantFrom, EventParticipant.SORMAS_TO_SORMAS_ORIGIN_INFO) + .add(eventParticipantFrom, EventParticipant.SORMAS_TO_SORMAS_SHARES); + } + public boolean isEventParticipantEditAllowed(EventParticipant eventParticipant) { if (eventParticipant.getSormasToSormasOriginInfo() != null && !eventParticipant.getSormasToSormasOriginInfo().isOwnershipHandedOver()) { return false; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java index 064fc8370c0..6201c6850d5 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventService.java @@ -40,6 +40,7 @@ import javax.persistence.criteria.Subquery; import javax.transaction.Transactional; +import de.symeda.sormas.backend.common.ChangeDateBuilder; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -474,31 +475,26 @@ public Predicate createCaseAndEventParticipantFilter(CriteriaBuilder cb, Criteri @Override public Predicate createChangeDateFilter(CriteriaBuilder cb, From eventPath, Timestamp date) { - return addChangeDateFilter(new ChangeDateFilterBuilder(cb, date), eventPath).build(); + return addChangeDates(new ChangeDateFilterBuilder(cb, date), eventPath, false).build(); } private Predicate createChangeDateFilter(CriteriaBuilder cb, From eventPath, Timestamp date, String lastSynchronizedUuid) { - ChangeDateFilterBuilder changeDateFilterBuilder = lastSynchronizedUuid == null ? new ChangeDateFilterBuilder(cb, date) : new ChangeDateFilterBuilder(cb, date, eventPath, lastSynchronizedUuid); - return addChangeDateFilter(changeDateFilterBuilder, eventPath).build(); + return addChangeDates(changeDateFilterBuilder, eventPath, false).build(); } public Predicate createChangeDateFilter(CriteriaBuilder cb, From eventPath, Expression dateExpression) { - - return addChangeDateFilter(new ChangeDateFilterBuilder(cb, dateExpression), eventPath).build(); + return addChangeDates(new ChangeDateFilterBuilder(cb, dateExpression), eventPath, false).build(); } - private ChangeDateFilterBuilder addChangeDateFilter(ChangeDateFilterBuilder filterBuilder, From eventPath) { - - filterBuilder.add(eventPath) - .add(eventPath, Event.EVENT_LOCATION) - .add(eventPath, Event.SORMAS_TO_SORMAS_ORIGIN_INFO) - .add(eventPath, Event.SORMAS_TO_SORMAS_SHARES); - - return filterBuilder; + @Override + protected > T addChangeDates(T builder, From eventFrom, boolean includeExtendedChangeDateFilters) { + return super.addChangeDates(builder, eventFrom, includeExtendedChangeDateFilters).add(eventFrom, Event.EVENT_LOCATION) + .add(eventFrom, Event.SORMAS_TO_SORMAS_ORIGIN_INFO) + .add(eventFrom, Event.SORMAS_TO_SORMAS_SHARES); } @Override diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java index 55ad3abee1c..f0697f370cd 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java @@ -45,7 +45,6 @@ import de.symeda.sormas.api.caze.CaseOutcome; import de.symeda.sormas.api.caze.CaseReferenceDto; import de.symeda.sormas.api.common.Page; -import de.symeda.sormas.api.deletionconfiguration.AutomaticDeletionInfoDto; import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Strings; @@ -76,6 +75,7 @@ import de.symeda.sormas.api.vaccination.VaccinationDto; import de.symeda.sormas.backend.caze.CaseFacadeEjb; import de.symeda.sormas.backend.caze.CaseService; +import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; import de.symeda.sormas.backend.deletionconfiguration.CoreEntityType; import de.symeda.sormas.backend.immunization.entity.Immunization; @@ -115,6 +115,8 @@ public class ImmunizationFacadeEjb private final Logger logger = LoggerFactory.getLogger(ImmunizationFacadeEjb.class); + @EJB + private ImmunizationService immunizationService; @EJB private DirectoryImmunizationService directoryImmunizationService; @EJB @@ -160,6 +162,11 @@ public ImmunizationFacadeEjb(ImmunizationService service, UserService userServic super(Immunization.class, ImmunizationDto.class, service, userService); } + @Override + public AbstractCoreAdoService getEntityService() { + return immunizationService; + } + public static ImmunizationReferenceDto toReferenceDto(Immunization entity) { if (entity == null) { return null; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java index c064a3b57c4..18163320a84 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationService.java @@ -37,6 +37,7 @@ import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; +import de.symeda.sormas.backend.common.ChangeDateBuilder; import org.apache.commons.collections.CollectionUtils; import de.symeda.sormas.api.Disease; @@ -148,17 +149,25 @@ public Predicate createChangeDateFilter(CriteriaBuilder cb, From immunization, Timestamp date, String lastSynchronizedUuid) { + @Override + protected > T addChangeDates( + T builder, + From immunizationFrom, + boolean includeExtendedChangeDateFilters) { - Join vaccinations = immunization.join(Immunization.VACCINATIONS, JoinType.LEFT); + Join vaccinations = immunizationFrom.join(Immunization.VACCINATIONS, JoinType.LEFT); - ChangeDateFilterBuilder changeDateFilterBuilder = - lastSynchronizedUuid == null ? new ChangeDateFilterBuilder(cb, date) : new ChangeDateFilterBuilder(cb, date, immunization, lastSynchronizedUuid); - return changeDateFilterBuilder.add(immunization) - .add(vaccinations) - .add(immunization, Immunization.SORMAS_TO_SORMAS_ORIGIN_INFO) - .add(immunization, Immunization.SORMAS_TO_SORMAS_SHARES) - .build(); + return super.addChangeDates(builder, immunizationFrom, includeExtendedChangeDateFilters).add(vaccinations) + .add(immunizationFrom, Immunization.SORMAS_TO_SORMAS_ORIGIN_INFO) + .add(immunizationFrom, Immunization.SORMAS_TO_SORMAS_SHARES); + } + + private Predicate createChangeDateFilter(CriteriaBuilder cb, From immunization, Timestamp date, String lastSynchronizedUuid) { + ChangeDateFilterBuilder changeDateFilterBuilder = lastSynchronizedUuid == null + ? new ChangeDateFilterBuilder(cb, date) + : new ChangeDateFilterBuilder(cb, date, immunization, lastSynchronizedUuid); + + return addChangeDates(changeDateFilterBuilder, immunization, false).build(); } public List getAllAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { @@ -455,15 +464,10 @@ private Predicate createUserFilter(ImmunizationQueryContext qc) { filter = ImmunizationJurisdictionPredicateValidator.of(qc, currentUser).inJurisdictionOrOwned(); } else { filter = CriteriaBuilderHelper.or( - cb, + cb, cb.equal(qc.getRoot().get(Immunization.REPORTING_USER), currentUser), PersonJurisdictionPredicateValidator - .of( - qc.getQuery(), - cb, - new PersonJoins<>(((ImmunizationJoins) qc.getJoins()).getPerson()), - currentUser, - false) + .of(qc.getQuery(), cb, new PersonJoins<>(((ImmunizationJoins) qc.getJoins()).getPerson()), currentUser, false) .inJurisdictionOrOwned()); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java index 80d594c8942..4ebf352d63b 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java @@ -10,9 +10,8 @@ import javax.persistence.criteria.Root; import javax.validation.constraints.NotNull; -import de.symeda.sormas.api.deletionconfiguration.AutomaticDeletionInfoDto; -import de.symeda.sormas.api.deletionconfiguration.DeletionReference; import de.symeda.sormas.api.common.Page; +import de.symeda.sormas.api.deletionconfiguration.DeletionReference; import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Validations; @@ -29,8 +28,9 @@ import de.symeda.sormas.api.utils.ValidationRuntimeException; import de.symeda.sormas.backend.caze.CaseFacadeEjb; import de.symeda.sormas.backend.caze.CaseService; -import de.symeda.sormas.backend.deletionconfiguration.CoreEntityType; +import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; +import de.symeda.sormas.backend.deletionconfiguration.CoreEntityType; import de.symeda.sormas.backend.infrastructure.community.CommunityFacadeEjb; import de.symeda.sormas.backend.infrastructure.community.CommunityService; import de.symeda.sormas.backend.infrastructure.district.DistrictFacadeEjb; @@ -54,7 +54,9 @@ public class TravelEntryFacadeEjb implements TravelEntryFacade { @EJB - TravelEntryListService travelEntryListService; + private TravelEntryService travelEntryService; + @EJB + private TravelEntryListService travelEntryListService; @EJB private PersonService personService; @EJB @@ -73,6 +75,23 @@ public class TravelEntryFacadeEjb public TravelEntryFacadeEjb() { } + @Override + public AbstractCoreAdoService getEntityService() { + return travelEntryService; + } + + public static TravelEntryReferenceDto toReferenceDto(TravelEntry entity) { + + if (entity == null) { + return null; + } + return new TravelEntryReferenceDto( + entity.getUuid(), + entity.getExternalId(), + entity.getPerson().getFirstName(), + entity.getPerson().getLastName()); + } + @Inject public TravelEntryFacadeEjb(TravelEntryService service, UserService userService) { super(TravelEntry.class, TravelEntryDto.class, service, userService); @@ -83,13 +102,6 @@ public boolean isDeleted(String travelEntryUuid) { return service.isDeleted(travelEntryUuid); } - @Override - public void archiveOrDearchiveTravelEntry(String travelEntryUuid, boolean archive) { - TravelEntry travelEntry = service.getByUuid(travelEntryUuid); - travelEntry.setArchived(archive); - service.ensurePersisted(travelEntry); - } - @Override public Boolean isTravelEntryEditAllowed(String travelEntryUuid) { TravelEntry travelEntry = service.getByUuid(travelEntryUuid); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java index 98a9ef11750..25e4d0a3b12 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java @@ -7,13 +7,18 @@ import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.From; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.JoinType; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import de.symeda.sormas.api.utils.DateHelper; +import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.common.AbstractCoreAdoService; +import de.symeda.sormas.backend.common.ChangeDateBuilder; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.contact.Contact; +import de.symeda.sormas.backend.person.Person; import de.symeda.sormas.backend.travelentry.TravelEntry; import de.symeda.sormas.backend.travelentry.TravelEntryJurisdictionPredicateValidator; import de.symeda.sormas.backend.travelentry.TravelEntryQueryContext; @@ -87,4 +92,20 @@ public List getAllActiveAfter(Date date) { public List getAllAfter(Date date, Integer batchSize, String lastSynchronizedUuid) { return getAllActiveAfter(date); } + + @Override + protected > T addChangeDates( + T builder, + From travelEntryFrom, + boolean includeExtendedChangeDateFilters) { + + builder = super.addChangeDates(builder, travelEntryFrom, includeExtendedChangeDateFilters); + + if (includeExtendedChangeDateFilters) { + Join resultingCase = travelEntryFrom.join(TravelEntry.RESULTING_CASE, JoinType.LEFT); + builder = builder.add(resultingCase); + } + + return builder; + } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/TravelEntryService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/TravelEntryService.java index e5b0e434c86..d33f9bbc91d 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/TravelEntryService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/TravelEntryService.java @@ -18,9 +18,6 @@ import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; -import de.symeda.sormas.backend.event.Event; -import de.symeda.sormas.backend.event.EventQueryContext; -import de.symeda.sormas.backend.user.User; import org.apache.commons.collections4.CollectionUtils; import de.symeda.sormas.api.EntityRelevanceStatus; @@ -30,7 +27,6 @@ import de.symeda.sormas.api.travelentry.TravelEntryReferenceDto; import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.utils.DataHelper; -import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.api.utils.SortProperty; import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.common.AbstractDomainObject; @@ -45,6 +41,7 @@ import de.symeda.sormas.backend.travelentry.TravelEntryJoins; import de.symeda.sormas.backend.travelentry.TravelEntryQueryContext; import de.symeda.sormas.backend.travelentry.transformers.TravelEntryIndexDtoResultTransformer; +import de.symeda.sormas.backend.user.User; import de.symeda.sormas.backend.util.JurisdictionHelper; @Stateless diff --git a/sormas-backend/src/main/resources/sql/sormas_schema.sql b/sormas-backend/src/main/resources/sql/sormas_schema.sql index 4658f5172b0..66a89ae4dd6 100644 --- a/sormas-backend/src/main/resources/sql/sormas_schema.sql +++ b/sormas-backend/src/main/resources/sql/sormas_schema.sql @@ -9991,4 +9991,49 @@ ALTER TABLE testreport_history ADD COLUMN testpcrtestspecification varchar(255); INSERT INTO schema_version (version_number, comment) VALUES (443, 'Map variant specific Nucleic acid detection methods #5285'); +-- 2022-01-31 CoreAdo: Introduce "end of processing date" #7247 +ALTER TABLE cases ADD COLUMN endofprocessingdate timestamp without time zone; +ALTER TABLE cases ADD COLUMN archiveundonereason character varying(512); + +ALTER TABLE cases_history ADD COLUMN endofprocessingdate timestamp without time zone; +ALTER TABLE cases_history ADD COLUMN archiveundonereason character varying(512); + +ALTER TABLE contact ADD COLUMN endofprocessingdate timestamp without time zone; +ALTER TABLE contact ADD COLUMN archiveundonereason character varying(512); + +ALTER TABLE contact_history ADD COLUMN endofprocessingdate timestamp without time zone; +ALTER TABLE contact_history ADD COLUMN archiveundonereason character varying(512); + +ALTER TABLE events ADD COLUMN endofprocessingdate timestamp without time zone; +ALTER TABLE events ADD COLUMN archiveundonereason character varying(512); + +ALTER TABLE events_history ADD COLUMN endofprocessingdate timestamp without time zone; +ALTER TABLE events_history ADD COLUMN archiveundonereason character varying(512); + +ALTER TABLE eventparticipant ADD COLUMN endofprocessingdate timestamp without time zone; +ALTER TABLE eventparticipant ADD COLUMN archiveundonereason character varying(512); + +ALTER TABLE eventparticipant_history ADD COLUMN endofprocessingdate timestamp without time zone; +ALTER TABLE eventparticipant_history ADD COLUMN archiveundonereason character varying(512); + +ALTER TABLE immunization ADD COLUMN endofprocessingdate timestamp without time zone; +ALTER TABLE immunization ADD COLUMN archiveundonereason character varying(512); + +ALTER TABLE immunization_history ADD COLUMN endofprocessingdate timestamp without time zone; +ALTER TABLE immunization_history ADD COLUMN archiveundonereason character varying(512); + +ALTER TABLE travelentry ADD COLUMN endofprocessingdate timestamp without time zone; +ALTER TABLE travelentry ADD COLUMN archiveundonereason character varying(512); + +ALTER TABLE travelentry_history ADD COLUMN endofprocessingdate timestamp without time zone; +ALTER TABLE travelentry_history ADD COLUMN archiveundonereason character varying(512); + +ALTER TABLE campaigns ADD COLUMN endofprocessingdate timestamp without time zone; +ALTER TABLE campaigns ADD COLUMN archiveundonereason character varying(512); + +ALTER TABLE campaigns_history ADD COLUMN endofprocessingdate timestamp without time zone; +ALTER TABLE campaigns_history ADD COLUMN archiveundonereason character varying(512); + +INSERT INTO schema_version (version_number, comment) VALUES (444, 'CoreAdo: Introduce "end of processing date" #7247'); + -- *** Insert new sql commands BEFORE this line. Remember to always consider _history tables. *** diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java index b04bb7fd19d..c8df49d786a 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java @@ -1081,7 +1081,7 @@ public void testArchiveAndDearchiveCase() { assertEquals(1, getCaseFacade().getAllActiveCasesAfter(null).size()); assertEquals(1, getCaseFacade().getAllActiveUuids().size()); - getCaseFacade().archive(caze.getUuid()); + getCaseFacade().archiveCoreEntities(Collections.singletonList(caze.getUuid()), null); // getAllActiveCases and getAllUuids should return length 0 assertEquals(0, getCaseFacade().getAllActiveCasesAfter(null).size()); @@ -1090,7 +1090,7 @@ public void testArchiveAndDearchiveCase() { // getArchivedUuidsSince should return length 1 assertEquals(1, getCaseFacade().getArchivedUuidsSince(testStartDate).size()); - getCaseFacade().dearchive(caze.getUuid()); + getCaseFacade().dearchiveCoreEntities(Collections.singletonList(caze.getUuid()), null); // getAllActiveCases and getAllUuids should return length 1 assertEquals(1, getCaseFacade().getAllActiveCasesAfter(null).size()); @@ -1609,7 +1609,7 @@ public void testArchiveAllArchivableCases() { // One archived case CaseDataDto case1 = creator.createCase(user, person, rdcf); CaseFacadeEjbLocal cut = getBean(CaseFacadeEjbLocal.class); - cut.archive(case1.getUuid()); + cut.archiveCoreEntities(Collections.singletonList(case1.getUuid()), null); // One other case CaseDataDto case2 = creator.createCase(user, person, rdcf); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java index e862e10a1ce..ac2f38e4382 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java @@ -1285,7 +1285,7 @@ public void testArchiveOrDearchiveContact() { assertEquals(1, getVisitFacade().getAllActiveVisitsAfter(null).size()); assertEquals(1, getVisitFacade().getAllActiveUuids().size()); - getCaseFacade().archive(caze.getUuid()); + getCaseFacade().archiveCoreEntities(Collections.singletonList(caze.getUuid()), null); // getAllActiveContacts and getAllUuids should return length 0 assertEquals(0, getContactFacade().getAllAfter(null).size()); @@ -1293,7 +1293,7 @@ public void testArchiveOrDearchiveContact() { assertEquals(0, getVisitFacade().getAllActiveVisitsAfter(null).size()); assertEquals(0, getVisitFacade().getAllActiveUuids().size()); - getCaseFacade().dearchive(caze.getUuid()); + getCaseFacade().dearchiveCoreEntities(Collections.singletonList(caze.getUuid()), null); // getAllActiveContacts and getAllUuids should return length 1 assertEquals(1, getContactFacade().getAllAfter(null).size()); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbTest.java index dcd538e45f5..6a17983a4c6 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbTest.java @@ -257,7 +257,7 @@ public void testArchiveOrDearchiveEvent() { assertEquals(1, getEventParticipantFacade().getAllActiveEventParticipantsAfter(null).size()); assertEquals(1, getEventParticipantFacade().getAllActiveUuids().size()); - getEventFacade().archive(event.getUuid()); + getEventFacade().archiveCoreEntities(Collections.singletonList(event.getUuid()), null); // getAllActiveEvents/getAllActiveEventParticipants and getAllUuids should return length 0 assertEquals(0, getEventFacade().getAllAfter(null).size()); @@ -268,7 +268,7 @@ public void testArchiveOrDearchiveEvent() { // getArchivedUuidsSince should return length 1 assertEquals(1, getEventFacade().getArchivedUuidsSince(testStartDate).size()); - getEventFacade().dearchive(event.getUuid()); + getEventFacade().dearchiveCoreEntities(Collections.singletonList(event.getUuid()), null); // getAllActiveEvents/getAllActiveEventParticipants and getAllUuids should return length 1 assertEquals(1, getEventFacade().getAllAfter(null).size()); @@ -304,7 +304,7 @@ public void testArchiveAllArchivableEvents() { Disease.ANTHRAX, rdcf.district); EventFacadeEjbLocal cut = getBean(EventFacadeEjbLocal.class); - cut.archive(event1.getUuid()); + cut.archiveCoreEntities(Collections.singletonList(event1.getUuid()), null); // One other event EventDto event2 = creator.createEvent( diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java index 5dcfa734210..91c7b38a946 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java @@ -313,8 +313,8 @@ public void testGetMatchingNameDtos() { EventDto inactiveEvent = creator.createEvent(user.toReference()); creator.createEventParticipant(inactiveEvent.toReference(), person7, user.toReference()); - getCaseFacade().archive(inactiveCase.getUuid()); - getEventFacade().archive(inactiveEvent.getUuid()); + getCaseFacade().archiveCoreEntities(Collections.singletonList(inactiveCase.getUuid()), null); + getEventFacade().archiveCoreEntities(Collections.singletonList(inactiveEvent.getUuid()), null); // Only persons that have active case, contact or event participant associations should be retrieved List relevantNameUuids = @@ -325,8 +325,8 @@ public void testGetMatchingNameDtos() { containsInAnyOrder(person1.getUuid(), person2.getUuid(), person3.getUuid(), person5.getUuid(), person6.getUuid(), person7.getUuid())); creator.createCase(user.toReference(), person4.toReference(), rdcf); - getCaseFacade().dearchive(inactiveCase.getUuid()); - getEventFacade().archive(inactiveEvent.getUuid()); + getCaseFacade().dearchiveCoreEntities(Collections.singletonList(inactiveCase.getUuid()), null); + getEventFacade().dearchiveCoreEntities(Collections.singletonList(inactiveEvent.getUuid()), null); PersonSimilarityCriteria criteria = new PersonSimilarityCriteria().sex(Sex.MALE).birthdateYYYY(1980).birthdateMM(1).birthdateDD(1); List matchingUuids = diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/SampleFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/SampleFacadeEjbTest.java index ed95bbad989..64c9723dc06 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/SampleFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/SampleFacadeEjbTest.java @@ -31,6 +31,7 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; @@ -507,7 +508,7 @@ public void testArchivedSampleNotGettingTransfered() { assertEquals(1, getSampleTestFacade().getAllActivePathogenTestsAfter(null).size()); assertEquals(1, getSampleTestFacade().getAllActiveUuids().size()); - getCaseFacade().archive(caze.getUuid()); + getCaseFacade().archiveCoreEntities(Collections.singletonList(caze.getUuid()), null); // getAllActiveSamples/getAllActiveSampleTests and getAllUuids should return length 0 assertEquals(0, getSampleFacade().getAllActiveSamplesAfter(null).size()); @@ -515,7 +516,7 @@ public void testArchivedSampleNotGettingTransfered() { assertEquals(0, getSampleTestFacade().getAllActivePathogenTestsAfter(null).size()); assertEquals(0, getSampleTestFacade().getAllActiveUuids().size()); - getCaseFacade().dearchive(caze.getUuid()); + getCaseFacade().dearchiveCoreEntities(Collections.singletonList(caze.getUuid()), null); // getAllActiveSamples/getAllActiveSampleTests and getAllUuids should return length 1 assertEquals(1, getSampleFacade().getAllActiveSamplesAfter(null).size()); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/task/TaskFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/task/TaskFacadeEjbTest.java index 8e2fd0ec4fc..082d0cbffab 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/task/TaskFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/task/TaskFacadeEjbTest.java @@ -173,15 +173,15 @@ public void testArchivedTaskNotGettingTransfered() { assertEquals(6, getTaskFacade().getAllActiveTasksAfter(null).size()); assertEquals(6, getTaskFacade().getAllActiveUuids().size()); - getCaseFacade().archive(caze.getUuid()); - getEventFacade().archive(event.getUuid()); + getCaseFacade().archiveCoreEntities(Collections.singletonList(caze.getUuid()), null); + getEventFacade().archiveCoreEntities(Collections.singletonList(event.getUuid()), null); // getAllActiveTasks and getAllUuids should return length 1 assertEquals(1, getTaskFacade().getAllActiveTasksAfter(null).size()); assertEquals(1, getTaskFacade().getAllActiveUuids().size()); - getCaseFacade().dearchive(caze.getUuid()); - getEventFacade().dearchive(event.getUuid()); + getCaseFacade().dearchiveCoreEntities(Collections.singletonList(caze.getUuid()), null); + getEventFacade().dearchiveCoreEntities(Collections.singletonList(event.getUuid()), null); // getAllActiveTasks and getAllUuids should return length 5 + 1 (contact investigation) assertEquals(6, getTaskFacade().getAllActiveTasksAfter(null).size()); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/ControllerProvider.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/ControllerProvider.java index 7a794e4d2c9..0088078f6a4 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/ControllerProvider.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/ControllerProvider.java @@ -44,6 +44,7 @@ import de.symeda.sormas.ui.therapy.TherapyController; import de.symeda.sormas.ui.travelentry.TravelEntryController; import de.symeda.sormas.ui.user.UserController; +import de.symeda.sormas.ui.utils.ArchiveController; import de.symeda.sormas.ui.utils.BaseControllerProvider; import de.symeda.sormas.ui.vaccination.VaccinationController; import de.symeda.sormas.ui.visit.VisitController; @@ -79,6 +80,7 @@ public class ControllerProvider extends BaseControllerProvider { private final TravelEntryController travelEntryController; private final ImmunizationController immunizationController; private final VaccinationController vaccinationController; + private final ArchiveController archiveController; public ControllerProvider() { super(); @@ -112,6 +114,7 @@ public ControllerProvider() { travelEntryController = new TravelEntryController(); immunizationController = new ImmunizationController(); vaccinationController = new VaccinationController(); + archiveController = new ArchiveController(); } protected static ControllerProvider get() { @@ -233,4 +236,8 @@ public static ImmunizationController getImmunizationController() { public static VaccinationController getVaccinationController() { return get().vaccinationController; } + + public static ArchiveController getArchiveController() { + return get().archiveController; + } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/campaign/CampaignController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/campaign/CampaignController.java index 7f8c9281aec..4e3841ab589 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/campaign/CampaignController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/campaign/CampaignController.java @@ -20,7 +20,6 @@ import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; -import com.vaadin.ui.Label; import com.vaadin.ui.Notification; import com.vaadin.ui.Notification.Type; import com.vaadin.ui.UI; @@ -38,6 +37,7 @@ import de.symeda.sormas.api.i18n.Validations; import de.symeda.sormas.api.user.UserDto; import de.symeda.sormas.api.user.UserRight; +import de.symeda.sormas.ui.ControllerProvider; import de.symeda.sormas.ui.SormasUI; import de.symeda.sormas.ui.UserProvider; import de.symeda.sormas.ui.campaign.campaigndata.CampaignDataView; @@ -73,14 +73,7 @@ public void createOrEditCampaign(String uuid) { // Initialize 'Archive' button if (UserProvider.getCurrent().hasUserRight(UserRight.CAMPAIGN_ARCHIVE)) { - boolean archived = FacadeProvider.getCampaignFacade().isArchived(campaign.getUuid()); - Button archiveCampaignButton = ButtonHelper.createButton(archived ? Captions.actionDearchive : Captions.actionArchive, e -> { - campaignComponent.commit(); - archiveOrDearchiveCampaign(campaign.getUuid(), !archived); - }, ValoTheme.BUTTON_LINK); - - campaignComponent.getButtonsPanel().addComponentAsFirst(archiveCampaignButton); - campaignComponent.getButtonsPanel().setComponentAlignment(archiveCampaignButton, Alignment.BOTTOM_LEFT); + createArchiveButton(campaignComponent, campaign); } heading = I18nProperties.getString(Strings.headingEditCampaign); } else { @@ -93,6 +86,38 @@ public void createOrEditCampaign(String uuid) { VaadinUiUtil.showModalPopupWindow(campaignComponent, heading); } + private static void createArchiveButton(CommitDiscardWrapperComponent campaignComponent, CampaignDto campaign) { + boolean archived = FacadeProvider.getCampaignFacade().isArchived(campaign.getUuid()); + Button archiveCampaignButton = ButtonHelper.createButton(archived ? Captions.actionDearchive : Captions.actionArchive, e -> { + campaignComponent.commit(); + + if (archived) { + ControllerProvider.getArchiveController() + .dearchiveEntity( + campaign, + FacadeProvider.getCampaignFacade(), + Strings.headingDearchiveCampaign, + Strings.confirmationDearchiveCampaign, + Strings.entityCampaign, + Strings.messageCampaignDearchived, + CampaignView.VIEW_NAME); + } else { + ControllerProvider.getArchiveController() + .archiveEntity( + campaign, + FacadeProvider.getCampaignFacade(), + Strings.headingArchiveCampaign, + Strings.confirmationArchiveCampaign, + Strings.entityCampaign, + Strings.messageCampaignArchived, + CampaignView.VIEW_NAME); + } + }, ValoTheme.BUTTON_LINK); + + campaignComponent.getButtonsPanel().addComponentAsFirst(archiveCampaignButton); + campaignComponent.getButtonsPanel().setComponentAlignment(archiveCampaignButton, Alignment.BOTTOM_LEFT); + } + public void createCampaignDataForm(CampaignReferenceDto campaign, CampaignFormMetaReferenceDto campaignForm) { Window window = VaadinUiUtil.createPopupWindow(); @@ -109,47 +134,6 @@ public void createCampaignDataForm(CampaignReferenceDto campaign, CampaignFormMe UI.getCurrent().addWindow(window); } - private void archiveOrDearchiveCampaign(String campaignUuid, boolean archive) { - - if (archive) { - Label contentLabel = new Label( - String.format( - I18nProperties.getString(Strings.confirmationArchiveCampaign), - I18nProperties.getString(Strings.entityCampaign).toLowerCase(), - I18nProperties.getString(Strings.entityCampaign).toLowerCase())); - VaadinUiUtil.showConfirmationPopup( - I18nProperties.getString(Strings.headingArchiveCampaign), - contentLabel, - I18nProperties.getString(Strings.yes), - I18nProperties.getString(Strings.no), - 640, - e -> { - if (e) { - FacadeProvider.getCampaignFacade().archive(campaignUuid); - SormasUI.refreshView(); - } - }); - } else { - Label contentLabel = new Label( - String.format( - I18nProperties.getString(Strings.confirmationDearchiveCampaign), - I18nProperties.getString(Strings.entityCampaign).toLowerCase(), - I18nProperties.getString(Strings.entityCampaign).toLowerCase())); - VaadinUiUtil.showConfirmationPopup( - I18nProperties.getString(Strings.headingDearchiveCampaign), - contentLabel, - I18nProperties.getString(Strings.yes), - I18nProperties.getString(Strings.no), - 640, - e -> { - if (e) { - FacadeProvider.getCampaignFacade().dearchive(campaignUuid); - SormasUI.refreshView(); - } - }); - } - } - public CommitDiscardWrapperComponent getCampaignComponent(CampaignDto campaignDto, Runnable callback) { CampaignEditForm campaignEditForm = new CampaignEditForm(campaignDto); @@ -183,15 +167,8 @@ public void discard() { // Initialize 'Archive' button if (UserProvider.getCurrent().hasUserRight(UserRight.CAMPAIGN_ARCHIVE) && !isCreate) { - final String campaignUuid = campaignDto.getUuid(); - boolean archived = FacadeProvider.getCampaignFacade().isArchived(campaignUuid); - Button archiveCampaignButton = ButtonHelper.createButton(archived ? Captions.actionDearchive : Captions.actionArchive, e -> { - campaignComponent.commit(); - archiveOrDearchiveCampaign(campaignUuid, !archived); - }, ValoTheme.BUTTON_LINK); - - campaignComponent.getButtonsPanel().addComponentAsFirst(archiveCampaignButton); - campaignComponent.getButtonsPanel().setComponentAlignment(archiveCampaignButton, Alignment.BOTTOM_LEFT); + final CampaignDto campaign = campaignDto; + createArchiveButton(campaignComponent, campaign); } campaignComponent.addCommitListener(() -> { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java index 240ad1a0981..35cebc7805a 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java @@ -17,7 +17,6 @@ *******************************************************************************/ package de.symeda.sormas.ui.caze; -import de.symeda.sormas.ui.utils.CssStyles; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -130,6 +129,7 @@ import de.symeda.sormas.ui.utils.AbstractView; import de.symeda.sormas.ui.utils.ButtonHelper; import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent; +import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.DateHelper8; import de.symeda.sormas.ui.utils.DetailSubComponentWrapper; import de.symeda.sormas.ui.utils.NullableOptionGroup; @@ -1120,8 +1120,32 @@ private void appendSpecialCommands(CaseDataDto caze, CommitDiscardWrapperCompone if (UserProvider.getCurrent().hasUserRight(UserRight.CASE_ARCHIVE)) { boolean archived = FacadeProvider.getCaseFacade().isArchived(caze.getUuid()); Button archiveCaseButton = ButtonHelper.createButton(archived ? Captions.actionDearchive : Captions.actionArchive, e -> { - editView.commit(); - archiveOrDearchiveCase(caze.getUuid(), !archived); + if (editView.isModified()) { + editView.commit(); + } + + if (archived) { + ControllerProvider.getArchiveController() + .dearchiveEntity( + caze, + FacadeProvider.getCaseFacade(), + Strings.headingDearchiveCase, + Strings.confirmationDearchiveCase, + Strings.entityCase, + Strings.messageCaseDearchived, + CaseDataView.VIEW_NAME); + } else { + ControllerProvider.getArchiveController() + .archiveEntity( + caze, + FacadeProvider.getCaseFacade(), + Strings.headingArchiveCase, + Strings.confirmationArchiveCase, + Strings.entityCase, + Strings.messageCaseArchived, + CaseDataView.VIEW_NAME); + } + }, ValoTheme.BUTTON_LINK); editView.getButtonsPanel().addComponentAsFirst(archiveCaseButton); @@ -1140,6 +1164,39 @@ private void appendSpecialCommands(CaseDataDto caze, CommitDiscardWrapperCompone } } + public void archiveAllSelectedItems(Collection selectedRows, Runnable callback) { + + List caseUuids = selectedRows.stream().map(CaseIndexDto::getUuid).collect(Collectors.toList()); + + ControllerProvider.getArchiveController() + .archiveSelectedItems( + caseUuids, + FacadeProvider.getCaseFacade(), + Strings.headingNoCasesSelected, + Strings.confirmationArchiveCases, + Strings.headingCasesArchived, + Strings.messageCasesArchived, + callback); + } + + public void dearchiveAllSelectedItems(Collection selectedRows, Runnable callback) { + + List caseUuids = selectedRows.stream().map(CaseIndexDto::getUuid).collect(Collectors.toList()); + + ControllerProvider.getArchiveController() + .dearchiveSelectedItems( + caseUuids, + FacadeProvider.getCaseFacade(), + Strings.headingNoCasesSelected, + Strings.messageNoCasesSelected, + Strings.confirmationDearchiveCases, + Strings.entityCase, + Strings.headingConfirmDearchiving, + Strings.headingCasesDearchived, + Strings.messageCasesDearchived, + callback); + } + public CommitDiscardWrapperComponent getHospitalizationComponent(final String caseUuid, ViewMode viewMode) { CaseDataDto caze = findCase(caseUuid); @@ -1393,53 +1450,6 @@ public void referFromPointOfEntry(CaseDataDto caze) { view.getButtonsPanel().replaceComponent(view.getDiscardButton(), btnCancel); } - private void archiveOrDearchiveCase(String caseUuid, boolean archive) { - - if (archive) { - Label contentLabel = new Label( - String.format( - I18nProperties.getString(Strings.confirmationArchiveCase), - I18nProperties.getString(Strings.entityCase).toLowerCase(), - I18nProperties.getString(Strings.entityCase).toLowerCase())); - VaadinUiUtil.showConfirmationPopup( - I18nProperties.getString(Strings.headingArchiveCase), - contentLabel, - I18nProperties.getString(Strings.yes), - I18nProperties.getString(Strings.no), - 640, - e -> { - if (e.booleanValue() == true) { - FacadeProvider.getCaseFacade().archive(caseUuid); - Notification.show( - String.format(I18nProperties.getString(Strings.messageCaseArchived), I18nProperties.getString(Strings.entityCase)), - Type.ASSISTIVE_NOTIFICATION); - navigateToView(CaseDataView.VIEW_NAME, caseUuid, null); - } - }); - } else { - Label contentLabel = new Label( - String.format( - I18nProperties.getString(Strings.confirmationDearchiveCase), - I18nProperties.getString(Strings.entityCase).toLowerCase(), - I18nProperties.getString(Strings.entityCase).toLowerCase())); - VaadinUiUtil.showConfirmationPopup( - I18nProperties.getString(Strings.headingDearchiveCase), - contentLabel, - I18nProperties.getString(Strings.yes), - I18nProperties.getString(Strings.no), - 640, - e -> { - if (e.booleanValue()) { - FacadeProvider.getCaseFacade().dearchive(caseUuid); - Notification.show( - String.format(I18nProperties.getString(Strings.messageCaseDearchived), I18nProperties.getString(Strings.entityCase)), - Type.ASSISTIVE_NOTIFICATION); - navigateToView(CaseDataView.VIEW_NAME, caseUuid, null); - } - }); - } - } - public void openClassificationRulesPopup(DiseaseClassificationCriteriaDto diseaseCriteria) { VerticalLayout classificationRulesLayout = new VerticalLayout(); @@ -1581,66 +1591,6 @@ public void sendSmsToAllSelectedItems(Collection selecte } } - public void archiveAllSelectedItems(Collection selectedRows, Runnable callback) { - - if (selectedRows.size() == 0) { - new Notification( - I18nProperties.getString(Strings.headingNoCasesSelected), - I18nProperties.getString(Strings.messageNoCasesSelected), - Type.WARNING_MESSAGE, - false).show(Page.getCurrent()); - } else { - VaadinUiUtil.showConfirmationPopup( - I18nProperties.getString(Strings.headingConfirmArchiving), - new Label(String.format(I18nProperties.getString(Strings.confirmationArchiveCases), selectedRows.size())), - I18nProperties.getString(Strings.yes), - I18nProperties.getString(Strings.no), - null, - e -> { - if (e.booleanValue() == true) { - List caseUuids = selectedRows.stream().map(r -> r.getUuid()).collect(Collectors.toList()); - FacadeProvider.getCaseFacade().updateArchived(caseUuids, true); - callback.run(); - new Notification( - I18nProperties.getString(Strings.headingCasesArchived), - I18nProperties.getString(Strings.messageCasesArchived), - Type.HUMANIZED_MESSAGE, - false).show(Page.getCurrent()); - } - }); - } - } - - public void dearchiveAllSelectedItems(Collection selectedRows, Runnable callback) { - - if (selectedRows.size() == 0) { - new Notification( - I18nProperties.getString(Strings.headingNoCasesSelected), - I18nProperties.getString(Strings.messageNoCasesSelected), - Type.WARNING_MESSAGE, - false).show(Page.getCurrent()); - } else { - VaadinUiUtil.showConfirmationPopup( - I18nProperties.getString(Strings.headingConfirmDearchiving), - new Label(String.format(I18nProperties.getString(Strings.confirmationDearchiveCases), selectedRows.size())), - I18nProperties.getString(Strings.yes), - I18nProperties.getString(Strings.no), - null, - e -> { - if (e.booleanValue() == true) { - List caseUuids = selectedRows.stream().map(r -> r.getUuid()).collect(Collectors.toList()); - FacadeProvider.getCaseFacade().updateArchived(caseUuids, false); - callback.run(); - new Notification( - I18nProperties.getString(Strings.headingCasesDearchived), - I18nProperties.getString(Strings.messageCasesDearchived), - Type.HUMANIZED_MESSAGE, - false).show(Page.getCurrent()); - } - }); - } - } - public void openLineListingWindow() { Window window = new Window(I18nProperties.getString(Strings.headingLineListing)); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CasesView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CasesView.java index 4147359b0ea..af5ffed66cd 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CasesView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CasesView.java @@ -680,12 +680,12 @@ public HorizontalLayout createStatusFilterBar() { } menuBarItems.add(new MenuBarHelper.MenuBarItem(I18nProperties.getCaption(Captions.actionArchive), VaadinIcons.ARCHIVE, mi -> { grid.bulkActionHandler( - items -> ControllerProvider.getCaseController().archiveAllSelectedItems(items, () -> navigateTo(criteria)), + items -> ControllerProvider.getCaseController().archiveAllSelectedItems(items, () -> navigateTo(criteria, true)), true); }, hasBulkOperationsRight && EntityRelevanceStatus.ACTIVE.equals(criteria.getRelevanceStatus()))); menuBarItems.add(new MenuBarHelper.MenuBarItem(I18nProperties.getCaption(Captions.actionDearchive), VaadinIcons.ARCHIVE, mi -> { grid.bulkActionHandler( - items -> ControllerProvider.getCaseController().dearchiveAllSelectedItems(items, () -> navigateTo(criteria)), + items -> ControllerProvider.getCaseController().dearchiveAllSelectedItems(items, () -> navigateTo(criteria, true)), true); }, hasBulkOperationsRight && EntityRelevanceStatus.ARCHIVED.equals(criteria.getRelevanceStatus()))); menuBarItems.add(new MenuBarHelper.MenuBarItem(I18nProperties.getCaption(Captions.sormasToSormasShare), VaadinIcons.SHARE, mi -> { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactController.java index c06ce50a971..2ca0b894d3c 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactController.java @@ -24,6 +24,11 @@ import java.util.function.Supplier; import java.util.stream.Collectors; +import com.vaadin.ui.Alignment; +import com.vaadin.ui.Button; +import com.vaadin.ui.themes.ValoTheme; +import de.symeda.sormas.ui.immunization.ImmunizationDataView; +import de.symeda.sormas.ui.utils.ButtonHelper; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -594,6 +599,40 @@ public CommitDiscardWrapperComponent getContactDataEditComponen }, I18nProperties.getString(Strings.entityContact)); } + // Initialize 'Archive' button + if (UserProvider.getCurrent().hasUserRight(UserRight.CONTACT_ARCHIVE)) { + boolean archived = FacadeProvider.getContactFacade().isArchived(contact.getUuid()); + Button archiveButton = ButtonHelper.createButton(archived ? Captions.actionDearchive : Captions.actionArchive, e -> { + editComponent.commit(); + + if (archived) { + ControllerProvider.getArchiveController() + .dearchiveEntity( + contact, + FacadeProvider.getContactFacade(), + Strings.headingDearchiveContact, + Strings.confirmationDearchiveContact, + Strings.entityContact, + Strings.messageContactDearchived, + ContactDataView.VIEW_NAME); + } else { + ControllerProvider.getArchiveController() + .archiveEntity( + contact, + FacadeProvider.getContactFacade(), + Strings.headingArchiveContact, + Strings.confirmationArchiveContact, + Strings.entityContact, + Strings.messageContactArchived, + ContactDataView.VIEW_NAME); + } + + }, ValoTheme.BUTTON_LINK); + + editComponent.getButtonsPanel().addComponentAsFirst(archiveButton); + editComponent.getButtonsPanel().setComponentAlignment(archiveButton, Alignment.BOTTOM_LEFT); + } + return editComponent; } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventController.java index 8e6e646d412..29c11597bc8 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventController.java @@ -17,9 +17,6 @@ *******************************************************************************/ package de.symeda.sormas.ui.events; -import com.vaadin.ui.TextArea; -import com.vaadin.ui.VerticalLayout; -import de.symeda.sormas.ui.utils.CssStyles; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -44,7 +41,9 @@ import com.vaadin.ui.Label; import com.vaadin.ui.Notification; import com.vaadin.ui.Notification.Type; +import com.vaadin.ui.TextArea; import com.vaadin.ui.UI; +import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window; import com.vaadin.ui.themes.ValoTheme; @@ -86,6 +85,7 @@ import de.symeda.sormas.ui.utils.ButtonHelper; import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent; import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent.CommitListener; +import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.DateFormatHelper; import de.symeda.sormas.ui.utils.NotificationHelper; import de.symeda.sormas.ui.utils.VaadinUiUtil; @@ -807,7 +807,29 @@ public CommitDiscardWrapperComponent getEventDataEditComponent(fi boolean archived = FacadeProvider.getEventFacade().isArchived(eventUuid); Button archiveEventButton = ButtonHelper.createButton(archived ? Captions.actionDearchive : Captions.actionArchive, e -> { editView.commit(); - archiveOrDearchiveEvent(eventUuid, !archived); + + if (archived) { + ControllerProvider.getArchiveController() + .dearchiveEntity( + event, + FacadeProvider.getEventFacade(), + Strings.headingDearchiveEvent, + Strings.confirmationDearchiveEvent, + Strings.entityEvent, + Strings.messageEventDearchived, + EventDataView.VIEW_NAME); + } else { + ControllerProvider.getArchiveController() + .archiveEntity( + event, + FacadeProvider.getEventFacade(), + Strings.headingArchiveEvent, + Strings.confirmationArchiveEvent, + Strings.entityEvent, + Strings.messageEventArchived, + EventDataView.VIEW_NAME); + } + }, ValoTheme.BUTTON_LINK); editView.getButtonsPanel().addComponentAsFirst(archiveEventButton); @@ -890,53 +912,6 @@ public EventDto createNewEvent(Disease disease) { return event; } - private void archiveOrDearchiveEvent(String eventUuid, boolean archive) { - - if (archive) { - Label contentLabel = new Label( - String.format( - I18nProperties.getString(Strings.confirmationArchiveEvent), - I18nProperties.getString(Strings.entityEvent).toLowerCase(), - I18nProperties.getString(Strings.entityEvent).toLowerCase())); - VaadinUiUtil.showConfirmationPopup( - I18nProperties.getString(Strings.headingArchiveEvent), - contentLabel, - I18nProperties.getString(Strings.yes), - I18nProperties.getString(Strings.no), - 640, - e -> { - if (e.booleanValue() == true) { - FacadeProvider.getEventFacade().archive(eventUuid); - Notification.show( - String.format(I18nProperties.getString(Strings.messageEventArchived), I18nProperties.getString(Strings.entityEvent)), - Type.ASSISTIVE_NOTIFICATION); - navigateToData(eventUuid); - } - }); - } else { - Label contentLabel = new Label( - String.format( - I18nProperties.getString(Strings.confirmationDearchiveEvent), - I18nProperties.getString(Strings.entityEvent).toLowerCase(), - I18nProperties.getString(Strings.entityEvent).toLowerCase())); - VaadinUiUtil.showConfirmationPopup( - I18nProperties.getString(Strings.headingDearchiveEvent), - contentLabel, - I18nProperties.getString(Strings.yes), - I18nProperties.getString(Strings.no), - 640, - e -> { - if (e.booleanValue()) { - FacadeProvider.getEventFacade().dearchive(eventUuid); - Notification.show( - String.format(I18nProperties.getString(Strings.messageEventDearchived), I18nProperties.getString(Strings.entityEvent)), - Type.ASSISTIVE_NOTIFICATION); - navigateToData(eventUuid); - } - }); - } - } - public void deleteAllSelectedItems(Collection selectedRows, Runnable callback) { if (selectedRows.size() == 0) { @@ -1023,65 +998,34 @@ private Boolean existEventParticipantsLinkedToEvent(EventDto event) { } public void archiveAllSelectedItems(Collection selectedRows, Runnable callback) { - - if (selectedRows.size() == 0) { - new Notification( - I18nProperties.getString(Strings.headingNoEventsSelected), - I18nProperties.getString(Strings.messageNoEventsSelected), - Type.WARNING_MESSAGE, - false).show(Page.getCurrent()); - } else { - VaadinUiUtil.showConfirmationPopup( - I18nProperties.getString(Strings.headingConfirmArchiving), - new Label(String.format(I18nProperties.getString(Strings.confirmationArchiveEvents), selectedRows.size())), - I18nProperties.getString(Strings.yes), - I18nProperties.getString(Strings.no), - null, - e -> { - if (e.booleanValue() == true) { - for (EventIndexDto selectedRow : selectedRows) { - FacadeProvider.getEventFacade().archive(selectedRow.getUuid()); - } - callback.run(); - new Notification( - I18nProperties.getString(Strings.headingEventsArchived), - I18nProperties.getString(Strings.messageEventsArchived), - Type.HUMANIZED_MESSAGE, - false).show(Page.getCurrent()); - } - }); - } + List eventUuids = selectedRows.stream().map(EventIndexDto::getUuid).collect(Collectors.toList()); + + ControllerProvider.getArchiveController() + .archiveSelectedItems( + eventUuids, + FacadeProvider.getEventFacade(), + Strings.headingNoEventsSelected, + Strings.confirmationArchiveEvents, + Strings.headingEventsArchived, + Strings.messageEventArchived, + callback); } public void dearchiveAllSelectedItems(Collection selectedRows, Runnable callback) { - - if (selectedRows.size() == 0) { - new Notification( - I18nProperties.getString(Strings.headingNoEventsSelected), - I18nProperties.getString(Strings.messageNoEventsSelected), - Type.WARNING_MESSAGE, - false).show(Page.getCurrent()); - } else { - VaadinUiUtil.showConfirmationPopup( - I18nProperties.getString(Strings.headingConfirmDearchiving), - new Label(String.format(I18nProperties.getString(Strings.confirmationDearchiveEvents), selectedRows.size())), - I18nProperties.getString(Strings.yes), - I18nProperties.getString(Strings.no), - null, - e -> { - if (e.booleanValue() == true) { - for (EventIndexDto selectedRow : selectedRows) { - FacadeProvider.getEventFacade().dearchive(selectedRow.getUuid()); - } - callback.run(); - new Notification( - I18nProperties.getString(Strings.headingEventsDearchived), - I18nProperties.getString(Strings.messageEventsDearchived), - Type.HUMANIZED_MESSAGE, - false).show(Page.getCurrent()); - } - }); - } + List eventUuids = selectedRows.stream().map(EventIndexDto::getUuid).collect(Collectors.toList()); + + ControllerProvider.getArchiveController() + .dearchiveSelectedItems( + eventUuids, + FacadeProvider.getEventFacade(), + Strings.headingNoEventsSelected, + Strings.messageNoEventsSelected, + Strings.confirmationDearchiveEvents, + Strings.entityEvent, + Strings.headingConfirmDearchiving, + Strings.headingEventsDearchived, + Strings.messageEventsDearchived, + callback); } public TitleLayout getEventViewTitleLayout(String uuid) { @@ -1126,28 +1070,29 @@ public void sendAllSelectedToExternalSurveillanceTool(Set selecte List ownershipHandedOverUuids = FacadeProvider.getEventFacade().getEventUuidsWithOwnershipHandedOver(selectedUuids); if (CollectionUtils.isNotEmpty(ownershipHandedOverUuids)) { List uuidsWithoutNotSharable = - selectedUuids.stream().filter(uuid -> !ownershipHandedOverUuids.contains(uuid)).collect(Collectors.toList()); + selectedUuids.stream().filter(uuid -> !ownershipHandedOverUuids.contains(uuid)).collect(Collectors.toList()); TextArea notShareableListComponent = new TextArea("", new ArrayList<>(ownershipHandedOverUuids).toString()); notShareableListComponent.setWidthFull(); notShareableListComponent.setEnabled(false); Label notSharableLabel = new Label( - String.format(I18nProperties.getString(Strings.errorExternalSurveillanceToolEventNotOwned), ownershipHandedOverUuids.size()), - ContentMode.HTML); + String.format(I18nProperties.getString(Strings.errorExternalSurveillanceToolEventNotOwned), ownershipHandedOverUuids.size()), + ContentMode.HTML); notSharableLabel.addStyleName(CssStyles.LABEL_WHITE_SPACE_NORMAL); VaadinUiUtil.showConfirmationPopup( - I18nProperties.getCaption(Captions.ExternalSurveillanceToolGateway_send), - new VerticalLayout( - notSharableLabel, - notShareableListComponent), - String.format(I18nProperties.getCaption(Captions.ExternalSurveillanceToolGateway_excludeAndSend), uuidsWithoutNotSharable.size(), selectedUuids.size()), - I18nProperties.getCaption(Captions.actionCancel), - 800, - (confirmed) -> { - if (confirmed) { - ExternalSurveillanceServiceGateway.sendEventsToExternalSurveillanceTool(selectedUuids, callback, false); - } - }); + I18nProperties.getCaption(Captions.ExternalSurveillanceToolGateway_send), + new VerticalLayout(notSharableLabel, notShareableListComponent), + String.format( + I18nProperties.getCaption(Captions.ExternalSurveillanceToolGateway_excludeAndSend), + uuidsWithoutNotSharable.size(), + selectedUuids.size()), + I18nProperties.getCaption(Captions.actionCancel), + 800, + (confirmed) -> { + if (confirmed) { + ExternalSurveillanceServiceGateway.sendEventsToExternalSurveillanceTool(selectedUuids, callback, false); + } + }); } else { ExternalSurveillanceServiceGateway.sendEventsToExternalSurveillanceTool(selectedUuids, callback, true); } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsController.java index d23fe6b55a6..de4323ad0f5 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsController.java @@ -20,6 +20,12 @@ import java.util.Collection; import java.util.function.Consumer; +import com.vaadin.ui.Alignment; +import com.vaadin.ui.Button; +import com.vaadin.ui.themes.ValoTheme; +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.ui.contact.ContactDataView; +import de.symeda.sormas.ui.utils.ButtonHelper; import org.apache.commons.lang3.StringUtils; import com.vaadin.server.Page; @@ -223,6 +229,41 @@ public CommitDiscardWrapperComponent getEventParticipantDataEditComponent(Str }, I18nProperties.getString(Strings.entityEventParticipant)); } + // Initialize 'Archive' button + if (UserProvider.getCurrent().hasUserRight(UserRight.EVENTPARTICIPANT_ARHIVE)) { + boolean archived = FacadeProvider.getEventParticipantFacade().isArchived(eventParticipant.getUuid()); + Button archiveButton = ButtonHelper.createButton(archived ? Captions.actionDearchive : Captions.actionArchive, e -> { + editComponent.commit(); + + if (archived) { + ControllerProvider.getArchiveController() + .dearchiveEntity( + eventParticipant, + FacadeProvider.getEventParticipantFacade(), + Strings.headingDearchiveEventParticipant, + Strings.confirmationDearchiveEventParticipant, + Strings.entityEventParticipant, + Strings.messageEventParticipantDearchived, + EventParticipantDataView.VIEW_NAME); + } else { + ControllerProvider.getArchiveController() + .archiveEntity( + eventParticipant, + FacadeProvider.getEventParticipantFacade(), + Strings.headingArchiveEventParticipant, + Strings.confirmationArchiveEventParticipant, + Strings.entityEventParticipant, + Strings.messageEventParticipantArchived, + EventParticipantDataView.VIEW_NAME); + } + + }, ValoTheme.BUTTON_LINK); + + editComponent.getButtonsPanel().addComponentAsFirst(archiveButton); + editComponent.getButtonsPanel().setComponentAlignment(archiveButton, Alignment.BOTTOM_LEFT); + } + + return editComponent; } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventsView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventsView.java index 132c46e46d9..2bf3ba30320 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventsView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventsView.java @@ -27,6 +27,7 @@ import java.util.Set; import java.util.stream.Collectors; +import org.hibernate.event.spi.RefreshEvent; import org.vaadin.hene.popupbutton.PopupButton; import com.vaadin.icons.VaadinIcons; @@ -547,7 +548,7 @@ public HorizontalLayout createStatusFilterBar() { I18nProperties.getCaption(Captions.actionArchive), VaadinIcons.ARCHIVE, mi -> grid.bulkActionHandler( - items -> ControllerProvider.getEventController().archiveAllSelectedItems(items, () -> navigateTo(eventCriteria)), + items -> ControllerProvider.getEventController().archiveAllSelectedItems(items, () -> navigateTo(eventCriteria, true)), true), EntityRelevanceStatus.ACTIVE.equals(eventCriteria.getRelevanceStatus()))); bulkActions.add( @@ -556,7 +557,7 @@ public HorizontalLayout createStatusFilterBar() { VaadinIcons.ARCHIVE, mi -> grid.bulkActionHandler( items -> ControllerProvider.getEventController() - .dearchiveAllSelectedItems(eventGrid.asMultiSelect().getSelectedItems(), () -> navigateTo(eventCriteria)), + .dearchiveAllSelectedItems(eventGrid.asMultiSelect().getSelectedItems(), () -> navigateTo(eventCriteria, true)), true), EntityRelevanceStatus.ARCHIVED.equals(eventCriteria.getRelevanceStatus()))); } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java index 2a99272418c..e9fe31d9bfb 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java @@ -8,7 +8,6 @@ import com.vaadin.server.Sizeable; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; -import com.vaadin.ui.Label; import com.vaadin.ui.Notification; import com.vaadin.ui.UI; import com.vaadin.ui.themes.ValoTheme; @@ -192,7 +191,29 @@ public void discard() { boolean archived = FacadeProvider.getImmunizationFacade().isArchived(immunizationDto.getUuid()); Button archiveButton = ButtonHelper.createButton(archived ? Captions.actionDearchive : Captions.actionArchive, e -> { editComponent.commit(); - archiveOrDearchiveImmunization(immunizationDto.getUuid(), !archived); + + if (archived) { + ControllerProvider.getArchiveController() + .dearchiveEntity( + immunizationDto, + FacadeProvider.getImmunizationFacade(), + Strings.headingDearchiveImmunization, + Strings.confirmationDearchiveImmunization, + Strings.entityImmunization, + Strings.messageImmunizationDearchived, + ImmunizationDataView.VIEW_NAME); + } else { + ControllerProvider.getArchiveController() + .archiveEntity( + immunizationDto, + FacadeProvider.getImmunizationFacade(), + Strings.headingArchiveImmunization, + Strings.confirmationArchiveImmunization, + Strings.entityImmunization, + Strings.messageImmunizationArchived, + ImmunizationDataView.VIEW_NAME); + } + }, ValoTheme.BUTTON_LINK); editComponent.getButtonsPanel().addComponentAsFirst(archiveButton); @@ -226,57 +247,6 @@ private ImmunizationDto findImmunization(String uuid) { return FacadeProvider.getImmunizationFacade().getByUuid(uuid); } - private void archiveOrDearchiveImmunization(String uuid, boolean archive) { - - if (archive) { - Label contentLabel = new Label( - String.format( - I18nProperties.getString(Strings.confirmationArchiveImmunization), - I18nProperties.getString(Strings.entityImmunization).toLowerCase(), - I18nProperties.getString(Strings.entityImmunization).toLowerCase())); - VaadinUiUtil.showConfirmationPopup( - I18nProperties.getString(Strings.headingArchiveImmunization), - contentLabel, - I18nProperties.getString(Strings.yes), - I18nProperties.getString(Strings.no), - 640, - e -> { - if (e) { - FacadeProvider.getImmunizationFacade().archive(uuid); - Notification.show( - String.format( - I18nProperties.getString(Strings.messageImmunizationArchived), - I18nProperties.getString(Strings.entityImmunization)), - Notification.Type.ASSISTIVE_NOTIFICATION); - navigateToImmunization(uuid); - } - }); - } else { - Label contentLabel = new Label( - String.format( - I18nProperties.getString(Strings.confirmationDearchiveImmunization), - I18nProperties.getString(Strings.entityImmunization).toLowerCase(), - I18nProperties.getString(Strings.entityImmunization).toLowerCase())); - VaadinUiUtil.showConfirmationPopup( - I18nProperties.getString(Strings.headingDearchiveImmunization), - contentLabel, - I18nProperties.getString(Strings.yes), - I18nProperties.getString(Strings.no), - 640, - e -> { - if (e) { - FacadeProvider.getImmunizationFacade().dearchive(uuid); - Notification.show( - String.format( - I18nProperties.getString(Strings.messageImmunizationDearchived), - I18nProperties.getString(Strings.entityImmunization)), - Notification.Type.ASSISTIVE_NOTIFICATION); - navigateToImmunization(uuid); - } - }); - } - } - private void selectOrCreateimmunizationForPerson(ImmunizationDto dto, PersonReferenceDto selectedPerson) { dto.setPerson(selectedPerson); selectOrCreateImmunization(dto, uuid -> { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryController.java index 7cd2657fc65..bd4ba4629d0 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryController.java @@ -5,7 +5,6 @@ import com.vaadin.navigator.Navigator; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; -import com.vaadin.ui.Label; import com.vaadin.ui.Notification; import com.vaadin.ui.UI; import com.vaadin.ui.themes.ValoTheme; @@ -43,8 +42,7 @@ public void registerViews(Navigator navigator) { } public void create() { - CommitDiscardWrapperComponent travelEntryCreateComponent = - getTravelEntryCreateComponent(null, null); + CommitDiscardWrapperComponent travelEntryCreateComponent = getTravelEntryCreateComponent(null, null); VaadinUiUtil.showModalPopupWindow(travelEntryCreateComponent, I18nProperties.getString(Strings.headingCreateNewTravelEntry)); } @@ -54,7 +52,9 @@ public void create(TravelEntryListCriteria travelEntryListCriteria) { VaadinUiUtil.showModalPopupWindow(travelEntryCreateComponent, I18nProperties.getString(Strings.headingCreateNewTravelEntry)); } - private CommitDiscardWrapperComponent getTravelEntryCreateComponent(CaseReferenceDto caseReferenceDto, PersonReferenceDto personReferenceDto) { + private CommitDiscardWrapperComponent getTravelEntryCreateComponent( + CaseReferenceDto caseReferenceDto, + PersonReferenceDto personReferenceDto) { TravelEntryCreateForm createForm; TravelEntryDto travelEntry = TravelEntryDto.build(null); @@ -164,7 +164,28 @@ public CommitDiscardWrapperComponent getTravelEntryDataEdit boolean archived = FacadeProvider.getTravelEntryFacade().isArchived(travelEntryUuid); Button archiveTravelEntryButton = ButtonHelper.createButton(archived ? Captions.actionDearchive : Captions.actionArchive, e -> { editComponent.commit(); - archiveOrDearchiveTraveEntry(travelEntryUuid, !archived); + + if (archived) { + ControllerProvider.getArchiveController() + .dearchiveEntity( + travelEntry, + FacadeProvider.getTravelEntryFacade(), + Strings.headingDearchiveTravelEntry, + Strings.confirmationDearchiveTravelEntry, + Strings.entityTravel, + Strings.messageTravelEntryDearchived, + TravelEntryDataView.VIEW_NAME); + } else { + ControllerProvider.getArchiveController() + .archiveEntity( + travelEntry, + FacadeProvider.getTravelEntryFacade(), + Strings.headingArchiveTravelEntry, + Strings.confirmationArchiveTravelEntry, + Strings.entityTravel, + Strings.messageTravelEntryArchived, + TravelEntryDataView.VIEW_NAME); + } }, ValoTheme.BUTTON_LINK); editComponent.getButtonsPanel().addComponentAsFirst(archiveTravelEntryButton); @@ -197,54 +218,4 @@ public TitleLayout getTravelEntryViewTitleLayout(String uuid) { return titleLayout; } - - private void archiveOrDearchiveTraveEntry(String travelEntryUuid, boolean archive) { - - if (archive) { - Label contentLabel = new Label( - String.format( - I18nProperties.getString(Strings.confirmationArchiveTravelEntry), - I18nProperties.getString(Strings.entityTravel).toLowerCase(), - I18nProperties.getString(Strings.entityTravel).toLowerCase())); - VaadinUiUtil.showConfirmationPopup( - I18nProperties.getString(Strings.headingArchiveTravelEntry), - contentLabel, - I18nProperties.getString(Strings.yes), - I18nProperties.getString(Strings.no), - 640, - e -> { - if (e) { - FacadeProvider.getTravelEntryFacade().archiveOrDearchiveTravelEntry(travelEntryUuid, true); - Notification.show( - String - .format(I18nProperties.getString(Strings.messageTravelEntryArchived), I18nProperties.getString(Strings.entityTravel)), - Notification.Type.ASSISTIVE_NOTIFICATION); - navigateToTravelEntry(travelEntryUuid); - } - }); - } else { - Label contentLabel = new Label( - String.format( - I18nProperties.getString(Strings.confirmationDearchiveTravelEntry), - I18nProperties.getString(Strings.entityTravel).toLowerCase(), - I18nProperties.getString(Strings.entityTravel).toLowerCase())); - VaadinUiUtil.showConfirmationPopup( - I18nProperties.getString(Strings.headingDearchiveTravelEntry), - contentLabel, - I18nProperties.getString(Strings.yes), - I18nProperties.getString(Strings.no), - 640, - e -> { - if (e) { - FacadeProvider.getTravelEntryFacade().archiveOrDearchiveTravelEntry(travelEntryUuid, false); - Notification.show( - String.format( - I18nProperties.getString(Strings.messageTravelEntryDearchived), - I18nProperties.getString(Strings.entityTravel)), - Notification.Type.ASSISTIVE_NOTIFICATION); - navigateToTravelEntry(travelEntryUuid); - } - }); - } - } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchiveController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchiveController.java new file mode 100644 index 00000000000..4e172ad33a1 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchiveController.java @@ -0,0 +1,250 @@ +package de.symeda.sormas.ui.utils; + +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import com.vaadin.server.Page; +import com.vaadin.server.Sizeable; +import com.vaadin.server.UserError; +import com.vaadin.ui.DateField; +import com.vaadin.ui.Label; +import com.vaadin.ui.Notification; +import com.vaadin.ui.TextArea; +import com.vaadin.ui.VerticalLayout; + +import de.symeda.sormas.api.CoreFacade; +import de.symeda.sormas.api.EntityDto; +import de.symeda.sormas.api.i18n.Captions; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.ui.SormasUI; +import de.symeda.sormas.ui.caze.AbstractCaseView; +import de.symeda.sormas.ui.events.EventDataView; + +public class ArchiveController { + + public void archiveEntity( + EntityDto coreEntityDto, + CoreFacade entityFacade, + String popupHeading, + String archiveConfirmationMessage, + String entity, + String archiveMessage, + String detailViewName) { + VerticalLayout verticalLayout = new VerticalLayout(); + + Label contentLabel = new Label( + String.format( + I18nProperties.getString(archiveConfirmationMessage), + I18nProperties.getString(entity).toLowerCase(), + I18nProperties.getString(entity).toLowerCase())); + contentLabel.setWidth(100, Sizeable.Unit.PERCENTAGE); + verticalLayout.addComponent(contentLabel); + + DateField endOfProcessingDate = new DateField(); + endOfProcessingDate + .setValue(DateHelper8.toLocalDate(entityFacade.calculateEndOfProcessingDate(Collections.singletonList(coreEntityDto.getUuid())))); + endOfProcessingDate.setCaption(I18nProperties.getCaption(Captions.endOfProcessingDate)); + verticalLayout.addComponent(endOfProcessingDate); + + VaadinUiUtil.showConfirmationPopup( + I18nProperties.getString(popupHeading), + verticalLayout, + I18nProperties.getString(Strings.yes), + I18nProperties.getString(Strings.no), + 640, + e -> { + if (Boolean.TRUE.equals(e)) { + entityFacade + .archiveCoreEntities(Collections.singletonList(coreEntityDto.getUuid()), DateHelper8.toDate(endOfProcessingDate.getValue())); + + Notification.show( + String.format(I18nProperties.getString(archiveMessage), I18nProperties.getString(entity)), + Notification.Type.ASSISTIVE_NOTIFICATION); + navigateToView(detailViewName, coreEntityDto.getUuid(), null); + } + }); + } + + public void dearchiveEntity( + EntityDto coreEntityDto, + CoreFacade entityFacade, + String popupHeading, + String dearchiveConfirmationMessage, + String entity, + String dearchiveMessage, + String detailViewName) { + VerticalLayout verticalLayout = new VerticalLayout(); + + Label contentLabel = new Label( + String.format( + I18nProperties.getString(dearchiveConfirmationMessage), + I18nProperties.getString(entity).toLowerCase(), + I18nProperties.getString(entity).toLowerCase())); + contentLabel.setWidth(100, Sizeable.Unit.PERCENTAGE); + verticalLayout.addComponent(contentLabel); + + TextArea dearchiveReason = new TextArea(); + dearchiveReason.setCaption(I18nProperties.getCaption(Captions.dearchiveReason)); + dearchiveReason.setWidth(100, Sizeable.Unit.PERCENTAGE); + dearchiveReason.setRows(2); + dearchiveReason.setRequiredIndicatorVisible(true); + verticalLayout.addComponent(dearchiveReason); + + VaadinUiUtil.showConfirmationPopup( + I18nProperties.getString(popupHeading), + verticalLayout, + I18nProperties.getString(Strings.yes), + I18nProperties.getString(Strings.no), + 640, + confirmed -> { + if (Boolean.TRUE.equals(confirmed)) { + if (dearchiveReason.getValue().isEmpty()) { + dearchiveReason.setComponentError(new UserError(I18nProperties.getString(Strings.messageArchiveUndoneReasonMandatory))); + return false; + } + entityFacade.dearchiveCoreEntities(Collections.singletonList(coreEntityDto.getUuid()), dearchiveReason.getValue()); + Notification.show( + String.format(I18nProperties.getString(dearchiveMessage), I18nProperties.getString(entity)), + Notification.Type.ASSISTIVE_NOTIFICATION); + navigateToView(detailViewName, coreEntityDto.getUuid(), null); + } + return true; + }); + } + + public void archiveSelectedItems( + List entityUuids, + CoreFacade entityFacade, + String noSelectionMessage, + String archiveConfirmationMessage, + String archivedHeading, + String archivedMessage, + Runnable callback) { + + if (entityUuids.isEmpty()) { + new Notification( + I18nProperties.getString(noSelectionMessage), + I18nProperties.getString(noSelectionMessage), + Notification.Type.WARNING_MESSAGE, + false).show(Page.getCurrent()); + } else { + VaadinUiUtil.showConfirmationPopup( + I18nProperties.getString(Strings.headingConfirmArchiving), + new Label(String.format(I18nProperties.getString(archiveConfirmationMessage), entityUuids.size())), + I18nProperties.getString(Strings.yes), + I18nProperties.getString(Strings.no), + null, + e -> { + if (Boolean.TRUE.equals(e)) { + Date endOfProcessingDate = entityFacade.calculateEndOfProcessingDate(entityUuids); + entityFacade.archiveCoreEntities(entityUuids, endOfProcessingDate); + + callback.run(); + new Notification( + I18nProperties.getString(archivedHeading), + I18nProperties.getString(archivedMessage), + Notification.Type.HUMANIZED_MESSAGE, + false).show(Page.getCurrent()); + } + }); + } + } + + public void dearchiveSelectedItems( + List entityUuids, + CoreFacade entityFacade, + String noSelectionMessage, + String messageNoEntitySelected, + String dearchiveConfirmationMessage, + String entity, + String headingConfirmationDeachiving, + String headingEntityDearchived, + String messageEntityDearchived, + Runnable callback) { + + if (entityUuids.isEmpty()) { + new Notification( + I18nProperties.getString(noSelectionMessage), + I18nProperties.getString(messageNoEntitySelected), + Notification.Type.WARNING_MESSAGE, + false).show(Page.getCurrent()); + } else { + VerticalLayout verticalLayout = new VerticalLayout(); + + Label contentLabel = new Label( + String.format( + String.format(I18nProperties.getString(dearchiveConfirmationMessage), entityUuids.size()), + I18nProperties.getString(entity).toLowerCase(), + I18nProperties.getString(entity).toLowerCase())); + contentLabel.setWidth(100, Sizeable.Unit.PERCENTAGE); + verticalLayout.addComponent(contentLabel); + + TextArea dearchiveReason = new TextArea(); + dearchiveReason.setCaption(I18nProperties.getCaption(Captions.dearchiveReason)); + dearchiveReason.setWidth(100, Sizeable.Unit.PERCENTAGE); + dearchiveReason.setRows(2); + dearchiveReason.setRequiredIndicatorVisible(true); + verticalLayout.addComponent(dearchiveReason); + + VaadinUiUtil.showConfirmationPopup( + I18nProperties.getString(headingConfirmationDeachiving), + verticalLayout, + I18nProperties.getString(Strings.yes), + I18nProperties.getString(Strings.no), + null, + connfirmed -> { + if (Boolean.TRUE.equals(connfirmed)) { + if (dearchiveReason.getValue().isEmpty()) { + dearchiveReason.setComponentError(new UserError(I18nProperties.getString(Strings.messageArchiveUndoneReasonMandatory))); + return false; + } + entityFacade.dearchiveCoreEntities(entityUuids, dearchiveReason.getValue()); + + callback.run(); + new Notification( + I18nProperties.getString(headingEntityDearchived), + I18nProperties.getString(messageEntityDearchived), + Notification.Type.HUMANIZED_MESSAGE, + false).show(Page.getCurrent()); + } + return true; + }); + } + } + + public void navigateToView(String viewName, String caseUuid, ViewMode viewMode) { + navigateToView(viewName, caseUuid, viewMode, false); + } + + public void navigateToView(String viewName, String caseUuid, ViewMode viewMode, boolean openTab) { + + String navigationState = viewName + "/" + caseUuid; + if (viewMode == ViewMode.NORMAL) { + // pass full view mode as param so it's also used for other views when switching + navigationState += "?" + AbstractCaseView.VIEW_MODE_URL_PREFIX + "=" + viewMode; + } + + if (openTab) { + SormasUI.get().getPage().open(SormasUI.get().getPage().getLocation().getRawPath() + "#!" + navigationState, "_blank", false); + } else { + SormasUI.get().getNavigator().navigateTo(navigationState); + } + } + + public void navigateToData(String eventUuid) { + navigateToData(eventUuid, false); + } + + public void navigateToData(String eventUuid, boolean openTab) { + + String navigationState = EventDataView.VIEW_NAME + "/" + eventUuid; + if (openTab) { + SormasUI.get().getPage().open(SormasUI.get().getPage().getLocation().getRawPath() + "#!" + navigationState, "_blank", false); + } else { + SormasUI.get().getNavigator().navigateTo(navigationState); + } + } + +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/VaadinUiUtil.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/VaadinUiUtil.java index 32726bf8b81..5e7b0b3c908 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/VaadinUiUtil.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/VaadinUiUtil.java @@ -19,6 +19,7 @@ import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.UnaryOperator; import com.vaadin.icons.VaadinIcons; import com.vaadin.server.Sizeable.Unit; @@ -127,7 +128,6 @@ public static Window showPopupWindowWithWidth(Component content, String caption, window.setWidth(width, Unit.PERCENTAGE); } - UI.getCurrent().addWindow(window); return window; } @@ -199,6 +199,41 @@ protected void onCancel() { }, width); } + public static Window showConfirmationPopup( + String caption, + Component content, + String confirmCaption, + String cancelCaption, + Integer width, + UnaryOperator resultConsumer) { + + return showConfirmationPopup(caption, content, popupWindow -> { + ConfirmationComponent confirmationComponent = new ConfirmationComponent(false) { + + private static final long serialVersionUID = 1L; + + @Override + protected void onConfirm() { + if (Boolean.TRUE.equals(resultConsumer.apply(true))) { + popupWindow.close(); + } + } + + @Override + protected void onCancel() { + if (Boolean.TRUE.equals(resultConsumer.apply(false))) { + popupWindow.close(); + } + } + }; + + confirmationComponent.getConfirmButton().setCaption(confirmCaption); + confirmationComponent.getCancelButton().setCaption(cancelCaption); + + return confirmationComponent; + }, width); + } + public static Window showConfirmationPopup( String caption, Component content, From 12b9fdb19d261452b11138f861f66bb7cda206f4 Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Wed, 16 Feb 2022 17:49:17 +0200 Subject: [PATCH 099/253] #7747-Fix-Allure-Report : removed last usage of old version --- .../sormas/e2etests/common/CommonModule.java | 11 ---- .../e2etests/common/PropertiesModule.java | 10 ---- .../sormas/e2etests/enums/TestDataUser.java | 59 ------------------- .../properties/common.properties | 2 +- .../environment/test-performance.properties | 20 ------- 5 files changed, 1 insertion(+), 101 deletions(-) delete mode 100644 sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/TestDataUser.java delete mode 100644 sormas-e2e-tests/src/main/resources/configuration/properties/environment/test-performance.properties diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/CommonModule.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/CommonModule.java index 04fae7be8a6..0a96eca1317 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/CommonModule.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/CommonModule.java @@ -91,15 +91,4 @@ ObjectMapper provideObjectMapper() { objectMapper.registerModule(new Jdk8Module()); return objectMapper; } - - // @Provides - // @Exposed - // RequestSpecification provideRestAssured() { - // return RestAssured.given() - // .auth() - // .preemptive() - // .basic( - // TestDataUser.REST_AUTOMATION.getUsername(), - // TestDataUser.REST_AUTOMATION.getPassword()); - // } } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/PropertiesModule.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/PropertiesModule.java index ac581c99283..e984bc5830f 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/PropertiesModule.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/common/PropertiesModule.java @@ -18,9 +18,6 @@ package org.sormas.e2etests.common; -import static com.google.common.base.MoreObjects.firstNonNull; -import static com.google.common.base.Strings.emptyToNull; - import com.google.common.annotations.VisibleForTesting; import com.google.inject.AbstractModule; import com.google.inject.name.Names; @@ -49,12 +46,6 @@ public class PropertiesModule extends AbstractModule { public static final String CONFIGURATION_PROPERTIES_COMMON_PROPERTIES_PATH = "configuration/properties/common.properties"; - public static final String ENVIRONMENT = - firstNonNull(emptyToNull(System.getenv("ENVIRONMENT")), "test-performance"); - - private static final Map DEFAULT_ENVIRONMENT_PROPERTIES = - MoreResources.getConfig( - String.format("configuration/properties/environment/%s.properties", ENVIRONMENT)); private static final Map DEFAULT_COMMON_ENVIRONMENT_PROPERTIES = MoreResources.getConfig(CONFIGURATION_PROPERTIES_COMMON_PROPERTIES_PATH); @@ -63,7 +54,6 @@ public class PropertiesModule extends AbstractModule { public void configure() { Map allProperties = new HashMap<>(); allProperties.putAll(DEFAULT_COMMON_ENVIRONMENT_PROPERTIES); - allProperties.putAll(DEFAULT_ENVIRONMENT_PROPERTIES); allProperties.putAll(getProperties(System.getProperties())); allProperties.putAll(System.getenv()); Names.bindProperties(binder(), allProperties); diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/TestDataUser.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/TestDataUser.java deleted file mode 100644 index 7dc55a3dcd7..00000000000 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/TestDataUser.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.sormas.e2etests.enums; - -import java.util.stream.Stream; -import lombok.Getter; - -@Getter -public enum TestDataUser { - NATIONAL_USER("NatUser", "NatUser38118", "National User", "XXFIKA-I653UK-XTLOIT-VWZYKGXY"), - CONTACT_SUPERVISOR( - "ContSup", "ContSup38118", "Contact Supervisor", "U77AIW-PC5LLO-VHEUOW-K3KZKF6E"), - SURVEILLANCE_OFFICER( - "SurvOff", "SurvOff38118", "Surveillance Officer", "Q2IYCN-TNYTOY-4OAYCA-DW662MTA"), - LABORATORY_OFFICER( - "LabOff", "LabOff38118", "Laboratory Officer", "UAAXB6-G6KRR2-YD7IDA-GJV2SM3A"), - POINT_OF_ENTRY_SUPERVISOR( - "PoeSup", "PoeSup38118", "Point of Entry Supervisor", "SJDRMA-6MGKJ4-I2GYDU-U3HCSE3M"), - ADMIN_USER("automation_admin", "DbXC5Yimro9m", "Admin User", "W5QCZW-XLFVFT-E5MK66-O3SUKE7E"), - REST_AUTOMATION("RestAuto", "umpQyGMSq4zy", "Rest AUTOMATION", "QLW4AN-TGWLRA-3UQVEM-WCDFCIVM"); - - private final String username; - private final String password; - private final String userRole; - private final String uuid; - - TestDataUser(String username, String password, String userRole, String uuid) { - this.username = username; - this.password = password; - this.userRole = userRole; - this.uuid = uuid; - } - - public static Stream stream() { - return Stream.of(TestDataUser.values()); - } - - public static TestDataUser gertUserByRole(String userRole) { - return stream() - .filter(testDataUser -> testDataUser.getUserRole().contentEquals(userRole)) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException(userRole + " this type is not recognized")); - } -} diff --git a/sormas-e2e-tests/src/main/resources/configuration/properties/common.properties b/sormas-e2e-tests/src/main/resources/configuration/properties/common.properties index 7092796a0a3..518b5e15f91 100644 --- a/sormas-e2e-tests/src/main/resources/configuration/properties/common.properties +++ b/sormas-e2e-tests/src/main/resources/configuration/properties/common.properties @@ -17,6 +17,6 @@ # BROWSER=chrome -REMOTE_DRIVER=false +REMOTE_DRIVER=true HEADLESS=true LOG_RESTASSURED=false diff --git a/sormas-e2e-tests/src/main/resources/configuration/properties/environment/test-performance.properties b/sormas-e2e-tests/src/main/resources/configuration/properties/environment/test-performance.properties deleted file mode 100644 index 2ded204d5b5..00000000000 --- a/sormas-e2e-tests/src/main/resources/configuration/properties/environment/test-performance.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# SORMAS® - Surveillance Outbreak Response Management & Analysis System -# Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -ENVIRONMENT_URL=https://test-performance.sormas.netzlink.com - From bb2e40519f0fc7aeda197a53f522e10d565789ec Mon Sep 17 00:00:00 2001 From: marius Date: Wed, 16 Feb 2022 23:48:28 +0200 Subject: [PATCH 100/253] #7946 shareRequest endpoints (getIndexPage, getByUuid) --- .../SormasToSormasShareRequestFacade.java | 7 +++ .../SormasToSormasShareRequestFacadeEJB.java | 11 +++++ .../sormas/rest/ShareRequestResource.java | 45 +++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 sormas-rest/src/main/java/de/symeda/sormas/rest/ShareRequestResource.java diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/sormastosormas/sharerequest/SormasToSormasShareRequestFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/sormastosormas/sharerequest/SormasToSormasShareRequestFacade.java index 0bf5263feee..9a2e05d3de4 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/sormastosormas/sharerequest/SormasToSormasShareRequestFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/sormastosormas/sharerequest/SormasToSormasShareRequestFacade.java @@ -20,6 +20,7 @@ import javax.ejb.Remote; import javax.validation.Valid; +import de.symeda.sormas.api.common.Page; import de.symeda.sormas.api.utils.SortProperty; @Remote @@ -36,4 +37,10 @@ List getIndexList( List sortProperties); long count(ShareRequestCriteria criteria); + + Page getIndexPage( + ShareRequestCriteria criteria, + Integer offset, + Integer size, + List sortProperties); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/share/sharerequest/SormasToSormasShareRequestFacadeEJB.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/share/sharerequest/SormasToSormasShareRequestFacadeEJB.java index 200b3c0d853..401a0202fdb 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/share/sharerequest/SormasToSormasShareRequestFacadeEJB.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sormastosormas/share/sharerequest/SormasToSormasShareRequestFacadeEJB.java @@ -36,6 +36,7 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; +import de.symeda.sormas.api.common.Page; import de.symeda.sormas.api.sormastosormas.SormasServerDescriptor; import de.symeda.sormas.api.sormastosormas.sharerequest.ShareRequestCriteria; import de.symeda.sormas.api.sormastosormas.sharerequest.SormasToSormasShareRequestDto; @@ -175,6 +176,16 @@ public long count(ShareRequestCriteria criteria) { return em.createQuery(cq).getSingleResult(); } + public Page getIndexPage( + ShareRequestCriteria criteria, + Integer first, + Integer max, + List sortProperties) { + List shareRequestIndexList = getIndexList(criteria, first, max, sortProperties); + long totalElementCount = count(criteria); + return new Page<>(shareRequestIndexList, first, max, totalElementCount); + } + public SormasToSormasShareRequest fromDto(@NotNull SormasToSormasShareRequestDto source, boolean checkChangeDate) { SormasToSormasShareRequest target = diff --git a/sormas-rest/src/main/java/de/symeda/sormas/rest/ShareRequestResource.java b/sormas-rest/src/main/java/de/symeda/sormas/rest/ShareRequestResource.java new file mode 100644 index 00000000000..ae5d74826fc --- /dev/null +++ b/sormas-rest/src/main/java/de/symeda/sormas/rest/ShareRequestResource.java @@ -0,0 +1,45 @@ +package de.symeda.sormas.rest; + +import javax.annotation.security.RolesAllowed; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.caze.CriteriaWithSorting; +import de.symeda.sormas.api.common.Page; +import de.symeda.sormas.api.sormastosormas.sharerequest.ShareRequestCriteria; +import de.symeda.sormas.api.sormastosormas.sharerequest.SormasToSormasShareRequestDto; +import de.symeda.sormas.api.sormastosormas.sharerequest.SormasToSormasShareRequestIndexDto; +import io.swagger.v3.oas.annotations.parameters.RequestBody; + +@Path("/sharerequests") +@Produces(MediaType.APPLICATION_JSON + "; charset=UTF-8") +@Consumes(MediaType.APPLICATION_JSON + "; charset=UTF-8") +@RolesAllowed({ + "USER", + "REST_USER" }) +public class ShareRequestResource extends EntityDtoResource { + + @POST + @Path("/indexList") + public Page getIndexList( + @RequestBody CriteriaWithSorting criteriaWithSorting, + @QueryParam("offset") int offset, + @QueryParam("size") int size) { + return FacadeProvider.getSormasToSormasShareRequestFacade() + .getIndexPage(criteriaWithSorting.getCriteria(), offset, size, criteriaWithSorting.getSortProperties()); + } + + @GET + @Path("/{uuid}") + public SormasToSormasShareRequestDto getByUuid(@PathParam("uuid") String uuid) { + return FacadeProvider.getSormasToSormasShareRequestFacade().getShareRequestByUuid(uuid); + } + +} From 1b6bb838cbe055c73294177084e79355545f7ff5 Mon Sep 17 00:00:00 2001 From: FredrikSchaeferVitagroup <67001822+FredrikSchaeferVitagroup@users.noreply.github.com> Date: Thu, 17 Feb 2022 07:13:06 +0100 Subject: [PATCH 101/253] #24 configurable token lifetime (#8015) * #24 configurable token lifetime * #24 use token initialization that is not @GwtIncompatible * #24 add external journal change warning to test --- .../externaljournal/PatientDiaryConfig.java | 12 +++++++++ .../backend/common/ConfigFacadeEjb.java | 3 +++ .../externaljournal/PatientDiaryClient.java | 15 +++++++++-- .../backend/common/ConfigFacadeEjbTest.java | 27 +++++++++++++++++++ sormas-base/setup/sormas.properties | 3 +++ .../workflow-documentation.properties | 7 +++-- 6 files changed, 63 insertions(+), 4 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/externaljournal/PatientDiaryConfig.java b/sormas-api/src/main/java/de/symeda/sormas/api/externaljournal/PatientDiaryConfig.java index 29751f8d3b0..c40927d5bba 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/externaljournal/PatientDiaryConfig.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/externaljournal/PatientDiaryConfig.java @@ -1,6 +1,7 @@ package de.symeda.sormas.api.externaljournal; import java.io.Serializable; +import java.time.Duration; import java.util.Objects; public class PatientDiaryConfig implements Serializable, Cloneable { @@ -11,6 +12,7 @@ public class PatientDiaryConfig implements Serializable, Cloneable { private String probandsUrl; private String authUrl; private String frontendAuthUrl; + private Duration tokenLifetime; private String email; private String password; private UserConfig defaultUser; @@ -48,6 +50,14 @@ public void setFrontendAuthUrl(String frontendAuthUrl) { this.frontendAuthUrl = frontendAuthUrl; } + public Duration getTokenLifetime() { + return tokenLifetime; + } + + public void setTokenLifetime(Duration tokenLifetime) { + this.tokenLifetime = tokenLifetime; + } + public String getEmail() { return email; } @@ -94,6 +104,8 @@ public boolean equals(Object o) { return Objects.equals(url, that.url) && Objects.equals(probandsUrl, that.probandsUrl) && Objects.equals(authUrl, that.authUrl) + && Objects.equals(frontendAuthUrl, that.frontendAuthUrl) + && Objects.equals(tokenLifetime, that.tokenLifetime) && Objects.equals(email, that.email) && Objects.equals(password, that.password) && Objects.equals(defaultUser, that.defaultUser) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ConfigFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ConfigFacadeEjb.java index 397e3cb344c..4733a346aae 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ConfigFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ConfigFacadeEjb.java @@ -15,6 +15,7 @@ package de.symeda.sormas.backend.common; import java.nio.charset.StandardCharsets; +import java.time.Duration; import java.util.List; import java.util.Locale; import java.util.Map; @@ -109,6 +110,7 @@ public class ConfigFacadeEjb implements ConfigFacade { public static final String INTERFACE_PATIENT_DIARY_PROBANDS_URL = "interface.patientdiary.probandsurl"; public static final String INTERFACE_PATIENT_DIARY_AUTH_URL = "interface.patientdiary.authurl"; public static final String INTERFACE_PATIENT_DIARY_FRONTEND_AUTH_URL = "interface.patientdiary.frontendAuthurl"; + public static final String INTERFACE_PATIENT_DIARY_TOKEN_LIFETIME = "interface.patientdiary.tokenLifetime"; public static final String INTERFACE_PATIENT_DIARY_EMAIL = "interface.patientdiary.email"; public static final String INTERFACE_PATIENT_DIARY_PASSWORD = "interface.patientdiary.password"; public static final String INTERFACE_PATIENT_DIARY_DEFAULT_USER_USERNAME = "interface.patientdiary.defaultuser.username"; @@ -502,6 +504,7 @@ public PatientDiaryConfig getPatientDiaryConfig() { config.setProbandsUrl(getProperty(INTERFACE_PATIENT_DIARY_PROBANDS_URL, null)); config.setAuthUrl(getProperty(INTERFACE_PATIENT_DIARY_AUTH_URL, null)); config.setFrontendAuthUrl(getProperty(INTERFACE_PATIENT_DIARY_FRONTEND_AUTH_URL, null)); + config.setTokenLifetime(Duration.ofSeconds(getLong(INTERFACE_PATIENT_DIARY_TOKEN_LIFETIME, 21600L))); config.setEmail(getProperty(INTERFACE_PATIENT_DIARY_EMAIL, null)); config.setPassword(getProperty(INTERFACE_PATIENT_DIARY_PASSWORD, null)); config.setAcceptPhoneContact(getBoolean(INTERFACE_PATIENT_DIARY_ACCEPT_PHONE_CONTACT, true)); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/externaljournal/PatientDiaryClient.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/externaljournal/PatientDiaryClient.java index 3509ad41d08..d99389b4907 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/externaljournal/PatientDiaryClient.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/externaljournal/PatientDiaryClient.java @@ -22,6 +22,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import javax.annotation.PostConstruct; import javax.ejb.EJB; import javax.ejb.LocalBean; import javax.ejb.Stateless; @@ -60,12 +61,22 @@ public class PatientDiaryClient { public static final String MOBILE_PHONE_QUERY_PARAM = "Mobile phone"; private static final String PATIENT_DIARY_KEY = "patientDiary"; - private static final Cache backendAuthTokenCache = CacheBuilder.newBuilder().expireAfterWrite(6, TimeUnit.HOURS).build(); - private static final Cache frontendAuthTokenCache = CacheBuilder.newBuilder().expireAfterWrite(6, TimeUnit.HOURS).build(); + private Cache backendAuthTokenCache; + private Cache frontendAuthTokenCache; @EJB private ConfigFacadeEjb.ConfigFacadeEjbLocal configFacade; + @PostConstruct + private void init() { + backendAuthTokenCache = CacheBuilder.newBuilder() + .expireAfterWrite(configFacade.getPatientDiaryConfig().getTokenLifetime().getSeconds(), TimeUnit.SECONDS) + .build(); + frontendAuthTokenCache = CacheBuilder.newBuilder() + .expireAfterWrite(configFacade.getPatientDiaryConfig().getTokenLifetime().getSeconds(), TimeUnit.SECONDS) + .build(); + } + /** * Attempts to register a new patient in the CLIMEDO patient diary. * Sets the person symptom journal status to REGISTERED if successful. diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/common/ConfigFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/common/ConfigFacadeEjbTest.java index bf12f12a050..e86074bd0ae 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/common/ConfigFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/common/ConfigFacadeEjbTest.java @@ -18,6 +18,7 @@ package de.symeda.sormas.backend.common; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.isEmptyString; import static org.junit.Assert.fail; @@ -29,6 +30,8 @@ import de.symeda.sormas.backend.AbstractBeanTest; import de.symeda.sormas.backend.MockProducer; +import java.time.Duration; + public class ConfigFacadeEjbTest extends AbstractBeanTest { @Test @@ -115,4 +118,28 @@ public void testNormalizeLocaleString() { assertThat(ConfigFacadeEjb.normalizeLocaleString("en-CA"), is("en-CA")); assertThat(ConfigFacadeEjb.normalizeLocaleString("en-cA"), is("en-CA")); } + + @Test + /* + * If you need to change this test to make it pass, you probably changed the behaviour of the ExternalVisitsResource. + * Please note that other system used alongside with SORMAS are depending on this, so that their developers must be notified of any + * relevant API changes some time before they go into any test and productive system. Please inform the SORMAS core development team at + * https://gitter.im/SORMAS-Project! + */ + public void testPatientDiaryConfigTokenLifetime() { + // property not specified + assertThat(getConfigFacade().getPatientDiaryConfig().getTokenLifetime(), equalTo(Duration.ofSeconds(21600L))); + + // property specifies empty value + MockProducer.getProperties().setProperty(ConfigFacadeEjb.INTERFACE_PATIENT_DIARY_TOKEN_LIFETIME, ""); + assertThat(getConfigFacade().getPatientDiaryConfig().getTokenLifetime(), equalTo(Duration.ofSeconds(21600L))); + + // property specifies zero + MockProducer.getProperties().setProperty(ConfigFacadeEjb.INTERFACE_PATIENT_DIARY_TOKEN_LIFETIME, "0"); + assertThat(getConfigFacade().getPatientDiaryConfig().getTokenLifetime(), equalTo(Duration.ofSeconds(0L))); + + // property specifies value > 0 + MockProducer.getProperties().setProperty(ConfigFacadeEjb.INTERFACE_PATIENT_DIARY_TOKEN_LIFETIME, "666"); + assertThat(getConfigFacade().getPatientDiaryConfig().getTokenLifetime(), equalTo(Duration.ofSeconds(666L))); + } } diff --git a/sormas-base/setup/sormas.properties b/sormas-base/setup/sormas.properties index df2f58c19b8..7a494061642 100644 --- a/sormas-base/setup/sormas.properties +++ b/sormas-base/setup/sormas.properties @@ -367,6 +367,9 @@ app.url= # URL used to retrieve tokens for frontend requests. If not specified, the authurl is used instead. #interface.patientdiary.frontendAuthurl= +# Number of seconds tokens fetched via the authurl (and frontendAuthurl) are cached. Defaults to 21600 (6 hrs.). +#interface.patientdiary.tokenLifetime=21600 + # Credentials used for both authurls. #interface.patientdiary.email= #interface.patientdiary.password= diff --git a/sormas-rest/src/main/resources/workflow-documentation.properties b/sormas-rest/src/main/resources/workflow-documentation.properties index 15245aa4927..9fab79ea0b3 100644 --- a/sormas-rest/src/main/resources/workflow-documentation.properties +++ b/sormas-rest/src/main/resources/workflow-documentation.properties @@ -31,6 +31,8 @@ The follow up status describes the follow up for a contact or a case. Possible v Configuration in SORMAS
    \ In the domain folder, there is a sormas.properties. it holds the following values relevant for an external journal:
    \ ``interface.patientdiary.authurl``: used to fetch an authentication token (see 1. below).
    \ +``interface.patientdiary.frontendAuthurl``: URL used to retrieve tokens for frontend requests. If not specified, the authurl is used instead.
    \ +``interface.patientdiary.tokenLifetime``: Lifetime of tokens fetched via the authurl or the frontendAuthurl. To be specified in seconds. Can be set to 0 for no token caching. Defaults to 21600 (6 hrs.).
    \ ``interface.patientdiary.probandsurl``: used to register new persons in the external journal (see 2. below).
    \ ``interface.patientdiary.url``: used to open a person in the external journal (see 6. below).
    \ ``interface.patientdiary.email``: used to authenticate at the external journal (see 1. below).
    \ @@ -54,7 +56,8 @@ In the domain folder, there is a sormas.properties. it holds the following value   "userId" : [some-user-id],
    \   "token" : [token]
    \ }
    \ - The token returned will be used to authenticate in other requests.
    \ + The token returned will be used to authenticate in other requests. Its lifetime can be configured via the ``interface.patientdiary.tokenLifetime`` property.
    \ + One special scenario is fetching a token for frontend calls (see 6.): When the interface.patientdiary.frontendAuthurl is configured, it is used instead of the interface.patientdiary.authurl here.
    \
    \
  • Registration of a new person in the external journal

  • \ This process involves several steps that are triggered via the REGISTER button a privileged user can see in the top right corner when having opened a case or a contact.
    \ @@ -186,7 +189,7 @@ In the domain folder, there is a sormas.properties. it holds the following value
  • Opening a person in the external journal from within SORMAS

  • \ Once the symptom journal status of a person is set to REGISTERED or ACCEPTED, the external journal button in the SORMAS-UI changes. It does not provide a registration anymore, \ but the options to open the person in the external journal and to cancel external follow up. This button can be found when having opened a contact (or a case if the case follow up feature is enabled in SORMAS) \ - in the top right corner. If the user choses to open the person in the external journal, SORMAS fetches an authentication token as described in 1. and opens a new browser tab with the following URL:
    \ + in the top right corner. If the user chooses to open the person in the external journal, SORMAS fetches an authentication token as described in 1 (using the interface.patientdiary.frontendAuthurl if configured), and opens a new browser tab with the following URL:
    \ [interface.patientdiary.url]/data?q=[personUuid]&queryKey=sicFieldIdentifier&token=[token]
    \ SORMAS expects the external journal to present a view of the person there.
    \
    \ From eedd14fd1cc092b255afa2287e9068d1a346fb2b Mon Sep 17 00:00:00 2001 From: sormas-vitagroup Date: Thu, 17 Feb 2022 06:49:01 +0000 Subject: [PATCH 102/253] [GitHub Actions] Update external visits API spec files --- openapi/external_visits_API.json | 2 +- openapi/external_visits_API.yaml | 46 +++++++++++++++++++------------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/openapi/external_visits_API.json b/openapi/external_visits_API.json index 195f0fdafc8..3a56731b71b 100644 --- a/openapi/external_visits_API.json +++ b/openapi/external_visits_API.json @@ -2,7 +2,7 @@ "openapi" : "3.0.1", "info" : { "title" : "SORMAS external visits journal API", - "description" : "The purpose of this API is to enable communication between SORMAS and other symptom journals.
    Only users with the role ``REST_EXTERNAL_VISITS_USER`` are authorized to use the endpoints. Authentication is done using basic auth, with the user and password.
    For technical details please contact the dev team on
    gitter.

    #### Workflow Description ####

    About external follow up:
    Follow up in SORMAS is done via visits. Visits hold information about symptoms at a specific time point.
    Visits can be created for cases and contacts, either via the SORMAS-UI or the external visits journal API.

    About persons, cases and contacts:
    This is a very basic concept that one needs to understand when working with visits. In SORMAS, a person entity represents a phisically existing person. Cases and contacts represent epidemiological occurrences. When a person was in contact with an infectious environment, the person has a contact in SORMAS. When the person was in contact with such environments twice, it gets two contacts.When a person falls ill, it gets a case with the according disease. This means: In SORMAS, each contact and case relates to exactly one person. One person can have several contacts and cases, though. Follow up is done for a contact (or a case, which can be enabled in the SORMAS feature configuration). Contacts (or cases) initiate follow up. A person, though, either shows symptoms or not. It can not show symptoms for just one contact and not for the other. Thus, visits are related to all active contacts (and cases) of a person. Also the communication with external symptom journals is PERSON BASED. Only the person uuid is used, visits are uploaded to each active case and contact of a person.

    Person status variables:
    It is important to understand the meaning of two variables: the follow up status and the symptom journal status.
    The follow up status describes the follow up for a contact or a case. Possible values are defined in the FollowUpStatus enum. Follow up can be done with, or without an external journal, the follow up status makes no distinction there. Because the follow up status is contact and case specific, but the communication with external journals is person based, SORMAS determines the most important follow up status of all contacts and cases related to the person in question when communicating with external journals. Whenever there is follow up ongoing for any of the persons contacts (and cases if the case follow up feature is enabled in SORMAS), SORMAS will state the FollowUpStatus.FOLLOW_UP for that person towards external journals.
    The SymptomJournalStatus describes the state of a person related to external symptom journals. it is not contact or case specific.

    Configuration in SORMAS
    In the domain folder, there is a sormas.properties. it holds the following values relevant for an external journal:
    ``interface.patientdiary.authurl``: used to fetch an authentication token (see 1. below).
    ``interface.patientdiary.probandsurl``: used to register new persons in the external journal (see 2. below).
    ``interface.patientdiary.url``: used to open a person in the external journal (see 6. below).
    ``interface.patientdiary.email``: used to authenticate at the external journal (see 1. below).
    ``interface.patientdiary.password``: used to authenticate at the external journal.
    ``interface.patientdiary.defaultuser.username``: This user will be created in SORMAS and can be used by the external journal to authenticate.
    ``interface.patientdiary.defaultuser.password``: The above user's password.
    ``interface.patientdiary.acceptPhoneContact``: used to configure whether the phone number is considered relevant for registering a person in the external journal. It affects the validation of persons in SORMAS (see 2. below). Defaults to true

    1. SORMAS fetching an authentication token from the external journal

    2. POST to the interface.patientdiary.authurl
      Request body:
      {
        \"email\" : [patientdiary.email],
        \"password\" : [patientdiary.password]
      }
      where [patientdiary.email] is replaced with interface.patientdiary.email and [patientdiary.password] with interface.patientdiary.password specified in the sormas.properties
      Expected response body:
      {
        \"success\" : true,
        \"userId\" : [some-user-id],
        \"token\" : [token]
      }
      The token returned will be used to authenticate in other requests.

    3. Registration of a new person in the external journal

    4. This process involves several steps that are triggered via the REGISTER button a privileged user can see in the top right corner when having opened a case or a contact.
      To be able to see this button, the user must have at least one of the following user roles: national user, contact supervisor, contact officer, community officer,surveillance officer, surveillance supervisor, or admin supervisor.

      First comes a SORMAS-internal validation of contact details. The person to be registered needs to have at least an email address (or a phone number if that is accepted for registration, see ``interface.patientdiary.acceptPhoneContact``) to pass this validation.Also, when there are several email addresses or phone numbers, one of them has to be marked primary contact detail, so that it is clear which contact detail shall be used.

      Then comes an external validation of the contact details. For this, SORMAS fetches an authentication token as in 1. Then it sends a GET request to the following URL for each contact detail to be used in the external journal:
      GET [interface.patientdiary.probandsurl]/probands?q=[URL-encoded-query-parameter-and-value]', with a header like 'x-access-token: [token]'
      The [URL-encoded-query-parameter-and-value] consists of a parameter-value-pair. The parameter is either 'Email' or 'Mobile phone'. The value holds the contact detail to be validated.
      An unencoded example for this is \"Email\" = \"example@example.de\"
      The URL-encoded version is %22Email%22%20%3D%20%22example%40example.de%22
      [token] is replaced with the token fetched for authorization.
      The CURL equivalent for an exemplary call is curl --request GET 'https://probands-URL.com//probands?q=%22Email%22%20%3D%20%22example%40example.de%22' --header 'x-access-token: my-access-token'

      Expected result is a PatientDiaryQueryResponse which information about any person already registered in the external journal and using the same contact detail.
      It needs to be structured as follows:
      ``PatientDiaryQueryResponse`` {
       total   integer
       count   integer
       results   List (``PatientDiaryPersonData``)
      }
      - total should state how many persons are registered in the external journal (this information is currently never used in SORMAS).
      - count should state how many registered persons using the same contact detail were found.
      - results needs to contain a PatientDiaryPersonData for each match:
      ``PatientDiaryPersonData``{
       _id   string
       idatId   ``PatientDiaryIdatId``
      }
      - _id should be a unique identifier for the person this data is about (this information is currently never used in SORMAS)
      The PatientDiaryIdatId needs to be structured as follows:
      ``PatientDiaryIdatId``{
       idat   ``PatientDiaryPersonDto``
      }
      The PatientDiaryPersonDto holds the actual person data:
      ``PatientDiaryPersonDto``{
       personUUID   string
       firstName    string
       lastName    string
       gender     string
       birthday     string
       contactInformation   ``PatientDiaryContactInformation``
       endDate     string
      }
      - personUUID should be the UUID of the person in SORMAS. This UUID is used to sync with external journals (this information is currently never used in SORMAS).
      - firstName and lastName need to hold the first and last name of the person.
      - gender should hold the persons gender (this information is currently never used in SORMAS).
      - birthday should hold the persons birthday (this information is currently never used in SORMAS).
      - contactInformation should hold the contact information of that person, which should for logical reasons always contain (at least) the contact detail provided by SORMAS in the query.
      - endDate should hold the date after which follow up is supposed to be stopped by the external journal.
      ``PatientDiaryIdatId``{
       email   string
       phone   ``PatientDiaryPhone``
      }
      - email should hold the email address for the person
      - phone should hold the phone number of that person:
      ``PatientDiaryPhone``{
       number      string
       internationalNumber   string
       nationalNumber    string
       countryCode    string
       dialCode   string
      }
      To put this all together, here is an example PatientDiaryQueryResponse with one person using the same contact detail:
      {
        \"total\" : 100,
        \"count\" : 1,
        \"results\" : [
          {
            \"_id\" : \"60586691d4c30700119515c8\"
            \"idatId\" : {
              \"idat\" : {
                \"contactInformation\" : {
                  \"phone\" : null,
                  \"email\" : \"example@example.de\"
                },
                \"personUUID\" : \"RMTEF2-UZXCXE-7YBJK6-KUMSSEME\"
                ,\"firstName\" : \"Maria\",
                ,\"lastName\" : \"Muster\",
                \"gender\" : \"female\"
                \"birthday\" : null
              },
            }
          }
        ]
      }
      SORMAS allows to continue with the registration of a new person only when the person has a unique first name, so when all persons of the response have a different one (or if the response does not contain any matches, which needs to show in PatientDiaryQueryResponse.count == 0). This validation is necessary to avoid confusion of person related data in some external journals.

      When there are no validation errors in the process described above, SORMAS fetches an authentication token as described in 1. and then uses it to request the external journal to register the person:
      POST [interface.patientdiary.probandsurl]/external-data/[personUUID]
      The [personUUID] is replaced with the UUID of the person, which is later used to sync data between the external journal and SORMAS.
      Expected response body:
      {
       \"success\" : [boolean]
       \"message\" : [messageString]
      }
      [boolean] is expected to be true in case of successful registration. SORMAS then sets the symptom journal status to REGISTERED and displays the message to the user.
      When [boolean] is false, the message is shown as an error to the user.
      To fetch data relevent for the registration, the external journal can use the ``/visits-external/person/{personUuid}`` API endpoint described below.

    5. Synchronization of person data changed in SORMAS

    6. It may happen that person data (like a contact detail) gets changed after a person is registered in an external journal. SORMAS notifies external journals about such a change with first fetching an authentication token as descriced in 1., and the using this token for this request:
      PUT [interface.patientdiary.probandsurl]/external-data/[personUUID]
      The external journal is expected to refetch the person data via the ``/visits-external/person/{personUuid}`` API endpoint described below and save the changes.
      After refetching the person data, the symptom journal does its own internal validation and responds to SORMAS with the synchronization result, containing eventual validation errors.The expected response body:
      {
       \"success\" : [boolean]
       \"message\" : [messageString]
       \"errors\" : [
        {[errorKey]:[errorString]}
       ]
      }
      If the changes were done manually by a user from the person edit form, the synchronization result is shown to the user in a popup window, so that the user can fix eventual errors and resynchronize the person data.
    7. Upload of symptom journal data to SORMAS

    8. For this, the ``/visits-external`` API endpoint is to be used. This is described below.

    9. Upload of a symptom journal status to SORMAS

    10. For this, the ``/visits-external/person/{personUuid}/status`` API endpoint is to be used. This is described below.

    11. Opening a person in the external journal from within SORMAS

    12. Once the symptom journal status of a person is set to REGISTERED or ACCEPTED, the external journal button in the SORMAS-UI changes. It does not provide a registration anymore, but the options to open the person in the external journal and to cancel external follow up. This button can be found when having opened a contact (or a case if the case follow up feature is enabled in SORMAS) in the top right corner. If the user choses to open the person in the external journal, SORMAS fetches an authentication token as described in 1. and opens a new browser tab with the following URL:
      [interface.patientdiary.url]/data?q=[personUuid]&queryKey=sicFieldIdentifier&token=[token]
      SORMAS expects the external journal to present a view of the person there.

    13. Deletion of a person from an external journal

    14. As described above, the journal button can offer the option to cancel external follow up. If a user choses this option, SORMAS fetches an authentication token as described in 1., and uses it to request:
      DELETE [interface.patientdiary.probandsurl]/external-data/[personUUID]
      Expected response body:
      {
       \"success\" : [boolean]
       \"message\" : [messageString]
      }
      [boolean] is expected to be true in case of successful deletion. SORMAS then sets the symptom journal status to DELETED and displays the message to the user.
      When [boolean] is false, the message is shown as an error to the user.
      Please note that this does not affect any follow up status. Cancelling follow up of a contact or case is independent from cancelling external follow up of a person.
    It follows a autogenerated description of the relevant API endpoints provided by SORMAS.", + "description" : "The purpose of this API is to enable communication between SORMAS and other symptom journals.
    Only users with the role ``REST_EXTERNAL_VISITS_USER`` are authorized to use the endpoints. Authentication is done using basic auth, with the user and password.
    For technical details please contact the dev team on gitter.

    #### Workflow Description ####

    About external follow up:
    Follow up in SORMAS is done via visits. Visits hold information about symptoms at a specific time point.
    Visits can be created for cases and contacts, either via the SORMAS-UI or the external visits journal API.

    About persons, cases and contacts:
    This is a very basic concept that one needs to understand when working with visits. In SORMAS, a person entity represents a phisically existing person. Cases and contacts represent epidemiological occurrences. When a person was in contact with an infectious environment, the person has a contact in SORMAS. When the person was in contact with such environments twice, it gets two contacts.When a person falls ill, it gets a case with the according disease. This means: In SORMAS, each contact and case relates to exactly one person. One person can have several contacts and cases, though. Follow up is done for a contact (or a case, which can be enabled in the SORMAS feature configuration). Contacts (or cases) initiate follow up. A person, though, either shows symptoms or not. It can not show symptoms for just one contact and not for the other. Thus, visits are related to all active contacts (and cases) of a person. Also the communication with external symptom journals is PERSON BASED. Only the person uuid is used, visits are uploaded to each active case and contact of a person.

    Person status variables:
    It is important to understand the meaning of two variables: the follow up status and the symptom journal status.
    The follow up status describes the follow up for a contact or a case. Possible values are defined in the FollowUpStatus enum. Follow up can be done with, or without an external journal, the follow up status makes no distinction there. Because the follow up status is contact and case specific, but the communication with external journals is person based, SORMAS determines the most important follow up status of all contacts and cases related to the person in question when communicating with external journals. Whenever there is follow up ongoing for any of the persons contacts (and cases if the case follow up feature is enabled in SORMAS), SORMAS will state the FollowUpStatus.FOLLOW_UP for that person towards external journals.
    The SymptomJournalStatus describes the state of a person related to external symptom journals. it is not contact or case specific.

    Configuration in SORMAS
    In the domain folder, there is a sormas.properties. it holds the following values relevant for an external journal:
    ``interface.patientdiary.authurl``: used to fetch an authentication token (see 1. below).
    ``interface.patientdiary.frontendAuthurl``: URL used to retrieve tokens for frontend requests. If not specified, the authurl is used instead.
    ``interface.patientdiary.tokenLifetime``: Lifetime of tokens fetched via the authurl or the frontendAuthurl. To be specified in seconds. Can be set to 0 for no token caching. Defaults to 21600 (6 hrs.).
    ``interface.patientdiary.probandsurl``: used to register new persons in the external journal (see 2. below).
    ``interface.patientdiary.url``: used to open a person in the external journal (see 6. below).
    ``interface.patientdiary.email``: used to authenticate at the external journal (see 1. below).
    ``interface.patientdiary.password``: used to authenticate at the external journal.
    ``interface.patientdiary.defaultuser.username``: This user will be created in SORMAS and can be used by the external journal to authenticate.
    ``interface.patientdiary.defaultuser.password``: The above user's password.
    ``interface.patientdiary.acceptPhoneContact``: used to configure whether the phone number is considered relevant for registering a person in the external journal. It affects the validation of persons in SORMAS (see 2. below). Defaults to true

    1. SORMAS fetching an authentication token from the external journal

    2. POST to the interface.patientdiary.authurl
      Request body:
      {
        \"email\" : [patientdiary.email],
        \"password\" : [patientdiary.password]
      }
      where [patientdiary.email] is replaced with interface.patientdiary.email and [patientdiary.password] with interface.patientdiary.password specified in the sormas.properties
      Expected response body:
      {
        \"success\" : true,
        \"userId\" : [some-user-id],
        \"token\" : [token]
      }
      The token returned will be used to authenticate in other requests. Its lifetime can be configured via the ``interface.patientdiary.tokenLifetime`` property.
      One special scenario is fetching a token for frontend calls (see 6.): When the interface.patientdiary.frontendAuthurl is configured, it is used instead of the interface.patientdiary.authurl here.

    3. Registration of a new person in the external journal

    4. This process involves several steps that are triggered via the REGISTER button a privileged user can see in the top right corner when having opened a case or a contact.
      To be able to see this button, the user must have at least one of the following user roles: national user, contact supervisor, contact officer, community officer,surveillance officer, surveillance supervisor, or admin supervisor.

      First comes a SORMAS-internal validation of contact details. The person to be registered needs to have at least an email address (or a phone number if that is accepted for registration, see ``interface.patientdiary.acceptPhoneContact``) to pass this validation.Also, when there are several email addresses or phone numbers, one of them has to be marked primary contact detail, so that it is clear which contact detail shall be used.

      Then comes an external validation of the contact details. For this, SORMAS fetches an authentication token as in 1. Then it sends a GET request to the following URL for each contact detail to be used in the external journal:
      GET [interface.patientdiary.probandsurl]/probands?q=[URL-encoded-query-parameter-and-value]', with a header like 'x-access-token: [token]'
      The [URL-encoded-query-parameter-and-value] consists of a parameter-value-pair. The parameter is either 'Email' or 'Mobile phone'. The value holds the contact detail to be validated.
      An unencoded example for this is \"Email\" = \"example@example.de\"
      The URL-encoded version is %22Email%22%20%3D%20%22example%40example.de%22
      [token] is replaced with the token fetched for authorization.
      The CURL equivalent for an exemplary call is curl --request GET 'https://probands-URL.com//probands?q=%22Email%22%20%3D%20%22example%40example.de%22' --header 'x-access-token: my-access-token'

      Expected result is a PatientDiaryQueryResponse which information about any person already registered in the external journal and using the same contact detail.
      It needs to be structured as follows:
      ``PatientDiaryQueryResponse`` {
       total   integer
       count   integer
       results   List (``PatientDiaryPersonData``)
      }
      - total should state how many persons are registered in the external journal (this information is currently never used in SORMAS).
      - count should state how many registered persons using the same contact detail were found.
      - results needs to contain a PatientDiaryPersonData for each match:
      ``PatientDiaryPersonData``{
       _id   string
       idatId   ``PatientDiaryIdatId``
      }
      - _id should be a unique identifier for the person this data is about (this information is currently never used in SORMAS)
      The PatientDiaryIdatId needs to be structured as follows:
      ``PatientDiaryIdatId``{
       idat   ``PatientDiaryPersonDto``
      }
      The PatientDiaryPersonDto holds the actual person data:
      ``PatientDiaryPersonDto``{
       personUUID   string
       firstName    string
       lastName    string
       gender     string
       birthday     string
       contactInformation   ``PatientDiaryContactInformation``
       endDate     string
      }
      - personUUID should be the UUID of the person in SORMAS. This UUID is used to sync with external journals (this information is currently never used in SORMAS).
      - firstName and lastName need to hold the first and last name of the person.
      - gender should hold the persons gender (this information is currently never used in SORMAS).
      - birthday should hold the persons birthday (this information is currently never used in SORMAS).
      - contactInformation should hold the contact information of that person, which should for logical reasons always contain (at least) the contact detail provided by SORMAS in the query.
      - endDate should hold the date after which follow up is supposed to be stopped by the external journal.
      ``PatientDiaryIdatId``{
       email   string
       phone   ``PatientDiaryPhone``
      }
      - email should hold the email address for the person
      - phone should hold the phone number of that person:
      ``PatientDiaryPhone``{
       number      string
       internationalNumber   string
       nationalNumber    string
       countryCode    string
       dialCode   string
      }
      To put this all together, here is an example PatientDiaryQueryResponse with one person using the same contact detail:
      {
        \"total\" : 100,
        \"count\" : 1,
        \"results\" : [
          {
            \"_id\" : \"60586691d4c30700119515c8\"
            \"idatId\" : {
              \"idat\" : {
                \"contactInformation\" : {
                  \"phone\" : null,
                  \"email\" : \"example@example.de\"
                },
                \"personUUID\" : \"RMTEF2-UZXCXE-7YBJK6-KUMSSEME\"
                ,\"firstName\" : \"Maria\",
                ,\"lastName\" : \"Muster\",
                \"gender\" : \"female\"
                \"birthday\" : null
              },
            }
          }
        ]
      }
      SORMAS allows to continue with the registration of a new person only when the person has a unique first name, so when all persons of the response have a different one (or if the response does not contain any matches, which needs to show in PatientDiaryQueryResponse.count == 0). This validation is necessary to avoid confusion of person related data in some external journals.

      When there are no validation errors in the process described above, SORMAS fetches an authentication token as described in 1. and then uses it to request the external journal to register the person:
      POST [interface.patientdiary.probandsurl]/external-data/[personUUID]
      The [personUUID] is replaced with the UUID of the person, which is later used to sync data between the external journal and SORMAS.
      Expected response body:
      {
       \"success\" : [boolean]
       \"message\" : [messageString]
      }
      [boolean] is expected to be true in case of successful registration. SORMAS then sets the symptom journal status to REGISTERED and displays the message to the user.
      When [boolean] is false, the message is shown as an error to the user.
      To fetch data relevent for the registration, the external journal can use the ``/visits-external/person/{personUuid}`` API endpoint described below.

    5. Synchronization of person data changed in SORMAS

    6. It may happen that person data (like a contact detail) gets changed after a person is registered in an external journal. SORMAS notifies external journals about such a change with first fetching an authentication token as descriced in 1., and the using this token for this request:
      PUT [interface.patientdiary.probandsurl]/external-data/[personUUID]
      The external journal is expected to refetch the person data via the ``/visits-external/person/{personUuid}`` API endpoint described below and save the changes.
      After refetching the person data, the symptom journal does its own internal validation and responds to SORMAS with the synchronization result, containing eventual validation errors.The expected response body:
      {
       \"success\" : [boolean]
       \"message\" : [messageString]
       \"errors\" : [
        {[errorKey]:[errorString]}
       ]
      }
      If the changes were done manually by a user from the person edit form, the synchronization result is shown to the user in a popup window, so that the user can fix eventual errors and resynchronize the person data.
    7. Upload of symptom journal data to SORMAS

    8. For this, the ``/visits-external`` API endpoint is to be used. This is described below.

    9. Upload of a symptom journal status to SORMAS

    10. For this, the ``/visits-external/person/{personUuid}/status`` API endpoint is to be used. This is described below.

    11. Opening a person in the external journal from within SORMAS

    12. Once the symptom journal status of a person is set to REGISTERED or ACCEPTED, the external journal button in the SORMAS-UI changes. It does not provide a registration anymore, but the options to open the person in the external journal and to cancel external follow up. This button can be found when having opened a contact (or a case if the case follow up feature is enabled in SORMAS) in the top right corner. If the user chooses to open the person in the external journal, SORMAS fetches an authentication token as described in 1 (using the interface.patientdiary.frontendAuthurl if configured), and opens a new browser tab with the following URL:
      [interface.patientdiary.url]/data?q=[personUuid]&queryKey=sicFieldIdentifier&token=[token]
      SORMAS expects the external journal to present a view of the person there.

    13. Deletion of a person from an external journal

    14. As described above, the journal button can offer the option to cancel external follow up. If a user choses this option, SORMAS fetches an authentication token as described in 1., and uses it to request:
      DELETE [interface.patientdiary.probandsurl]/external-data/[personUUID]
      Expected response body:
      {
       \"success\" : [boolean]
       \"message\" : [messageString]
      }
      [boolean] is expected to be true in case of successful deletion. SORMAS then sets the symptom journal status to DELETED and displays the message to the user.
      When [boolean] is false, the message is shown as an error to the user.
      Please note that this does not affect any follow up status. Cancelling follow up of a contact or case is independent from cancelling external follow up of a person.
    It follows a autogenerated description of the relevant API endpoints provided by SORMAS.", "version" : "1.41.1" }, "servers" : [ { diff --git a/openapi/external_visits_API.yaml b/openapi/external_visits_API.yaml index 621206a84f8..343ce32f0c2 100644 --- a/openapi/external_visits_API.yaml +++ b/openapi/external_visits_API.yaml @@ -41,7 +41,11 @@ info: \ symptom journals. it is not contact or case specific.

    Configuration\ \ in SORMAS
    In the domain folder, there is a sormas.properties. it holds\ \ the following values relevant for an external journal:
    ``interface.patientdiary.authurl``:\ - \ used to fetch an authentication token (see 1. below).
    ``interface.patientdiary.probandsurl``:\ + \ used to fetch an authentication token (see 1. below).
    ``interface.patientdiary.frontendAuthurl``:\ + \ URL used to retrieve tokens for frontend requests. If not specified, the authurl\ + \ is used instead.
    ``interface.patientdiary.tokenLifetime``: Lifetime of tokens\ + \ fetched via the authurl or the frontendAuthurl. To be specified in seconds.\ + \ Can be set to 0 for no token caching. Defaults to 21600 (6 hrs.).
    ``interface.patientdiary.probandsurl``:\ \ used to register new persons in the external journal (see 2. below).
    ``interface.patientdiary.url``:\ \ used to open a person in the external journal (see 6. below).
    ``interface.patientdiary.email``:\ \ used to authenticate at the external journal (see 1. below).
    ``interface.patientdiary.password``:\ @@ -59,21 +63,25 @@ info: \ specified in the sormas.properties
    Expected response body:
    {
      \"\ success\" : true,
      \"userId\" : [some-user-id],
      \"\ token\" : [token]
    }
    The token returned will be used to authenticate in other\ - \ requests.

  • Registration of a new person in the external journal

  • This\ - \ process involves several steps that are triggered via the REGISTER button a\ - \ privileged user can see in the top right corner when having opened a case or\ - \ a contact.
    To be able to see this button, the user must have at least one\ - \ of the following user roles: national user, contact supervisor, contact officer,\ - \ community officer,surveillance officer, surveillance supervisor, or admin supervisor.

    First\ - \ comes a SORMAS-internal validation of contact details. The person to be registered\ - \ needs to have at least an email address (or a phone number if that is accepted\ - \ for registration, see ``interface.patientdiary.acceptPhoneContact``) to pass\ - \ this validation.Also, when there are several email addresses or phone numbers,\ - \ one of them has to be marked primary contact detail, so that it is clear which\ - \ contact detail shall be used.

    Then comes an external validation of the\ - \ contact details. For this, SORMAS fetches an authentication token as in 1. Then\ - \ it sends a GET request to the following URL for each contact detail to be used\ - \ in the external journal:
    GET [interface.patientdiary.probandsurl]/probands?q=[URL-encoded-query-parameter-and-value]',\ + \ requests. Its lifetime can be configured via the ``interface.patientdiary.tokenLifetime``\ + \ property.
    One special scenario is fetching a token for frontend calls (see\ + \ 6.): When the interface.patientdiary.frontendAuthurl is configured, it is used\ + \ instead of the interface.patientdiary.authurl here.

  • Registration\ + \ of a new person in the external journal

  • This process involves several\ + \ steps that are triggered via the REGISTER button a privileged user can see in\ + \ the top right corner when having opened a case or a contact.
    To be able to\ + \ see this button, the user must have at least one of the following user roles:\ + \ national user, contact supervisor, contact officer, community officer,surveillance\ + \ officer, surveillance supervisor, or admin supervisor.

    First comes a\ + \ SORMAS-internal validation of contact details. The person to be registered needs\ + \ to have at least an email address (or a phone number if that is accepted for\ + \ registration, see ``interface.patientdiary.acceptPhoneContact``) to pass this\ + \ validation.Also, when there are several email addresses or phone numbers, one\ + \ of them has to be marked primary contact detail, so that it is clear which contact\ + \ detail shall be used.

    Then comes an external validation of the contact\ + \ details. For this, SORMAS fetches an authentication token as in 1. Then it sends\ + \ a GET request to the following URL for each contact detail to be used in the\ + \ external journal:
    GET [interface.patientdiary.probandsurl]/probands?q=[URL-encoded-query-parameter-and-value]',\ \ with a header like 'x-access-token: [token]'
    The [URL-encoded-query-parameter-and-value]\ \ consists of a parameter-value-pair. The parameter is either 'Email' or 'Mobile\ \ phone'. The value holds the contact detail to be validated.
    An unencoded\ @@ -159,9 +167,9 @@ info: \ but the options to open the person in the external journal and to cancel external\ \ follow up. This button can be found when having opened a contact (or a case\ \ if the case follow up feature is enabled in SORMAS) in the top right corner.\ - \ If the user choses to open the person in the external journal, SORMAS fetches\ - \ an authentication token as described in 1. and opens a new browser tab with\ - \ the following URL:
    [interface.patientdiary.url]/data?q=[personUuid]&queryKey=sicFieldIdentifier&token=[token]
    SORMAS\ + \ If the user chooses to open the person in the external journal, SORMAS fetches\ + \ an authentication token as described in 1 (using the interface.patientdiary.frontendAuthurl\ + \ if configured), and opens a new browser tab with the following URL:
    [interface.patientdiary.url]/data?q=[personUuid]&queryKey=sicFieldIdentifier&token=[token]
    SORMAS\ \ expects the external journal to present a view of the person there.

  • Deletion\ \ of a person from an external journal

  • As described above, the journal\ \ button can offer the option to cancel external follow up. If a user choses this\ From 093bdcfb4514ed15dc4fe8aefefc9972caa950c0 Mon Sep 17 00:00:00 2001 From: Stefan Kock Date: Thu, 17 Feb 2022 08:02:13 +0100 Subject: [PATCH 103/253] #7978: False positives suppessed: apache-mime4j, netty-tcnative-classes --- .../dependencies/check-suppressions.xml | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/sormas-base/dependencies/check-suppressions.xml b/sormas-base/dependencies/check-suppressions.xml index 04503e85e3c..5e119e384b4 100644 --- a/sormas-base/dependencies/check-suppressions.xml +++ b/sormas-base/dependencies/check-suppressions.xml @@ -86,6 +86,33 @@ .*\betcd-java.*\.jar CVE-2020-15113 + + + .*\bapache-mime4j.*\.jar + CVE-2021-38542 + CVE-2021-40110 + CVE-2021-40111 + CVE-2021-40525 + + + + .*\bnetty-tcnative-classes.*\.jar + CVE-2014-3488 + CVE-2015-2156 + CVE-2019-16869 + CVE-2019-20444 + CVE-2019-20445 + CVE-2021-21290 + CVE-2021-21295 + CVE-2021-21409 + CVE-2021-37136 + CVE-2021-37137 + CVE-2021-43797 + From 3c7eae3c3156cc56c69ae09ec51b41fb8d9657aa Mon Sep 17 00:00:00 2001 From: Stefan Kock Date: Thu, 17 Feb 2022 08:13:45 +0100 Subject: [PATCH 104/253] #7978: Refactoring: False positives clustered by filename --- .../dependencies/check-suppressions.xml | 54 ++++++++----------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/sormas-base/dependencies/check-suppressions.xml b/sormas-base/dependencies/check-suppressions.xml index 5e119e384b4..c037e01285a 100644 --- a/sormas-base/dependencies/check-suppressions.xml +++ b/sormas-base/dependencies/check-suppressions.xml @@ -25,10 +25,12 @@ .*\bkeycloak-.*\.jar - CVE-2017-12161 + CVE-2017-12161 + CVE-2018-10912 + CVE-2020-1728 .*\betcd-java.*\.jar - CVE-2020-15106 - - - - .*\betcd-java.*\.jar - CVE-2020-15112 - - - - .*\betcd-java.*\.jar - CVE-2020-15113 + CVE-2020-15106 + CVE-2020-15112 + CVE-2020-15113 .*\bapache-mime4j.*\.jar - CVE-2021-38542 - CVE-2021-40110 - CVE-2021-40111 - CVE-2021-40525 + CVE-2021-38542 + CVE-2021-40110 + CVE-2021-40111 + CVE-2021-40525 .*\bnetty-tcnative-classes.*\.jar - CVE-2014-3488 - CVE-2015-2156 - CVE-2019-16869 - CVE-2019-20444 - CVE-2019-20445 - CVE-2021-21290 - CVE-2021-21295 - CVE-2021-21409 - CVE-2021-37136 - CVE-2021-37137 - CVE-2021-43797 + CVE-2014-3488 + CVE-2015-2156 + CVE-2019-16869 + CVE-2019-20444 + CVE-2019-20445 + CVE-2021-21290 + CVE-2021-21295 + CVE-2021-21409 + CVE-2021-37136 + CVE-2021-37137 + CVE-2021-43797 From 588adf6bc67dd2fad2acded140651bf57049f801 Mon Sep 17 00:00:00 2001 From: syntakker Date: Wed, 16 Feb 2022 18:16:55 +0100 Subject: [PATCH 105/253] remove freemarker dependency #7978 --- sormas-backend/pom.xml | 5 ----- sormas-base/pom.xml | 6 ------ 2 files changed, 11 deletions(-) diff --git a/sormas-backend/pom.xml b/sormas-backend/pom.xml index f0a84285dae..5c9d1ba51c4 100644 --- a/sormas-backend/pom.xml +++ b/sormas-backend/pom.xml @@ -94,11 +94,6 @@ docx4j-JAXB-ReferenceImpl - - org.freemarker - freemarker - - diff --git a/sormas-base/pom.xml b/sormas-base/pom.xml index 44ad19bc613..6f9227db30f 100644 --- a/sormas-base/pom.xml +++ b/sormas-base/pom.xml @@ -630,12 +630,6 @@ ${docx4j.version} - - org.freemarker - freemarker - 2.3.31 - - org.geotools gt-shapefile From 25098dd47474da39bbb38ce015f6108c5cb78d9b Mon Sep 17 00:00:00 2001 From: Stefan Kock Date: Thu, 17 Feb 2022 09:28:56 +0100 Subject: [PATCH 106/253] #7978: Updated xmlgraphics (fop, commons) - fop-events 2.6 -> 2.7 - xmlgraphics-commons 2.4 -> 2.7 --- sormas-base/pom.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sormas-base/pom.xml b/sormas-base/pom.xml index 6f9227db30f..6d33d802dee 100644 --- a/sormas-base/pom.xml +++ b/sormas-base/pom.xml @@ -443,6 +443,17 @@ provided + + org.apache.xmlgraphics + fop-events + 2.7 + + + org.apache.xmlgraphics + xmlgraphics-commons + 2.7 + + org.bouncycastle bcpkix-jdk15on From ee97977ee08ae594809e53c8c41c76e0c9c6b463 Mon Sep 17 00:00:00 2001 From: Levente Gal <62599627+leventegal-she@users.noreply.github.com> Date: Thu, 17 Feb 2022 15:12:04 +0200 Subject: [PATCH 107/253] #7792 Make tile server used for map configurable (#7963) --- .../java/de/symeda/sormas/api/ConfigFacade.java | 4 ++++ .../sormas/backend/common/ConfigFacadeEjb.java | 12 ++++++++++++ sormas-base/setup/sormas.properties | 7 +++++++ .../java/de/symeda/sormas/ui/map/LeafletMap.java | 14 +++++++++++--- .../main/webapp/VAADIN/map/leaflet-connector.js | 9 +++++++++ 5 files changed, 43 insertions(+), 3 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/ConfigFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/ConfigFacade.java index 9351b4b6048..c0fdb461109 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/ConfigFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/ConfigFacade.java @@ -100,6 +100,10 @@ public interface ConfigFacade { boolean isMapUseCountryCenter(); + String getMapTilersUrl(); + + String getMapTilersAttribution(); + int getMapZoom(); String getGeocodingServiceUrlTemplate(); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ConfigFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ConfigFacadeEjb.java index 4733a346aae..4da5b1ebd4d 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ConfigFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ConfigFacadeEjb.java @@ -64,6 +64,8 @@ public class ConfigFacadeEjb implements ConfigFacade { private static final String COUNTRY_CENTER_LAT = "country.center.latitude"; private static final String COUNTRY_CENTER_LON = "country.center.longitude"; private static final String MAP_USE_COUNTRY_CENTER = "map.usecountrycenter"; + private static final String MAP_TILES_URL = "map.tiles.url"; + private static final String MAP_TILES_ATTRIBUTION = "map.tiles.attribution"; private static final String MAP_ZOOM = "map.zoom"; public static final String VERSION_PLACEHOLER = "%version"; @@ -291,6 +293,16 @@ public boolean isMapUseCountryCenter() { return getBoolean(MAP_USE_COUNTRY_CENTER, false); } + @Override + public String getMapTilersUrl() { + return getProperty(MAP_TILES_URL, null); + } + + @Override + public String getMapTilersAttribution() { + return getProperty(MAP_TILES_ATTRIBUTION, null); + } + @Override public int getMapZoom() { return getInt(MAP_ZOOM, 1); diff --git a/sormas-base/setup/sormas.properties b/sormas-base/setup/sormas.properties index 7a494061642..9e212e946ff 100644 --- a/sormas-base/setup/sormas.properties +++ b/sormas-base/setup/sormas.properties @@ -50,6 +50,13 @@ country.center.longitude=0 # Default: 1 #map.zoom=1 +# Tileset of the map +# Example: https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png +map.tiles.url= +# Attribution of the tileset, required for tiles from OpenStreatMap @see https://www.openstreetmap.org/copyright +# Example: © OpenStreetMap contributors +map.tiles.attribution= + # The character used in .csv files to separate columns from each other. Should match the separator that is commonly used in the locale specified in country.locale. # Default: , # Examples: , or ; - you can use \u0020 for a whitespace or \u0009 for a horizontal tab diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/map/LeafletMap.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/map/LeafletMap.java index da4f9debbcc..5c52d76df00 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/map/LeafletMap.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/map/LeafletMap.java @@ -22,6 +22,10 @@ import java.util.EventObject; import java.util.List; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.vaadin.annotations.JavaScript; import com.vaadin.annotations.StyleSheet; import com.vaadin.ui.AbstractJavaScriptComponent; @@ -32,8 +36,6 @@ import de.symeda.sormas.api.geo.GeoLatLon; import elemental.json.Json; import elemental.json.JsonArray; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * JS and CSS files are in the VAADIN folder, so we can also access required @@ -75,6 +77,13 @@ public LeafletMap() { getState().setTileLayerVisible(true); getState().setTileLayerOpacity(1); + String tilesUrl = FacadeProvider.getConfigFacade().getMapTilersUrl(); + if(StringUtils.isNoneBlank(tilesUrl)) { + callFunction( + "setTileLayer", + tilesUrl, + FacadeProvider.getConfigFacade().getMapTilersAttribution()); + } addFunction("onClick", new JavaScriptFunction() { @Override @@ -87,7 +96,6 @@ public void call(JsonArray arguments) { // credit where credit's due String attribution = FacadeProvider.getGeoShapeProvider().loadShapefileAttributions(); this.addShapefileAttribution(attribution); - } /** diff --git a/sormas-ui/src/main/webapp/VAADIN/map/leaflet-connector.js b/sormas-ui/src/main/webapp/VAADIN/map/leaflet-connector.js index 06b613c5a27..fd05b51f233 100644 --- a/sormas-ui/src/main/webapp/VAADIN/map/leaflet-connector.js +++ b/sormas-ui/src/main/webapp/VAADIN/map/leaflet-connector.js @@ -74,6 +74,15 @@ window.de_symeda_sormas_ui_map_LeafletMap = function () { attribution: '© OpenStreetMap contributors. Tiles courtesy of Humanitarian OpenStreetMap Team' }); + this.setTileLayer = function(layerUri, attribution){ + openStreetMapsLayer.remove(); + openStreetMapsLayer = L.tileLayer(layerUri, { + attribution: attribution + }); + + this.onStateChange(); + } + this.onStateChange = function () { map.setView([this.getState().centerLatitude, this.getState().centerLongitude], this.getState().zoom); From b8c60d06a5a16a65a19275838354337fded2b848 Mon Sep 17 00:00:00 2001 From: FredrikSchaeferVitagroup <67001822+FredrikSchaeferVitagroup@users.noreply.github.com> Date: Thu, 17 Feb 2022 14:30:22 +0100 Subject: [PATCH 108/253] Bug 7958 hide 'national health id' field in german systems (#8038) * #7958 simplify field name * #7958 add missing annotation --- .../sormas/api/event/EventParticipantExportDto.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventParticipantExportDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventParticipantExportDto.java index 251018e46a7..f0206d3c90f 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventParticipantExportDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventParticipantExportDto.java @@ -47,6 +47,7 @@ import de.symeda.sormas.api.person.PresentCondition; import de.symeda.sormas.api.person.Salutation; import de.symeda.sormas.api.person.Sex; +import de.symeda.sormas.api.utils.HideForCountries; import de.symeda.sormas.api.utils.HideForCountriesExcept; import de.symeda.sormas.api.utils.Order; import de.symeda.sormas.api.utils.PersonalData; @@ -116,7 +117,7 @@ public class EventParticipantExportDto implements Serializable { private String approximateAge; private String ageGroup; private BirthDateDto birthdate; - private String personNationalHealthId; + private String nationalHealthId; private PresentCondition presentCondition; private Date deathDate; @@ -176,7 +177,7 @@ public class EventParticipantExportDto implements Serializable { private long contactCount; //@formatter:off - public EventParticipantExportDto(long id, long personId, String personUuid, String eventParticipantUuid, String personNationalHealthId, long personAddressId, boolean isInJurisdiction, String eventUuid, + public EventParticipantExportDto(long id, long personId, String personUuid, String eventParticipantUuid, String nationalHealthId, long personAddressId, boolean isInJurisdiction, String eventUuid, EventStatus eventStatus, EventInvestigationStatus eventInvestigationStatus, Disease eventDisease, TypeOfPlace typeOfPlace, Date eventStartDate, Date eventEndDate, String eventTitle, String eventDesc, String eventRegion, String eventDistrict, String eventCommunity, String eventCity, String eventStreet, String eventHouseNumber, @@ -193,7 +194,7 @@ public EventParticipantExportDto(long id, long personId, String personUuid, Stri this.personId = personId; this.personUuid = personUuid; this.eventParticipantUuid = eventParticipantUuid; - this.personNationalHealthId = personNationalHealthId; + this.nationalHealthId = nationalHealthId; this.personAddressId = personAddressId; this.eventUuid = eventUuid; @@ -283,8 +284,9 @@ public String getPersonUuid() { EventParticipantDto.PERSON, PersonDto.NATIONAL_HEALTH_ID }) @ExportGroup(ExportGroupType.PERSON) - public String getPersonNationalHealthId() { - return personNationalHealthId; + @HideForCountries + public String getNationalHealthId() { + return nationalHealthId; } @Order(12) From edb61b93983757eda4e35baaaa88fe1410e3dcb8 Mon Sep 17 00:00:00 2001 From: syntakker Date: Thu, 17 Feb 2022 21:26:32 +0100 Subject: [PATCH 109/253] reset place of stay on discard #7783 --- .../symeda/sormas/ui/caze/CaseDataForm.java | 65 ++++++++++++------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java index d5247b8ef18..768cc1a0434 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java @@ -302,6 +302,7 @@ public class CaseDataForm extends AbstractEditForm { private ComboBox facilityTypeGroup; private ComboBox facilityTypeCombo; private ComboBox facilityCombo; + private TextField facilityDetails; private boolean quarantineChangedByFollowUpUntilChange = false; private TextField tfExpectedFollowUpUntilDate; private boolean ignoreDifferentPlaceOfStayJurisdiction = false; @@ -803,7 +804,7 @@ protected void addFields() { facilityTypeCombo = addField(CaseDataDto.FACILITY_TYPE); facilityCombo = addInfrastructureField(CaseDataDto.HEALTH_FACILITY); facilityCombo.setImmediate(true); - TextField facilityDetails = addField(CaseDataDto.HEALTH_FACILITY_DETAILS, TextField.class); + facilityDetails = addField(CaseDataDto.HEALTH_FACILITY_DETAILS, TextField.class); facilityDetails.setVisible(false); regionCombo.addValueChangeListener(e -> { @@ -1291,29 +1292,7 @@ protected void addFields() { externalTokenWarningLabel, (externalToken) -> FacadeProvider.getCaseFacade().doesExternalTokenExist(externalToken, getValue().getUuid())); - if (getValue().getHealthFacility() != null) { - boolean facilityOrHomeReadOnly = facilityOrHome.isReadOnly(); - boolean facilityTypeGroupReadOnly = facilityTypeGroup.isReadOnly(); - facilityOrHome.setReadOnly(false); - facilityTypeGroup.setReadOnly(false); - boolean noneHealthFacility = getValue().getHealthFacility().getUuid().equals(FacilityDto.NONE_FACILITY_UUID); - - FacilityType caseFacilityType = getValue().getFacilityType(); - if (noneHealthFacility || caseFacilityType == null) { - facilityOrHome.setValue(TypeOfPlace.HOME); - } else { - facilityOrHome.setValue(TypeOfPlace.FACILITY); - facilityTypeGroup.setValue(caseFacilityType.getFacilityTypeGroup()); - if (!facilityTypeCombo.isReadOnly()) { - facilityTypeCombo.setValue(caseFacilityType); - } - } - - facilityOrHome.setReadOnly(facilityOrHomeReadOnly); - facilityTypeGroup.setReadOnly(facilityTypeGroupReadOnly); - } else { - facilityOrHome.setVisible(false); - } + updateFacilityOrHome(); // Set health facility/point of entry visibility based on case origin if (getValue().getCaseOrigin() == CaseOrigin.POINT_OF_ENTRY) { @@ -1421,6 +1400,32 @@ public String getFormattedHtmlMessage() { }); } + private void updateFacilityOrHome() { + if (getValue().getHealthFacility() != null) { + boolean facilityOrHomeReadOnly = facilityOrHome.isReadOnly(); + boolean facilityTypeGroupReadOnly = facilityTypeGroup.isReadOnly(); + facilityOrHome.setReadOnly(false); + facilityTypeGroup.setReadOnly(false); + boolean noneHealthFacility = getValue().getHealthFacility().getUuid().equals(FacilityDto.NONE_FACILITY_UUID); + + FacilityType caseFacilityType = getValue().getFacilityType(); + if (noneHealthFacility || caseFacilityType == null) { + facilityOrHome.setValue(TypeOfPlace.HOME); + } else { + facilityOrHome.setValue(TypeOfPlace.FACILITY); + facilityTypeGroup.setValue(caseFacilityType.getFacilityTypeGroup()); + if (!facilityTypeCombo.isReadOnly()) { + facilityTypeCombo.setValue(caseFacilityType); + } + } + + facilityOrHome.setReadOnly(facilityOrHomeReadOnly); + facilityTypeGroup.setReadOnly(facilityTypeGroupReadOnly); + } else { + facilityOrHome.setVisible(false); + } + } + private boolean diseaseClassificationExists() { DiseaseClassificationCriteriaDto diseaseClassificationCriteria = FacadeProvider.getCaseClassificationFacade().getByDisease(disease); return disease != Disease.OTHER && diseaseClassificationCriteria != null; @@ -1678,6 +1683,17 @@ public void onDiscard() { ignoreDifferentPlaceOfStayJurisdiction = true; updateVisibilityDifferentPlaceOfStayJurisdiction(getValue()); ignoreDifferentPlaceOfStayJurisdiction = false; + FacilityReferenceDto healthFacility = getValue().getHealthFacility(); + String healthFacilityDetails = getValue().getHealthFacilityDetails(); + updateFacilityOrHome(); + boolean readOnlyFacility = facilityCombo.isReadOnly(); + boolean readOnlyFacilityDetails = facilityDetails.isReadOnly(); + facilityCombo.setReadOnly(false); + facilityDetails.setReadOnly(false); + facilityCombo.setValue(healthFacility); + facilityDetails.setValue(healthFacilityDetails); + facilityCombo.setReadOnly(readOnlyFacility); + facilityDetails.setReadOnly(readOnlyFacilityDetails); } private void updateVisibilityDifferentPlaceOfStayJurisdiction(CaseDataDto newFieldValue) { @@ -1714,7 +1730,6 @@ private void updateFacility() { FacadeProvider.getFacilityFacade().getActiveFacilitiesByDistrictAndType(district, facilityType, true, false)); } else { FieldHelper.removeItems(facilityCombo); - } } else { if (TypeOfPlace.HOME.equals(facilityOrHome.getValue())) { From 9049090cb20d39d0007102b906aaee28361f22ab Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 18 Feb 2022 08:23:49 +0200 Subject: [PATCH 110/253] #6822 Automatically check history tables (#8041) * #6822 Setup test container * #6822 Run checkHistoryTables against the testcontainer * #6822 Cleanup * #6822 Fix lint issue * #6822 Fix lint warning * #6822 Make file executable * #6822 Fix linting issue * #6822 Apply review remarks * #6822 Fix lint warnings * #6822 Uncomment code --- sormas-backend/pom.xml | 5 + .../common/StartupShutdownServiceTest.java | 155 +++++++++++++++--- .../test/resources}/checkHistoryTables.sql | 4 +- .../test/resources/testcontainers/Dockerfile | 10 ++ .../testcontainers/setup_sormas_db.sh | 31 ++++ sormas-base/pom.xml | 7 + 6 files changed, 188 insertions(+), 24 deletions(-) rename sormas-backend/{utils => src/test/resources}/checkHistoryTables.sql (91%) create mode 100644 sormas-backend/src/test/resources/testcontainers/Dockerfile create mode 100644 sormas-backend/src/test/resources/testcontainers/setup_sormas_db.sh diff --git a/sormas-backend/pom.xml b/sormas-backend/pom.xml index 5c9d1ba51c4..48b45586014 100644 --- a/sormas-backend/pom.xml +++ b/sormas-backend/pom.xml @@ -232,6 +232,11 @@ javaee-web-api test + + org.testcontainers + postgresql + test + diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/common/StartupShutdownServiceTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/common/StartupShutdownServiceTest.java index 375bf6a46da..c530fd0a3a0 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/common/StartupShutdownServiceTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/common/StartupShutdownServiceTest.java @@ -1,25 +1,45 @@ package de.symeda.sormas.backend.common; +import static java.time.temporal.ChronoUnit.SECONDS; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.testcontainers.containers.PostgreSQLContainer.POSTGRESQL_PORT; import java.io.IOException; import java.io.InputStream; +import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.time.Duration; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.Scanner; import java.util.stream.Collectors; +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; + +import org.apache.commons.collections.CollectionUtils; import org.hamcrest.Matchers; import org.junit.Test; +import org.testcontainers.containers.JdbcDatabaseContainer; +import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; +import org.testcontainers.images.builder.ImageFromDockerfile; + +import info.novatec.beantest.api.BaseBeanTest; -public class StartupShutdownServiceTest { +public class StartupShutdownServiceTest extends BaseBeanTest { - private String[] supportedDatabaseVersions = new String[] { + private final String[] SUPPORTED_DATABASE_VERSIONS = new String[] { "9.5", "9.5.25", "9.6.5", @@ -27,7 +47,7 @@ public class StartupShutdownServiceTest { "10.1", "10.14 (Ubuntu 10.14-1.pgdg20.04+1)" }; - private String[] unsupportedDatabaseVersions = new String[] { + private final String[] UNSUPPORTED_DATABASE_VERSIONS = new String[] { "8.4", "8.4.22", "9.1", @@ -36,13 +56,13 @@ public class StartupShutdownServiceTest { @Test public void testIsSupportedDatabaseVersion() { - for (String version : supportedDatabaseVersions) { + for (String version : SUPPORTED_DATABASE_VERSIONS) { assertTrue( String.format("Supported version not recognized correctly: '%s'", version), StartupShutdownService.isSupportedDatabaseVersion(version)); } - for (String version : unsupportedDatabaseVersions) { + for (String version : UNSUPPORTED_DATABASE_VERSIONS) { assertFalse( String.format("Unsupported version not recognized correctly: '%s'", version), StartupShutdownService.isSupportedDatabaseVersion(version)); @@ -94,39 +114,130 @@ public void testAuditSchemaVersions() throws IOException { assertContinuousSchemaVersions(StartupShutdownService.AUDIT_SCHEMA); } + @Test + public void testHistoryTablesMatch() throws IOException, URISyntaxException { + + SormasPostgresSQLContainer container = new SormasPostgresSQLContainer().withDatabaseName("sormas"); + container.start(); + + Map properties = new HashMap<>(); + properties.put("javax.persistence.jdbc.url", container.getJdbcUrl()); + properties.put("javax.persistence.jdbc.user", container.getUsername()); + properties.put("javax.persistence.jdbc.password", container.getPassword()); + properties.put("javax.persistence.jdbc.driver", container.getDriverClassName()); + properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQL94Dialect"); + properties.put("hibernate.transaction.jta.platform", "org.hibernate.service.jta.platform.internal.SunOneJtaPlatform"); + properties.put("hibernate.jdbc.batch_size", "100"); + properties.put("hibernate.order_inserts", "true"); + properties.put("hibernate.order_updates", "true"); + + EntityManagerFactory emf = Persistence.createEntityManagerFactory("beanTestPU", properties); + EntityManager em = emf.createEntityManager(); + + String checkHistoryTablesSql = new String( + Files.readAllBytes(Paths.get(Objects.requireNonNull(getClass().getClassLoader().getResource("checkHistoryTables.sql")).toURI()))); + @SuppressWarnings("unchecked") + List results = (List) em.createNativeQuery(checkHistoryTablesSql).getResultList(); + assertTrue(CollectionUtils.isEmpty(results)); + + } + /** * Checks that the order of the updates is correct - * + * * @param schemaResource + * {@link StartupShutdownService#SORMAS_SCHEMA} or {@link StartupShutdownService#AUDIT_SCHEMA} * @param omittedVersions - * @throws IOException + * versions to skip */ private void assertContinuousSchemaVersions(String schemaResource, int... omittedVersions) throws IOException { - Collection omittedVersionsList = Arrays.stream(omittedVersions).mapToObj(i -> i).collect(Collectors.toSet()); + Collection omittedVersionsList = Arrays.stream(omittedVersions).boxed().collect(Collectors.toSet()); - try (InputStream schemaStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(schemaResource); - Scanner scanner = new Scanner(schemaStream, StandardCharsets.UTF_8.name())) { + try (InputStream schemaStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(schemaResource)) { + try (Scanner scanner = new Scanner(Objects.requireNonNull(schemaStream), StandardCharsets.UTF_8.name())) { - int currentVersion = 0; + int currentVersion = 0; - while (scanner.hasNextLine()) { - String nextLine = scanner.nextLine(); + while (scanner.hasNextLine()) { + String nextLine = scanner.nextLine(); - Integer nextVersion = StartupShutdownService.extractSchemaVersion(nextLine); - if (nextVersion != null) { + Integer nextVersion = StartupShutdownService.extractSchemaVersion(nextLine); + if (nextVersion != null) { - assertThat(nextVersion, Matchers.greaterThan(currentVersion)); + assertThat(nextVersion, Matchers.greaterThan(currentVersion)); - for (int v = currentVersion + 1; v < nextVersion; v++) { - assertThat( - "Missing version: " + v + " ( found " + nextVersion + " after " + currentVersion + ")", - omittedVersionsList.contains(v)); - } + for (int v = currentVersion + 1; v < nextVersion; v++) { + assertTrue( + "Missing version: " + v + " ( found " + nextVersion + " after " + currentVersion + ")", + omittedVersionsList.contains(v)); + } - currentVersion = nextVersion; + currentVersion = nextVersion; + } } } } } + + public static class SormasPostgresSQLContainer extends JdbcDatabaseContainer { + + private String databaseName; + + public SormasPostgresSQLContainer() { + super( + new ImageFromDockerfile().withFileFromClasspath("setup_sormas_db.sh", "testcontainers/setup_sormas_db.sh") + .withFileFromClasspath("sormas_schema.sql", "sql/sormas_schema.sql") + .withFileFromClasspath("Dockerfile", "testcontainers/Dockerfile")); + this.waitStrategy = new LogMessageWaitStrategy().withRegEx(".*database system is ready to accept connections.*\\s") + .withTimes(2) + .withStartupTimeout(Duration.of(60, SECONDS)); + addExposedPort(POSTGRESQL_PORT); + withEnv("POSTGRES_USER", getUsername()); + withEnv("POSTGRES_PASSWORD", getPassword()); + } + + @Override + public String getDriverClassName() { + return "org.postgresql.Driver"; + } + + @Override + public String getJdbcUrl() { + String additionalUrlParams = constructUrlParameters("?", "&"); + return "jdbc:postgresql://" + getContainerIpAddress() + ":" + getMappedPort(POSTGRESQL_PORT) + "/" + getDatabaseName() + + additionalUrlParams; + } + + @Override + public SormasPostgresSQLContainer withDatabaseName(String dbName) { + this.databaseName = dbName; + return self(); + } + + @Override + public String getDatabaseName() { + return databaseName; + } + + @Override + public String getUsername() { + return "sormas_user"; + } + + @Override + public String getPassword() { + return "password"; + } + + @Override + protected String getTestQueryString() { + return "SELECT 1"; + } + + @Override + protected void waitUntilContainerStarted() { + getWaitStrategy().waitUntilReady(this); + } + } } diff --git a/sormas-backend/utils/checkHistoryTables.sql b/sormas-backend/src/test/resources/checkHistoryTables.sql similarity index 91% rename from sormas-backend/utils/checkHistoryTables.sql rename to sormas-backend/src/test/resources/checkHistoryTables.sql index 703c013af2f..e5d14b81755 100644 --- a/sormas-backend/utils/checkHistoryTables.sql +++ b/sormas-backend/src/test/resources/checkHistoryTables.sql @@ -17,7 +17,7 @@ SELECT 'missing column' as remark, concat(c.table_name, '_history') as table_name, c.column_name as column_name, c.data_type as data_type FROM information_schema."columns" c LEFT OUTER JOIN information_schema."columns" c_hist ON concat(c.table_name, '_history') = c_hist.table_name AND c.column_name = c_hist.column_name -WHERE c.table_schema = 'public' AND c.table_name NOT LIKE '%_history' AND c.table_name NOT IN ('schema_version', 'systemevent') +WHERE c.table_schema = 'public' AND c.table_name NOT LIKE '%_history' AND c.table_name NOT IN ('schema_version', 'systemevent') AND c.table_name NOT like 'pg_%' AND c_hist.column_name IS NULL /* exclude tables where the history table is missing altogether */ AND c.table_name NOT IN @@ -26,6 +26,6 @@ AND c.table_name NOT IN AND (SELECT COUNT(t_hist.table_name) FROM information_schema."tables" t_hist WHERE concat(t.table_name,'_history') = t_hist .table_name) = 0) UNION SELECT 'no history table' as remark, t.table_name, null as column_name, null as data_type FROM information_schema."tables" t -WHERE t.table_schema = 'public' AND t.table_name NOT LIKE '%_history' AND t.table_name NOT IN ('schema_version', 'systemevent') +WHERE t.table_schema = 'public' AND t.table_name NOT LIKE '%_history' AND t.table_name NOT IN ('schema_version', 'systemevent') AND t.table_name NOT like 'pg_%' AND (SELECT COUNT(t_hist.table_name) FROM information_schema."tables" t_hist WHERE concat(t.table_name,'_history') = t_hist .table_name) = 0 ORDER BY remark, table_name , column_name; diff --git a/sormas-backend/src/test/resources/testcontainers/Dockerfile b/sormas-backend/src/test/resources/testcontainers/Dockerfile new file mode 100644 index 00000000000..47528e3917d --- /dev/null +++ b/sormas-backend/src/test/resources/testcontainers/Dockerfile @@ -0,0 +1,10 @@ +FROM postgres:10.18-alpine + +RUN apk add --no-cache --repository http://dl-cdn.alpinelinux.org/alpine/v3.13/main/ musl=1.2.2-r1 musl-dev=1.2.2-r1 && \ + apk add --no-cache openssl=1.1.1l-r0 curl=7.79.1-r0 tzdata=2021e-r0 py-pip=20.3.4-r1 python3-dev=3.9.5-r2 \ + postgresql-dev=13.6-r0 postgresql-contrib=13.6-r0 make=4.3-r0 gcc=10.3.1_git20210424-r2 py3-psutil=5.8.0-r1 && \ + pip install --no-cache-dir pgxnclient==1.3.2 && \ + pgxnclient install temporal_tables + +COPY setup_sormas_db.sh /docker-entrypoint-initdb.d/ +COPY sormas_schema.sql /tmp/sormas_schema.sql diff --git a/sormas-backend/src/test/resources/testcontainers/setup_sormas_db.sh b/sormas-backend/src/test/resources/testcontainers/setup_sormas_db.sh new file mode 100644 index 00000000000..3f2f6a6a85b --- /dev/null +++ b/sormas-backend/src/test/resources/testcontainers/setup_sormas_db.sh @@ -0,0 +1,31 @@ +#!/bin/bash +set -e + +# Set up the database +echo "Starting database setup..." + +SORMAS_POSTGRES_USER=sormas_user +SORMAS_POSTGRES_PASSWORD=password +DB_NAME=sormas +DB_NAME_AUDIT=sormas_audit + +psql -v ON_ERROR_STOP=1 --username "${SORMAS_POSTGRES_USER}" < + + org.testcontainers + postgresql + 1.16.3 + test + + info.novatec bean-test From 7262504e875ceaf7b0815fb6412fe5e0bdd058fa Mon Sep 17 00:00:00 2001 From: Frank Hautpmann Date: Fri, 18 Feb 2022 09:37:48 +0100 Subject: [PATCH 111/253] New Crowdin updates (#8042) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * New translations enum.properties (Czech) * New translations enum.properties (Finnish) * New translations enum.properties (Chinese Simplified) * New translations enum.properties (Italian) * New translations enum.properties (Japanese) * New translations enum.properties (Dutch) * New translations enum.properties (Norwegian) * New translations enum.properties (Polish) * New translations enum.properties (Portuguese) * New translations enum.properties (Russian) * New translations enum.properties (Swedish) * New translations enum.properties (Turkish) * New translations enum.properties (Ukrainian) * New translations strings.properties (Swedish) * New translations strings.properties (Turkish) * New translations strings.properties (Italian, Switzerland) * New translations captions.properties (German, Switzerland) * New translations captions.properties (French) * New translations captions.properties (German) * New translations strings.properties (English, Ghana) * New translations strings.properties (English, Nigeria) * New translations strings.properties (English, Afghanistan) * New translations strings.properties (Spanish, Cuba) * New translations strings.properties (Pashto) * New translations strings.properties (Dari) * New translations strings.properties (French, Switzerland) * New translations strings.properties (Ukrainian) * New translations strings.properties (German, Switzerland) * New translations strings.properties (Swahili) * New translations strings.properties (Fijian) * New translations strings.properties (Filipino) * New translations strings.properties (Hindi) * New translations strings.properties (Croatian) * New translations strings.properties (Spanish, Ecuador) * New translations strings.properties (Urdu (Pakistan)) * New translations strings.properties (Chinese Simplified) * New translations captions.properties (Spanish, Cuba) * New translations captions.properties (Urdu (Pakistan)) * New translations strings.properties (Spanish) * New translations enum.properties (Swahili) * New translations enum.properties (French, Switzerland) * New translations enum.properties (Italian, Switzerland) * New translations enum.properties (Dari) * New translations enum.properties (Pashto) * New translations enum.properties (English, Afghanistan) * New translations enum.properties (English, Nigeria) * New translations enum.properties (English, Ghana) * New translations strings.properties (Romanian) * New translations strings.properties (Czech) * New translations enum.properties (Filipino) * New translations strings.properties (Finnish) * New translations strings.properties (Italian) * New translations strings.properties (Japanese) * New translations strings.properties (Dutch) * New translations strings.properties (Norwegian) * New translations strings.properties (Polish) * New translations strings.properties (Portuguese) * New translations strings.properties (Russian) * New translations strings.properties (Swedish) * New translations strings.properties (Turkish) * New translations enum.properties (Fijian) * New translations enum.properties (Hindi) * New translations enum.properties (German, Switzerland) * New translations enum.properties (Italian) * New translations strings.properties (French) * New translations strings.properties (German) * New translations enum.properties (French) * New translations enum.properties (Urdu (Pakistan)) * New translations enum.properties (Spanish, Cuba) * New translations enum.properties (Romanian) * New translations enum.properties (Spanish) * New translations enum.properties (Czech) * New translations enum.properties (German) * New translations enum.properties (Finnish) * New translations enum.properties (Japanese) * New translations enum.properties (Croatian) * New translations enum.properties (Dutch) * New translations enum.properties (Norwegian) * New translations enum.properties (Polish) * New translations enum.properties (Portuguese) * New translations enum.properties (Russian) * New translations enum.properties (Swedish) * New translations enum.properties (Turkish) * New translations enum.properties (Ukrainian) * New translations enum.properties (Chinese Simplified) * New translations enum.properties (Spanish, Ecuador) * New translations strings.properties (Ukrainian) * New translations strings.properties (Chinese Simplified) * New translations captions.properties (Hindi) * New translations captions.properties (Polish) * New translations captions.properties (Portuguese) * New translations captions.properties (Russian) * New translations captions.properties (Swedish) * New translations captions.properties (Turkish) * New translations captions.properties (Ukrainian) * New translations captions.properties (Chinese Simplified) * New translations captions.properties (Spanish, Ecuador) * New translations captions.properties (Croatian) * New translations captions.properties (Filipino) * New translations captions.properties (Dutch) * New translations captions.properties (Fijian) * New translations captions.properties (Swahili) * New translations captions.properties (German, Switzerland) * New translations captions.properties (French, Switzerland) * New translations captions.properties (Italian, Switzerland) * New translations captions.properties (Dari) * New translations captions.properties (Pashto) * New translations captions.properties (Spanish, Cuba) * New translations captions.properties (English, Afghanistan) * New translations captions.properties (English, Nigeria) * New translations captions.properties (Norwegian) * New translations captions.properties (Japanese) * New translations strings.properties (Urdu (Pakistan)) * New translations strings.properties (Dari) * New translations strings.properties (Spanish, Ecuador) * New translations strings.properties (Croatian) * New translations strings.properties (Hindi) * New translations strings.properties (Filipino) * New translations strings.properties (Fijian) * New translations strings.properties (Swahili) * New translations strings.properties (German, Switzerland) * New translations strings.properties (French, Switzerland) * New translations strings.properties (Italian, Switzerland) * New translations strings.properties (Pashto) * New translations captions.properties (Italian) * New translations strings.properties (Spanish, Cuba) * New translations strings.properties (English, Afghanistan) * New translations strings.properties (English, Nigeria) * New translations strings.properties (English, Ghana) * New translations captions.properties (German) * New translations captions.properties (Romanian) * New translations captions.properties (French) * New translations captions.properties (Spanish) * New translations captions.properties (Czech) * New translations captions.properties (Finnish) * New translations captions.properties (English, Ghana) * New translations enum.properties (German, Switzerland) * New translations strings.properties (German, Switzerland) * New translations captions.properties (German, Switzerland) * New translations strings.properties (French) * New translations validations.properties (Czech) * New translations strings.properties (Dari) * New translations strings.properties (Pashto) * New translations strings.properties (Spanish, Cuba) * New translations strings.properties (English, Afghanistan) * New translations strings.properties (English, Nigeria) * New translations strings.properties (English, Ghana) * New translations validations.properties (Romanian) * New translations validations.properties (French) * New translations validations.properties (Spanish) * New translations validations.properties (German) * New translations strings.properties (French, Switzerland) * New translations validations.properties (Finnish) * New translations validations.properties (Italian) * New translations validations.properties (Japanese) * New translations validations.properties (Dutch) * New translations validations.properties (Norwegian) * New translations validations.properties (Polish) * New translations validations.properties (Portuguese) * New translations validations.properties (Russian) * New translations validations.properties (Swedish) * New translations validations.properties (Turkish) * New translations strings.properties (Italian, Switzerland) * New translations strings.properties (German, Switzerland) * New translations strings.properties (German) * New translations strings.properties (Portuguese) * New translations validations.properties (Urdu (Pakistan)) * New translations strings.properties (Romanian) * New translations strings.properties (Spanish) * New translations strings.properties (Czech) * New translations strings.properties (Finnish) * New translations strings.properties (Italian) * New translations strings.properties (Japanese) * New translations strings.properties (Dutch) * New translations strings.properties (Norwegian) * New translations strings.properties (Polish) * New translations strings.properties (Russian) * New translations strings.properties (Swahili) * New translations strings.properties (Swedish) * New translations strings.properties (Turkish) * New translations strings.properties (Ukrainian) * New translations strings.properties (Chinese Simplified) * New translations strings.properties (Urdu (Pakistan)) * New translations strings.properties (Spanish, Ecuador) * New translations strings.properties (Croatian) * New translations strings.properties (Hindi) * New translations strings.properties (Filipino) * New translations strings.properties (Fijian) * New translations validations.properties (Ukrainian) * New translations validations.properties (Chinese Simplified) * New translations validations.properties (Spanish, Ecuador) * New translations validations.properties (Croatian) * New translations validations.properties (Hindi) * New translations validations.properties (Filipino) * New translations validations.properties (Fijian) * New translations validations.properties (Swahili) * New translations validations.properties (German, Switzerland) * New translations validations.properties (French, Switzerland) * New translations validations.properties (Italian, Switzerland) * New translations validations.properties (Dari) * New translations validations.properties (Pashto) * New translations validations.properties (Spanish, Cuba) * New translations validations.properties (English, Afghanistan) * New translations validations.properties (English, Nigeria) * New translations validations.properties (English, Ghana) * New translations strings.properties (French) * New translations enum.properties (French) * New translations strings.properties (German, Switzerland) * New translations strings.properties (Spanish, Cuba) * New translations captions.properties (Norwegian) * New translations captions.properties (Romanian) * New translations captions.properties (French) * New translations captions.properties (Spanish) * New translations captions.properties (Czech) * New translations captions.properties (Finnish) * New translations captions.properties (Italian) * New translations captions.properties (Japanese) * New translations captions.properties (Dutch) * New translations captions.properties (German) * New translations captions.properties (Dari) * New translations captions.properties (German, Switzerland) * New translations captions.properties (French, Switzerland) * New translations captions.properties (Italian, Switzerland) * New translations captions.properties (Urdu (Pakistan)) * New translations captions.properties (Pashto) * New translations captions.properties (Spanish, Cuba) * New translations captions.properties (English, Afghanistan) * New translations captions.properties (English, Nigeria) * New translations captions.properties (Fijian) * New translations captions.properties (Swahili) * New translations captions.properties (Ukrainian) * New translations captions.properties (Filipino) * New translations captions.properties (Hindi) * New translations captions.properties (Croatian) * New translations captions.properties (Spanish, Ecuador) * New translations captions.properties (Chinese Simplified) * New translations captions.properties (Turkish) * New translations captions.properties (Swedish) * New translations captions.properties (Russian) * New translations captions.properties (Portuguese) * New translations captions.properties (Polish) * New translations captions.properties (English, Ghana) * New translations captions.properties (Urdu (Pakistan)) * New translations captions.properties (German) * New translations captions.properties (Czech) * New translations captions.properties (German, Switzerland) * New translations captions.properties (Spanish, Cuba) Co-authored-by: Maté Strysewske --- .../main/resources/captions_cs-CZ.properties | 6 +-- .../main/resources/captions_de-CH.properties | 40 +++++++++---------- .../main/resources/captions_de-DE.properties | 40 +++++++++---------- .../main/resources/captions_es-CU.properties | 36 ++++++++--------- .../main/resources/captions_ur-PK.properties | 34 ++++++++-------- 5 files changed, 77 insertions(+), 79 deletions(-) diff --git a/sormas-api/src/main/resources/captions_cs-CZ.properties b/sormas-api/src/main/resources/captions_cs-CZ.properties index 042a264f8fa..417dd9f63c7 100644 --- a/sormas-api/src/main/resources/captions_cs-CZ.properties +++ b/sormas-api/src/main/resources/captions_cs-CZ.properties @@ -174,7 +174,7 @@ actionDiscardAndContinue=Zahodit a pokračovat activityAsCaseFlightNumber=Číslo letu -ActivityAsCase=Activity as case +ActivityAsCase=Aktivita jako případ ActivityAsCase.startDate=Začátek aktivity ActivityAsCase.endDate=Konec aktivity ActivityAsCase.activityAsCaseDate=Datum aktivity @@ -315,7 +315,7 @@ CampaignFormData.edit=Upravit # CaseData caseCasesList=Seznam případů caseInfrastructureDataChanged=Údaje o infrastruktuře se změnily -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Vytvořit nový případ pro caseContacts=Kontakty caseDocuments=Dokumenty případu caseEditData=Upravit data @@ -601,7 +601,7 @@ caseImportMergeCase=Přepsat existující případ změnami z importovaného př # CasePreviousHospitalization CasePreviousHospitalization=Předchozí hospitalizace CasePreviousHospitalization.admissionAndDischargeDate=Datum přijetí a propuštění -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Byl pacient přijat v zařízení jako neodkladný? CasePreviousHospitalization.admissionDate=Datum přijetí CasePreviousHospitalization.description=Popis CasePreviousHospitalization.dischargeDate=Datum propuštění nebo přemístění diff --git a/sormas-api/src/main/resources/captions_de-CH.properties b/sormas-api/src/main/resources/captions_de-CH.properties index bedeb0e977b..e0cd3b3f2ec 100644 --- a/sormas-api/src/main/resources/captions_de-CH.properties +++ b/sormas-api/src/main/resources/captions_de-CH.properties @@ -174,7 +174,7 @@ actionDiscardAndContinue=Verwerfen und fortfahren activityAsCaseFlightNumber=Flugnummer -ActivityAsCase=Activity as case +ActivityAsCase=Betreuung/Unterbringung/Tätigkeit in Einrichtung ActivityAsCase.startDate=Start der Aktivität ActivityAsCase.endDate=Ende der Aktivität ActivityAsCase.activityAsCaseDate=Datum der Aktivität @@ -315,7 +315,7 @@ CampaignFormData.edit=Bearbeiten # CaseData caseCasesList=Fall-Liste caseInfrastructureDataChanged=Infrastrukturdaten wurden geändert -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Neuen Fall erstellen für caseContacts=Kontakte caseDocuments=Dokumente caseEditData=Daten bearbeiten @@ -601,7 +601,7 @@ caseImportMergeCase=Bestehenden Fall mit Änderungen aus dem importierten Fall # CasePreviousHospitalization CasePreviousHospitalization=Vorheriger Krankenhausaufenthalt CasePreviousHospitalization.admissionAndDischargeDate=Datum der Aufnahme & Entlassung -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Wurde der Patient im Krankenhaus stationär aufgenommen? CasePreviousHospitalization.admissionDate=Datum der Aufnahme CasePreviousHospitalization.description=Beschreibung CasePreviousHospitalization.dischargeDate=Datum der Entlassung / Verlegung @@ -640,7 +640,7 @@ columnVaccineManufacturer=Impfstoffhersteller # Community -Community=Community +Community=Gemeinde Community.archived=Archiviert Community.externalID=Externe ID @@ -1018,7 +1018,7 @@ districtActiveDistricts=Aktive Bezirke districtArchivedDistricts=Archivierte Bezirke districtAllDistricts=Alle Bezirke -District=District +District=Bezirk District.archived=Archiviert District.epidCode=EPID-Nummer District.growthRate=Wachstumsrate @@ -1083,7 +1083,7 @@ eventSearchEvent=Ereignis suchen eventSearchSpecificEvent=Nach einem bestimmten Ereignis suchen linkEvent=Ereignis verknüpfen linkEventGroup=Ereignisgruppe verknüpfen -eventSelect=Select event +eventSelect=Ereignis auswählen eventSelectGroup=Ereignisgruppe auswählen eventDefaultView=Ereignisse eventActionsView=Aktionen @@ -1288,7 +1288,7 @@ exposureFlightNumber=Flugnummer exposureTimePeriod=Zeitraum exposureSourceCaseName=Name des Indexfalls -Exposure=Exposure +Exposure=Exposition Exposure.probableInfectionEnvironment= Wahrscheinlichste infektiöse Exposition Exposure.startDate=Beginn der Exposition Exposure.endDate=Ende der Exposition @@ -1351,7 +1351,7 @@ Facility.CONFIGURED_FACILITY=Konfigurierte Einrichtung Facility.NO_FACILITY=Zuhause oder anderer Ort Facility.OTHER_FACILITY=Andere Einrichtung -Facility=Facility +Facility=Einrichtung Facility.additionalInformation=Weitere Informationen Facility.archived=Archiviert Facility.areaType=Gebietsart (städtisch/ländlich) @@ -1409,8 +1409,8 @@ HealthConditions.otherConditions=Zusätzliche relevante Vorerkrankungen HealthConditions.immunodeficiencyOtherThanHiv=Immundefekt außer HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Herz-Kreislauf-Erkrankung einschliesslich Hypertonie HealthConditions.obesity=Adipositas -HealthConditions.currentSmoker=Current smoker -HealthConditions.formerSmoker=Former smoker +HealthConditions.currentSmoker=Aktuell Raucher +HealthConditions.formerSmoker=Ehemaliger Raucher HealthConditions.asthma=Asthma bronchiale HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunschwäche, einschließlich HIV @@ -1724,7 +1724,7 @@ personContactDetailOwnerName = Name des Besitzers personContactDetailThisPerson = Diese Person personContactDetailThirdParty = Kontaktdaten einer anderen Person oder Einrichtung erheben -PersonContactDetail = Person contact detail +PersonContactDetail = Personenkontaktdetails PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primäre Kontaktdetails PersonContactDetail.personContactDetailType = Art der Kontaktdetails @@ -1745,7 +1745,7 @@ PointOfEntry.OTHER_SEAPORT=Anderer Seehafen PointOfEntry.OTHER_GROUND_CROSSING=Anderer Bodenübergang PointOfEntry.OTHER_POE=Anderer Einreiseort -PointOfEntry=Point of entry +PointOfEntry=Einreiseort PointOfEntry.pointOfEntryType=Art des Einreiseorts PointOfEntry.active=Aktiv? PointOfEntry.latitude=Breitengrad @@ -1783,7 +1783,7 @@ PortHealthInfo.details=Einreiseort Details # Prescription prescriptionNewPrescription=Neues Rezept -Prescription=Prescription +Prescription=Verschreibung Prescription.additionalNotes=Zusätzliche Bemerkungen Prescription.dose=Dosis Prescription.drugIntakeDetails=Medikamentenname @@ -1808,7 +1808,7 @@ continentActiveContinents=Aktive Kontinente continentArchivedContinents=Archivierte Kontinente continentAllContinents=Alle Kontinente -Continent=Continent +Continent=Kontinent Continent.archived=Archiviert Continent.externalId=Externe ID Continent.defaultName=Standardname @@ -1819,7 +1819,7 @@ subcontinentActiveSubcontinents=Aktive Subkontinente subcontinentArchivedSubcontinents=Archivierte Subkontinente subcontinentAllSubcontinents=Alle Subkontinente -Subcontinent=Subcontinent +Subcontinent=Subkontinent Subcontinent.archived=Archiviert Subcontinent.externalId=Externe ID Subcontinent.defaultName=Standardname @@ -1831,7 +1831,7 @@ countryActiveCountries=Aktive Länder countryArchivedCountries=Archivierte Länder countryAllCountries=Alle Länder -Country=Country +Country=Land Country.archived=Archiviert Country.externalId=Externe ID Country.defaultName=Standardname @@ -1845,7 +1845,7 @@ regionActiveRegions=Aktive Kantone regionArchivedRegions=Archivierte Kantone regionAllRegions=Alle Kantone -Region=Region +Region=Kanton Region.archived=Archiviert Region.epidCode=EPID-Nummer Region.growthRate=Wachstumsrate @@ -2299,7 +2299,7 @@ Task.taskPriority=Aufgabenpriorität Task.travelEntry=Einreise # TestReport -TestReport=Test report +TestReport=Testbericht TestReport.testDateTime=Datum und Uhrzeit des Ergebnisses TestReport.testLabCity=Labor Stadt TestReport.testLabExternalId=Labor Externe ID @@ -2314,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Nur genesene Einreisende travelEntryOnlyVaccinatedEntries=Nur geimpfte Einreisende travelEntryOnlyEntriesTestedNegative=Nur negativ getestete Einreisende travelEntryOnlyEntriesConvertedToCase=Nur in Fälle konvertierte Einreisen -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Fall zu dieser Einreise öffnen travelEntryActiveTravelEntries=Aktive Einreisen travelEntryArchivedTravelEntries=Archivierte Einreisen travelEntryAllTravelEntries=Alle Einreisen @@ -2365,7 +2365,7 @@ treatmentCreateTreatment=Behandlung erstellen treatmentNewTreatment=Neue Behandlung treatmentOpenPrescription=Öffne Verschreibung -Treatment=Treatment +Treatment=Behandlung Treatment.additionalNotes=Zusätzliche Bemerkungen Treatment.dose=Dosis Treatment.drugIntakeDetails=Medikamentenname diff --git a/sormas-api/src/main/resources/captions_de-DE.properties b/sormas-api/src/main/resources/captions_de-DE.properties index 027cf337d9b..35f93d4cabd 100644 --- a/sormas-api/src/main/resources/captions_de-DE.properties +++ b/sormas-api/src/main/resources/captions_de-DE.properties @@ -174,7 +174,7 @@ actionDiscardAndContinue=Verwerfen und fortfahren activityAsCaseFlightNumber=Flugnummer -ActivityAsCase=Activity as case +ActivityAsCase=Betreuung/Unterbringung/Tätigkeit in Einrichtung ActivityAsCase.startDate=Start der Aktivität ActivityAsCase.endDate=Ende der Aktivität ActivityAsCase.activityAsCaseDate=Datum der Aktivität @@ -315,7 +315,7 @@ CampaignFormData.edit=Bearbeiten # CaseData caseCasesList=Fall-Liste caseInfrastructureDataChanged=Infrastrukturdaten wurden geändert -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Neuen Fall erstellen für caseContacts=Kontakte caseDocuments=Dokumente caseEditData=Daten bearbeiten @@ -601,7 +601,7 @@ caseImportMergeCase=Bestehenden Fall mit Änderungen aus dem importierten Fall # CasePreviousHospitalization CasePreviousHospitalization=Vorheriger Krankenhausaufenthalt CasePreviousHospitalization.admissionAndDischargeDate=Datum der Aufnahme & Entlassung -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =Wurde der Patient im Krankenhaus stationär aufgenommen? CasePreviousHospitalization.admissionDate=Datum der Aufnahme CasePreviousHospitalization.description=Beschreibung CasePreviousHospitalization.dischargeDate=Datum der Entlassung / Verlegung @@ -640,7 +640,7 @@ columnVaccineManufacturer=Impfstoffhersteller # Community -Community=Community +Community=Gemeinde Community.archived=Archiviert Community.externalID=Externe ID @@ -1018,7 +1018,7 @@ districtActiveDistricts=Aktive Landkreise districtArchivedDistricts=Archivierte Landkreise districtAllDistricts=Alle Landkreise -District=District +District=Landkreis/Kreisfreie Stadt District.archived=Archiviert District.epidCode=EPID-Nummer District.growthRate=Wachstumsrate @@ -1083,7 +1083,7 @@ eventSearchEvent=Ereignis suchen eventSearchSpecificEvent=Nach einem bestimmten Ereignis suchen linkEvent=Ereignis verknüpfen linkEventGroup=Gruppe verknüpfen -eventSelect=Select event +eventSelect=Ereignis auswählen eventSelectGroup=Ereignisgruppe auswählen eventDefaultView=Ereignisse eventActionsView=Aktionen @@ -1288,7 +1288,7 @@ exposureFlightNumber=Flugnummer exposureTimePeriod=Zeitraum exposureSourceCaseName=Name des Indexfalls -Exposure=Exposure +Exposure=Exposition Exposure.probableInfectionEnvironment= Wahrscheinliches Infektionsumfeld Exposure.startDate=Beginn der Exposition Exposure.endDate=Ende der Exposition @@ -1351,7 +1351,7 @@ Facility.CONFIGURED_FACILITY=Konfigurierte Einrichtung Facility.NO_FACILITY=Zuhause oder anderer Ort Facility.OTHER_FACILITY=Andere Einrichtung -Facility=Facility +Facility=Einrichtung Facility.additionalInformation=Weitere Informationen Facility.archived=Archiviert Facility.areaType=Gebietsart (städtisch/ländlich) @@ -1409,8 +1409,8 @@ HealthConditions.otherConditions=Zusätzliche relevante Vorerkrankungen HealthConditions.immunodeficiencyOtherThanHiv=Immundefekt außer HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Herz-Kreislauf-Erkrankung einschließlich Hypertonie HealthConditions.obesity=Adipositas -HealthConditions.currentSmoker=Current smoker -HealthConditions.formerSmoker=Former smoker +HealthConditions.currentSmoker=Aktuell Raucher +HealthConditions.formerSmoker=Ehemaliger Raucher HealthConditions.asthma=Asthma bronchiale HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=Immunschwäche, einschließlich HIV @@ -1724,7 +1724,7 @@ personContactDetailOwnerName = Name des Besitzers personContactDetailThisPerson = Diese Person personContactDetailThirdParty = Kontaktdaten einer anderen Person oder Einrichtung erheben -PersonContactDetail = Person contact detail +PersonContactDetail = Personenkontaktdetails PersonContactDetail.person = Person PersonContactDetail.primaryContact = Primäre Kontaktdetails PersonContactDetail.personContactDetailType = Art der Kontaktdetails @@ -1745,7 +1745,7 @@ PointOfEntry.OTHER_SEAPORT=Anderer Seehafen PointOfEntry.OTHER_GROUND_CROSSING=Anderer Grenzübergang/Landweg PointOfEntry.OTHER_POE=Anderer Einreiseort -PointOfEntry=Point of entry +PointOfEntry=Einreiseort PointOfEntry.pointOfEntryType=Art des Einreiseorts PointOfEntry.active=Aktiv? PointOfEntry.latitude=Breitengrad @@ -1783,7 +1783,7 @@ PortHealthInfo.details=Einreiseort Details # Prescription prescriptionNewPrescription=Neue Verschreibung -Prescription=Prescription +Prescription=Verschreibung Prescription.additionalNotes=Zusätzliche Bemerkungen Prescription.dose=Dosis Prescription.drugIntakeDetails=Medikamentenname @@ -1808,7 +1808,7 @@ continentActiveContinents=Aktive Kontinente continentArchivedContinents=Archivierte Kontinente continentAllContinents=Alle Kontinente -Continent=Continent +Continent=Kontinent Continent.archived=Archiviert Continent.externalId=Externe ID Continent.defaultName=Standardname @@ -1819,7 +1819,7 @@ subcontinentActiveSubcontinents=Aktive Subkontinente subcontinentArchivedSubcontinents=Archivierte Subkontinente subcontinentAllSubcontinents=Alle Subkontinente -Subcontinent=Subcontinent +Subcontinent=Subkontinent Subcontinent.archived=Archiviert Subcontinent.externalId=Externe ID Subcontinent.defaultName=Standardname @@ -1831,7 +1831,7 @@ countryActiveCountries=Aktive Länder countryArchivedCountries=Archivierte Länder countryAllCountries=Alle Länder -Country=Country +Country=Land Country.archived=Archiviert Country.externalId=Externe ID Country.defaultName=Standardname @@ -1845,7 +1845,7 @@ regionActiveRegions=Aktive Bundesländer regionArchivedRegions=Archivierte Bundesländer regionAllRegions=Alle Bundesländer -Region=Region +Region=Bundesland Region.archived=Archiviert Region.epidCode=EPID-Nummer Region.growthRate=Wachstumsrate @@ -2299,7 +2299,7 @@ Task.taskPriority=Aufgabenpriorität Task.travelEntry=Einreise # TestReport -TestReport=Test report +TestReport=Testbericht TestReport.testDateTime=Datum und Uhrzeit des Ergebnisses TestReport.testLabCity=Labor Stadt TestReport.testLabExternalId=Labor Externe ID @@ -2314,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Nur genesene Einreisende travelEntryOnlyVaccinatedEntries=Nur geimpfte Einreisende travelEntryOnlyEntriesTestedNegative=Nur negativ getestete Einreisende travelEntryOnlyEntriesConvertedToCase=Nur in Fälle konvertierte Einreisen -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Fall zu dieser Einreise öffnen travelEntryActiveTravelEntries=Aktive Einreisen travelEntryArchivedTravelEntries=Archivierte Einreisen travelEntryAllTravelEntries=Alle Einreisen @@ -2365,7 +2365,7 @@ treatmentCreateTreatment=Behandlung erstellen treatmentNewTreatment=Neue Behandlung treatmentOpenPrescription=Öffne Verschreibung -Treatment=Treatment +Treatment=Behandlung Treatment.additionalNotes=Zusätzliche Bemerkungen Treatment.dose=Dosis Treatment.drugIntakeDetails=Medikamentenname diff --git a/sormas-api/src/main/resources/captions_es-CU.properties b/sormas-api/src/main/resources/captions_es-CU.properties index d0cab7579c5..b0851b435cc 100644 --- a/sormas-api/src/main/resources/captions_es-CU.properties +++ b/sormas-api/src/main/resources/captions_es-CU.properties @@ -174,7 +174,7 @@ actionDiscardAndContinue=Descartar y continuar activityAsCaseFlightNumber=Número de vuelo -ActivityAsCase=Activity as case +ActivityAsCase=Actividad como caso ActivityAsCase.startDate=Inicio de la actividad ActivityAsCase.endDate=Fin de la actividad ActivityAsCase.activityAsCaseDate=Fecha de actividad @@ -315,7 +315,7 @@ CampaignFormData.edit=Editar # CaseData caseCasesList=Lista de casos caseInfrastructureDataChanged=Los datos de infraestructura han cambiado -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=Generar nuevo caso para caseContacts=Contactos caseDocuments=Documentos del caso caseEditData=Editar datos @@ -601,7 +601,7 @@ caseImportMergeCase=¿Sobrescribir el caso existente con los cambios del caso im # CasePreviousHospitalization CasePreviousHospitalization=Hospitalización anterior CasePreviousHospitalization.admissionAndDischargeDate=Fecha de admisión & alta -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =¿El paciente se admitió en la instalación como paciente internado? CasePreviousHospitalization.admissionDate=Fecha de admisión CasePreviousHospitalization.description=Descripción CasePreviousHospitalization.dischargeDate=Fecha de alta o transferencia @@ -640,7 +640,7 @@ columnVaccineManufacturer=Fabricante de vacuna # Community -Community=Community +Community=Área de salud Community.archived=Archivado Community.externalID=ID externa @@ -1018,7 +1018,7 @@ districtActiveDistricts=Municipios activos districtArchivedDistricts=Municipios archivados districtAllDistricts=Todos los municipios -District=District +District=Municipio District.archived=Archivado District.epidCode=Código epid District.growthRate=Tasa de crecimiento @@ -1083,7 +1083,7 @@ eventSearchEvent=Buscar evento eventSearchSpecificEvent=Buscar evento específico linkEvent=Vincular evento linkEventGroup=Vincular grupo de eventos -eventSelect=Select event +eventSelect=Seleccionar evento eventSelectGroup=Seleccionar grupo de eventos eventDefaultView=Eventos eventActionsView=Acciones @@ -1288,7 +1288,7 @@ exposureFlightNumber=Número de vuelo exposureTimePeriod=Periodo de tiempo exposureSourceCaseName=Nombre del caso de origen -Exposure=Exposure +Exposure=Exposición Exposure.probableInfectionEnvironment= Entorno de infección probable Exposure.startDate=Inicio de la exposición Exposure.endDate=Fin de la exposición @@ -1351,7 +1351,7 @@ Facility.CONFIGURED_FACILITY=Instalación configurada Facility.NO_FACILITY=Casa u otro lugar Facility.OTHER_FACILITY=Otra instalación -Facility=Facility +Facility=Instalación Facility.additionalInformation=Información adicional Facility.archived=Archivado Facility.areaType=Tipo de zona (urbana/rural) @@ -1724,7 +1724,7 @@ personContactDetailOwnerName = Nombre del propietario personContactDetailThisPerson = Esta persona personContactDetailThirdParty = Recopilar datos de contacto de otra persona o centro -PersonContactDetail = Person contact detail +PersonContactDetail = Datos de contacto de la persona PersonContactDetail.person = Persona PersonContactDetail.primaryContact = Datos de contacto primarios PersonContactDetail.personContactDetailType = Detalles del tipo de contacto @@ -1745,7 +1745,7 @@ PointOfEntry.OTHER_SEAPORT=Otro puerto marítimo PointOfEntry.OTHER_GROUND_CROSSING=Otro cruce fronterizo terrestre PointOfEntry.OTHER_POE=Otro punto de entrada -PointOfEntry=Point of entry +PointOfEntry=Punto de entrada PointOfEntry.pointOfEntryType=Tipo de punto de entrada PointOfEntry.active=¿Activo? PointOfEntry.latitude=Latitud @@ -1783,7 +1783,7 @@ PortHealthInfo.details=Detalles del punto de entrada # Prescription prescriptionNewPrescription=Nueva prescripción -Prescription=Prescription +Prescription=Prescripción Prescription.additionalNotes=Notas adicionales Prescription.dose=Dosis Prescription.drugIntakeDetails=Nombre del medicamento @@ -1808,7 +1808,7 @@ continentActiveContinents=Continentes activos continentArchivedContinents=Continentes archivados continentAllContinents=Todos los continentes -Continent=Continent +Continent=Continente Continent.archived=Archivado Continent.externalId=ID externo Continent.defaultName=Nombre por defecto @@ -1819,7 +1819,7 @@ subcontinentActiveSubcontinents=Subcontinentes activos subcontinentArchivedSubcontinents=Subcontinentes archivados subcontinentAllSubcontinents=Todos los subcontinentes -Subcontinent=Subcontinent +Subcontinent=Subcontinente Subcontinent.archived=Archivado Subcontinent.externalId=ID externo Subcontinent.defaultName=Nombre por defecto @@ -1831,7 +1831,7 @@ countryActiveCountries=Países activos countryArchivedCountries=Países archivados countryAllCountries=Todos los países -Country=Country +Country=País Country.archived=Archivado Country.externalId=ID externa Country.defaultName=Nombre por defecto @@ -1845,7 +1845,7 @@ regionActiveRegions=Provincias activas regionArchivedRegions=Provincias archivadas regionAllRegions=Todas las provincias -Region=Region +Region=Provincia Region.archived=Archivado Region.epidCode=Código epid Region.growthRate=Tasa de crecimiento @@ -2299,7 +2299,7 @@ Task.taskPriority=Prioridad de tarea Task.travelEntry=Entrada de viaje # TestReport -TestReport=Test report +TestReport=Informe de prueba TestReport.testDateTime=Fecha y hora del resultado TestReport.testLabCity=Ciudad del laboratorio TestReport.testLabExternalId=ID externa del laboratorio @@ -2314,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Sólo entradas recuperadas travelEntryOnlyVaccinatedEntries=Sólo entradas vacunadas travelEntryOnlyEntriesTestedNegative=Sólo entradas que dieron negativo travelEntryOnlyEntriesConvertedToCase=Sólo entradas convertidas en caso -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Abrir caso de esta entrada de viaje travelEntryActiveTravelEntries=Entradas de viaje activas travelEntryArchivedTravelEntries=Entradas de viaje archivadas travelEntryAllTravelEntries=Todas las entradas de viaje @@ -2365,7 +2365,7 @@ treatmentCreateTreatment=Crear tratamiento treatmentNewTreatment=Nuevo tratamiento treatmentOpenPrescription=Abrir prescripción -Treatment=Treatment +Treatment=Tratamiento Treatment.additionalNotes=Notas adicionales Treatment.dose=Dosis Treatment.drugIntakeDetails=Nombre del medicamento diff --git a/sormas-api/src/main/resources/captions_ur-PK.properties b/sormas-api/src/main/resources/captions_ur-PK.properties index dda07133bc0..910e472ff8f 100644 --- a/sormas-api/src/main/resources/captions_ur-PK.properties +++ b/sormas-api/src/main/resources/captions_ur-PK.properties @@ -51,8 +51,6 @@ creationDate=بنانے کی تاریخ notAvailableShort=دستیاب نہیں ہے inaccessibleValue=رازدارانہ numberOfCharacters=حروف کی تعداد\: %d /%d -facility=سہولت گاہ -pointOfEntry=داخلے کی جگہ remove=مٹا دیا reportingUser=رپورٹنگ صارف notTestedYet=ابھی تک ٹیسٹ نہیں ہوا @@ -176,7 +174,7 @@ actionDiscardAndContinue=رد کر دیں اور جاری رکھیں activityAsCaseFlightNumber=پرواز نمبر -ActivityAsCase=Activity as case +ActivityAsCase=سرگرمی بطور کیس ActivityAsCase.startDate=سرگرمی کا آغاز ActivityAsCase.endDate=سرگرمی کا اختتام ActivityAsCase.activityAsCaseDate=سرگرمی کی تاریخ @@ -642,7 +640,7 @@ columnVaccineManufacturer=ویکسین بنانے والا # Community -Community=Community +Community=کمیونیٹی Community.archived=آرکائیوڈ Community.externalID=بیرونی شناخت @@ -1020,7 +1018,7 @@ districtActiveDistricts=فعال اضلاع districtArchivedDistricts=آرکائیو شدہ اضلاع districtAllDistricts=تمام اضلاع -District=District +District=ضلع District.archived=آرکائیوڈ District.epidCode=Epid کوڈ District.growthRate=اضافے کی شرح @@ -1290,7 +1288,7 @@ exposureFlightNumber=پرواز نمبر exposureTimePeriod=وقت کی مدت exposureSourceCaseName=سورس کیس کا نام -Exposure=Exposure +Exposure=ایکسپوژر/سامنا Exposure.probableInfectionEnvironment= ممکنہ انفیکشن ماحول Exposure.startDate=سامنے کی شروعات Exposure.endDate=سامنے کا اختتام @@ -1353,7 +1351,7 @@ Facility.CONFIGURED_FACILITY=کنفیگرڈ سہولت گاہ Facility.NO_FACILITY=گھر یا دوسری جگہ Facility.OTHER_FACILITY=دوسری سہولت گاہ -Facility=Facility +Facility=سہولت گاہ Facility.additionalInformation=اضافی معلومات Facility.archived=آرکائیوڈ Facility.areaType=خطے کی قسم (شہری/دیہی) @@ -1411,8 +1409,8 @@ HealthConditions.otherConditions=اضافی متعلقہ، پہلے سے موج HealthConditions.immunodeficiencyOtherThanHiv=ایچ آئی وی کے علاوہ امیونو کی کمی HealthConditions.cardiovascularDiseaseIncludingHypertension=ہائپر ٹینشن سمیت دل کی بیماری HealthConditions.obesity=موٹاپا -HealthConditions.currentSmoker=Current smoker -HealthConditions.formerSmoker=Former smoker +HealthConditions.currentSmoker=موجودہ سگریٹ نوش +HealthConditions.formerSmoker=سابقہ سگریٹ نوش HealthConditions.asthma=دمہ HealthConditions.sickleCellDisease=Sickle cell disease HealthConditions.immunodeficiencyIncludingHiv=ایچ آئی وی سمیت امیونو کی کمی @@ -1726,7 +1724,7 @@ personContactDetailOwnerName = مالک کا نام personContactDetailThisPerson = یہ شخص personContactDetailThirdParty = کسی دوسرے شخص یا سہولت گاہ کے رابطے کی تفصیلات جمع کریں -PersonContactDetail = Person contact detail +PersonContactDetail = شخص کے رابطے کی تفصیل PersonContactDetail.person = شخص PersonContactDetail.primaryContact = ابتدائی رابطے کی تفصیلات PersonContactDetail.personContactDetailType = رابطے قسم کی تفصیلات @@ -1747,7 +1745,7 @@ PointOfEntry.OTHER_SEAPORT=دوسری بندرگاہ PointOfEntry.OTHER_GROUND_CROSSING=دوسری گراؤنڈ کراسنگ PointOfEntry.OTHER_POE=داخلے کی دیگر جگہيں -PointOfEntry=Point of entry +PointOfEntry=داخلے کی جگہ PointOfEntry.pointOfEntryType=داخلے کی جگہ کی قسم PointOfEntry.active=فعال؟ PointOfEntry.latitude=عرض بلد @@ -1785,7 +1783,7 @@ PortHealthInfo.details=داخلے کی جگہ کی تفصیلات # Prescription prescriptionNewPrescription=نیا نسخہ -Prescription=Prescription +Prescription=نسخہ Prescription.additionalNotes=اضافی نوٹس Prescription.dose=خوراک Prescription.drugIntakeDetails=دوا کا نام @@ -1810,7 +1808,7 @@ continentActiveContinents=فعال براعظموں continentArchivedContinents=آرکائیوڈ براعظم continentAllContinents=تمام براعظم -Continent=Continent +Continent=براعظم Continent.archived=آرکائیوڈ Continent.externalId=بیرونی شناخت Continent.defaultName=پہلے سے طے شدہ نام @@ -1821,7 +1819,7 @@ subcontinentActiveSubcontinents=فعال برصغیر subcontinentArchivedSubcontinents=آرکائیوڈ برصغیر subcontinentAllSubcontinents=تمام برصغیر -Subcontinent=Subcontinent +Subcontinent=برصغیر Subcontinent.archived=آرکائیوڈ Subcontinent.externalId=بیرونی شناخت Subcontinent.defaultName=پہلے سے طے شدہ نام @@ -1833,7 +1831,7 @@ countryActiveCountries=فعال ممالک countryArchivedCountries=آرکائیوڈ شدہ ممالک countryAllCountries=تمام ممالک -Country=Country +Country=ملک Country.archived=آرکائیوڈ Country.externalId=بیرونی شناخت Country.defaultName=پہلے سے طے شدہ نام @@ -1847,7 +1845,7 @@ regionActiveRegions=فعال علاقے regionArchivedRegions=آرکائیوڈ علاقے regionAllRegions=تمام علاقے -Region=Region +Region=علاقہ Region.archived=آرکائیوڈ Region.epidCode=Epid کوڈ Region.growthRate=اضافے کی شرح @@ -2301,7 +2299,7 @@ Task.taskPriority=کام کی ترجیح Task.travelEntry=سفری اندراج # TestReport -TestReport=Test report +TestReport=ٹیسٹ رپورٹ TestReport.testDateTime=نتیجہ کی تاریخ اور وقت TestReport.testLabCity=لیبارٹری کا شہر TestReport.testLabExternalId=لیب کی بیرونی شناخت @@ -2367,7 +2365,7 @@ treatmentCreateTreatment=علاج کا انداج کریں treatmentNewTreatment=نیا علاج treatmentOpenPrescription=نسخہ کھولیں -Treatment=Treatment +Treatment=علاج Treatment.additionalNotes=اضافی نوٹس Treatment.dose=خوراک Treatment.drugIntakeDetails=دوا کا نام From a5fb87a93b2fc0543e1f2f66ed5d6757cd95cbae Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Fri, 18 Feb 2022 13:31:57 +0100 Subject: [PATCH 112/253] test scenario for bulk linking cases and contacts to event --- .../application/cases/CaseDirectoryPage.java | 3 ++ .../contacts/ContactDirectoryPage.java | 1 + .../e2etests/services/api/CaseApiService.java | 2 +- .../services/api/EventApiService.java | 2 +- .../application/cases/CaseDirectorySteps.java | 30 ++++++++++++ .../contacts/ContactDirectorySteps.java | 25 +++++++++- .../application/events/EditEventSteps.java | 14 ++++++ .../events/EventDirectorySteps.java | 40 ++++++++++++---- .../features/sanity/web/Case.feature | 41 ++++++++++++++-- .../features/sanity/web/Contacts.feature | 48 +++++++++++++++++++ 10 files changed, 191 insertions(+), 15 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java index 03b56ae00ac..5722a2d312b 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java @@ -34,6 +34,7 @@ public class CaseDirectoryPage { By.cssSelector("thead .v-grid-column-default-header-content"); public static final By CASE_DETAILED_TABLE_ROWS = By.cssSelector("div.v-grid-tablewrapper tbody tr"); + public static final By SAVE_BUTTON_IN_LINK_FORM = By.cssSelector(".popupContent #commit"); public static final By FIRST_CASE_ID_BUTTON = By.cssSelector(".v-grid-row-has-data a[title]"); public static final By NAME_UUID_EPID_NUMBER_LIKE_INPUT = By.cssSelector("input#caseLike"); public static final By PERSON_ID_NAME_CONTACT_INFORMATION_LIKE_INPUT = @@ -93,6 +94,8 @@ public class CaseDirectoryPage { By.cssSelector("[id='dateType'] [class='v-filterselect-button']"); public static final By CASE_DISPLAY_FILTER_COMBOBOX = By.cssSelector("[id='relevanceStatus'] [class='v-filterselect-button']"); + public static final By BULK_ACTIONS = By.id("bulkActions-2"); + public static final By BULK_ACTIONS_VALUES = By.id("bulkActions-10"); public static final By CASE_REPORTING_USER_FILTER = By.cssSelector("[id='reportingUserLike']"); public static final By CASE_YEAR_FILTER = By.cssSelector("[id='birthdateYYYY'] [class='v-filterselect-button']"); diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/ContactDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/ContactDirectoryPage.java index 7d083025ce0..5bd0ec2890e 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/ContactDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/ContactDirectoryPage.java @@ -82,4 +82,5 @@ public class ContactDirectoryPage { public static final By ACTIVE_CONTACT_BUTTON = By.id("status-Active contact"); public static final By CONVERTED_TO_CASE_BUTTON = By.id("status-Converted to case"); public static final By DROPPED_BUTTON = By.id("status-Dropped"); + public static final By BULK_ACTIONS_CONTACT_VALUES = By.id("bulkActions-9"); } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/CaseApiService.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/CaseApiService.java index ae17b538ef9..96c7806c69b 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/CaseApiService.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/CaseApiService.java @@ -37,7 +37,7 @@ public CaseApiService() {} public Case buildGeneratedCase(Person person) { return Case.builder() - .disease(DiseasesValues.getRandomDiseaseName()) + .disease(DiseasesValues.CORONAVIRUS.getDiseaseName()) .diseaseDetails("Test Disease") .pseudonymized(false) .uuid(UUID.randomUUID().toString()) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/EventApiService.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/EventApiService.java index a01f1c7a516..c2aef468c55 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/EventApiService.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/EventApiService.java @@ -35,7 +35,7 @@ public EventApiService() {} public Event buildGeneratedEvent() { return Event.builder() .uuid(UUID.randomUUID().toString()) - .disease(DiseasesValues.getRandomDiseaseName()) + .disease(DiseasesValues.CORONAVIRUS.getDiseaseName()) .reportingUser(ReportingUser.builder().uuid("QLW4AN-TGWLRA-3UQVEM-WCDFCIVM").build()) .eventStatus("SIGNAL") .srcType(SourceTypeValues.getRandomSourceTypeName()) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java index 5655dd8b1b9..6d33e4ac8db 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java @@ -99,6 +99,36 @@ public CaseDirectorySteps( webDriverHelpers.clickOnWebElementBySelector(FIRST_CHECKBOX); webDriverHelpers.waitForPageLoaded(); }); + And( + "I click on Bulk Actions combobox on Case Directory Page", + () -> webDriverHelpers.clickOnWebElementBySelector(BULK_ACTIONS)); + + And( + "I click on Link to Event from Bulk Actions combobox on Case Directory Page", + () -> webDriverHelpers.clickOnWebElementBySelector(BULK_ACTIONS_VALUES)); + + And( + "I click on New Event option in Link to Event Form", + () -> + webDriverHelpers.clickOnWebElementBySelector( + By.xpath( + "/html/body/div[2]/div[3]/div/div/div[3]/div/div/div[1]/div/div[2]/div/div/div[9]/div"))); + And( + "I fill Event Id filter with last created EventId on Link to Event form", + () -> { + String eventUuid = apiState.getCreatedEvent().getUuid(); + webDriverHelpers.fillInWebElement( + By.id("search"), dataOperations.getPartialUuidFromAssociatedLink(eventUuid)); + TimeUnit.SECONDS.sleep(5); + }); + And( + "I click first result in grid on Link to Event form", + () -> + webDriverHelpers.clickOnWebElementBySelector( + By.xpath("//div[contains(@class, 'popupContent')]//tr[@role='row']"))); + When( + "^I click on SAVE button in Link Event to group form$", + () -> webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON_IN_LINK_FORM)); When( "I filter by CaseID on Case directory page", diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/ContactDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/ContactDirectorySteps.java index ff4efead918..02d73fcc950 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/ContactDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/ContactDirectorySteps.java @@ -120,8 +120,31 @@ public ContactDirectorySteps( dataOperations.getPartialUuidFromAssociatedLink( apiState.getCreatedContact().getUuid()); webDriverHelpers.fillAndSubmitInWebElement( - CONTACT_DIRECTORY_DETAILED_PAGE_FILTER_INPUT, apiState.getCreatedContact().getUuid()); + CONTACT_DIRECTORY_DETAILED_PAGE_FILTER_INPUT, contactUuid); + }); + When( + "I click on the More button on Contact directory page", + () -> { + webDriverHelpers.clickOnWebElementBySelector(MORE_BUTTON); + }); + And( + "I click on Link to Event from Bulk Actions combobox on Contact Directory Page", + () -> webDriverHelpers.clickOnWebElementBySelector(BULK_ACTIONS_CONTACT_VALUES)); + When( + "I click Enter Bulk Edit Mode on Contact directory page", + () -> { + webDriverHelpers.clickOnWebElementBySelector(ENTER_BULK_EDIT_MODE); + webDriverHelpers.waitForPageLoaded(); }); + When( + "I click checkbox to choose all Contact results", + () -> { + webDriverHelpers.clickOnWebElementBySelector(FIRST_CHECKBOX); + webDriverHelpers.waitForPageLoaded(); + }); + And( + "I click on Bulk Actions combobox on Contact Directory Page", + () -> webDriverHelpers.clickOnWebElementBySelector(BULK_ACTIONS)); And( "I filter by mocked ContactID on Contact directory page", () -> { diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java index 92f27f47037..d046fe6086e 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java @@ -23,6 +23,7 @@ import static org.sormas.e2etests.pages.application.events.EditEventPage.*; import static org.sormas.e2etests.pages.application.events.EditEventPage.SAVE_BUTTON; import static org.sormas.e2etests.pages.application.events.EventActionsPage.CREATE_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.TOTAL_EVENTS_COUNTER; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.getByEventUuid; import static org.sormas.e2etests.pages.application.events.EventParticipantsPage.*; import static org.sormas.e2etests.pages.application.events.EventParticipantsPage.EVENT_PARTICIPANTS_TAB; @@ -372,6 +373,19 @@ public EditEventSteps( webDriverHelpers.clickOnWebElementBySelector(EditEventPage.CREATE_EVENT_HANDOUT_BUTTON); webDriverHelpers.clickOnWebElementBySelector(EditEventPage.CANCEL_EVENT_HANDOUT_BUTTON); }); + And( + "I check that number of displayed Event Participants is {int}", + (Integer number) -> { + webDriverHelpers.clickOnWebElementBySelector(EditEventPage.EVENT_PARTICIPANTS_TAB); + webDriverHelpers.waitForPageLoaded(); + assertHelpers.assertWithPoll20Second( + () -> + Assert.assertEquals( + Integer.parseInt( + webDriverHelpers.getTextFromPresentWebElement(TOTAL_EVENTS_COUNTER)), + number.intValue(), + "Number of displayed actions is not correct")); + }); And( "I check that number of actions in Edit Event Tab is {int}", (Integer number) -> diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index 5f67d338414..e90b0b054e6 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -21,6 +21,7 @@ import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_GRID_RESULTS_ROWS; import static org.sormas.e2etests.pages.application.events.EditEventPage.*; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.*; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.UUID_INPUT; import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.APPLY_FILTERS_BUTTON; import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.RESET_FILTERS_BUTTON; @@ -56,6 +57,27 @@ public EventDirectorySteps( SEARCH_EVENT_BY_FREE_TEXT, dataOperations.getPartialUuidFromAssociatedLink(eventUuid)); }); + When( + "I navigate to the last created Event page via URL", + () -> { + String createdEventUUID = CreateNewEventSteps.newEvent.getUuid(); + String LAST_CREATED_EVENT_PAGE_URL = + environmentUrl + "/sormas-webdriver/#!events/data/" + createdEventUUID; + webDriverHelpers.accessWebSite(LAST_CREATED_EVENT_PAGE_URL); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(UUID_INPUT, 50); + TimeUnit.SECONDS.sleep(5); + }); + When( + "I navigate to the last created through API Event page via URL", + () -> { + String createdEventUUID = apiState.getCreatedEvent().getUuid(); + String LAST_CREATED_EVENT_PAGE_URL = + environmentUrl + "/sormas-webdriver/#!events/data/" + createdEventUUID; + webDriverHelpers.accessWebSite(LAST_CREATED_EVENT_PAGE_URL); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(UUID_INPUT, 50); + }); When( "I click on the NEW EVENT button", @@ -266,15 +288,15 @@ public EventDirectorySteps( "I click Create Case for Event Participant", () -> webDriverHelpers.clickOnWebElementBySelector(CREATE_CASE_BUTTON)); - Then( - "I check that number of displayed Event results is {int}", - (Integer number) -> - assertHelpers.assertWithPoll20Second( - () -> - Assert.assertEquals( - webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), - number.intValue(), - "Number of displayed cases is not correct"))); + Then( + "I check that number of displayed Event results is {int}", + (Integer number) -> + assertHelpers.assertWithPoll20Second( + () -> + Assert.assertEquals( + webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), + number.intValue(), + "Number of displayed cases is not correct"))); Then( "I check the number of displayed Event results from All button is {int}", diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature index dd9f4d2af03..8c2bd5680d5 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature @@ -325,11 +325,11 @@ Feature: Case end to end tests And I check if Quarantine change comment field was saved correctly @issue=SORDEV-7452 - Scenario: Bulk mode for linking/adding to Events + Scenario: Bulk mode for linking/adding cases to new Event When API: I create a new person Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 - When API: I create 10 new cases + When API: I create 2 new cases Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 Given I log in as a Admin User @@ -342,7 +342,42 @@ Feature: Case end to end tests And I click on the More button on Case directory page And I click Enter Bulk Edit Mode on Case directory page And I click checkbox to choose all Case results - And I click on New Sample + And I click on Bulk Actions combobox on Case Directory Page + And I click on Link to Event from Bulk Actions combobox on Case Directory Page + And I click on New Event option in Link to Event Form + And I click on SAVE button in Link Event to group form + And I create a new event with status CLUSTER + And I navigate to the last created Event page via URL + And I check that number of displayed Event Participants is 1 + + @issue=SORDEV-7452 + Scenario: Bulk mode for linking/adding case to existing Event + Given API: I create a new event + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + When API: I create a new person + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + When API: I create 2 new cases + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in as a Admin User + And I click on the Cases button from navbar + And I click SHOW MORE FILTERS button on Case directory page + And I apply Date type filter to "Case report date" on Case directory page + And I fill Cases from input to 1 days before mocked Cases created on Case directory page + And I apply last created api Person Id filter on Case directory page + And I click APPLY BUTTON in Case Directory Page + And I click on the More button on Case directory page + And I click Enter Bulk Edit Mode on Case directory page + And I click checkbox to choose all Case results + And I click on Bulk Actions combobox on Case Directory Page + And I click on Link to Event from Bulk Actions combobox on Case Directory Page + And I fill Event Id filter with last created EventId on Link to Event form + And I click first result in grid on Link to Event form + And I click on SAVE button in Link Event to group form + And I navigate to the last created through API Event page via URL + And I check that number of displayed Event Participants is 1 diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature index dd4128f8e80..c9fa8243545 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature @@ -241,3 +241,51 @@ Feature: Contacts end to end tests And I fill the specific data of visit with Set cleared to Unknown option to all symptoms Then I save the Visit data + @issue=SORDEV-7452 + Scenario: Bulk mode for linking/adding contacts to new Event + When API: I create a new person + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + When API: I create a new contact + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in as a Admin User + And I click on the Contacts button from navbar + And I apply Id of last api created Contact on Contact Directory Page + And I click APPLY BUTTON in Contact Directory Page + And I click on the More button on Contact directory page + And I click Enter Bulk Edit Mode on Contact directory page + And I click checkbox to choose all Contact results + And I click on Bulk Actions combobox on Contact Directory Page + And I click on Link to Event from Bulk Actions combobox on Contact Directory Page + And I click on New Event option in Link to Event Form + And I click on SAVE button in Link Event to group form + And I create a new event with status CLUSTER + And I navigate to the last created Event page via URL + And I check that number of displayed Event Participants is 1 + + @issue=SORDEV-7452 + Scenario: Bulk mode for linking/adding contacts to existing Event + Given API: I create a new event + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + When API: I create a new person + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + When API: I create a new contact + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in as a Admin User + And I click on the Contacts button from navbar + And I apply Id of last api created Contact on Contact Directory Page + And I click APPLY BUTTON in Contact Directory Page + And I click on the More button on Contact directory page + And I click Enter Bulk Edit Mode on Contact directory page + And I click checkbox to choose all Contact results + And I click on Bulk Actions combobox on Contact Directory Page + And I click on Link to Event from Bulk Actions combobox on Contact Directory Page + And I fill Event Id filter with last created EventId on Link to Event form + And I click first result in grid on Link to Event form + And I click on SAVE button in Link Event to group form + And I navigate to the last created through API Event page via URL + And I check that number of displayed Event Participants is 1 From 6a0a0909abf435ee61fa7d556e8731089e2557e5 Mon Sep 17 00:00:00 2001 From: sergiupacurariu <62688603+sergiupacurariu@users.noreply.github.com> Date: Fri, 18 Feb 2022 15:15:18 +0200 Subject: [PATCH 113/253] #7247 - CoreAdo: Introduce "end of processing date" --- .../java/de/symeda/sormas/api/CoreFacade.java | 8 ++- .../de/symeda/sormas/api/user/UserRight.java | 2 +- .../src/main/resources/strings.properties | 4 +- .../backend/campaign/CampaignFacadeEjb.java | 8 +-- .../sormas/backend/caze/CaseFacadeEjb.java | 12 +--- .../common/AbstractCoreAdoService.java | 67 +++++++++++++------ .../backend/common/AbstractCoreFacadeEjb.java | 20 +++--- ...ggregatedChangeDateExpressionBuilder.java} | 6 +- .../backend/contact/ContactFacadeEjb.java | 7 -- .../sormas/backend/event/EventFacadeEjb.java | 12 +--- .../event/EventParticipantFacadeEjb.java | 7 -- .../immunization/ImmunizationFacadeEjb.java | 7 -- .../travelentry/TravelEntryFacadeEjb.java | 7 -- .../services/BaseTravelEntryService.java | 9 +-- .../backend/caze/CaseFacadeEjbTest.java | 6 +- .../backend/contact/ContactFacadeEjbTest.java | 7 +- .../backend/event/EventFacadeEjbTest.java | 6 +- .../backend/person/PersonFacadeEjbTest.java | 8 +-- .../backend/sample/SampleFacadeEjbTest.java | 4 +- .../backend/task/TaskFacadeEjbTest.java | 8 +-- .../symeda/sormas/ui/ControllerProvider.java | 10 +-- .../ui/campaign/CampaignController.java | 6 +- .../symeda/sormas/ui/caze/CaseController.java | 12 ++-- .../sormas/ui/contact/ContactController.java | 4 +- .../sormas/ui/events/EventController.java | 4 +- .../events/EventParticipantsController.java | 35 +++++----- .../immunization/ImmunizationController.java | 4 +- .../ui/travelentry/TravelEntryController.java | 4 +- ...ntroller.java => ArchivingController.java} | 42 ++++-------- 29 files changed, 146 insertions(+), 190 deletions(-) rename sormas-backend/src/main/java/de/symeda/sormas/backend/common/{AgregatedChangeDateExpressionBuilder.java => AggregatedChangeDateExpressionBuilder.java} (77%) rename sormas-ui/src/main/java/de/symeda/sormas/ui/utils/{ArchiveController.java => ArchivingController.java} (83%) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/CoreFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/CoreFacade.java index 7704abc8325..879e164d8a1 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/CoreFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/CoreFacade.java @@ -34,9 +34,11 @@ public interface CoreFacade entityUuid, Date endOfProcessingDate); + void archive(String entityUuid, Date endOfProcessingDate); - void dearchiveCoreEntities(List entityUuids, String dearchiveReason); + void archive(List entityUuid); - Date calculateEndOfProcessingDate(List entityUuids); + void dearchive(List entityUuids, String dearchiveReason); + + Date calculateEndOfProcessingDate(String entityUuids); } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRight.java b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRight.java index 60db06febb8..a1526a509e3 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRight.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRight.java @@ -815,7 +815,7 @@ public enum UserRight { NATIONAL_USER, ADMIN_SUPERVISOR ), - EVENTPARTICIPANT_ARHIVE( + EVENTPARTICIPANT_ARCHIVE( ADMIN ), EVENTPARTICIPANT_CREATE( diff --git a/sormas-api/src/main/resources/strings.properties b/sormas-api/src/main/resources/strings.properties index bb021d501b9..16e7bf5fc2c 100644 --- a/sormas-api/src/main/resources/strings.properties +++ b/sormas-api/src/main/resources/strings.properties @@ -121,7 +121,7 @@ confirmationArchiveCases = Are you sure you want to archive all %d selected case confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? -confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the normal event participant directory. +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -135,7 +135,7 @@ confirmationDearchiveCases = Are you sure you want to de-archive all %d selected confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Are you sure you want to de-archive this event? This will make it appear in the normal event directory again. confirmationDearchiveEvents = Are you sure you want to de-archive all %d selected events? -confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant directory again. +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Are you sure you want to delete all %d selected cases? confirmationDeleteContacts = Are you sure you want to delete all %d selected contacts? diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java index 1a762530c43..361d0214fc1 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/CampaignFacadeEjb.java @@ -61,8 +61,6 @@ public class CampaignFacadeEjb extends AbstractCoreFacadeEjb implements CampaignFacade { - @EJB - CampaignService campaignService; @EJB private CampaignFormMetaService campaignFormMetaService; @EJB @@ -78,11 +76,6 @@ public CampaignFacadeEjb(CampaignService service, UserService userService) { super(Campaign.class, CampaignDto.class, service, userService); } - @Override - public AbstractCoreAdoService getEntityService() { - return campaignService; - } - @Override public List getIndexList(CampaignCriteria campaignCriteria, Integer first, Integer max, List sortProperties) { @@ -199,6 +192,7 @@ public Campaign fillOrBuildEntity(@NotNull CampaignDto source, Campaign target, @Override protected void delete(Campaign entity) { + service.delete(entity); } public void validate(CampaignReferenceDto campaignReferenceDto) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java index 3f71e031e63..6110e5eec66 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java @@ -209,7 +209,6 @@ import de.symeda.sormas.backend.clinicalcourse.ClinicalVisitFacadeEjb.ClinicalVisitFacadeEjbLocal; import de.symeda.sormas.backend.clinicalcourse.ClinicalVisitService; import de.symeda.sormas.backend.clinicalcourse.HealthConditions; -import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; @@ -332,8 +331,6 @@ public class CaseFacadeEjb extends AbstractCoreFacadeEjb getEntityService() { - return caseService; - } - @Override public List getAllActiveCasesAfter(Date date) { return getAllActiveCasesAfter(date, false); @@ -3417,12 +3409,12 @@ void archiveAllArchivableCases(int daysAfterCaseGetsArchived, LocalDate referenc Root from = cq.from(Case.class); Timestamp notChangedTimestamp = Timestamp.valueOf(notChangedSince.atStartOfDay()); - cq.where(cb.equal(from.get(Case.ARCHIVED), false), cb.not(caseService.createChangeDateFilter(cb, from, notChangedTimestamp, true))); + cq.where(cb.equal(from.get(Case.ARCHIVED), false), cb.not(service.createChangeDateFilter(cb, from, notChangedTimestamp, true))); cq.select(from.get(Case.UUID)).distinct(true); List caseUuids = em.createQuery(cq).getResultList(); if (!caseUuids.isEmpty()) { - archiveCoreEntities(caseUuids, null); + archive(caseUuids); } logger.debug( diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java index ace4a384221..18c17d3bfaa 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreAdoService.java @@ -17,8 +17,11 @@ import java.sql.Timestamp; import java.time.Instant; +import java.util.Collections; import java.util.Date; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; @@ -51,48 +54,72 @@ public boolean isArchived(String uuid) { return count > 0; } - protected > T addChangeDates(T builder, From adoPath, boolean includeExtendedChangeDateFilters){ + protected > T addChangeDates(T builder, From adoPath, boolean includeExtendedChangeDateFilters) { return builder.add(adoPath); } - public Date calculateCaseEndOfProcessingDate(List entityuuids) { + public Map calculateEndOfProcessingDate(List entityuuids) { if (entityuuids.isEmpty()) { - return null; + return Collections.emptyMap(); } + CriteriaBuilder cb = em.getCriteriaBuilder(); - CriteriaQuery cq = cb.createQuery(Date.class); + CriteriaQuery cq = cb.createQuery(Object[].class); Root from = cq.from(getElementClass()); - Expression agregatedChangeDateExpression = addChangeDates(new AgregatedChangeDateExpressionBuilder(cb), from, true).build(); - cq.select(cb.max(agregatedChangeDateExpression)); + Expression aggregatedChangeDateExpression = addChangeDates(new AggregatedChangeDateExpressionBuilder(cb), from, true).build(); + cq.multiselect(from.get(AbstractDomainObject.UUID), cb.max(aggregatedChangeDateExpression)); cq.where(from.get(ADO.UUID).in(entityuuids)); + cq.groupBy(from.get(AbstractDomainObject.UUID)); - return em.createQuery(cq).getSingleResult(); + Map collect = em.createQuery(cq).getResultList().stream().collect(Collectors.toMap(r -> (String) r[0], r -> (Date) r[1])); + return collect; } @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) - public void updateArchivedCoreEntities(List entityUuids, Date endOfProcessingDate) { + public void archive(String entityUuid, Date endOfProcessingDate) { - final Date finalEndOfProcessingDate = endOfProcessingDate != null ? endOfProcessingDate : calculateCaseEndOfProcessingDate(entityUuids); + if (endOfProcessingDate == null) { + endOfProcessingDate = calculateEndOfProcessingDate(Collections.singletonList(entityUuid)).get(entityUuid); + } - IterableHelper.executeBatched(entityUuids, ARCHIVE_BATCH_SIZE, batchedUuids -> { - CriteriaBuilder cb = em.getCriteriaBuilder(); - CriteriaUpdate cu = cb.createCriteriaUpdate(getElementClass()); - Root root = cu.from(getElementClass()); + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaUpdate cu = cb.createCriteriaUpdate(getElementClass()); + Root root = cu.from(getElementClass()); - cu.set(AbstractDomainObject.CHANGE_DATE, Timestamp.from(Instant.now())); - cu.set(root.get(Case.ARCHIVED), true); - cu.set(root.get(CoreAdo.END_OF_PROCESSING_DATE), finalEndOfProcessingDate); + cu.set(AbstractDomainObject.CHANGE_DATE, Timestamp.from(Instant.now())); + cu.set(root.get(Case.ARCHIVED), true); + cu.set(root.get(CoreAdo.END_OF_PROCESSING_DATE), endOfProcessingDate); - cu.where(root.get(AbstractDomainObject.UUID).in(batchedUuids)); + cu.where(cb.equal(root.get(AbstractDomainObject.UUID), entityUuid)); - em.createQuery(cu).executeUpdate(); - }); + em.createQuery(cu).executeUpdate(); + } + + @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) + public void archive(List entityUuids) { + + IterableHelper.executeBatched( + entityUuids, + ARCHIVE_BATCH_SIZE, + batchedUuids -> calculateEndOfProcessingDate(batchedUuids).forEach((entityUuid, finalEndOfProcessingDate) -> { + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaUpdate cu = cb.createCriteriaUpdate(getElementClass()); + Root root = cu.from(getElementClass()); + + cu.set(AbstractDomainObject.CHANGE_DATE, Timestamp.from(Instant.now())); + cu.set(root.get(Case.ARCHIVED), true); + cu.set(root.get(CoreAdo.END_OF_PROCESSING_DATE), finalEndOfProcessingDate); + + cu.where(cb.equal(root.get(AbstractDomainObject.UUID), entityUuid)); + + em.createQuery(cu).executeUpdate(); + })); } @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) - public void updateDearchivedCoreEntities(List entityUuids, String dearchiveReason) { + public void dearchive(List entityUuids, String dearchiveReason) { IterableHelper.executeBatched(entityUuids, ARCHIVE_BATCH_SIZE, batchedUuids -> { CriteriaBuilder cb = em.getCriteriaBuilder(); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreFacadeEjb.java index d013cd5d55a..0bd29cf5e51 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AbstractCoreFacadeEjb.java @@ -16,6 +16,7 @@ package de.symeda.sormas.backend.common; import java.io.Serializable; +import java.util.Collections; import java.util.Date; import java.util.List; import java.util.stream.Collectors; @@ -41,6 +42,7 @@ import de.symeda.sormas.backend.user.UserService; import de.symeda.sormas.backend.util.Pseudonymizer; import de.symeda.sormas.backend.util.QueryHelper; +import org.hibernate.mapping.Collection; public abstract class AbstractCoreFacadeEjb, CRITERIA extends BaseCriteria> extends AbstractBaseEjb @@ -56,8 +58,6 @@ protected AbstractCoreFacadeEjb(Class adoClass, Class dtoClass, SRV se super(adoClass, dtoClass, service, userService); } - public abstract AbstractCoreAdoService getEntityService(); - @Override public DTO getByUuid(String uuid) { Pseudonymizer pseudonymizer = Pseudonymizer.getDefault(userService::hasRight); @@ -179,15 +179,19 @@ private Object[] getDeletionData(String uuid, DeletionConfiguration entityConfig public abstract void validate(DTO dto) throws ValidationRuntimeException; - public void archiveCoreEntities(List entityUuids, Date endOfProcessingDate) { - getEntityService().updateArchivedCoreEntities(entityUuids, endOfProcessingDate); + public void archive(String entityUuid, Date endOfProcessingDate) { + service.archive(entityUuid, endOfProcessingDate); + } + + public void archive(List entityUuids) { + service.archive(entityUuids); } - public void dearchiveCoreEntities(List entityUuids, String dearchiveReason) { - getEntityService().updateDearchivedCoreEntities(entityUuids, dearchiveReason); + public void dearchive(List entityUuids, String dearchiveReason) { + service.dearchive(entityUuids, dearchiveReason); } - public Date calculateEndOfProcessingDate(List entityUuids) { - return getEntityService().calculateCaseEndOfProcessingDate(entityUuids); + public Date calculateEndOfProcessingDate(String entityUuid) { + return service.calculateEndOfProcessingDate(Collections.singletonList(entityUuid)).get(entityUuid); } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AgregatedChangeDateExpressionBuilder.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AggregatedChangeDateExpressionBuilder.java similarity index 77% rename from sormas-backend/src/main/java/de/symeda/sormas/backend/common/AgregatedChangeDateExpressionBuilder.java rename to sormas-backend/src/main/java/de/symeda/sormas/backend/common/AggregatedChangeDateExpressionBuilder.java index 5dc3c6860b7..c7528d86059 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AgregatedChangeDateExpressionBuilder.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/AggregatedChangeDateExpressionBuilder.java @@ -9,12 +9,12 @@ import javax.persistence.criteria.From; import javax.persistence.criteria.JoinType; -public class AgregatedChangeDateExpressionBuilder implements ChangeDateBuilder { +public class AggregatedChangeDateExpressionBuilder implements ChangeDateBuilder { private final CriteriaBuilder cb; private List> dateExpressions; - public AgregatedChangeDateExpressionBuilder(CriteriaBuilder cb) { + public AggregatedChangeDateExpressionBuilder(CriteriaBuilder cb) { this.cb = cb; this.dateExpressions = new ArrayList<>(); } @@ -23,7 +23,7 @@ public Expression build() { return cb.function("greatest", Date.class, dateExpressions.toArray(new Expression[] {})); } - public AgregatedChangeDateExpressionBuilder add(From path, String... joinFields) { + public AggregatedChangeDateExpressionBuilder add(From path, String... joinFields) { dateExpressions.add(changeDateExpression(path, joinFields)); return this; } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java index cb0d137ebc3..c837e2f77e0 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java @@ -215,8 +215,6 @@ public class ContactFacadeEjb @EJB private ConfigFacadeEjbLocal configFacade; @EJB - private ContactService contactService; - @EJB private ContactListCriteriaBuilder listCriteriaBuilder; @EJB private CaseService caseService; @@ -275,11 +273,6 @@ public ContactFacadeEjb(ContactService service, UserService userService) { super(Contact.class, ContactDto.class, service, userService); } - @Override - public AbstractCoreAdoService getEntityService() { - return contactService; - } - @Override protected void selectDtoFields(CriteriaQuery cq, Root root) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java index a7d976997b1..28d744d4fe3 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventFacadeEjb.java @@ -90,7 +90,6 @@ import de.symeda.sormas.api.utils.SortProperty; import de.symeda.sormas.api.utils.ValidationRuntimeException; import de.symeda.sormas.backend.caze.Case; -import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; @@ -131,8 +130,6 @@ public class EventFacadeEjb extends AbstractCoreFacadeEjb getEntityService() { - return eventService; - } - @Override public List getAllActiveUuids() { @@ -1195,12 +1187,12 @@ void archiveAllArchivableEvents(int daysAfterEventGetsArchived, @NotNull LocalDa Root from = cq.from(Event.class); Timestamp notChangedTimestamp = Timestamp.valueOf(notChangedSince.atStartOfDay()); - cq.where(cb.equal(from.get(Event.ARCHIVED), false), cb.not(eventService.createChangeDateFilter(cb, from, notChangedTimestamp))); + cq.where(cb.equal(from.get(Event.ARCHIVED), false), cb.not(service.createChangeDateFilter(cb, from, notChangedTimestamp))); cq.select(from.get(Event.UUID)).distinct(true); List eventUuids = em.createQuery(cq).getResultList(); if (!eventUuids.isEmpty()) { - archiveCoreEntities(eventUuids, null); + archive(eventUuids); } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java index 300180bd1ff..a72f132c4d8 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java @@ -140,8 +140,6 @@ public class EventParticipantFacadeEjb private final Logger logger = LoggerFactory.getLogger(getClass()); - @EJB - private EventParticipantService eventParticipantService; @EJB private EventService eventService; @EJB @@ -184,11 +182,6 @@ public static EventParticipantReferenceDto toReferenceDto(EventParticipant entit return new EventParticipantReferenceDto(entity.getUuid(), person.getFirstName(), person.getFirstName()); } - @Override - public AbstractCoreAdoService getEntityService() { - return eventParticipantService; - } - @Override public List getAllEventParticipantsByEventAfter(Date date, String eventUuid) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java index f0697f370cd..c0b59dfc3c0 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/immunization/ImmunizationFacadeEjb.java @@ -115,8 +115,6 @@ public class ImmunizationFacadeEjb private final Logger logger = LoggerFactory.getLogger(ImmunizationFacadeEjb.class); - @EJB - private ImmunizationService immunizationService; @EJB private DirectoryImmunizationService directoryImmunizationService; @EJB @@ -162,11 +160,6 @@ public ImmunizationFacadeEjb(ImmunizationService service, UserService userServic super(Immunization.class, ImmunizationDto.class, service, userService); } - @Override - public AbstractCoreAdoService getEntityService() { - return immunizationService; - } - public static ImmunizationReferenceDto toReferenceDto(Immunization entity) { if (entity == null) { return null; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java index 4ebf352d63b..f60d50d72e9 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryFacadeEjb.java @@ -53,8 +53,6 @@ public class TravelEntryFacadeEjb extends AbstractCoreFacadeEjb implements TravelEntryFacade { - @EJB - private TravelEntryService travelEntryService; @EJB private TravelEntryListService travelEntryListService; @EJB @@ -75,11 +73,6 @@ public class TravelEntryFacadeEjb public TravelEntryFacadeEjb() { } - @Override - public AbstractCoreAdoService getEntityService() { - return travelEntryService; - } - public static TravelEntryReferenceDto toReferenceDto(TravelEntry entity) { if (entity == null) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java index 25e4d0a3b12..6b5eb2e7a97 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java @@ -99,13 +99,6 @@ protected > T addChangeDates( From travelEntryFrom, boolean includeExtendedChangeDateFilters) { - builder = super.addChangeDates(builder, travelEntryFrom, includeExtendedChangeDateFilters); - - if (includeExtendedChangeDateFilters) { - Join resultingCase = travelEntryFrom.join(TravelEntry.RESULTING_CASE, JoinType.LEFT); - builder = builder.add(resultingCase); - } - - return builder; + return super.addChangeDates(builder, travelEntryFrom, includeExtendedChangeDateFilters); } } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java index c8df49d786a..b0155381a50 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java @@ -1081,7 +1081,7 @@ public void testArchiveAndDearchiveCase() { assertEquals(1, getCaseFacade().getAllActiveCasesAfter(null).size()); assertEquals(1, getCaseFacade().getAllActiveUuids().size()); - getCaseFacade().archiveCoreEntities(Collections.singletonList(caze.getUuid()), null); + getCaseFacade().archive(caze.getUuid(), null); // getAllActiveCases and getAllUuids should return length 0 assertEquals(0, getCaseFacade().getAllActiveCasesAfter(null).size()); @@ -1090,7 +1090,7 @@ public void testArchiveAndDearchiveCase() { // getArchivedUuidsSince should return length 1 assertEquals(1, getCaseFacade().getArchivedUuidsSince(testStartDate).size()); - getCaseFacade().dearchiveCoreEntities(Collections.singletonList(caze.getUuid()), null); + getCaseFacade().dearchive(Collections.singletonList(caze.getUuid()), null); // getAllActiveCases and getAllUuids should return length 1 assertEquals(1, getCaseFacade().getAllActiveCasesAfter(null).size()); @@ -1609,7 +1609,7 @@ public void testArchiveAllArchivableCases() { // One archived case CaseDataDto case1 = creator.createCase(user, person, rdcf); CaseFacadeEjbLocal cut = getBean(CaseFacadeEjbLocal.class); - cut.archiveCoreEntities(Collections.singletonList(case1.getUuid()), null); + cut.archive(case1.getUuid(), null); // One other case CaseDataDto case2 = creator.createCase(user, person, rdcf); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java index ac2f38e4382..1ebf143c453 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java @@ -400,7 +400,8 @@ public void testContactDeletion() { RDCF rdcf = creator.createRDCF("Region", "District", "Community", "Facility"); UserDto user = creator .createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); - UserDto admin = creator.createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Another", "Admin", UserRole.ADMIN); + UserDto admin = + creator.createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), rdcf.facility.getUuid(), "Another", "Admin", UserRole.ADMIN); String adminUuid = admin.getUuid(); PersonDto cazePerson = creator.createPerson("Case", "Person"); CaseDataDto caze = creator.createCase( @@ -1285,7 +1286,7 @@ public void testArchiveOrDearchiveContact() { assertEquals(1, getVisitFacade().getAllActiveVisitsAfter(null).size()); assertEquals(1, getVisitFacade().getAllActiveUuids().size()); - getCaseFacade().archiveCoreEntities(Collections.singletonList(caze.getUuid()), null); + getCaseFacade().archive(caze.getUuid(), null); // getAllActiveContacts and getAllUuids should return length 0 assertEquals(0, getContactFacade().getAllAfter(null).size()); @@ -1293,7 +1294,7 @@ public void testArchiveOrDearchiveContact() { assertEquals(0, getVisitFacade().getAllActiveVisitsAfter(null).size()); assertEquals(0, getVisitFacade().getAllActiveUuids().size()); - getCaseFacade().dearchiveCoreEntities(Collections.singletonList(caze.getUuid()), null); + getCaseFacade().dearchive(Collections.singletonList(caze.getUuid()), null); // getAllActiveContacts and getAllUuids should return length 1 assertEquals(1, getContactFacade().getAllAfter(null).size()); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbTest.java index 6a17983a4c6..926251f66c8 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/event/EventFacadeEjbTest.java @@ -257,7 +257,7 @@ public void testArchiveOrDearchiveEvent() { assertEquals(1, getEventParticipantFacade().getAllActiveEventParticipantsAfter(null).size()); assertEquals(1, getEventParticipantFacade().getAllActiveUuids().size()); - getEventFacade().archiveCoreEntities(Collections.singletonList(event.getUuid()), null); + getEventFacade().archive(event.getUuid(), null); // getAllActiveEvents/getAllActiveEventParticipants and getAllUuids should return length 0 assertEquals(0, getEventFacade().getAllAfter(null).size()); @@ -268,7 +268,7 @@ public void testArchiveOrDearchiveEvent() { // getArchivedUuidsSince should return length 1 assertEquals(1, getEventFacade().getArchivedUuidsSince(testStartDate).size()); - getEventFacade().dearchiveCoreEntities(Collections.singletonList(event.getUuid()), null); + getEventFacade().dearchive(Collections.singletonList(event.getUuid()), null); // getAllActiveEvents/getAllActiveEventParticipants and getAllUuids should return length 1 assertEquals(1, getEventFacade().getAllAfter(null).size()); @@ -304,7 +304,7 @@ public void testArchiveAllArchivableEvents() { Disease.ANTHRAX, rdcf.district); EventFacadeEjbLocal cut = getBean(EventFacadeEjbLocal.class); - cut.archiveCoreEntities(Collections.singletonList(event1.getUuid()), null); + cut.archive(event1.getUuid(), null); // One other event EventDto event2 = creator.createEvent( diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java index 91c7b38a946..8a345677603 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java @@ -313,8 +313,8 @@ public void testGetMatchingNameDtos() { EventDto inactiveEvent = creator.createEvent(user.toReference()); creator.createEventParticipant(inactiveEvent.toReference(), person7, user.toReference()); - getCaseFacade().archiveCoreEntities(Collections.singletonList(inactiveCase.getUuid()), null); - getEventFacade().archiveCoreEntities(Collections.singletonList(inactiveEvent.getUuid()), null); + getCaseFacade().archive(inactiveCase.getUuid(), null); + getEventFacade().archive(inactiveEvent.getUuid(), null); // Only persons that have active case, contact or event participant associations should be retrieved List relevantNameUuids = @@ -325,8 +325,8 @@ public void testGetMatchingNameDtos() { containsInAnyOrder(person1.getUuid(), person2.getUuid(), person3.getUuid(), person5.getUuid(), person6.getUuid(), person7.getUuid())); creator.createCase(user.toReference(), person4.toReference(), rdcf); - getCaseFacade().dearchiveCoreEntities(Collections.singletonList(inactiveCase.getUuid()), null); - getEventFacade().dearchiveCoreEntities(Collections.singletonList(inactiveEvent.getUuid()), null); + getCaseFacade().dearchive(Collections.singletonList(inactiveCase.getUuid()), null); + getEventFacade().dearchive(Collections.singletonList(inactiveEvent.getUuid()), null); PersonSimilarityCriteria criteria = new PersonSimilarityCriteria().sex(Sex.MALE).birthdateYYYY(1980).birthdateMM(1).birthdateDD(1); List matchingUuids = diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/SampleFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/SampleFacadeEjbTest.java index 64c9723dc06..79a179d1ebb 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/SampleFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/sample/SampleFacadeEjbTest.java @@ -508,7 +508,7 @@ public void testArchivedSampleNotGettingTransfered() { assertEquals(1, getSampleTestFacade().getAllActivePathogenTestsAfter(null).size()); assertEquals(1, getSampleTestFacade().getAllActiveUuids().size()); - getCaseFacade().archiveCoreEntities(Collections.singletonList(caze.getUuid()), null); + getCaseFacade().archive(caze.getUuid(), null); // getAllActiveSamples/getAllActiveSampleTests and getAllUuids should return length 0 assertEquals(0, getSampleFacade().getAllActiveSamplesAfter(null).size()); @@ -516,7 +516,7 @@ public void testArchivedSampleNotGettingTransfered() { assertEquals(0, getSampleTestFacade().getAllActivePathogenTestsAfter(null).size()); assertEquals(0, getSampleTestFacade().getAllActiveUuids().size()); - getCaseFacade().dearchiveCoreEntities(Collections.singletonList(caze.getUuid()), null); + getCaseFacade().dearchive(Collections.singletonList(caze.getUuid()), null); // getAllActiveSamples/getAllActiveSampleTests and getAllUuids should return length 1 assertEquals(1, getSampleFacade().getAllActiveSamplesAfter(null).size()); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/task/TaskFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/task/TaskFacadeEjbTest.java index 2c70c287abf..230f30a0259 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/task/TaskFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/task/TaskFacadeEjbTest.java @@ -173,15 +173,15 @@ public void testArchivedTaskNotGettingTransfered() { assertEquals(6, getTaskFacade().getAllActiveTasksAfter(null).size()); assertEquals(6, getTaskFacade().getAllActiveUuids().size()); - getCaseFacade().archiveCoreEntities(Collections.singletonList(caze.getUuid()), null); - getEventFacade().archiveCoreEntities(Collections.singletonList(event.getUuid()), null); + getCaseFacade().archive(caze.getUuid(), null); + getEventFacade().archive(event.getUuid(), null); // getAllActiveTasks and getAllUuids should return length 1 assertEquals(1, getTaskFacade().getAllActiveTasksAfter(null).size()); assertEquals(1, getTaskFacade().getAllActiveUuids().size()); - getCaseFacade().dearchiveCoreEntities(Collections.singletonList(caze.getUuid()), null); - getEventFacade().dearchiveCoreEntities(Collections.singletonList(event.getUuid()), null); + getCaseFacade().dearchive(Collections.singletonList(caze.getUuid()), null); + getEventFacade().dearchive(Collections.singletonList(event.getUuid()), null); // getAllActiveTasks and getAllUuids should return length 5 + 1 (contact investigation) assertEquals(6, getTaskFacade().getAllActiveTasksAfter(null).size()); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/ControllerProvider.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/ControllerProvider.java index 0088078f6a4..d6cf86f2740 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/ControllerProvider.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/ControllerProvider.java @@ -44,7 +44,7 @@ import de.symeda.sormas.ui.therapy.TherapyController; import de.symeda.sormas.ui.travelentry.TravelEntryController; import de.symeda.sormas.ui.user.UserController; -import de.symeda.sormas.ui.utils.ArchiveController; +import de.symeda.sormas.ui.utils.ArchivingController; import de.symeda.sormas.ui.utils.BaseControllerProvider; import de.symeda.sormas.ui.vaccination.VaccinationController; import de.symeda.sormas.ui.visit.VisitController; @@ -80,7 +80,7 @@ public class ControllerProvider extends BaseControllerProvider { private final TravelEntryController travelEntryController; private final ImmunizationController immunizationController; private final VaccinationController vaccinationController; - private final ArchiveController archiveController; + private final ArchivingController archivingController; public ControllerProvider() { super(); @@ -114,7 +114,7 @@ public ControllerProvider() { travelEntryController = new TravelEntryController(); immunizationController = new ImmunizationController(); vaccinationController = new VaccinationController(); - archiveController = new ArchiveController(); + archivingController = new ArchivingController(); } protected static ControllerProvider get() { @@ -237,7 +237,7 @@ public static VaccinationController getVaccinationController() { return get().vaccinationController; } - public static ArchiveController getArchiveController() { - return get().archiveController; + public static ArchivingController getArchiveController() { + return get().archivingController; } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/campaign/CampaignController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/campaign/CampaignController.java index 4e3841ab589..6a5c378b1fa 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/campaign/CampaignController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/campaign/CampaignController.java @@ -86,7 +86,7 @@ public void createOrEditCampaign(String uuid) { VaadinUiUtil.showModalPopupWindow(campaignComponent, heading); } - private static void createArchiveButton(CommitDiscardWrapperComponent campaignComponent, CampaignDto campaign) { + private void createArchiveButton(CommitDiscardWrapperComponent campaignComponent, CampaignDto campaign) { boolean archived = FacadeProvider.getCampaignFacade().isArchived(campaign.getUuid()); Button archiveCampaignButton = ButtonHelper.createButton(archived ? Captions.actionDearchive : Captions.actionArchive, e -> { campaignComponent.commit(); @@ -100,7 +100,7 @@ private static void createArchiveButton(CommitDiscardWrapperComponent navigateToCampaign(campaign.getUuid())); } else { ControllerProvider.getArchiveController() .archiveEntity( @@ -110,7 +110,7 @@ private static void createArchiveButton(CommitDiscardWrapperComponent navigateToCampaign(campaign.getUuid())); } }, ValoTheme.BUTTON_LINK); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java index 35cebc7805a..d20f36e16a7 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java @@ -1133,7 +1133,7 @@ private void appendSpecialCommands(CaseDataDto caze, CommitDiscardWrapperCompone Strings.confirmationDearchiveCase, Strings.entityCase, Strings.messageCaseDearchived, - CaseDataView.VIEW_NAME); + () -> navigateToView(CaseDataView.VIEW_NAME, caze.getUuid(), null)); } else { ControllerProvider.getArchiveController() .archiveEntity( @@ -1143,7 +1143,7 @@ private void appendSpecialCommands(CaseDataDto caze, CommitDiscardWrapperCompone Strings.confirmationArchiveCase, Strings.entityCase, Strings.messageCaseArchived, - CaseDataView.VIEW_NAME); + () -> navigateToView(CaseDataView.VIEW_NAME, caze.getUuid(), null)); } }, ValoTheme.BUTTON_LINK); @@ -1710,14 +1710,12 @@ public void sendCasesToExternalSurveillanceTool(Collection getContactDataEditComponen Strings.confirmationDearchiveContact, Strings.entityContact, Strings.messageContactDearchived, - ContactDataView.VIEW_NAME); + () -> navigateToView(ContactDataView.VIEW_NAME, contact.getUuid(), false)); } else { ControllerProvider.getArchiveController() .archiveEntity( @@ -624,7 +624,7 @@ public CommitDiscardWrapperComponent getContactDataEditComponen Strings.confirmationArchiveContact, Strings.entityContact, Strings.messageContactArchived, - ContactDataView.VIEW_NAME); + () -> navigateToView(ContactDataView.VIEW_NAME, contact.getUuid(), false)); } }, ValoTheme.BUTTON_LINK); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventController.java index 29c11597bc8..c417ecbf626 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventController.java @@ -817,7 +817,7 @@ public CommitDiscardWrapperComponent getEventDataEditComponent(fi Strings.confirmationDearchiveEvent, Strings.entityEvent, Strings.messageEventDearchived, - EventDataView.VIEW_NAME); + () -> navigateToData(event.getUuid())); } else { ControllerProvider.getArchiveController() .archiveEntity( @@ -827,7 +827,7 @@ public CommitDiscardWrapperComponent getEventDataEditComponent(fi Strings.confirmationArchiveEvent, Strings.entityEvent, Strings.messageEventArchived, - EventDataView.VIEW_NAME); + () -> navigateToData(event.getUuid())); } }, ValoTheme.BUTTON_LINK); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsController.java index de4323ad0f5..c92edd1d4d5 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsController.java @@ -230,31 +230,31 @@ public CommitDiscardWrapperComponent getEventParticipantDataEditComponent(Str } // Initialize 'Archive' button - if (UserProvider.getCurrent().hasUserRight(UserRight.EVENTPARTICIPANT_ARHIVE)) { + if (UserProvider.getCurrent().hasUserRight(UserRight.EVENTPARTICIPANT_ARCHIVE)) { boolean archived = FacadeProvider.getEventParticipantFacade().isArchived(eventParticipant.getUuid()); Button archiveButton = ButtonHelper.createButton(archived ? Captions.actionDearchive : Captions.actionArchive, e -> { editComponent.commit(); if (archived) { ControllerProvider.getArchiveController() - .dearchiveEntity( - eventParticipant, - FacadeProvider.getEventParticipantFacade(), - Strings.headingDearchiveEventParticipant, - Strings.confirmationDearchiveEventParticipant, - Strings.entityEventParticipant, - Strings.messageEventParticipantDearchived, - EventParticipantDataView.VIEW_NAME); + .dearchiveEntity( + eventParticipant, + FacadeProvider.getEventParticipantFacade(), + Strings.headingDearchiveEventParticipant, + Strings.confirmationDearchiveEventParticipant, + Strings.entityEventParticipant, + Strings.messageEventParticipantDearchived, + () -> navigateToData(eventParticipant.getUuid())); } else { ControllerProvider.getArchiveController() - .archiveEntity( - eventParticipant, - FacadeProvider.getEventParticipantFacade(), - Strings.headingArchiveEventParticipant, - Strings.confirmationArchiveEventParticipant, - Strings.entityEventParticipant, - Strings.messageEventParticipantArchived, - EventParticipantDataView.VIEW_NAME); + .archiveEntity( + eventParticipant, + FacadeProvider.getEventParticipantFacade(), + Strings.headingArchiveEventParticipant, + Strings.confirmationArchiveEventParticipant, + Strings.entityEventParticipant, + Strings.messageEventParticipantArchived, + () -> navigateToData(eventParticipant.getUuid())); } }, ValoTheme.BUTTON_LINK); @@ -263,7 +263,6 @@ public CommitDiscardWrapperComponent getEventParticipantDataEditComponent(Str editComponent.getButtonsPanel().setComponentAlignment(archiveButton, Alignment.BOTTOM_LEFT); } - return editComponent; } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java index e9fe31d9bfb..9f898f9d06c 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java @@ -201,7 +201,7 @@ public void discard() { Strings.confirmationDearchiveImmunization, Strings.entityImmunization, Strings.messageImmunizationDearchived, - ImmunizationDataView.VIEW_NAME); + () -> navigateToImmunization(immunizationDto.getUuid())); } else { ControllerProvider.getArchiveController() .archiveEntity( @@ -211,7 +211,7 @@ public void discard() { Strings.confirmationArchiveImmunization, Strings.entityImmunization, Strings.messageImmunizationArchived, - ImmunizationDataView.VIEW_NAME); + () -> navigateToImmunization(immunizationDto.getUuid())); } }, ValoTheme.BUTTON_LINK); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryController.java index bd4ba4629d0..650a086b0af 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryController.java @@ -174,7 +174,7 @@ public CommitDiscardWrapperComponent getTravelEntryDataEdit Strings.confirmationDearchiveTravelEntry, Strings.entityTravel, Strings.messageTravelEntryDearchived, - TravelEntryDataView.VIEW_NAME); + () -> navigateToTravelEntry(travelEntry.getUuid())); } else { ControllerProvider.getArchiveController() .archiveEntity( @@ -184,7 +184,7 @@ public CommitDiscardWrapperComponent getTravelEntryDataEdit Strings.confirmationArchiveTravelEntry, Strings.entityTravel, Strings.messageTravelEntryArchived, - TravelEntryDataView.VIEW_NAME); + () -> navigateToTravelEntry(travelEntry.getUuid())); } }, ValoTheme.BUTTON_LINK); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchiveController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchivingController.java similarity index 83% rename from sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchiveController.java rename to sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchivingController.java index 4e172ad33a1..0d1212058e2 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchiveController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchivingController.java @@ -22,7 +22,7 @@ import de.symeda.sormas.ui.caze.AbstractCaseView; import de.symeda.sormas.ui.events.EventDataView; -public class ArchiveController { +public class ArchivingController { public void archiveEntity( EntityDto coreEntityDto, @@ -31,7 +31,7 @@ public void archiveEntity( String archiveConfirmationMessage, String entity, String archiveMessage, - String detailViewName) { + Runnable callback) { VerticalLayout verticalLayout = new VerticalLayout(); Label contentLabel = new Label( @@ -43,8 +43,7 @@ public void archiveEntity( verticalLayout.addComponent(contentLabel); DateField endOfProcessingDate = new DateField(); - endOfProcessingDate - .setValue(DateHelper8.toLocalDate(entityFacade.calculateEndOfProcessingDate(Collections.singletonList(coreEntityDto.getUuid())))); + endOfProcessingDate.setValue(DateHelper8.toLocalDate(entityFacade.calculateEndOfProcessingDate(coreEntityDto.getUuid()))); endOfProcessingDate.setCaption(I18nProperties.getCaption(Captions.endOfProcessingDate)); verticalLayout.addComponent(endOfProcessingDate); @@ -56,13 +55,12 @@ public void archiveEntity( 640, e -> { if (Boolean.TRUE.equals(e)) { - entityFacade - .archiveCoreEntities(Collections.singletonList(coreEntityDto.getUuid()), DateHelper8.toDate(endOfProcessingDate.getValue())); + entityFacade.archive(coreEntityDto.getUuid(), DateHelper8.toDate(endOfProcessingDate.getValue())); Notification.show( String.format(I18nProperties.getString(archiveMessage), I18nProperties.getString(entity)), Notification.Type.ASSISTIVE_NOTIFICATION); - navigateToView(detailViewName, coreEntityDto.getUuid(), null); + callback.run(); } }); } @@ -74,7 +72,7 @@ public void dearchiveEntity( String dearchiveConfirmationMessage, String entity, String dearchiveMessage, - String detailViewName) { + Runnable callback) { VerticalLayout verticalLayout = new VerticalLayout(); Label contentLabel = new Label( @@ -104,11 +102,11 @@ public void dearchiveEntity( dearchiveReason.setComponentError(new UserError(I18nProperties.getString(Strings.messageArchiveUndoneReasonMandatory))); return false; } - entityFacade.dearchiveCoreEntities(Collections.singletonList(coreEntityDto.getUuid()), dearchiveReason.getValue()); + entityFacade.dearchive(Collections.singletonList(coreEntityDto.getUuid()), dearchiveReason.getValue()); Notification.show( String.format(I18nProperties.getString(dearchiveMessage), I18nProperties.getString(entity)), Notification.Type.ASSISTIVE_NOTIFICATION); - navigateToView(detailViewName, coreEntityDto.getUuid(), null); + callback.run(); } return true; }); @@ -138,8 +136,7 @@ public void archiveSelectedItems( null, e -> { if (Boolean.TRUE.equals(e)) { - Date endOfProcessingDate = entityFacade.calculateEndOfProcessingDate(entityUuids); - entityFacade.archiveCoreEntities(entityUuids, endOfProcessingDate); + entityFacade.archive(entityUuids); callback.run(); new Notification( @@ -194,13 +191,13 @@ public void dearchiveSelectedItems( I18nProperties.getString(Strings.yes), I18nProperties.getString(Strings.no), null, - connfirmed -> { - if (Boolean.TRUE.equals(connfirmed)) { + confirmed -> { + if (Boolean.TRUE.equals(confirmed)) { if (dearchiveReason.getValue().isEmpty()) { dearchiveReason.setComponentError(new UserError(I18nProperties.getString(Strings.messageArchiveUndoneReasonMandatory))); return false; } - entityFacade.dearchiveCoreEntities(entityUuids, dearchiveReason.getValue()); + entityFacade.dearchive(entityUuids, dearchiveReason.getValue()); callback.run(); new Notification( @@ -232,19 +229,4 @@ public void navigateToView(String viewName, String caseUuid, ViewMode viewMode, SormasUI.get().getNavigator().navigateTo(navigationState); } } - - public void navigateToData(String eventUuid) { - navigateToData(eventUuid, false); - } - - public void navigateToData(String eventUuid, boolean openTab) { - - String navigationState = EventDataView.VIEW_NAME + "/" + eventUuid; - if (openTab) { - SormasUI.get().getPage().open(SormasUI.get().getPage().getLocation().getRawPath() + "#!" + navigationState, "_blank", false); - } else { - SormasUI.get().getNavigator().navigateTo(navigationState); - } - } - } From 40ce750f04c41da2892901250f679460a15c1ca0 Mon Sep 17 00:00:00 2001 From: sergiupacurariu <62688603+sergiupacurariu@users.noreply.github.com> Date: Fri, 18 Feb 2022 15:26:37 +0200 Subject: [PATCH 114/253] #7247 - CoreAdo: Introduce "end of processing date" --- .../src/main/java/de/symeda/sormas/backend/common/CoreAdo.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CoreAdo.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CoreAdo.java index 4087ac60aca..cf0f02c4652 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CoreAdo.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CoreAdo.java @@ -15,6 +15,7 @@ package de.symeda.sormas.backend.common; +import static de.symeda.sormas.api.utils.FieldConstraints.CHARACTER_LIMIT_BIG; import static de.symeda.sormas.api.utils.FieldConstraints.CHARACTER_LIMIT_DEFAULT; import java.sql.Timestamp; @@ -59,7 +60,7 @@ public void setEndOfProcessingDate(Timestamp endOfProcessingDate) { this.endOfProcessingDate = endOfProcessingDate; } - @Column(length = CHARACTER_LIMIT_DEFAULT) + @Column(length = CHARACTER_LIMIT_BIG) public String getArchiveUndoneReason() { return archiveUndoneReason; } From 6a6ec877ac5403760d58fa3c6efd5ff992f7bdee Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Fri, 18 Feb 2022 17:29:12 +0200 Subject: [PATCH 115/253] Feature 7815 hide grid columns (#8005) * #7815 - hide country specific columns in person selection grid - add generic solution that uses HideForCountries annotations * #7815 - do not allow usage of setColumns from the Vaadin Grid to make sure country specific visibility errors cannot occur in the future using the new sormas grid * #7815 - remove not needed method * #7815 - rename class to not use project name --- .../sormas/api/person/SimilarPersonDto.java | 6 ++ .../sormas/ui/person/PersonSelectionGrid.java | 37 +++++----- .../sormas/ui/utils/CustomizableGrid.java | 68 +++++++++++++++++++ 3 files changed, 94 insertions(+), 17 deletions(-) create mode 100644 sormas-ui/src/main/java/de/symeda/sormas/ui/utils/CustomizableGrid.java diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/person/SimilarPersonDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/person/SimilarPersonDto.java index 35084b6c9b7..7555211e151 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/person/SimilarPersonDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/person/SimilarPersonDto.java @@ -1,5 +1,8 @@ package de.symeda.sormas.api.person; +import de.symeda.sormas.api.CountryHelper; +import de.symeda.sormas.api.utils.HideForCountries; + import java.io.Serializable; import java.util.Arrays; import java.util.List; @@ -30,6 +33,7 @@ public class SimilarPersonDto implements Serializable { private String uuid; private String firstName; private String lastName; + @HideForCountries private String nickname; private String ageAndBirthDate; private Sex sex; @@ -41,7 +45,9 @@ public class SimilarPersonDto implements Serializable { private String city; private String street; private String houseNumber; + @HideForCountries private String nationalHealthId; + @HideForCountries(countries = {CountryHelper.COUNTRY_CODE_GERMANY, CountryHelper.COUNTRY_CODE_FRANCE}) private String passportNumber; public String getUuid() { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonSelectionGrid.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonSelectionGrid.java index dabc3436e8a..a8a85fccf6a 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonSelectionGrid.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonSelectionGrid.java @@ -17,20 +17,21 @@ *******************************************************************************/ package de.symeda.sormas.ui.person; +import java.util.Arrays; import java.util.List; import com.vaadin.v7.data.util.BeanItemContainer; import com.vaadin.v7.data.util.GeneratedPropertyContainer; import com.vaadin.v7.shared.ui.grid.HeightMode; -import com.vaadin.v7.ui.Grid; import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.person.PersonSimilarityCriteria; import de.symeda.sormas.api.person.SimilarPersonDto; +import de.symeda.sormas.ui.utils.CustomizableGrid; @SuppressWarnings("serial") -public class PersonSelectionGrid extends Grid { +public class PersonSelectionGrid extends CustomizableGrid { /** * Create a grid of persons listing all persons similar to the given criteria. @@ -49,21 +50,23 @@ private void buildGrid() { setContainerDataSource(generatedContainer); setColumns( - SimilarPersonDto.FIRST_NAME, - SimilarPersonDto.LAST_NAME, - SimilarPersonDto.NICKNAME, - SimilarPersonDto.AGE_AND_BIRTH_DATE, - SimilarPersonDto.SEX, - SimilarPersonDto.PRESENT_CONDITION, - SimilarPersonDto.PHONE, - SimilarPersonDto.DISTRICT_NAME, - SimilarPersonDto.COMMUNITY_NAME, - SimilarPersonDto.POSTAL_CODE, - SimilarPersonDto.CITY, - SimilarPersonDto.STREET, - SimilarPersonDto.HOUSE_NUMBER, - SimilarPersonDto.NATIONAL_HEALTH_ID, - SimilarPersonDto.PASSPORT_NUMBER); + SimilarPersonDto.class, + Arrays.asList( + SimilarPersonDto.FIRST_NAME, + SimilarPersonDto.LAST_NAME, + SimilarPersonDto.NICKNAME, + SimilarPersonDto.AGE_AND_BIRTH_DATE, + SimilarPersonDto.SEX, + SimilarPersonDto.PRESENT_CONDITION, + SimilarPersonDto.PHONE, + SimilarPersonDto.DISTRICT_NAME, + SimilarPersonDto.COMMUNITY_NAME, + SimilarPersonDto.POSTAL_CODE, + SimilarPersonDto.CITY, + SimilarPersonDto.STREET, + SimilarPersonDto.HOUSE_NUMBER, + SimilarPersonDto.NATIONAL_HEALTH_ID, + SimilarPersonDto.PASSPORT_NUMBER)); for (Column column : getColumns()) { String propertyId = column.getPropertyId().toString(); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/CustomizableGrid.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/CustomizableGrid.java new file mode 100644 index 00000000000..6faaeb138cc --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/CustomizableGrid.java @@ -0,0 +1,68 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.ui.utils; + +import java.util.List; +import java.util.stream.Collectors; + +import com.vaadin.v7.ui.Grid; + +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; + +public class CustomizableGrid extends Grid { + + public void setColumns(Class clazz, List propertyIds) { + + FieldVisibilityCheckers fieldVisibilityCheckers = FieldVisibilityCheckers.withCountry(FacadeProvider.getConfigFacade().getCountryLocale()); + super.setColumns( + propertyIds.stream().filter(propertyId -> fieldVisibilityCheckers.isVisible(clazz, propertyId)).collect(Collectors.toList()).toArray()); + } + + public void setColumns(List columns) { + + FieldVisibilityCheckers fieldVisibilityCheckers = FieldVisibilityCheckers.withCountry(FacadeProvider.getConfigFacade().getCountryLocale()); + super.setColumns( + columns.stream() + .filter(column -> fieldVisibilityCheckers.isVisible(column.getClazz(), column.getPropertyId())) + .collect(Collectors.toList()) + .toArray()); + } + + @Override + public void setColumns(Object... propertyIds) { + throw new UnsupportedOperationException("This method should not be used! Please use setColumns of SormasGrid!"); + } + + public static class CustomizableGridColumn { + + private Class clazz; + private String propertyId; + + public CustomizableGridColumn(Class clazz, String propertyId) { + this.clazz = clazz; + this.propertyId = propertyId; + } + + public Class getClazz() { + return clazz; + } + + public String getPropertyId() { + return propertyId; + } + } +} From 845b5d44f747af9fe46cd841299d6c9cb8bbdeea Mon Sep 17 00:00:00 2001 From: syntakker Date: Fri, 18 Feb 2022 22:26:48 +0100 Subject: [PATCH 116/253] reset facility fields #7783 --- .../immunization/ImmunizationController.java | 2 +- .../components/form/ImmunizationDataForm.java | 20 ++++++++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java index 2a99272418c..b87cfb847e9 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java @@ -147,8 +147,8 @@ public CommitDiscardWrapperComponent getImmunizationDataEd @Override public void discard() { - super.discard(); immunizationDataForm.discard(); + super.discard(); } }; diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/components/form/ImmunizationDataForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/components/form/ImmunizationDataForm.java index ea8b48b40cc..5cd6d718862 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/components/form/ImmunizationDataForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/components/form/ImmunizationDataForm.java @@ -119,6 +119,7 @@ public class ImmunizationDataForm extends AbstractEditForm { private boolean ignoreMeansOfImmunizationChange = false; private MeansOfImmunization previousMeansOfImmunization; private CheckBox overwriteImmunizationManagementStatus; + private ComboBox facilityTypeGroup; public ImmunizationDataForm(boolean isPseudonymized, CaseReferenceDto relatedCase) { super( @@ -191,7 +192,7 @@ protected void addFields() { InfrastructureFieldsHelper.initInfrastructureFields(responsibleRegion, responsibleDistrictCombo, responsibleCommunityCombo); - ComboBox facilityTypeGroup = ComboBoxHelper.createComboBoxV7(); + facilityTypeGroup = ComboBoxHelper.createComboBoxV7(); facilityTypeGroup.setId("typeGroup"); facilityTypeGroup.setCaption(I18nProperties.getCaption(Captions.Facility_typeGroup)); facilityTypeGroup.setWidth(100, Unit.PERCENTAGE); @@ -424,12 +425,16 @@ protected void onCancel() { } }); - facilityTypeGroup.addValueChangeListener( - e -> FieldHelper.updateEnumData( + facilityTypeGroup.addValueChangeListener(e -> { + if (facilityTypeGroup.getValue() == null) { + facilityType.clear(); + } + FieldHelper.updateEnumData( facilityType, facilityTypeGroup.getValue() != null ? FacilityType.getTypes((FacilityTypeGroup) facilityTypeGroup.getValue()) - : Arrays.stream(FacilityType.values()).collect(Collectors.toList()))); + : Arrays.stream(FacilityType.values()).collect(Collectors.toList())); + }); facilityType.addValueChangeListener(e -> { FieldHelper.removeItems(facilityCombo); if (facilityType.getValue() != null && responsibleDistrictCombo.getValue() != null) { @@ -457,7 +462,6 @@ protected void onCancel() { facilityCombo.addValueChangeListener(e -> { updateFacilityFields(facilityCombo, facilityDetails); - this.getValue().setFacilityType((FacilityType) facilityType.getValue()); }); addValueChangeListener(e -> { @@ -552,6 +556,12 @@ public void setValue(ImmunizationDto newFieldValue) throws ReadOnlyException, Co @Override public void discard() throws SourceException { super.discard(); + FacilityType facilityTypeValue = getValue().getFacilityType(); + if (facilityTypeValue == null) { + facilityTypeGroup.clear(); + } else { + facilityTypeGroup.setValue(facilityTypeValue.getFacilityTypeGroup()); + } overwriteImmunizationManagementStatus.setValue(false); } } From 3b383d6e3b7169a56b0555bf38c747c8be26abe1 Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Sat, 19 Feb 2022 13:05:46 +0100 Subject: [PATCH 117/253] Common fixes --- .../e2etests/enums/CaseClassification.java | 12 ++++++- .../e2etests/enums/DistrictsValues.java | 6 ++-- .../e2etests/enums/PresentCondition.java | 5 +++ .../e2etests/services/api/CaseApiService.java | 4 +-- .../events/EventDirectorySteps.java | 18 +++++------ .../persons/PersonDirectorySteps.java | 32 +++++++++---------- .../samples/SamplesDirectorySteps.java | 30 ++++++++++++++--- 7 files changed, 72 insertions(+), 35 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CaseClassification.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CaseClassification.java index 6e445fb7cb5..17c8eec0963 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CaseClassification.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/CaseClassification.java @@ -44,7 +44,7 @@ public enum CaseClassification { public static String getUIValueFor(String option) { CaseClassification[] classifications = CaseClassification.values(); for (CaseClassification value : classifications) { - if (value.getClassificationAPIvalue().equalsIgnoreCase(option)) + if (value.getClassificationUIvalue().equalsIgnoreCase(option)) return value.getClassificationUIvalue(); } throw new Exception("Unable to find " + option + " value in CaseClassification Enum"); @@ -60,6 +60,16 @@ public static String getAPIValueFor(String option) { throw new Exception("Unable to find " + option + " value in CaseClassification Enum"); } + @SneakyThrows + public static String getUIValueForGivenAPIValue(String option) { + CaseClassification[] classifications = CaseClassification.values(); + for (CaseClassification value : classifications) { + if (value.getClassificationAPIvalue().equalsIgnoreCase(option)) + return value.getClassificationUIvalue(); + } + throw new Exception("Unable to find " + option + " value in CaseClassification Enum"); + } + public static String getRandomUIClassification() { Random random = new Random(); return String.valueOf( diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java index 71339799556..dc92302dde0 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/DistrictsValues.java @@ -33,7 +33,7 @@ public enum DistrictsValues { } @SneakyThrows - public static String getValueFor(String option) { + public static String getNameByUUID(String option) { DistrictsValues[] districtValuesOptions = DistrictsValues.values(); for (DistrictsValues value : districtValuesOptions) { if (value.uuid.equalsIgnoreCase(option)) return value.name; @@ -42,10 +42,10 @@ public static String getValueFor(String option) { } @SneakyThrows - public static String getNameFor(String option) { + public static String getValueFor(String option) { DistrictsValues[] districtsValues = DistrictsValues.values(); for (DistrictsValues value : districtsValues) { - if (value.uuid.equalsIgnoreCase(option)) return value.name; + if (value.getName().equalsIgnoreCase(option)) return value.getName(); } throw new Exception("Unable to find " + option + " value in District Enum"); } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PresentCondition.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PresentCondition.java index add9c5a3fb3..438e76dfc1a 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PresentCondition.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/PresentCondition.java @@ -36,6 +36,11 @@ public enum PresentCondition { } public static String getRandomPresentCondition() { + Random random = new Random(); + return String.valueOf(PresentCondition.values()[random.nextInt(values().length)]); + } + + public static String getRandomUIPresentCondition() { Random random = new Random(); return String.valueOf(PresentCondition.values()[random.nextInt(values().length)].condition); } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/CaseApiService.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/CaseApiService.java index ae17b538ef9..fd25f041405 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/CaseApiService.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/CaseApiService.java @@ -37,7 +37,7 @@ public CaseApiService() {} public Case buildGeneratedCase(Person person) { return Case.builder() - .disease(DiseasesValues.getRandomDiseaseName()) + .disease(DiseasesValues.CORONAVIRUS.getDiseaseName()) .diseaseDetails("Test Disease") .pseudonymized(false) .uuid(UUID.randomUUID().toString()) @@ -59,7 +59,7 @@ public Case buildGeneratedCase(Person person) { .firstName(person.getFirstName()) .lastName(person.getLastName()) .build()) - .caseClassification(CaseClassification.getRandomAPIClassification()) + .caseClassification("NOT_CLASSIFIED") .investigationStatus("PENDING") .outcome("NO_OUTCOME") .epiData(EpiData.builder().uuid(UUID.randomUUID().toString()).build()) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index 5f67d338414..53e011921f9 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -266,15 +266,15 @@ public EventDirectorySteps( "I click Create Case for Event Participant", () -> webDriverHelpers.clickOnWebElementBySelector(CREATE_CASE_BUTTON)); - Then( - "I check that number of displayed Event results is {int}", - (Integer number) -> - assertHelpers.assertWithPoll20Second( - () -> - Assert.assertEquals( - webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), - number.intValue(), - "Number of displayed cases is not correct"))); + Then( + "I check that number of displayed Event results is {int}", + (Integer number) -> + assertHelpers.assertWithPoll20Second( + () -> + Assert.assertEquals( + webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), + number.intValue(), + "Number of displayed cases is not correct"))); Then( "I check the number of displayed Event results from All button is {int}", diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java index 8cbef9226d0..0dead16ee70 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java @@ -135,7 +135,7 @@ public PersonDirectorySteps( String districtName = apiState.getLastCreatedPerson().getAddress().getDistrict(); webDriverHelpers.waitForPageLoaded(); webDriverHelpers.selectFromCombobox( - DISTRICTS_COMBOBOX, DistrictsValues.getValueFor(districtName)); + DISTRICTS_COMBOBOX, DistrictsValues.getNameByUUID(districtName)); }); Then( @@ -187,7 +187,7 @@ public PersonDirectorySteps( () -> { webDriverHelpers.waitForPageLoaded(); webDriverHelpers.selectFromCombobox( - PRESENT_CONDITION, PresentCondition.getRandomPresentCondition()); + PRESENT_CONDITION, PresentCondition.getRandomUIPresentCondition()); }); Then( @@ -246,14 +246,14 @@ public PersonDirectorySteps( webDriverHelpers.clickOnWebElementBySelector(By.cssSelector("[role='gridcell'] a")); }); - When( - "I apply on the APPLY FILTERS button", - () -> { - webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable( - APPLY_FILTERS_BUTTON, 30); - webDriverHelpers.clickOnWebElementBySelector(APPLY_FILTERS_BUTTON); - TimeUnit.SECONDS.sleep(10); - }); + When( + "I apply on the APPLY FILTERS button", + () -> { + webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable( + APPLY_FILTERS_BUTTON, 30); + webDriverHelpers.clickOnWebElementBySelector(APPLY_FILTERS_BUTTON); + TimeUnit.SECONDS.sleep(10); + }); When( "I click on the RESET FILTERS button for Person", @@ -279,12 +279,12 @@ public PersonDirectorySteps( + " " + apiState.getLastCreatedPerson().getFirstName(); break; - case "phone number": - searchText = apiState.getLastCreatedPerson().getPhone(); - break; - case "email": - searchText = apiState.getLastCreatedPerson().getEmailAddress(); - break; + case "phone number": + searchText = apiState.getLastCreatedPerson().getPhone(); + break; + case "email": + searchText = apiState.getLastCreatedPerson().getEmailAddress(); + break; } webDriverHelpers.waitUntilElementIsVisibleAndClickable(APPLY_FILTERS_BUTTON); webDriverHelpers.clickOnWebElementBySelector(ALL_BUTTON); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java index 8bb8fe65fe0..88c06e8af1c 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java @@ -18,14 +18,36 @@ package org.sormas.e2etests.steps.web.application.samples; -import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.*; +import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.APPLY_FILTER_BUTTON; +import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.FINAL_LABORATORY_RESULT; +import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.LABORATORY_SEARCH_COMBOBOX; +import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.RESET_FILTER_BUTTON; +import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.SAMPLE_CLASIFICATION_SEARCH_COMBOBOX; +import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.SAMPLE_DISEASE_SEARCH_COMBOBOX; +import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.SAMPLE_DISTRICT_SEARCH_COMBOBOX; +import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.SAMPLE_GRID_RESULTS_ROWS; +import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.SAMPLE_NOT_SHIPPED; +import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.SAMPLE_RECEIVED; +import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.SAMPLE_REFFERED_TO_OTHER_LAB; +import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.SAMPLE_REGION_SEARCH_COMBOBOX; +import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.SAMPLE_SEARCH_INPUT; +import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.SAMPLE_SHIPPED; +import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.SEARCH_RESULT_SAMPLE; +import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.SPECIMEN_CONDITION_SEARCH_COMBOBOX; +import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.TEST_RESULTS_SEARCH_COMBOBOX; import com.google.common.truth.Truth; import cucumber.api.java8.En; import java.util.Arrays; import javax.inject.Inject; import javax.inject.Named; -import org.sormas.e2etests.enums.*; +import org.sormas.e2etests.enums.CaseClassification; +import org.sormas.e2etests.enums.DiseasesValues; +import org.sormas.e2etests.enums.DistrictsValues; +import org.sormas.e2etests.enums.LaboratoryValues; +import org.sormas.e2etests.enums.PathogenTestResults; +import org.sormas.e2etests.enums.RegionsValues; +import org.sormas.e2etests.enums.SpecimenConditions; import org.sormas.e2etests.helpers.AssertHelpers; import org.sormas.e2etests.helpers.WebDriverHelpers; import org.sormas.e2etests.state.ApiState; @@ -107,7 +129,7 @@ public SamplesDirectorySteps( webDriverHelpers.waitForPageLoaded(); webDriverHelpers.selectFromCombobox( SAMPLE_CLASIFICATION_SEARCH_COMBOBOX, - CaseClassification.getUIValueFor(caseSpecification)); + CaseClassification.getUIValueForGivenAPIValue(caseSpecification)); }); When( @@ -158,7 +180,7 @@ public SamplesDirectorySteps( String district = apiState.getCreatedCase().getDistrict().getUuid(); webDriverHelpers.waitForPageLoaded(); webDriverHelpers.selectFromCombobox( - SAMPLE_DISTRICT_SEARCH_COMBOBOX, DistrictsValues.getNameFor(district)); + SAMPLE_DISTRICT_SEARCH_COMBOBOX, DistrictsValues.getNameByUUID(district)); }); When( From 564565de2f10b502314a931564a089d7130ed20b Mon Sep 17 00:00:00 2001 From: Christopher Riedel Date: Mon, 21 Feb 2022 07:39:22 +0100 Subject: [PATCH 118/253] #2802: Simplify user rights (#8039) --- .../symeda/sormas/api/caze/CaseExportDto.java | 14 ++--- .../api/importexport/ExportGroupType.java | 3 +- .../api/importexport/ImportExportUtils.java | 7 ++- .../de/symeda/sormas/api/user/UserRight.java | 52 ++++++++----------- sormas-api/src/main/resources/enum.properties | 18 +++---- .../res/layout/fragment_case_edit_layout.xml | 6 +-- .../res/layout/fragment_case_read_layout.xml | 6 +-- .../java/de/symeda/sormas/ui/MainScreen.java | 44 ++++++++-------- .../de/symeda/sormas/ui/UserProvider.java | 17 ++++++ .../sormas/ui/caze/AbstractCaseView.java | 7 +-- .../symeda/sormas/ui/caze/CaseDataForm.java | 2 +- .../symeda/sormas/ui/caze/CaseFilterForm.java | 3 +- .../symeda/sormas/ui/caze/CaseInfoLayout.java | 2 +- .../de/symeda/sormas/ui/caze/CasesView.java | 14 +++-- .../AbstractConfigurationView.java | 3 +- .../LineListingConfigurationView.java | 5 +- .../outbreak/OutbreakOverviewGrid.java | 21 ++++---- .../ui/dashboard/AbstractDashboardView.java | 6 +-- .../ui/dashboard/DashboardController.java | 6 +-- 19 files changed, 126 insertions(+), 110 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseExportDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseExportDto.java index 91bc995c26d..f50b786a3b3 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseExportDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseExportDto.java @@ -17,7 +17,6 @@ *******************************************************************************/ package de.symeda.sormas.api.caze; -import de.symeda.sormas.api.utils.HideForCountries; import java.io.Serializable; import java.util.ArrayList; import java.util.Date; @@ -63,6 +62,7 @@ import de.symeda.sormas.api.symptoms.SymptomsDto; import de.symeda.sormas.api.user.UserRole; import de.symeda.sormas.api.utils.DataHelper; +import de.symeda.sormas.api.utils.HideForCountries; import de.symeda.sormas.api.utils.HideForCountriesExcept; import de.symeda.sormas.api.utils.Order; import de.symeda.sormas.api.utils.PersonalData; @@ -1641,7 +1641,9 @@ public String getOtherContactDetails() { CaseDataDto.PERSON, PersonDto.EDUCATION_TYPE }) @ExportGroup(ExportGroupType.PERSON) - @HideForCountries(countries = {CountryHelper.COUNTRY_CODE_GERMANY, CountryHelper.COUNTRY_CODE_FRANCE}) + @HideForCountries(countries = { + CountryHelper.COUNTRY_CODE_GERMANY, + CountryHelper.COUNTRY_CODE_FRANCE }) public EducationType getEducationType() { return educationType; } @@ -1903,7 +1905,7 @@ public SymptomsDto getSymptoms() { @ExportTarget(caseExportTypes = { CaseExportType.CASE_MANAGEMENT }) @ExportProperty(ClinicalCourseDto.HEALTH_CONDITIONS) - @ExportGroup(ExportGroupType.CASE_MANAGEMENT) + @ExportGroup(ExportGroupType.CLINICAL_COURSE) public HealthConditionsDto getHealthConditions() { return healthConditions; } @@ -1912,7 +1914,7 @@ public HealthConditionsDto getHealthConditions() { @ExportTarget(caseExportTypes = { CaseExportType.CASE_MANAGEMENT }) @ExportProperty(NUMBER_OF_PRESCRIPTIONS) - @ExportGroup(ExportGroupType.CASE_MANAGEMENT) + @ExportGroup(ExportGroupType.THERAPY) public int getNumberOfPrescriptions() { return numberOfPrescriptions; } @@ -1921,7 +1923,7 @@ public int getNumberOfPrescriptions() { @ExportTarget(caseExportTypes = { CaseExportType.CASE_MANAGEMENT }) @ExportProperty(NUMBER_OF_TREATMENTS) - @ExportGroup(ExportGroupType.CASE_MANAGEMENT) + @ExportGroup(ExportGroupType.THERAPY) public int getNumberOfTreatments() { return numberOfTreatments; } @@ -1930,7 +1932,7 @@ public int getNumberOfTreatments() { @ExportTarget(caseExportTypes = { CaseExportType.CASE_MANAGEMENT }) @ExportProperty(NUMBER_OF_CLINICAL_VISITS) - @ExportGroup(ExportGroupType.CASE_MANAGEMENT) + @ExportGroup(ExportGroupType.CLINICAL_COURSE) public int getNumberOfClinicalVisits() { return numberOfClinicalVisits; } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/importexport/ExportGroupType.java b/sormas-api/src/main/java/de/symeda/sormas/api/importexport/ExportGroupType.java index add8d6abf34..e9dfb7d73e2 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/importexport/ExportGroupType.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/importexport/ExportGroupType.java @@ -10,7 +10,8 @@ public enum ExportGroupType { HOSPITALIZATION, EPIDEMIOLOGICAL, VACCINATION, - CASE_MANAGEMENT, + CLINICAL_COURSE, + THERAPY, FOLLOW_UP, ADDITIONAL, LOCATION, diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/importexport/ImportExportUtils.java b/sormas-api/src/main/java/de/symeda/sormas/api/importexport/ImportExportUtils.java index 7eb0a767bbe..2695897e117 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/importexport/ImportExportUtils.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/importexport/ImportExportUtils.java @@ -49,13 +49,16 @@ private ImportExportUtils() { public static List getCaseExportProperties( PropertyCaptionProvider propertyCaptionProvider, final boolean withFollowUp, - final boolean withCaseManagement, + final boolean withClinicalCourse, + final boolean withTherapy, String countryLocale) { return getExportProperties(CaseExportDto.class, new PropertyTypeFilter() { @Override public boolean accept(ExportGroupType groupType) { - if (ExportGroupType.CASE_MANAGEMENT == groupType && !withCaseManagement) { + if (ExportGroupType.CLINICAL_COURSE == groupType && !withClinicalCourse) { + return false; + } else if (ExportGroupType.THERAPY == groupType && !withTherapy) { return false; } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRight.java b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRight.java index d7653931546..f185dc16476 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRight.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRight.java @@ -933,26 +933,6 @@ public enum UserRight { // LAB_USER, // EVENT_OFFICER ), - CONFIGURATION_ACCESS( - ADMIN, - NATIONAL_USER, - NATIONAL_CLINICIAN, - NATIONAL_OBSERVER, - POE_NATIONAL_USER, - STATE_OBSERVER, - DISTRICT_OBSERVER, - SURVEILLANCE_SUPERVISOR, - ADMIN_SUPERVISOR, - POE_SUPERVISOR - ), - OUTBREAK_CONFIGURE_ALL( - ADMIN, - NATIONAL_USER - ), - OUTBREAK_CONFIGURE_RESTRICTED( - SURVEILLANCE_SUPERVISOR, - ADMIN_SUPERVISOR - ), SEND_MANUAL_EXTERNAL_MESSAGES( ADMIN, NATIONAL_USER @@ -1041,10 +1021,7 @@ public enum UserRight { ADMIN, NATIONAL_USER ), - USER_RIGHTS_MANAGE( - ADMIN - ), - DASHBOARD_SURVEILLANCE_ACCESS( + DASHBOARD_SURVEILLANCE_VIEW( ADMIN, NATIONAL_USER, NATIONAL_CLINICIAN, @@ -1062,7 +1039,7 @@ public enum UserRight { CASE_OFFICER, COMMUNITY_OFFICER ), - DASHBOARD_CONTACT_ACCESS( + DASHBOARD_CONTACT_VIEW( ADMIN, NATIONAL_USER, NATIONAL_OBSERVER, @@ -1080,7 +1057,7 @@ public enum UserRight { DISTRICT_OBSERVER, CONTACT_SUPERVISOR ), - DASHBOARD_CAMPAIGNS_ACCESS( + DASHBOARD_CAMPAIGNS_VIEW( ADMIN, NATIONAL_USER, SURVEILLANCE_SUPERVISOR, @@ -1095,7 +1072,7 @@ public enum UserRight { COMMUNITY_INFORMANT, COMMUNITY_OFFICER ), - CASE_MANAGEMENT_ACCESS( + CASE_CLINICIAN_VIEW( ADMIN, NATIONAL_CLINICIAN, CASE_SUPERVISOR, @@ -1227,9 +1204,6 @@ public enum UserRight { NATIONAL_USER, SURVEILLANCE_SUPERVISOR, ADMIN_SUPERVISOR), - LINE_LISTING_CONFIGURE_NATION( - ADMIN, - NATIONAL_USER), AGGREGATE_REPORT_VIEW( ADMIN, NATIONAL_USER, @@ -1504,6 +1478,24 @@ public enum UserRight { ), EXPORT_DATA_PROTECTION_DATA( ADMIN + ), + OUTBREAK_VIEW( + ADMIN, + NATIONAL_USER, + NATIONAL_CLINICIAN, + NATIONAL_OBSERVER, + POE_NATIONAL_USER, + STATE_OBSERVER, + DISTRICT_OBSERVER, + SURVEILLANCE_SUPERVISOR, + ADMIN_SUPERVISOR, + POE_SUPERVISOR + ), + OUTBREAK_EDIT( + ADMIN, + NATIONAL_USER, + SURVEILLANCE_SUPERVISOR, + ADMIN_SUPERVISOR ); //@formatter:on diff --git a/sormas-api/src/main/resources/enum.properties b/sormas-api/src/main/resources/enum.properties index 2a4ff680135..28d9cd48fb4 100644 --- a/sormas-api/src/main/resources/enum.properties +++ b/sormas-api/src/main/resources/enum.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/communities/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/communities/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/communities/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-app/app/src/main/res/layout/fragment_case_edit_layout.xml b/sormas-app/app/src/main/res/layout/fragment_case_edit_layout.xml index 6092f33d097..a5b0ba71259 100644 --- a/sormas-app/app/src/main/res/layout/fragment_case_edit_layout.xml +++ b/sormas-app/app/src/main/res/layout/fragment_case_edit_layout.xml @@ -803,7 +803,7 @@ @@ -816,13 +816,13 @@ diff --git a/sormas-app/app/src/main/res/layout/fragment_case_read_layout.xml b/sormas-app/app/src/main/res/layout/fragment_case_read_layout.xml index df5d4208fb9..ee41f881160 100644 --- a/sormas-app/app/src/main/res/layout/fragment_case_read_layout.xml +++ b/sormas-app/app/src/main/res/layout/fragment_case_read_layout.xml @@ -757,7 +757,7 @@ @@ -771,14 +771,14 @@ diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/MainScreen.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/MainScreen.java index 8e93ebda421..960172d7de7 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/MainScreen.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/MainScreen.java @@ -134,24 +134,24 @@ public View getView(String viewName) { menu = new Menu(navigator); if (enabled(FeatureType.DASHBOARD)) { ControllerProvider.getDashboardController().registerViews(navigator); - if (permitted(FeatureType.CASE_SURVEILANCE, UserRight.DASHBOARD_SURVEILLANCE_ACCESS)) { + if (permitted(FeatureType.CASE_SURVEILANCE, UserRight.DASHBOARD_SURVEILLANCE_VIEW)) { menu.addView( - SurveillanceDashboardView.class, - AbstractDashboardView.ROOT_VIEW_NAME, - I18nProperties.getCaption(Captions.mainMenuDashboard), - VaadinIcons.DASHBOARD); - } else if (permitted(FeatureType.CONTACT_TRACING, UserRight.DASHBOARD_CONTACT_ACCESS)) { + SurveillanceDashboardView.class, + AbstractDashboardView.ROOT_VIEW_NAME, + I18nProperties.getCaption(Captions.mainMenuDashboard), + VaadinIcons.DASHBOARD); + } else if (permitted(FeatureType.CONTACT_TRACING, UserRight.DASHBOARD_CONTACT_VIEW)) { menu.addView( - ContactsDashboardView.class, - AbstractDashboardView.ROOT_VIEW_NAME, - I18nProperties.getCaption(Captions.mainMenuDashboard), - VaadinIcons.DASHBOARD); - } else if (permitted(FeatureType.CAMPAIGNS, UserRight.DASHBOARD_CAMPAIGNS_ACCESS)) { + ContactsDashboardView.class, + AbstractDashboardView.ROOT_VIEW_NAME, + I18nProperties.getCaption(Captions.mainMenuDashboard), + VaadinIcons.DASHBOARD); + } else if (permitted(FeatureType.CAMPAIGNS, UserRight.DASHBOARD_CAMPAIGNS_VIEW)) { menu.addView( - CampaignDashboardView.class, - AbstractDashboardView.ROOT_VIEW_NAME, - I18nProperties.getCaption(Captions.mainMenuDashboard), - VaadinIcons.DASHBOARD); + CampaignDashboardView.class, + AbstractDashboardView.ROOT_VIEW_NAME, + I18nProperties.getCaption(Captions.mainMenuDashboard), + VaadinIcons.DASHBOARD); } } @@ -242,7 +242,7 @@ public View getView(String viewName) { if (permitted(UserRight.USER_VIEW)) { menu.addView(UsersView.class, UsersView.VIEW_NAME, I18nProperties.getCaption(Captions.mainMenuUsers), VaadinIcons.USERS); } - if (permitted(UserRight.CONFIGURATION_ACCESS)) { + if (UserProvider.getCurrent().hasConfigurationAccess()) { AbstractConfigurationView.registerViews(navigator); menu.addView( FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.OUTBREAKS) ? OutbreaksView.class : RegionsView.class, @@ -340,13 +340,13 @@ private static Set initKnownViews() { ImmunizationsView.VIEW_NAME)); if (enabled(FeatureType.DASHBOARD)) { - if (permitted(FeatureType.CASE_SURVEILANCE, UserRight.DASHBOARD_SURVEILLANCE_ACCESS)) { + if (permitted(FeatureType.CASE_SURVEILANCE, UserRight.DASHBOARD_SURVEILLANCE_VIEW)) { views.add(SurveillanceDashboardView.VIEW_NAME); } - if (permitted(FeatureType.CONTACT_TRACING, UserRight.DASHBOARD_CONTACT_ACCESS)) { + if (permitted(FeatureType.CONTACT_TRACING, UserRight.DASHBOARD_CONTACT_VIEW)) { views.add(ContactsDashboardView.VIEW_NAME); } - if (permitted(FeatureType.CAMPAIGNS, UserRight.DASHBOARD_CAMPAIGNS_ACCESS)) { + if (permitted(FeatureType.CAMPAIGNS, UserRight.DASHBOARD_CAMPAIGNS_VIEW)) { views.add(CampaignDashboardView.VIEW_NAME); } } @@ -391,11 +391,11 @@ public boolean beforeViewChange(ViewChangeEvent event) { if (event.getViewName().isEmpty()) { // redirect to default view String defaultView; - if (enabled(FeatureType.DASHBOARD) && permitted(FeatureType.CASE_SURVEILANCE, UserRight.DASHBOARD_SURVEILLANCE_ACCESS)) { + if (enabled(FeatureType.DASHBOARD) && permitted(FeatureType.CASE_SURVEILANCE, UserRight.DASHBOARD_SURVEILLANCE_VIEW)) { defaultView = SurveillanceDashboardView.VIEW_NAME; - } else if (enabled(FeatureType.DASHBOARD) && permitted(FeatureType.CONTACT_TRACING, UserRight.DASHBOARD_CONTACT_ACCESS)) { + } else if (enabled(FeatureType.DASHBOARD) && permitted(FeatureType.CONTACT_TRACING, UserRight.DASHBOARD_CONTACT_VIEW)) { defaultView = ContactsDashboardView.VIEW_NAME; - } else if (enabled(FeatureType.DASHBOARD) && permitted(FeatureType.CAMPAIGNS, UserRight.DASHBOARD_CAMPAIGNS_ACCESS)) { + } else if (enabled(FeatureType.DASHBOARD) && permitted(FeatureType.CAMPAIGNS, UserRight.DASHBOARD_CAMPAIGNS_VIEW)) { defaultView = CampaignDashboardView.VIEW_NAME; } else if (UserProvider.getCurrent().hasUserRole(UserRole.EXTERNAL_LAB_USER)) { defaultView = SamplesView.VIEW_NAME; diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/UserProvider.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/UserProvider.java index 2cc6e5e0973..d24c95a38d7 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/UserProvider.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/UserProvider.java @@ -18,6 +18,7 @@ package de.symeda.sormas.ui; import java.util.Arrays; +import java.util.List; import java.util.Objects; import java.util.Set; @@ -33,6 +34,13 @@ public class UserProvider { + private static final List configurationUserRoles = Arrays.asList( + UserRight.DOCUMENT_TEMPLATE_MANAGEMENT, + UserRight.INFRASTRUCTURE_VIEW, + UserRight.LINE_LISTING_CONFIGURE, + UserRight.OUTBREAK_VIEW, + UserRight.POPULATION_MANAGE); + private UserDto user; private UserReferenceDto userReference; private Set userRights; @@ -69,6 +77,11 @@ public boolean hasAnyUserRole(UserRole... userRoles) { return Arrays.stream(userRoles).anyMatch(currentUserRoles::contains); } + public boolean hasConfigurationAccess() { + Set currentUserRights = getUserRights(); + return configurationUserRoles.stream().anyMatch(currentUserRights::contains); + } + public boolean hasUserRight(UserRight userRight) { return getUserRights().contains(userRight); } @@ -81,6 +94,10 @@ public boolean hasNationalJurisdictionLevel() { return UserRole.getJurisdictionLevel(getCurrent().getUserRoles()) == JurisdictionLevel.NATION; } + public boolean hasNoneJurisdictionLevel() { + return UserRole.getJurisdictionLevel(getCurrent().getUserRoles()) == JurisdictionLevel.NONE; + } + public boolean hasRegion(RegionReferenceDto regionReference) { RegionReferenceDto userRegionReference = getCurrent().getUser().getRegion(); return Objects.equals(userRegionReference, regionReference); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/AbstractCaseView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/AbstractCaseView.java index 8f407c9855e..3361a5077dc 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/AbstractCaseView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/AbstractCaseView.java @@ -75,9 +75,10 @@ protected AbstractCaseView(String viewName, boolean redirectSimpleModeToCaseData if (!ViewModelProviders.of(AbstractCaseView.class).has(ViewConfiguration.class)) { // init default view mode - ViewConfiguration initViewConfiguration = UserProvider.getCurrent().hasUserRight(UserRight.CASE_MANAGEMENT_ACCESS) - ? new ViewConfiguration(ViewMode.NORMAL) - : new ViewConfiguration(ViewMode.SIMPLE); + ViewConfiguration initViewConfiguration = UserProvider.getCurrent().hasUserRight(UserRight.CLINICAL_COURSE_VIEW) + || UserProvider.getCurrent().hasUserRight(UserRight.THERAPY_VIEW) + ? new ViewConfiguration(ViewMode.NORMAL) + : new ViewConfiguration(ViewMode.SIMPLE); ViewModelProviders.of(AbstractCaseView.class).get(ViewConfiguration.class, initViewConfiguration); } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java index d5247b8ef18..c5be4a442da 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java @@ -1186,7 +1186,7 @@ protected void addFields() { null); /// CLINICIAN FIELDS - if (UserProvider.getCurrent().hasUserRight(UserRight.CASE_MANAGEMENT_ACCESS)) { + if (UserProvider.getCurrent().hasUserRight(UserRight.CASE_CLINICIAN_VIEW)) { if (isVisibleAllowed(CaseDataDto.CLINICIAN_NAME)) { FieldHelper.setVisibleWhen( getFieldGroup(), diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseFilterForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseFilterForm.java index d01c6a3bbf0..ee6400c3506 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseFilterForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseFilterForm.java @@ -281,7 +281,8 @@ public void addMoreFilters(CustomLayout moreFiltersContainer) { CssStyles.CHECKBOX_FILTER_INLINE)); } - if (UserProvider.getCurrent().hasUserRight(UserRight.CASE_MANAGEMENT_ACCESS)) { + if (UserProvider.getCurrent().hasUserRight(UserRight.CLINICAL_COURSE_VIEW) + || UserProvider.getCurrent().hasUserRight(UserRight.THERAPY_VIEW)) { addField( moreFiltersContainer, CheckBox.class, diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseInfoLayout.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseInfoLayout.java index 7fbffdad9a8..e35968f2e2f 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseInfoLayout.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseInfoLayout.java @@ -122,7 +122,7 @@ private void updateCaseInfo() { leftColumnLayout.addComponent(ageSexLayout); } - if (UserProvider.getCurrent().hasUserRight(UserRight.CASE_MANAGEMENT_ACCESS)) { + if (UserProvider.getCurrent().hasUserRight(UserRight.CASE_CLINICIAN_VIEW)) { addDescLabel( leftColumnLayout, CaseDataDto.CLINICIAN_NAME, diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CasesView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CasesView.java index 4147359b0ea..2f229dcb87c 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CasesView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CasesView.java @@ -123,7 +123,8 @@ public class CasesView extends AbstractView { public static final int BULK_EDIT_MODE_WARNING_THRESHOLD = 1000; private final boolean caseFollowUpEnabled; - private final boolean hasCaseManagementRight; + private final boolean hasClinicalCourseRight; + private final boolean hasTherapyRight; private final ExportConfigurationDto detailedExportConfiguration; private final CaseCriteria criteria; @@ -153,7 +154,8 @@ public CasesView() { super(VIEW_NAME); caseFollowUpEnabled = FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.CASE_FOLLOWUP); - hasCaseManagementRight = UserProvider.getCurrent().hasUserRight(UserRight.CASE_MANAGEMENT_ACCESS); + hasClinicalCourseRight = UserProvider.getCurrent().hasUserRight(UserRight.CLINICAL_COURSE_VIEW); + hasTherapyRight = UserProvider.getCurrent().hasUserRight(UserRight.THERAPY_VIEW); detailedExportConfiguration = buildDetailedExportConfiguration(); viewConfiguration = ViewModelProviders.of(CasesView.class).get(CasesViewConfiguration.class); if (viewConfiguration.getViewType() == null) { @@ -233,7 +235,8 @@ private ExportConfigurationDto buildDetailedExportConfiguration() { .getCaseExportProperties( CaseDownloadUtil::getPropertyCaption, caseFollowUpEnabled, - hasCaseManagementRight, + hasClinicalCourseRight, + hasTherapyRight, FacadeProvider.getConfigFacade().getCountryLocale()) .stream() .map(ExportPropertyMetaInfo::getPropertyId) @@ -308,7 +311,7 @@ private void addCommonCasesOverviewToolbar() { Strings.infoDetailedExport); } - if (hasCaseManagementRight) { + if (hasClinicalCourseRight || hasTherapyRight) { StreamResource caseManagementExportStreamResource = DownloadUtil.createCaseManagementExportResource(grid.getCriteria(), this::getSelectedRows, ExportEntityName.CONTACTS); addExportButton( @@ -372,7 +375,8 @@ private void addCommonCasesOverviewToolbar() { ImportExportUtils.getCaseExportProperties( CaseDownloadUtil::getPropertyCaption, caseFollowUpEnabled, - hasCaseManagementRight, + hasClinicalCourseRight, + hasTherapyRight, FacadeProvider.getConfigFacade().getCountryLocale()), customExportWindow::close); customExportsLayout.setExportCallback( diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/AbstractConfigurationView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/AbstractConfigurationView.java index 1540f3a27d5..c88c4dd31bd 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/AbstractConfigurationView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/AbstractConfigurationView.java @@ -113,7 +113,8 @@ public static void registerViews(Navigator navigator) { public void refreshMenu(SubMenu menu, String params) { menu.removeAllViews(); - if (FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.OUTBREAKS)) { + if (UserProvider.getCurrent().hasUserRight(UserRight.OUTBREAK_VIEW) + && FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.OUTBREAKS)) { menu.addView( OutbreaksView.VIEW_NAME, I18nProperties.getPrefixCaption("View", OutbreaksView.VIEW_NAME.replaceAll("/", ".") + ".short", ""), diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/linelisting/LineListingConfigurationView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/linelisting/LineListingConfigurationView.java index 78185c90eac..451179cd43d 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/linelisting/LineListingConfigurationView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/linelisting/LineListingConfigurationView.java @@ -28,7 +28,6 @@ import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Strings; import de.symeda.sormas.api.infrastructure.region.RegionReferenceDto; -import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.ui.SormasUI; import de.symeda.sormas.ui.UserProvider; import de.symeda.sormas.ui.configuration.AbstractConfigurationView; @@ -57,7 +56,7 @@ public LineListingConfigurationView() { private void buildView(Disease enteredDisease) { - if (region != null && UserProvider.getCurrent().hasUserRight(UserRight.LINE_LISTING_CONFIGURE_NATION)) { + if (region != null && (UserProvider.getCurrent().hasNationalJurisdictionLevel() || UserProvider.getCurrent().hasNoneJurisdictionLevel())) { Button btnBackToNationView = ButtonHelper.createIconButton(Captions.actionBackToNationOverview, VaadinIcons.ARROW_BACKWARD, e -> { SormasUI.get().getNavigator().navigateTo(LineListingConfigurationView.VIEW_NAME); }, ValoTheme.BUTTON_PRIMARY); @@ -193,7 +192,7 @@ public void enter(ViewChangeEvent event) { if (params.length > 1) { disease = Disease.valueOf(params[1].substring(params[1].indexOf("=") + 1)); } - } else if (!UserProvider.getCurrent().hasUserRight(UserRight.LINE_LISTING_CONFIGURE_NATION)) { + } else if (!(UserProvider.getCurrent().hasNationalJurisdictionLevel() || UserProvider.getCurrent().hasNoneJurisdictionLevel())) { this.region = UserProvider.getCurrent().getUser().getRegion(); } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/outbreak/OutbreakOverviewGrid.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/outbreak/OutbreakOverviewGrid.java index ddd850c3563..be855d63ca1 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/outbreak/OutbreakOverviewGrid.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/configuration/outbreak/OutbreakOverviewGrid.java @@ -81,9 +81,10 @@ public OutbreakRegionConfiguration convertToModel( public String convertToPresentation(OutbreakRegionConfiguration value, Class targetType, Locale locale) throws ConversionException { - boolean styleAsButton = UserProvider.getCurrent().hasUserRight(UserRight.OUTBREAK_CONFIGURE_ALL) - || (UserProvider.getCurrent().hasUserRight(UserRight.OUTBREAK_CONFIGURE_RESTRICTED) - && DataHelper.equal(UserProvider.getCurrent().getUser().getRegion(), value.getRegion())); + boolean styleAsButton = + (UserProvider.getCurrent().hasNoneJurisdictionLevel() || UserProvider.getCurrent().hasNationalJurisdictionLevel()) + || UserProvider.getCurrent().hasUserRight(UserRight.OUTBREAK_EDIT) + && DataHelper.equal(UserProvider.getCurrent().getUser().getRegion(), value.getRegion()); boolean moreThanHalfOfDistricts = value.getAffectedDistricts().size() >= value.getTotalDistricts() / 2.0f; String styles; @@ -220,18 +221,16 @@ public void itemClick(ItemClickEvent event) { // Open the outbreak configuration window for the clicked row when // a) the user is allowed to configure all existing outbreaks or // b) the user is allowed to configure outbreaks in his assigned region and has clicked the respective row - if (UserProvider.getCurrent().hasUserRight(UserRight.OUTBREAK_CONFIGURE_ALL)) { + if (UserProvider.getCurrent().hasNoneJurisdictionLevel() || UserProvider.getCurrent().hasNationalJurisdictionLevel()) { + ControllerProvider.getOutbreakController() + .openOutbreakConfigurationWindow( + (Disease) event.getPropertyId(), + (OutbreakRegionConfiguration) clickedItem.getItemProperty((Disease) event.getPropertyId()).getValue()); + } else if (clickedItem.getItemProperty(REGION).getValue().equals(user.getRegion())) { ControllerProvider.getOutbreakController() .openOutbreakConfigurationWindow( (Disease) event.getPropertyId(), (OutbreakRegionConfiguration) clickedItem.getItemProperty((Disease) event.getPropertyId()).getValue()); - } else if (UserProvider.getCurrent().hasUserRight(UserRight.OUTBREAK_CONFIGURE_RESTRICTED)) { - if (user.getRegion().equals(clickedItem.getItemProperty(REGION).getValue())) { - ControllerProvider.getOutbreakController() - .openOutbreakConfigurationWindow( - (Disease) event.getPropertyId(), - (OutbreakRegionConfiguration) clickedItem.getItemProperty((Disease) event.getPropertyId()).getValue()); - } } else { return; } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/AbstractDashboardView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/AbstractDashboardView.java index 3d89ad8ab83..fb464202c16 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/AbstractDashboardView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/AbstractDashboardView.java @@ -50,15 +50,15 @@ protected AbstractDashboardView(String viewName) { addStyleName(DashboardCssStyles.DASHBOARD_SCREEN); CssStyles.style(dashboardSwitcher, CssStyles.FORCE_CAPTION, ValoTheme.OPTIONGROUP_HORIZONTAL, CssStyles.OPTIONGROUP_HORIZONTAL_PRIMARY); - if (permitted(FeatureType.CASE_SURVEILANCE, UserRight.DASHBOARD_SURVEILLANCE_ACCESS)) { + if (permitted(FeatureType.CASE_SURVEILANCE, UserRight.DASHBOARD_SURVEILLANCE_VIEW)) { dashboardSwitcher.addItem(DashboardType.SURVEILLANCE); dashboardSwitcher.setItemCaption(DashboardType.SURVEILLANCE, I18nProperties.getEnumCaption(DashboardType.SURVEILLANCE)); } - if (permitted(FeatureType.CONTACT_TRACING, UserRight.DASHBOARD_CONTACT_ACCESS)) { + if (permitted(FeatureType.CONTACT_TRACING, UserRight.DASHBOARD_CONTACT_VIEW)) { dashboardSwitcher.addItem(DashboardType.CONTACTS); dashboardSwitcher.setItemCaption(DashboardType.CONTACTS, I18nProperties.getEnumCaption(DashboardType.CONTACTS)); } - if (permitted(FeatureType.CAMPAIGNS, UserRight.DASHBOARD_CAMPAIGNS_ACCESS)) { + if (permitted(FeatureType.CAMPAIGNS, UserRight.DASHBOARD_CAMPAIGNS_VIEW)) { dashboardSwitcher.addItem(DashboardType.CAMPAIGNS); dashboardSwitcher.setItemCaption(DashboardType.CAMPAIGNS, I18nProperties.getEnumCaption(DashboardType.CAMPAIGNS)); } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/DashboardController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/DashboardController.java index 46ee4e344ff..16ce5f73429 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/DashboardController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/dashboard/DashboardController.java @@ -34,13 +34,13 @@ public DashboardController() { } public void registerViews(Navigator navigator) { - if (permitted(FeatureType.CASE_SURVEILANCE, UserRight.DASHBOARD_SURVEILLANCE_ACCESS)) { + if (permitted(FeatureType.CASE_SURVEILANCE, UserRight.DASHBOARD_SURVEILLANCE_VIEW)) { navigator.addView(SurveillanceDashboardView.VIEW_NAME, SurveillanceDashboardView.class); } - if (permitted(FeatureType.CONTACT_TRACING, UserRight.DASHBOARD_CONTACT_ACCESS)) { + if (permitted(FeatureType.CONTACT_TRACING, UserRight.DASHBOARD_CONTACT_VIEW)) { navigator.addView(ContactsDashboardView.VIEW_NAME, ContactsDashboardView.class); } - if (permitted(FeatureType.CAMPAIGNS, UserRight.DASHBOARD_CAMPAIGNS_ACCESS)) { + if (permitted(FeatureType.CAMPAIGNS, UserRight.DASHBOARD_CAMPAIGNS_VIEW)) { navigator.addView(CampaignDashboardView.VIEW_NAME, CampaignDashboardView.class); } } From 8e58fd642ab64f5062142ff54e940962ed19b801 Mon Sep 17 00:00:00 2001 From: Frank Hautpmann Date: Mon, 21 Feb 2022 10:39:51 +0100 Subject: [PATCH 119/253] New Crowdin updates (#8066) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * New translations strings.properties (Spanish, Ecuador) * New translations strings.properties (Urdu (Pakistan)) * New translations strings.properties (Chinese Simplified) * New translations captions.properties (Spanish, Cuba) * New translations captions.properties (Urdu (Pakistan)) * New translations strings.properties (Spanish) * New translations enum.properties (Swahili) * New translations enum.properties (French, Switzerland) * New translations enum.properties (Italian, Switzerland) * New translations enum.properties (Dari) * New translations enum.properties (Pashto) * New translations enum.properties (English, Afghanistan) * New translations enum.properties (English, Nigeria) * New translations enum.properties (English, Ghana) * New translations strings.properties (Romanian) * New translations strings.properties (Czech) * New translations enum.properties (Filipino) * New translations strings.properties (Finnish) * New translations strings.properties (Italian) * New translations strings.properties (Japanese) * New translations strings.properties (Dutch) * New translations strings.properties (Norwegian) * New translations strings.properties (Polish) * New translations strings.properties (Portuguese) * New translations strings.properties (Russian) * New translations strings.properties (Swedish) * New translations strings.properties (Turkish) * New translations enum.properties (Fijian) * New translations enum.properties (Hindi) * New translations enum.properties (German, Switzerland) * New translations enum.properties (Italian) * New translations strings.properties (French) * New translations strings.properties (German) * New translations enum.properties (French) * New translations enum.properties (Urdu (Pakistan)) * New translations enum.properties (Spanish, Cuba) * New translations enum.properties (Romanian) * New translations enum.properties (Spanish) * New translations enum.properties (Czech) * New translations enum.properties (German) * New translations enum.properties (Finnish) * New translations enum.properties (Japanese) * New translations enum.properties (Croatian) * New translations enum.properties (Dutch) * New translations enum.properties (Norwegian) * New translations enum.properties (Polish) * New translations enum.properties (Portuguese) * New translations enum.properties (Russian) * New translations enum.properties (Swedish) * New translations enum.properties (Turkish) * New translations enum.properties (Ukrainian) * New translations enum.properties (Chinese Simplified) * New translations enum.properties (Spanish, Ecuador) * New translations strings.properties (Ukrainian) * New translations strings.properties (Chinese Simplified) * New translations captions.properties (Hindi) * New translations captions.properties (Polish) * New translations captions.properties (Portuguese) * New translations captions.properties (Russian) * New translations captions.properties (Swedish) * New translations captions.properties (Turkish) * New translations captions.properties (Ukrainian) * New translations captions.properties (Chinese Simplified) * New translations captions.properties (Spanish, Ecuador) * New translations captions.properties (Croatian) * New translations captions.properties (Filipino) * New translations captions.properties (Dutch) * New translations captions.properties (Fijian) * New translations captions.properties (Swahili) * New translations captions.properties (German, Switzerland) * New translations captions.properties (French, Switzerland) * New translations captions.properties (Italian, Switzerland) * New translations captions.properties (Dari) * New translations captions.properties (Pashto) * New translations captions.properties (Spanish, Cuba) * New translations captions.properties (English, Afghanistan) * New translations captions.properties (English, Nigeria) * New translations captions.properties (Norwegian) * New translations captions.properties (Japanese) * New translations strings.properties (Urdu (Pakistan)) * New translations strings.properties (Dari) * New translations strings.properties (Spanish, Ecuador) * New translations strings.properties (Croatian) * New translations strings.properties (Hindi) * New translations strings.properties (Filipino) * New translations strings.properties (Fijian) * New translations strings.properties (Swahili) * New translations strings.properties (German, Switzerland) * New translations strings.properties (French, Switzerland) * New translations strings.properties (Italian, Switzerland) * New translations strings.properties (Pashto) * New translations captions.properties (Italian) * New translations strings.properties (Spanish, Cuba) * New translations strings.properties (English, Afghanistan) * New translations strings.properties (English, Nigeria) * New translations strings.properties (English, Ghana) * New translations captions.properties (German) * New translations captions.properties (Romanian) * New translations captions.properties (French) * New translations captions.properties (Spanish) * New translations captions.properties (Czech) * New translations captions.properties (Finnish) * New translations captions.properties (English, Ghana) * New translations enum.properties (German, Switzerland) * New translations strings.properties (German, Switzerland) * New translations captions.properties (German, Switzerland) * New translations strings.properties (French) * New translations validations.properties (Czech) * New translations strings.properties (Dari) * New translations strings.properties (Pashto) * New translations strings.properties (Spanish, Cuba) * New translations strings.properties (English, Afghanistan) * New translations strings.properties (English, Nigeria) * New translations strings.properties (English, Ghana) * New translations validations.properties (Romanian) * New translations validations.properties (French) * New translations validations.properties (Spanish) * New translations validations.properties (German) * New translations strings.properties (French, Switzerland) * New translations validations.properties (Finnish) * New translations validations.properties (Italian) * New translations validations.properties (Japanese) * New translations validations.properties (Dutch) * New translations validations.properties (Norwegian) * New translations validations.properties (Polish) * New translations validations.properties (Portuguese) * New translations validations.properties (Russian) * New translations validations.properties (Swedish) * New translations validations.properties (Turkish) * New translations strings.properties (Italian, Switzerland) * New translations strings.properties (German, Switzerland) * New translations strings.properties (German) * New translations strings.properties (Portuguese) * New translations validations.properties (Urdu (Pakistan)) * New translations strings.properties (Romanian) * New translations strings.properties (Spanish) * New translations strings.properties (Czech) * New translations strings.properties (Finnish) * New translations strings.properties (Italian) * New translations strings.properties (Japanese) * New translations strings.properties (Dutch) * New translations strings.properties (Norwegian) * New translations strings.properties (Polish) * New translations strings.properties (Russian) * New translations strings.properties (Swahili) * New translations strings.properties (Swedish) * New translations strings.properties (Turkish) * New translations strings.properties (Ukrainian) * New translations strings.properties (Chinese Simplified) * New translations strings.properties (Urdu (Pakistan)) * New translations strings.properties (Spanish, Ecuador) * New translations strings.properties (Croatian) * New translations strings.properties (Hindi) * New translations strings.properties (Filipino) * New translations strings.properties (Fijian) * New translations validations.properties (Ukrainian) * New translations validations.properties (Chinese Simplified) * New translations validations.properties (Spanish, Ecuador) * New translations validations.properties (Croatian) * New translations validations.properties (Hindi) * New translations validations.properties (Filipino) * New translations validations.properties (Fijian) * New translations validations.properties (Swahili) * New translations validations.properties (German, Switzerland) * New translations validations.properties (French, Switzerland) * New translations validations.properties (Italian, Switzerland) * New translations validations.properties (Dari) * New translations validations.properties (Pashto) * New translations validations.properties (Spanish, Cuba) * New translations validations.properties (English, Afghanistan) * New translations validations.properties (English, Nigeria) * New translations validations.properties (English, Ghana) * New translations strings.properties (French) * New translations enum.properties (French) * New translations strings.properties (German, Switzerland) * New translations strings.properties (Spanish, Cuba) * New translations captions.properties (Norwegian) * New translations captions.properties (Romanian) * New translations captions.properties (French) * New translations captions.properties (Spanish) * New translations captions.properties (Czech) * New translations captions.properties (Finnish) * New translations captions.properties (Italian) * New translations captions.properties (Japanese) * New translations captions.properties (Dutch) * New translations captions.properties (German) * New translations captions.properties (Dari) * New translations captions.properties (German, Switzerland) * New translations captions.properties (French, Switzerland) * New translations captions.properties (Italian, Switzerland) * New translations captions.properties (Urdu (Pakistan)) * New translations captions.properties (Pashto) * New translations captions.properties (Spanish, Cuba) * New translations captions.properties (English, Afghanistan) * New translations captions.properties (English, Nigeria) * New translations captions.properties (Fijian) * New translations captions.properties (Swahili) * New translations captions.properties (Ukrainian) * New translations captions.properties (Filipino) * New translations captions.properties (Hindi) * New translations captions.properties (Croatian) * New translations captions.properties (Spanish, Ecuador) * New translations captions.properties (Chinese Simplified) * New translations captions.properties (Turkish) * New translations captions.properties (Swedish) * New translations captions.properties (Russian) * New translations captions.properties (Portuguese) * New translations captions.properties (Polish) * New translations captions.properties (English, Ghana) * New translations captions.properties (Urdu (Pakistan)) * New translations captions.properties (German) * New translations captions.properties (Czech) * New translations captions.properties (German, Switzerland) * New translations captions.properties (Spanish, Cuba) * New translations enum.properties (French) * New translations enum.properties (Urdu (Pakistan)) * New translations enum.properties (English, Nigeria) * New translations enum.properties (English, Afghanistan) * New translations enum.properties (Spanish, Cuba) * New translations enum.properties (Pashto) * New translations enum.properties (Dari) * New translations enum.properties (Italian, Switzerland) * New translations enum.properties (French, Switzerland) * New translations enum.properties (German, Switzerland) * New translations enum.properties (Swahili) * New translations enum.properties (Fijian) * New translations enum.properties (Filipino) * New translations enum.properties (Hindi) * New translations enum.properties (Croatian) * New translations enum.properties (Spanish, Ecuador) * New translations enum.properties (Chinese Simplified) * New translations enum.properties (German) * New translations enum.properties (Ukrainian) * New translations enum.properties (Turkish) * New translations enum.properties (Swedish) * New translations enum.properties (Russian) * New translations enum.properties (Portuguese) * New translations enum.properties (Polish) * New translations enum.properties (Norwegian) * New translations enum.properties (Dutch) * New translations enum.properties (Japanese) * New translations enum.properties (Italian) * New translations enum.properties (Finnish) * New translations enum.properties (Czech) * New translations enum.properties (Spanish) * New translations enum.properties (Romanian) * New translations enum.properties (English, Ghana) Co-authored-by: Maté Strysewske --- .../src/main/resources/enum_cs-CZ.properties | 18 +++++++----------- .../src/main/resources/enum_de-CH.properties | 18 +++++++----------- .../src/main/resources/enum_de-DE.properties | 18 +++++++----------- .../src/main/resources/enum_en-AF.properties | 18 +++++++----------- .../src/main/resources/enum_en-GH.properties | 18 +++++++----------- .../src/main/resources/enum_en-NG.properties | 18 +++++++----------- .../src/main/resources/enum_es-CU.properties | 18 +++++++----------- .../src/main/resources/enum_es-EC.properties | 18 +++++++----------- .../src/main/resources/enum_es-ES.properties | 18 +++++++----------- .../src/main/resources/enum_fa-AF.properties | 18 +++++++----------- .../src/main/resources/enum_fi-FI.properties | 18 +++++++----------- .../src/main/resources/enum_fil-PH.properties | 18 +++++++----------- .../src/main/resources/enum_fj-FJ.properties | 18 +++++++----------- .../src/main/resources/enum_fr-CH.properties | 18 +++++++----------- .../src/main/resources/enum_fr-FR.properties | 18 +++++++----------- .../src/main/resources/enum_hi-IN.properties | 18 +++++++----------- .../src/main/resources/enum_hr-HR.properties | 18 +++++++----------- .../src/main/resources/enum_it-CH.properties | 18 +++++++----------- .../src/main/resources/enum_it-IT.properties | 18 +++++++----------- .../src/main/resources/enum_ja-JP.properties | 18 +++++++----------- .../src/main/resources/enum_nl-NL.properties | 18 +++++++----------- .../src/main/resources/enum_no-NO.properties | 18 +++++++----------- .../src/main/resources/enum_pl-PL.properties | 18 +++++++----------- .../src/main/resources/enum_ps-AF.properties | 18 +++++++----------- .../src/main/resources/enum_pt-PT.properties | 18 +++++++----------- .../src/main/resources/enum_ro-RO.properties | 18 +++++++----------- .../src/main/resources/enum_ru-RU.properties | 18 +++++++----------- .../src/main/resources/enum_sv-SE.properties | 18 +++++++----------- .../src/main/resources/enum_sw-KE.properties | 18 +++++++----------- .../src/main/resources/enum_tr-TR.properties | 18 +++++++----------- .../src/main/resources/enum_uk-UA.properties | 18 +++++++----------- .../src/main/resources/enum_ur-PK.properties | 18 +++++++----------- .../src/main/resources/enum_zh-CN.properties | 18 +++++++----------- 33 files changed, 231 insertions(+), 363 deletions(-) diff --git a/sormas-api/src/main/resources/enum_cs-CZ.properties b/sormas-api/src/main/resources/enum_cs-CZ.properties index 561aa8b4571..d43e8672a36 100644 --- a/sormas-api/src/main/resources/enum_cs-CZ.properties +++ b/sormas-api/src/main/resources/enum_cs-CZ.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = Obecné údaje o osobě ExportGroupType.HOSPITALIZATION = Data o hospitalizaci ExportGroupType.EPIDEMIOLOGICAL = Epidemiologická data ExportGroupType.VACCINATION = Data o očkování -ExportGroupType.CASE_MANAGEMENT = Data řízení případů ExportGroupType.FOLLOW_UP = Data následných opatření ExportGroupType.ADDITIONAL = Další Data ExportGroupType.LOCATION = Údaje o poloze ExportGroupType.EVENT = Data události ExportGroupType.EVENT_GROUP = Data skupiny událostí ExportGroupType.EVENT_SOURCE = Zdroj dat události +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Nelze použít EventSourceType.MEDIA_NEWS = Média/Noviny @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = Zobrazit archivované případy UserRight.CASE_TRANSFER = Přenos případů do jiného regionu/okresu/zařízení UserRight.CASE_REFER_FROM_POE = Viz případ z místa vstupu UserRight.CASE_VIEW = Zobrazit existující případy -UserRight.CONFIGURATION_ACCESS = Nastavení systému přístupu UserRight.CONTACT_ASSIGN = Přiřadit kontakty úředníkům UserRight.CONTACT_CLASSIFY = Upravit klasifikaci kontaktů UserRight.CONTACT_CONVERT = Vytvořit výsledné případy z kontaktů @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Upravit existující kontakty UserRight.CONTACT_EXPORT = Exportovat kontakty ze SORMAS UserRight.CONTACT_SEE_ARCHIVED = Zobrazit archivované kontakty UserRight.CONTACT_VIEW = Zobrazit existující kontakty -UserRight.DASHBOARD_VIEW = Zobrazit ovládací panel -UserRight.DASHBOARD_CONTACT_ACCESS = Přístup k ovládacínu panelu kontaktního orgánu -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Přístup do ovládacího panelu dozorčího orgánu +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Exportovat celou databázi UserRight.EVENT_ARCHIVE = Archivovat události UserRight.EVENT_CREATE = Vytvořit nové události @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Upravit existující účastníky události UserRight.INFRASTRUCTURE_CREATE = Vytvořit nové regiony/okresy/komunity/zařízení UserRight.INFRASTRUCTURE_EDIT = Upravit regiony/okresy/komunity/zařízení UserRight.INFRASTRUCTURE_VIEW = Zobrazit regiony/okresy/komunity/zařízení v systému -UserRight.OUTBREAK_CONFIGURE_ALL = Konfigurovat ohniska pro všechny regiony -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Konfigurovat ohniska pro přiřazený region UserRight.PERFORM_BULK_OPERATIONS = Provést hromadné operace v seznamech UserRight.SAMPLE_CREATE = Vytvořit nové vzorky UserRight.SAMPLE_EDIT = Upravit existující vzorky @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Provést hromadné operace na v UserRight.INFRASTRUCTURE_EXPORT = Exportovat data infrastruktury ze SORMAS UserRight.INFRASTRUCTURE_IMPORT = Importovat data infrastruktury UserRight.INFRASTRUCTURE_ARCHIVE = Importovat data infrastruktury -UserRight.USER_RIGHTS_MANAGE = Správa uživatelských práv UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = Zobrazit řetězce přenosu kontaktů na ovládacím panelu -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Ovládací panel kampaní přístupu -UserRight.CASE_MANAGEMENT_ACCESS = Oddíly pro případy přístupu, které se týkají řízení případů +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = Zobrazit existující terapie UserRight.PRESCRIPTION_CREATE = Vytvořit nový předpis UserRight.PRESCRIPTION_EDIT = Upravit existující předpisy @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Spravovat populační data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Spravovat šablony dokumentů UserRight.QUARANTINE_ORDER_CREATE = Vytvořit nové karanténní příkazy UserRight.LINE_LISTING_CONFIGURE = Konfigurovat řádek výpisu -UserRight.LINE_LISTING_CONFIGURE_NATION = Konfigurace řádkového seznamu na vnitrostátní úrovni UserRight.AGGREGATE_REPORT_VIEW = Vytvořit nové souhrnné zprávy UserRight.AGGREGATE_REPORT_EXPORT = Exportovat souhrnné zprávy ze SORMAS UserRight.AGGREGATE_REPORT_EDIT = Upravit existující souhrnné zprávy @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Exportovat data o ochraně údajů +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Vyšetřování případů diff --git a/sormas-api/src/main/resources/enum_de-CH.properties b/sormas-api/src/main/resources/enum_de-CH.properties index a570f961b47..1eb86d076b3 100644 --- a/sormas-api/src/main/resources/enum_de-CH.properties +++ b/sormas-api/src/main/resources/enum_de-CH.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = Allgemeine Personendaten ExportGroupType.HOSPITALIZATION = Daten zum Krankenhausaufenthalt ExportGroupType.EPIDEMIOLOGICAL = Epidemiologische Daten ExportGroupType.VACCINATION = Impfdaten -ExportGroupType.CASE_MANAGEMENT = Daten zur Fallverwaltung ExportGroupType.FOLLOW_UP = Daten der Nachverfolgung ExportGroupType.ADDITIONAL = Zusätzliche Daten ExportGroupType.LOCATION = Ortsdaten ExportGroupType.EVENT = Ereignisdaten ExportGroupType.EVENT_GROUP = Ereignisgruppendaten ExportGroupType.EVENT_SOURCE = Ereignis-Quelldaten +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Nicht zutreffend EventSourceType.MEDIA_NEWS = Medien/Neuigkeiten @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = Archivierte Fälle anzeigen UserRight.CASE_TRANSFER = Fälle zu einem anderen Kanton/Bezirk/Einrichtung übertragen UserRight.CASE_REFER_FROM_POE = Fall vom Einreiseort weiterleiten UserRight.CASE_VIEW = Bestehende Fälle anzeigen -UserRight.CONFIGURATION_ACCESS = Zugriff auf Systemkonfiguration UserRight.CONTACT_ASSIGN = Kontakte an Beauftragte zuweisen UserRight.CONTACT_CLASSIFY = Kontaktdefinitionskategorie ändern UserRight.CONTACT_CONVERT = Erstelle resultierende Fälle aus Kontakten @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Bestehende Kontakte bearbeiten UserRight.CONTACT_EXPORT = Kontakte von SORMAS exportieren UserRight.CONTACT_SEE_ARCHIVED = Archivierte Kontakte anzeigen UserRight.CONTACT_VIEW = Bestehende Kontakte anzeigen -UserRight.DASHBOARD_VIEW = Übersicht anzeigen -UserRight.DASHBOARD_CONTACT_ACCESS = Zugriff auf die Kontaktleitungs-Übersicht -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Zugriff auf die Überwachungsleitungs-Übersicht +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Die gesamte Datenbank exportieren UserRight.EVENT_ARCHIVE = Ereignisse archivieren UserRight.EVENT_CREATE = Neue Ereignisse erstellen @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Bestehende Ereignisteilnehmende bearbeiten UserRight.INFRASTRUCTURE_CREATE = Neue Kantone/Bezirke/Gemeinden/Einrichtungen erstellen UserRight.INFRASTRUCTURE_EDIT = Kantone/Bezirke/Gemeinden/Einrichtungen bearbeiten UserRight.INFRASTRUCTURE_VIEW = Kantone/Bezirke/Gemeinden/Einrichtungen im System anzeigen -UserRight.OUTBREAK_CONFIGURE_ALL = Ausbrüche für alle Kantone konfigurieren -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Ausbrüche für zugewiesenes Kanton konfigurieren UserRight.PERFORM_BULK_OPERATIONS = Massen-Operationen in Listen durchführen UserRight.SAMPLE_CREATE = Neue Proben erstellen UserRight.SAMPLE_EDIT = Bestehende Proben bearbeiten @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Massenbearbeitung von Fall-Prob UserRight.INFRASTRUCTURE_EXPORT = Infrastrukturdaten von SORMAS exportieren UserRight.INFRASTRUCTURE_IMPORT = Infrastrukturdaten importieren UserRight.INFRASTRUCTURE_ARCHIVE = Infrastrukturdaten archivieren -UserRight.USER_RIGHTS_MANAGE = Benutzerrechte verwalten UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = Kontaktübertragungsketten auf dem Dashboard einsehen -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Zugriff auf Kampagnen Dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Zugriff auf Fallabschnitte im Zusammenhang mit der Fallverwaltung +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = Vorhandene Therapien einsehen UserRight.PRESCRIPTION_CREATE = Neue Verschreibungen erstellen UserRight.PRESCRIPTION_EDIT = Vorhandene Verschreibungen bearbeiten @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Bevölkerungsdaten verwalten UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Dokumentvorlagen verwalten UserRight.QUARANTINE_ORDER_CREATE = Neue Dokumente erstellen UserRight.LINE_LISTING_CONFIGURE = Zeilenauflistung konfigurieren -UserRight.LINE_LISTING_CONFIGURE_NATION = Zeilenauflistung auf nationaler Ebene konfigurieren UserRight.AGGREGATE_REPORT_VIEW = Neue zusammenfassende Berichte erstellen UserRight.AGGREGATE_REPORT_EXPORT = Zusammenfassende Berichte von SORMAS exportieren UserRight.AGGREGATE_REPORT_EDIT = Bestehende Berichte bearbeiten @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Vorhandene Einreisen bearbeiten UserRight.TRAVEL_ENTRY_DELETE = Einreisen aus dem System löschen UserRight.TRAVEL_ENTRY_ARCHIVE = Einreisen archivieren UserRight.EXPORT_DATA_PROTECTION_DATA = Datenschutz-Daten exportieren +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Falluntersuchung diff --git a/sormas-api/src/main/resources/enum_de-DE.properties b/sormas-api/src/main/resources/enum_de-DE.properties index 93b9480cef6..2ae2235e8d8 100644 --- a/sormas-api/src/main/resources/enum_de-DE.properties +++ b/sormas-api/src/main/resources/enum_de-DE.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = Allgemeine Personendaten ExportGroupType.HOSPITALIZATION = Daten zum Krankenhausaufenthalt ExportGroupType.EPIDEMIOLOGICAL = Epidemiologische Daten ExportGroupType.VACCINATION = Impfdaten -ExportGroupType.CASE_MANAGEMENT = Daten zur Fallverwaltung ExportGroupType.FOLLOW_UP = Nachverfolgungsdaten ExportGroupType.ADDITIONAL = Zusätzliche Daten ExportGroupType.LOCATION = Ortsdaten ExportGroupType.EVENT = Ereignisdaten ExportGroupType.EVENT_GROUP = Ereignisgruppendaten ExportGroupType.EVENT_SOURCE = Ereignis-Quelldaten +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Nicht erhoben EventSourceType.MEDIA_NEWS = Medien/ Nachrichten @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = Archivierte Fälle anzeigen UserRight.CASE_TRANSFER = Fälle zu einem anderen Bundesland/Landkreis/Einrichtung übertragen UserRight.CASE_REFER_FROM_POE = Fall vom Einreiseort weiterleiten UserRight.CASE_VIEW = Bestehende Fälle anzeigen -UserRight.CONFIGURATION_ACCESS = Zugriff auf Systemkonfiguration UserRight.CONTACT_ASSIGN = Kontakte an Beauftragte zuweisen UserRight.CONTACT_CLASSIFY = Kontaktklassifikation ändern UserRight.CONTACT_CONVERT = Erstelle resultierende Fälle aus Kontakten @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Bestehende Kontakte bearbeiten UserRight.CONTACT_EXPORT = Kontakte von SORMAS exportieren UserRight.CONTACT_SEE_ARCHIVED = Archivierte Kontakte anzeigen UserRight.CONTACT_VIEW = Bestehende Kontakte anzeigen -UserRight.DASHBOARD_VIEW = Übersicht anzeigen -UserRight.DASHBOARD_CONTACT_ACCESS = Zugriff auf die Kontaktleitungs-Übersicht -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Zugriff auf die Überwachungsleitungs-Übersicht +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Die gesamte Datenbank exportieren UserRight.EVENT_ARCHIVE = Ereignisse archivieren UserRight.EVENT_CREATE = Neue Ereignisse erstellen @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Bestehende Ereignisteilnehmende bearbeiten UserRight.INFRASTRUCTURE_CREATE = Neue Bundesländer/Landkreise/Gemeinden/Einrichtungen erstellen UserRight.INFRASTRUCTURE_EDIT = Bearbeite Bundesländer/Landkreise/Gemeinden/Einrichtungen UserRight.INFRASTRUCTURE_VIEW = Bundesländer/Landkreise/Gemeinden/Einrichtungen im System anzeigen -UserRight.OUTBREAK_CONFIGURE_ALL = Ausbrüche für alle Bundesländer konfigurieren -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Ausbrüche für zugewiesenes Bundesland konfigurieren UserRight.PERFORM_BULK_OPERATIONS = Massen-Operationen in Listen durchführen UserRight.SAMPLE_CREATE = Neue Proben erstellen UserRight.SAMPLE_EDIT = Bestehende Proben bearbeiten @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Massenbearbeitung von Fall-Prob UserRight.INFRASTRUCTURE_EXPORT = Infrastrukturdaten von SORMAS exportieren UserRight.INFRASTRUCTURE_IMPORT = Infrastrukturdaten importieren UserRight.INFRASTRUCTURE_ARCHIVE = Infrastrukturdaten archivieren -UserRight.USER_RIGHTS_MANAGE = Benutzerrechte verwalten UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = Kontaktübertragungsketten auf dem Dashboard einsehen -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Zugriff auf Kampagnen Dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Zugriff auf Fallabschnitte im Zusammenhang mit der Fallverwaltung +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = Vorhandene Therapien einsehen UserRight.PRESCRIPTION_CREATE = Neue Verschreibungen erstellen UserRight.PRESCRIPTION_EDIT = Vorhandene Verschreibungen bearbeiten @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Bevölkerungsdaten verwalten UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Dokumentvorlagen verwalten UserRight.QUARANTINE_ORDER_CREATE = Neue Dokumente erstellen UserRight.LINE_LISTING_CONFIGURE = Zeilenauflistung konfigurieren -UserRight.LINE_LISTING_CONFIGURE_NATION = Zeilenauflistung auf nationaler Ebene konfigurieren UserRight.AGGREGATE_REPORT_VIEW = Neue zusammenfassende Berichte erstellen UserRight.AGGREGATE_REPORT_EXPORT = Zusammenfassende Berichte von SORMAS exportieren UserRight.AGGREGATE_REPORT_EDIT = Bestehende Berichte bearbeiten @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Vorhandene Einreisen bearbeiten UserRight.TRAVEL_ENTRY_DELETE = Einreisen aus dem System löschen UserRight.TRAVEL_ENTRY_ARCHIVE = Einreisen archivieren UserRight.EXPORT_DATA_PROTECTION_DATA = Datenschutz-Daten exportieren +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Falluntersuchung diff --git a/sormas-api/src/main/resources/enum_en-AF.properties b/sormas-api/src/main/resources/enum_en-AF.properties index 821bd202205..c05627d2a11 100644 --- a/sormas-api/src/main/resources/enum_en-AF.properties +++ b/sormas-api/src/main/resources/enum_en-AF.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another province/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new provinces/districts/clusters/villages UserRight.INFRASTRUCTURE_EDIT = Edit provinces/districts/clusters/villages UserRight.INFRASTRUCTURE_VIEW = View provinces/districts/clusters/villages in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all provinces -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned province UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_en-GH.properties b/sormas-api/src/main/resources/enum_en-GH.properties index 2afd1c0202b..d75b061e3f6 100644 --- a/sormas-api/src/main/resources/enum_en-GH.properties +++ b/sormas-api/src/main/resources/enum_en-GH.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/sub districts/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/sub districts/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/sub districts/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_en-NG.properties b/sormas-api/src/main/resources/enum_en-NG.properties index 038404d8dda..c12df24d20c 100644 --- a/sormas-api/src/main/resources/enum_en-NG.properties +++ b/sormas-api/src/main/resources/enum_en-NG.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/communities/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/communities/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/communities/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_es-CU.properties b/sormas-api/src/main/resources/enum_es-CU.properties index 5402e1706a8..e507fefccb0 100644 --- a/sormas-api/src/main/resources/enum_es-CU.properties +++ b/sormas-api/src/main/resources/enum_es-CU.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = Datos personales generales ExportGroupType.HOSPITALIZATION = Datos de hospitalización ExportGroupType.EPIDEMIOLOGICAL = Datos epidemiológicos ExportGroupType.VACCINATION = Datos de vacunación -ExportGroupType.CASE_MANAGEMENT = Datos de gestión de casos ExportGroupType.FOLLOW_UP = Datos de seguimiento ExportGroupType.ADDITIONAL = Datos adicionales ExportGroupType.LOCATION = Datos de ubicación ExportGroupType.EVENT = Datos de evento ExportGroupType.EVENT_GROUP = Datos de grupo de eventos ExportGroupType.EVENT_SOURCE = Datos fuente del evento +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = No aplicable EventSourceType.MEDIA_NEWS = Medios/Noticias @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = Ver casos archivados UserRight.CASE_TRANSFER = Transferir casos a otra provincia/municipio/centro UserRight.CASE_REFER_FROM_POE = Referir caso desde punto de entrada UserRight.CASE_VIEW = Ver casos existentes -UserRight.CONFIGURATION_ACCESS = Acceder a la configuración del sistema UserRight.CONTACT_ASSIGN = Asignar contactos a funcionarios UserRight.CONTACT_CLASSIFY = Editar clasificación de contactos UserRight.CONTACT_CONVERT = Crear casos resultantes a partir de contactos @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Editar contactos existentes UserRight.CONTACT_EXPORT = Exportar contactos de SORMAS UserRight.CONTACT_SEE_ARCHIVED = Ver contactos archivados UserRight.CONTACT_VIEW = Ver contactos existentes -UserRight.DASHBOARD_VIEW = Ver el tablero de control -UserRight.DASHBOARD_CONTACT_ACCESS = Acceder al tablero de control de supervisor de contactos -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Acceder al tablero de control de supervisor de vigilancia +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Exportar toda la base de datos UserRight.EVENT_ARCHIVE = Archivar eventos UserRight.EVENT_CREATE = Crear nuevos eventos @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Editar participantes existentes de evento UserRight.INFRASTRUCTURE_CREATE = Crear nuevas provincias/municipios/áreas de salud/centros UserRight.INFRASTRUCTURE_EDIT = Editar provincias/municipios/áreas de salud/centros UserRight.INFRASTRUCTURE_VIEW = Ver provincias/municipios/áreas de salud/centros en el sistema -UserRight.OUTBREAK_CONFIGURE_ALL = Configurar brotes para todas las provincias -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configurar brotes para la provincia asignada UserRight.PERFORM_BULK_OPERATIONS = Realizar operaciones masivas en listas UserRight.SAMPLE_CREATE = Crear nuevas muestras UserRight.SAMPLE_EDIT = Editar muestras existentes @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Realizar operaciones masivas en UserRight.INFRASTRUCTURE_EXPORT = Exportar datos de infraestructura de SORMAS UserRight.INFRASTRUCTURE_IMPORT = Importar datos de infraestructura UserRight.INFRASTRUCTURE_ARCHIVE = Archivar datos de infraestructura -UserRight.USER_RIGHTS_MANAGE = Administrar derechos de usuario UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = Ver cadenas de transmisión de contactos en el tablero de control -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Acceso a tablero de control de campañas -UserRight.CASE_MANAGEMENT_ACCESS = Acceso a secciones de casos relacionadas con la gestión de casos +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = Ver terapias existentes UserRight.PRESCRIPTION_CREATE = Crear nuevas prescripciones UserRight.PRESCRIPTION_EDIT = Editar prescripciones existentes @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Administrar datos de población UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Administrar plantillas de documento UserRight.QUARANTINE_ORDER_CREATE = Crear nuevas órdenes de cuarentena UserRight.LINE_LISTING_CONFIGURE = Configurar listado de líneas -UserRight.LINE_LISTING_CONFIGURE_NATION = Configurar listado de líneas a nivel nacional UserRight.AGGREGATE_REPORT_VIEW = Crear nuevos informes agregados UserRight.AGGREGATE_REPORT_EXPORT = Exportar informes agregados de SORMAS UserRight.AGGREGATE_REPORT_EDIT = Editar informes agregados existentes @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Editar entradas de viaje existentes UserRight.TRAVEL_ENTRY_DELETE = Eliminar entradas de viaje del sistema UserRight.TRAVEL_ENTRY_ARCHIVE = Archivar entradas de viaje UserRight.EXPORT_DATA_PROTECTION_DATA = Exportar datos de protección de datos +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Investigación de caso diff --git a/sormas-api/src/main/resources/enum_es-EC.properties b/sormas-api/src/main/resources/enum_es-EC.properties index 65142823ee1..29ca9fa68e7 100644 --- a/sormas-api/src/main/resources/enum_es-EC.properties +++ b/sormas-api/src/main/resources/enum_es-EC.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = Datos personales generales ExportGroupType.HOSPITALIZATION = Datos de hospitalización ExportGroupType.EPIDEMIOLOGICAL = Datos epidemiológicos ExportGroupType.VACCINATION = Datos de vacunación -ExportGroupType.CASE_MANAGEMENT = Datos de gestión de caso ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Datos adicionales ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = Ver casos archivados UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = Ver casos existentes -UserRight.CONFIGURATION_ACCESS = Acceder a la configuración del sistema UserRight.CONTACT_ASSIGN = Asignar contactos a Oficiales UserRight.CONTACT_CLASSIFY = Editar clasificación de contacto UserRight.CONTACT_CONVERT = Crear casos resultantes desde contactos @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Editar contactos existentes UserRight.CONTACT_EXPORT = Exportar contactos desde SORMAS UserRight.CONTACT_SEE_ARCHIVED = Ver contactos archivados UserRight.CONTACT_VIEW = Ver contactos existentes -UserRight.DASHBOARD_VIEW = Mirar tablero de control -UserRight.DASHBOARD_CONTACT_ACCESS = Acceder el tablero de control de supervisor de contactos -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Acceder tablero de control de supervisor de vigilancia +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Exportar toda la base de datos UserRight.EVENT_ARCHIVE = Eventos archivados UserRight.EVENT_CREATE = Crear nuevos eventos @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Editar participantes existentes de evento UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/communities/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/communities/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/communities/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Realizar operaciones masivas en listas UserRight.SAMPLE_CREATE = Crear nuevas muestras UserRight.SAMPLE_EDIT = Editar muestras existentes @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Investigación de caso diff --git a/sormas-api/src/main/resources/enum_es-ES.properties b/sormas-api/src/main/resources/enum_es-ES.properties index 038404d8dda..c12df24d20c 100644 --- a/sormas-api/src/main/resources/enum_es-ES.properties +++ b/sormas-api/src/main/resources/enum_es-ES.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/communities/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/communities/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/communities/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_fa-AF.properties b/sormas-api/src/main/resources/enum_fa-AF.properties index 73214e3eeb4..46253b11430 100644 --- a/sormas-api/src/main/resources/enum_fa-AF.properties +++ b/sormas-api/src/main/resources/enum_fa-AF.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/communities/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/communities/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/communities/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_fi-FI.properties b/sormas-api/src/main/resources/enum_fi-FI.properties index 2d7e8966f88..b632fe4161e 100644 --- a/sormas-api/src/main/resources/enum_fi-FI.properties +++ b/sormas-api/src/main/resources/enum_fi-FI.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = Yleiset henkilötiedot ExportGroupType.HOSPITALIZATION = Sairaalahoidon tiedot ExportGroupType.EPIDEMIOLOGICAL = Epidemiologiset tiedot ExportGroupType.VACCINATION = Rokotustiedot -ExportGroupType.CASE_MANAGEMENT = Potilaiden käsittelytiedot ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Lisätiedot ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = Näytä arkistoidut potilaat UserRight.CASE_TRANSFER = Siirrä potilaat toiseen erva-alueeseen / sairaanhoitopiiriin / hoitolaitokseen UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = Näytä olemassaolevat potilaat -UserRight.CONFIGURATION_ACCESS = Hallinnoi järjestelmäasetuksia UserRight.CONTACT_ASSIGN = Toimeksianna kontaktit virkailijoille UserRight.CONTACT_CLASSIFY = Muokkaa kontaktiluokitusta UserRight.CONTACT_CONVERT = Lisää tartunnan saaneita potilaita kontakteista @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Muokkaa olemassaolevia kontakteja UserRight.CONTACT_EXPORT = Vie kontakteja SORMAS-järjestelmästä UserRight.CONTACT_SEE_ARCHIVED = Näytä arkistoidut kontaktit UserRight.CONTACT_VIEW = Näytä olemassaolevat kontaktit -UserRight.DASHBOARD_VIEW = Näytä hallintatyöpöytä -UserRight.DASHBOARD_CONTACT_ACCESS = Kontaktivalvojan hallintatyöpöytä -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Seurantavalvojan työpöytä +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Vie koko tietokanta UserRight.EVENT_ARCHIVE = Arkistoi tapahtumia UserRight.EVENT_CREATE = Luo uusia tapahtumia @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Muokkaa olemassaolevan tapahtuman osallistujia UserRight.INFRASTRUCTURE_CREATE = Luo uusia erva-alueita/sairaanhoitopiirejä/kuntia/hoitolaitoksia UserRight.INFRASTRUCTURE_EDIT = Mokkaa erva-alueita/sairaanhoitopiirejä/kuntia/hoitolaitoksia UserRight.INFRASTRUCTURE_VIEW = Katsele järjestelmässä olevia erva-alueita/sairaanhoitopiirejä/kuntia/hoitolaitoksia -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Tee listoille massaoperaatioita UserRight.SAMPLE_CREATE = Lisää uusia näytteitä UserRight.SAMPLE_EDIT = Muokkaa olemassaolevia näytteitä @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Potilaan selvittely diff --git a/sormas-api/src/main/resources/enum_fil-PH.properties b/sormas-api/src/main/resources/enum_fil-PH.properties index 038404d8dda..c12df24d20c 100644 --- a/sormas-api/src/main/resources/enum_fil-PH.properties +++ b/sormas-api/src/main/resources/enum_fil-PH.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/communities/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/communities/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/communities/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_fj-FJ.properties b/sormas-api/src/main/resources/enum_fj-FJ.properties index 038404d8dda..c12df24d20c 100644 --- a/sormas-api/src/main/resources/enum_fj-FJ.properties +++ b/sormas-api/src/main/resources/enum_fj-FJ.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/communities/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/communities/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/communities/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_fr-CH.properties b/sormas-api/src/main/resources/enum_fr-CH.properties index bc68ecaa17b..48155de569e 100644 --- a/sormas-api/src/main/resources/enum_fr-CH.properties +++ b/sormas-api/src/main/resources/enum_fr-CH.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = Données personnelles générales ExportGroupType.HOSPITALIZATION = Données d'hospitalisation ExportGroupType.EPIDEMIOLOGICAL = Données épidémiologiques ExportGroupType.VACCINATION = Données de vaccination -ExportGroupType.CASE_MANAGEMENT = Données de gestion de cas ExportGroupType.FOLLOW_UP = Données de suivi ExportGroupType.ADDITIONAL = Données supplémentaires ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Données de l'événement ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Non applicable EventSourceType.MEDIA_NEWS = Médias/Actualités @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = Afficher les cas archivés UserRight.CASE_TRANSFER = Transférer des cas vers un autre Région/District/établissement UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = Voir les cas existants -UserRight.CONFIGURATION_ACCESS = Accéss sur le système de configuration UserRight.CONTACT_ASSIGN = Attribuer des contacts aux officiers UserRight.CONTACT_CLASSIFY = Modifier la classification des contacts UserRight.CONTACT_CONVERT = Créer les cas résultant des contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Modifier les contacts existants UserRight.CONTACT_EXPORT = Exporter les contacts de SORMAS UserRight.CONTACT_SEE_ARCHIVED = Voir les contacts archivés UserRight.CONTACT_VIEW = Voir les contacts existants -UserRight.DASHBOARD_VIEW = Voir le tableau de bord -UserRight.DASHBOARD_CONTACT_ACCESS = Accéder le tableau de bord du superviseur des contacts -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Accéder au tableau de bord du superviseur de surveillance +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Exporter toute la base de données UserRight.EVENT_ARCHIVE = Archiver les événements UserRight.EVENT_CREATE = Créer un nouvel évènement @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Modifier les participants de l'événement exi UserRight.INFRASTRUCTURE_CREATE = Créer de nouveaux états/districts/communes/établissements de santé UserRight.INFRASTRUCTURE_EDIT = Modifier les cantons/districts/communes/établissements UserRight.INFRASTRUCTURE_VIEW = Voir les états/districts/communes/établissements de santé dans le système -UserRight.OUTBREAK_CONFIGURE_ALL = Configurer les épidémies pour tous les états -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configurer les épidémies pour l'état assigné UserRight.PERFORM_BULK_OPERATIONS = Effectuer des opérations en bloc dans des listes UserRight.SAMPLE_CREATE = Créer de nouveaux échantillons UserRight.SAMPLE_EDIT = Modifier les échantillons existants @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Enquête de cas diff --git a/sormas-api/src/main/resources/enum_fr-FR.properties b/sormas-api/src/main/resources/enum_fr-FR.properties index 253aeccf1a5..9603db23f0a 100644 --- a/sormas-api/src/main/resources/enum_fr-FR.properties +++ b/sormas-api/src/main/resources/enum_fr-FR.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = Données personnelles générales ExportGroupType.HOSPITALIZATION = Données d'hospitalisation ExportGroupType.EPIDEMIOLOGICAL = Données épidémiologiques ExportGroupType.VACCINATION = Données de vaccination -ExportGroupType.CASE_MANAGEMENT = Données de gestion de cas ExportGroupType.FOLLOW_UP = Données de suivi ExportGroupType.ADDITIONAL = Données supplémentaires ExportGroupType.LOCATION = Données de localisation ExportGroupType.EVENT = Données de l'événement ExportGroupType.EVENT_GROUP = Données du groupe d'événements ExportGroupType.EVENT_SOURCE = Données de la source de l'événement +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Non applicable EventSourceType.MEDIA_NEWS = Médias/Nouvelles @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = Afficher les cas archivés UserRight.CASE_TRANSFER = Transférer des cas vers une autre région/département/établissement UserRight.CASE_REFER_FROM_POE = Référez le cas à partir du point d'entrée UserRight.CASE_VIEW = Voir les cas existants -UserRight.CONFIGURATION_ACCESS = Accéder à la configuration du système UserRight.CONTACT_ASSIGN = Attribuer des contacts aux officiers UserRight.CONTACT_CLASSIFY = Modifier la classification des contacts UserRight.CONTACT_CONVERT = Créer les cas résultant des contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Modifier les contacts existants UserRight.CONTACT_EXPORT = Exporter les contacts de SORMAS UserRight.CONTACT_SEE_ARCHIVED = Voir les contacts archivés UserRight.CONTACT_VIEW = Voir les contacts existants -UserRight.DASHBOARD_VIEW = Voir le tableau de bord -UserRight.DASHBOARD_CONTACT_ACCESS = Accéder le tableau de bord du superviseur des contacts -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Accéder au tableau de bord du superviseur de surveillance +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Exporter toute la base de données UserRight.EVENT_ARCHIVE = Archiver les événements UserRight.EVENT_CREATE = Créer un nouvel évènement @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Modifier les participants de l'événement exi UserRight.INFRASTRUCTURE_CREATE = Créer de nouvelles régions/départements/communautés/établissements de santé UserRight.INFRASTRUCTURE_EDIT = Créer des régions/départements/communautés/établissements de santé UserRight.INFRASTRUCTURE_VIEW = Voir les régions/départements/communautés/établissements de santé du système -UserRight.OUTBREAK_CONFIGURE_ALL = Configurer les épidémies pour toutes les régions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configurer les épidémies pour une région donnée UserRight.PERFORM_BULK_OPERATIONS = Effectuer des opérations en bloc dans des listes UserRight.SAMPLE_CREATE = Créer de nouveaux échantillons UserRight.SAMPLE_EDIT = Modifier les échantillons existants @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Effectuer des opérations en ma UserRight.INFRASTRUCTURE_EXPORT = Exporter les données d'infrastructure depuis SORMAS UserRight.INFRASTRUCTURE_IMPORT = Importer des données d'infrastructure UserRight.INFRASTRUCTURE_ARCHIVE = Archiver les données d'infrastructure -UserRight.USER_RIGHTS_MANAGE = Gérer les droits de l'utilisateur UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = Afficher les chaînes de transmission des contacts sur le tableau de bord -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Accéder au tableau de bord des campagnes -UserRight.CASE_MANAGEMENT_ACCESS = Accéder aux sections de cas concernées par la gestion des cas +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = Voir les thérapies existantes UserRight.PRESCRIPTION_CREATE = Créer de nouvelles ordonnances UserRight.PRESCRIPTION_EDIT = Modifier les ordonnances existantes @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Gérer les données de la population UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Gérer les modèles de document UserRight.QUARANTINE_ORDER_CREATE = Créer de nouvelles commandes de quarantaine UserRight.LINE_LISTING_CONFIGURE = Configurer la liste de lignes -UserRight.LINE_LISTING_CONFIGURE_NATION = Configurer la liste des lignes au niveau national UserRight.AGGREGATE_REPORT_VIEW = Créer un nouveau rapport agrégé UserRight.AGGREGATE_REPORT_EXPORT = Exporter les rapports agrégés depuis SORMAS UserRight.AGGREGATE_REPORT_EDIT = Modifier les rapports agrégés existants @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Exporter les données de protection des données +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Enquête de cas diff --git a/sormas-api/src/main/resources/enum_hi-IN.properties b/sormas-api/src/main/resources/enum_hi-IN.properties index 038404d8dda..c12df24d20c 100644 --- a/sormas-api/src/main/resources/enum_hi-IN.properties +++ b/sormas-api/src/main/resources/enum_hi-IN.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/communities/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/communities/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/communities/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_hr-HR.properties b/sormas-api/src/main/resources/enum_hr-HR.properties index 038404d8dda..c12df24d20c 100644 --- a/sormas-api/src/main/resources/enum_hr-HR.properties +++ b/sormas-api/src/main/resources/enum_hr-HR.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/communities/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/communities/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/communities/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_it-CH.properties b/sormas-api/src/main/resources/enum_it-CH.properties index 282a6967f7d..5ed14f84229 100644 --- a/sormas-api/src/main/resources/enum_it-CH.properties +++ b/sormas-api/src/main/resources/enum_it-CH.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = Dati personali generali ExportGroupType.HOSPITALIZATION = Dati ospedalizzazione ExportGroupType.EPIDEMIOLOGICAL = Dati epidemiologici ExportGroupType.VACCINATION = Dati Vaccinazione -ExportGroupType.CASE_MANAGEMENT = Dati della gestione casi ExportGroupType.FOLLOW_UP = Dati Di Follow-up ExportGroupType.ADDITIONAL = Dati aggiuntivi ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Dati Evento ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Non applicabile EventSourceType.MEDIA_NEWS = Media/Notizie @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = Visualizza casi archiviati UserRight.CASE_TRANSFER = Trasferimento di casi in un altro Cantone/distretto/struttura UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = Visualizza casi esistenti -UserRight.CONFIGURATION_ACCESS = Accesso configurazione di systema UserRight.CONTACT_ASSIGN = Assegna contatti a responsabili UserRight.CONTACT_CLASSIFY = Modifica classificazione contatto UserRight.CONTACT_CONVERT = Crea casi risultanti dai contatti @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Modifica contatto esistente UserRight.CONTACT_EXPORT = Esporta contatti da SORMAS UserRight.CONTACT_SEE_ARCHIVED = Visualizza contatti archiviati UserRight.CONTACT_VIEW = Vedi contatti esistenti -UserRight.DASHBOARD_VIEW = Visualizzare il dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Accedi alla dashboard del supervisore di contatto -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Accedi alla dashboard del supervisore di sorveglianza +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Esporta l'intera banca dati UserRight.EVENT_ARCHIVE = Archivia eventi UserRight.EVENT_CREATE = Crea evento nuovo @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Modifica i partecipanti esistenti all'evento UserRight.INFRASTRUCTURE_CREATE = Creare nuovi Cantoni/distretti/comuni/strutture UserRight.INFRASTRUCTURE_EDIT = Modifica nuovi Cantoni/distretti/comuni/strutture UserRight.INFRASTRUCTURE_VIEW = Visualizza Cantoni/distretti/comuni/strutture nel sistema -UserRight.OUTBREAK_CONFIGURE_ALL = Configura focolai per tutti i Cantoni -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configura focolai per Cantone assegnato UserRight.PERFORM_BULK_OPERATIONS = Effettuare operazioni in blocco dentro le liste UserRight.SAMPLE_CREATE = Crea nuovo campione UserRight.SAMPLE_EDIT = Modifica campioni esistenti @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Indagine sul caso diff --git a/sormas-api/src/main/resources/enum_it-IT.properties b/sormas-api/src/main/resources/enum_it-IT.properties index 33021626c6c..5f43a3ec514 100644 --- a/sormas-api/src/main/resources/enum_it-IT.properties +++ b/sormas-api/src/main/resources/enum_it-IT.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = Dati personali generali ExportGroupType.HOSPITALIZATION = Dati ospedalizzazione ExportGroupType.EPIDEMIOLOGICAL = Dati epidemiologici ExportGroupType.VACCINATION = Dati Vaccinazione -ExportGroupType.CASE_MANAGEMENT = Dati della gestione casi ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Dati aggiuntivi ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Non applicabile EventSourceType.MEDIA_NEWS = Media/Notizie @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = Visualizza casi archiviati UserRight.CASE_TRANSFER = Trasferimento di casi in un altro Cantone/distretto/struttura UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = Visualizza casi esistenti -UserRight.CONFIGURATION_ACCESS = Accesso configurazione di systema UserRight.CONTACT_ASSIGN = Assegna contatti a responsabili UserRight.CONTACT_CLASSIFY = Modifica classificazione contatto UserRight.CONTACT_CONVERT = Crea casi risultanti dai contatti @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Modifica contatto esistente UserRight.CONTACT_EXPORT = Esporta contatti da SORMAS UserRight.CONTACT_SEE_ARCHIVED = Visualizza contatti archiviati UserRight.CONTACT_VIEW = Vedi contatti esistenti -UserRight.DASHBOARD_VIEW = Visualizzare la panoramica -UserRight.DASHBOARD_CONTACT_ACCESS = Accedi alla panoramica del supervisore di contatto -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Accedi alla panoramica del supervisore di sorveglianza +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Esporta l'intera banca dati UserRight.EVENT_ARCHIVE = Archivia eventi UserRight.EVENT_CREATE = Crea evento nuovo @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Modifica i partecipanti esistenti all'evento UserRight.INFRASTRUCTURE_CREATE = Creare nuovi Cantoni/distretti/comuni/strutture UserRight.INFRASTRUCTURE_EDIT = Modifica nuovi Cantoni/distretti/comuni/strutture UserRight.INFRASTRUCTURE_VIEW = Visualizza Cantoni/distretti/comuni/strutture nel sistema -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Effettuare operazioni in blocco dentro le liste UserRight.SAMPLE_CREATE = Crea nuovo campione UserRight.SAMPLE_EDIT = Modifica campioni esistenti @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Indagine sul caso diff --git a/sormas-api/src/main/resources/enum_ja-JP.properties b/sormas-api/src/main/resources/enum_ja-JP.properties index 038404d8dda..c12df24d20c 100644 --- a/sormas-api/src/main/resources/enum_ja-JP.properties +++ b/sormas-api/src/main/resources/enum_ja-JP.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/communities/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/communities/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/communities/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_nl-NL.properties b/sormas-api/src/main/resources/enum_nl-NL.properties index 038404d8dda..c12df24d20c 100644 --- a/sormas-api/src/main/resources/enum_nl-NL.properties +++ b/sormas-api/src/main/resources/enum_nl-NL.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/communities/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/communities/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/communities/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_no-NO.properties b/sormas-api/src/main/resources/enum_no-NO.properties index 038404d8dda..c12df24d20c 100644 --- a/sormas-api/src/main/resources/enum_no-NO.properties +++ b/sormas-api/src/main/resources/enum_no-NO.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/communities/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/communities/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/communities/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_pl-PL.properties b/sormas-api/src/main/resources/enum_pl-PL.properties index 038404d8dda..c12df24d20c 100644 --- a/sormas-api/src/main/resources/enum_pl-PL.properties +++ b/sormas-api/src/main/resources/enum_pl-PL.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/communities/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/communities/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/communities/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_ps-AF.properties b/sormas-api/src/main/resources/enum_ps-AF.properties index 73214e3eeb4..46253b11430 100644 --- a/sormas-api/src/main/resources/enum_ps-AF.properties +++ b/sormas-api/src/main/resources/enum_ps-AF.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/communities/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/communities/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/communities/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_pt-PT.properties b/sormas-api/src/main/resources/enum_pt-PT.properties index 038404d8dda..c12df24d20c 100644 --- a/sormas-api/src/main/resources/enum_pt-PT.properties +++ b/sormas-api/src/main/resources/enum_pt-PT.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/communities/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/communities/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/communities/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_ro-RO.properties b/sormas-api/src/main/resources/enum_ro-RO.properties index 038404d8dda..c12df24d20c 100644 --- a/sormas-api/src/main/resources/enum_ro-RO.properties +++ b/sormas-api/src/main/resources/enum_ro-RO.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/communities/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/communities/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/communities/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_ru-RU.properties b/sormas-api/src/main/resources/enum_ru-RU.properties index d9eacf4340a..f2a7db808e3 100644 --- a/sormas-api/src/main/resources/enum_ru-RU.properties +++ b/sormas-api/src/main/resources/enum_ru-RU.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/communities/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/communities/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/communities/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_sv-SE.properties b/sormas-api/src/main/resources/enum_sv-SE.properties index 038404d8dda..c12df24d20c 100644 --- a/sormas-api/src/main/resources/enum_sv-SE.properties +++ b/sormas-api/src/main/resources/enum_sv-SE.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/communities/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/communities/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/communities/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_sw-KE.properties b/sormas-api/src/main/resources/enum_sw-KE.properties index 038404d8dda..c12df24d20c 100644 --- a/sormas-api/src/main/resources/enum_sw-KE.properties +++ b/sormas-api/src/main/resources/enum_sw-KE.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/communities/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/communities/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/communities/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_tr-TR.properties b/sormas-api/src/main/resources/enum_tr-TR.properties index 038404d8dda..c12df24d20c 100644 --- a/sormas-api/src/main/resources/enum_tr-TR.properties +++ b/sormas-api/src/main/resources/enum_tr-TR.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/communities/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/communities/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/communities/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_uk-UA.properties b/sormas-api/src/main/resources/enum_uk-UA.properties index 038404d8dda..c12df24d20c 100644 --- a/sormas-api/src/main/resources/enum_uk-UA.properties +++ b/sormas-api/src/main/resources/enum_uk-UA.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/communities/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/communities/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/communities/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_ur-PK.properties b/sormas-api/src/main/resources/enum_ur-PK.properties index 67da9501162..3e1a1000454 100644 --- a/sormas-api/src/main/resources/enum_ur-PK.properties +++ b/sormas-api/src/main/resources/enum_ur-PK.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = افراد کا عمومی ڈیٹا ExportGroupType.HOSPITALIZATION = ہسپتال میں داخل ہونے کی معلومات ExportGroupType.EPIDEMIOLOGICAL = وبائی امراض کا ڈیٹا ExportGroupType.VACCINATION = ویکسینیشن ڈیٹا -ExportGroupType.CASE_MANAGEMENT = کیس مینجمنٹ ڈیٹا ExportGroupType.FOLLOW_UP = فالو اپ ڈیٹا ExportGroupType.ADDITIONAL = اضافی ڈیٹا ExportGroupType.LOCATION = پتے کا ڈیٹا ExportGroupType.EVENT = تقریب کا ڈیٹا ExportGroupType.EVENT_GROUP = تقریب گروپ ڈیٹا ExportGroupType.EVENT_SOURCE = تقریب سورس ڈیٹا +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = قابل اطلاق نہیں EventSourceType.MEDIA_NEWS = میڈیا/نیوز @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = محفوظ شدہ کیسز دیکھیں UserRight.CASE_TRANSFER = کیسز کو دوسرے علاقے/ضلع/سہولت گاہ میں منتقل کریں UserRight.CASE_REFER_FROM_POE = داخلے کا مقام سے کیس کا حوالہ دیں UserRight.CASE_VIEW = موجودہ کیسز دیکھیں -UserRight.CONFIGURATION_ACCESS = سسٹم کنفیگریشن تک رسائی حاصل کریں UserRight.CONTACT_ASSIGN = افسران کو رابطے مختص کردیں UserRight.CONTACT_CLASSIFY = رابطے کی درجہ بندی میں ترمیم کریں UserRight.CONTACT_CONVERT = رابطوں کے نتیجے میں کیسز بنائیں @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = موجودہ روابط میں ترمیم کریں UserRight.CONTACT_EXPORT = سورماس سے روابط ايکسپورٹ کریں UserRight.CONTACT_SEE_ARCHIVED = محفوظ شدہ روابط دیکھیں UserRight.CONTACT_VIEW = موجودہ روابط دیکھیں -UserRight.DASHBOARD_VIEW = کنٹرول پینل دیکھیں -UserRight.DASHBOARD_CONTACT_ACCESS = رابطہ سپروائزر ڈیش بورڈ تک رسائی حاصل کریں -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = نگران سپروائزر ڈیش بورڈ تک رسائی حاصل کریں +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = پورا ڈیٹا بیس ايکسپورٹ کریں UserRight.EVENT_ARCHIVE = تقریبات کو آرکائیو کریں UserRight.EVENT_CREATE = نئے تقریبات بنائیں @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = تقریب کے موجودہ شرکاء میں UserRight.INFRASTRUCTURE_CREATE = نئے علاقے/اضلاع/کمیونٹیز/سہولیات گاہيں بنائیں UserRight.INFRASTRUCTURE_EDIT = علاقوں/اضلاع/کمیونٹیز/سہولیات گاہوں میں ترمیم کریں UserRight.INFRASTRUCTURE_VIEW = سسٹم میں علاقے/اضلاع/کمیونٹیز/سہولیات گاہيں دیکھیں -UserRight.OUTBREAK_CONFIGURE_ALL = تمام علاقوں کے لیے پھیلاو کو کنفیگر کریں -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = مختص کردہ علاقے کے لیے پھیلاؤ کو کنفیگر کریں۔ UserRight.PERFORM_BULK_OPERATIONS = فہرستوں میں بلک آپریشنز انجام دیں UserRight.SAMPLE_CREATE = نئے نمونے بنائیں UserRight.SAMPLE_EDIT = موجودہ نمونوں میں ترمیم کریں @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = کیس کے نمونوں پر UserRight.INFRASTRUCTURE_EXPORT = سورماس سے انفراسٹرکچر ڈیٹا ايکسپورٹ کریں UserRight.INFRASTRUCTURE_IMPORT = انفراسٹرکچر ڈیٹا امپورٹ کریں UserRight.INFRASTRUCTURE_ARCHIVE = انفراسٹرکچر ڈیٹا آرکائیو کریں -UserRight.USER_RIGHTS_MANAGE = صارف کے حقوق کا مینج کریں UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = ڈیش بورڈ پر کونٹيکٹ ٹرانسمیشن چینز دیکھیں -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = مہمات کے ڈیش بورڈ تک رسائی حاصل کریں -UserRight.CASE_MANAGEMENT_ACCESS = کیس مینجمنٹ سے متعلق کیس سیکشن تک رسائی حاصل کریں +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = موجودہ تھراپیزدیکھیں UserRight.PRESCRIPTION_CREATE = نئے نسخے بنائیں UserRight.PRESCRIPTION_EDIT = موجودہ نسخوں میں ترمیم کریں @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = آبادی کے اعداد و شمار مینج ک UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = دستاویز کے ٹیمپلیٹس مینج کریں۔ UserRight.QUARANTINE_ORDER_CREATE = نئے قرنطینہ آرڈرز بنائیں UserRight.LINE_LISTING_CONFIGURE = لائن لسٹنگ کوکنفیگر کریں -UserRight.LINE_LISTING_CONFIGURE_NATION = قومی سطح پر لائن لسٹنگ کوکنفیگر کریں UserRight.AGGREGATE_REPORT_VIEW = نئی مجموعی رپورٹیں بنائیں UserRight.AGGREGATE_REPORT_EXPORT = سورماس سے مجموعی رپورٹیں ايکسپورٹ کریں UserRight.AGGREGATE_REPORT_EDIT = موجودہ مجموعی رپورٹس میں ترمیم کریں @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = موجودہ سفری اندراجات میں تر UserRight.TRAVEL_ENTRY_DELETE = سسٹم سے سفری اندراجات کو مٹا دیں UserRight.TRAVEL_ENTRY_ARCHIVE = آرکائیو سفری اندراجات UserRight.EXPORT_DATA_PROTECTION_DATA = ڈیٹا پروٹیکشن ڈیٹا ایکسپورٹ کریں +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = کیس کی تفتیش diff --git a/sormas-api/src/main/resources/enum_zh-CN.properties b/sormas-api/src/main/resources/enum_zh-CN.properties index 7b9e930e080..56364e0de79 100644 --- a/sormas-api/src/main/resources/enum_zh-CN.properties +++ b/sormas-api/src/main/resources/enum_zh-CN.properties @@ -574,13 +574,14 @@ ExportGroupType.PERSON = General Person Data ExportGroupType.HOSPITALIZATION = Hospitalization Data ExportGroupType.EPIDEMIOLOGICAL = Epidemiological Data ExportGroupType.VACCINATION = Vaccination Data -ExportGroupType.CASE_MANAGEMENT = Case Management Data ExportGroupType.FOLLOW_UP = Follow-up Data ExportGroupType.ADDITIONAL = Additional Data ExportGroupType.LOCATION = Location Data ExportGroupType.EVENT = Event Data ExportGroupType.EVENT_GROUP = Event Group Data ExportGroupType.EVENT_SOURCE = Event Source Data +ExportGroupType.CLINICAL_COURSE = Clinical Course Data +ExportGroupType.THERAPY = Therapy Data EventSourceType.NOT_APPLICABLE = Not applicable EventSourceType.MEDIA_NEWS = Media/News @@ -1272,7 +1273,6 @@ UserRight.CASE_SEE_ARCHIVED = View archived cases UserRight.CASE_TRANSFER = Transfer cases to another region/district/facility UserRight.CASE_REFER_FROM_POE = Refer case from point of entry UserRight.CASE_VIEW = View existing cases -UserRight.CONFIGURATION_ACCESS = Access system configuration UserRight.CONTACT_ASSIGN = Assign contacts to officers UserRight.CONTACT_CLASSIFY = Edit contact classification UserRight.CONTACT_CONVERT = Create resulting cases from contacts @@ -1283,9 +1283,8 @@ UserRight.CONTACT_EDIT = Edit existing contacts UserRight.CONTACT_EXPORT = Export contacts from SORMAS UserRight.CONTACT_SEE_ARCHIVED = View archived contacts UserRight.CONTACT_VIEW = View existing contacts -UserRight.DASHBOARD_VIEW = View the dashboard -UserRight.DASHBOARD_CONTACT_ACCESS = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_ACCESS = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Export the whole database UserRight.EVENT_ARCHIVE = Archive events UserRight.EVENT_CREATE = Create new events @@ -1298,8 +1297,6 @@ UserRight.EVENTPARTICIPANT_EDIT = Edit existing event participants UserRight.INFRASTRUCTURE_CREATE = Create new regions/districts/communities/facilities UserRight.INFRASTRUCTURE_EDIT = Edit regions/districts/communities/facilities UserRight.INFRASTRUCTURE_VIEW = View regions/districts/communities/facilities in the system -UserRight.OUTBREAK_CONFIGURE_ALL = Configure outbreaks for all regions -UserRight.OUTBREAK_CONFIGURE_RESTRICTED = Configure outbreaks for assigned region UserRight.PERFORM_BULK_OPERATIONS = Perform bulk operations in lists UserRight.SAMPLE_CREATE = Create new samples UserRight.SAMPLE_EDIT = Edit existing samples @@ -1356,10 +1353,9 @@ UserRight.PERFORM_BULK_OPERATIONS_CASE_SAMPLES = Perform bulk operations on case UserRight.INFRASTRUCTURE_EXPORT = Export infrastructure data from SORMAS UserRight.INFRASTRUCTURE_IMPORT = Import infrastructure data UserRight.INFRASTRUCTURE_ARCHIVE = Archive infrastructure data -UserRight.USER_RIGHTS_MANAGE = Manage user rights UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = View contact transmission chains on the dashboard -UserRight.DASHBOARD_CAMPAIGNS_ACCESS = Access campaigns dashboard -UserRight.CASE_MANAGEMENT_ACCESS = Access case sections concerned with case management +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = View existing therapies UserRight.PRESCRIPTION_CREATE = Create new prescriptions UserRight.PRESCRIPTION_EDIT = Edit existing prescriptions @@ -1378,7 +1374,6 @@ UserRight.POPULATION_MANAGE = Manage population data UserRight.DOCUMENT_TEMPLATE_MANAGEMENT = Manage document templates UserRight.QUARANTINE_ORDER_CREATE = Create new quarantine orders UserRight.LINE_LISTING_CONFIGURE = Configure line listing -UserRight.LINE_LISTING_CONFIGURE_NATION = Configure line listing on national level UserRight.AGGREGATE_REPORT_VIEW = Create new aggregate reports UserRight.AGGREGATE_REPORT_EXPORT = Export aggregate reports from SORMAS UserRight.AGGREGATE_REPORT_EDIT = Edit existing aggregate reports @@ -1420,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data +UserRight.OUTBREAK_VIEW = View outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation From eb4364e0cea411d90c772a7b0168eee732f8bc87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9=20Strysewske?= Date: Mon, 21 Feb 2022 12:17:58 +0100 Subject: [PATCH 120/253] #7813 - Remove system user annotation from enum service --- .../main/java/de/symeda/sormas/backend/common/EnumService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/EnumService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/EnumService.java index d3a77fcb284..5f428c81ba1 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/EnumService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/EnumService.java @@ -29,7 +29,6 @@ import de.symeda.sormas.backend.user.UserService; @Singleton(name = "EnumService") -@RunAs(UserRole._SYSTEM) public class EnumService { private final Map, Map> enumCaptions = new HashMap<>(); From 5e0e458300c8e3325472a7ff9d7b346dacd6d94d Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Mon, 21 Feb 2022 13:19:51 +0200 Subject: [PATCH 121/253] #6879 - remove sql script used for debugging --- .../de/symeda/sormas/backend/util/test.sql | 50 ------------------- 1 file changed, 50 deletions(-) delete mode 100644 sormas-backend/src/main/java/de/symeda/sormas/backend/util/test.sql diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/util/test.sql b/sormas-backend/src/main/java/de/symeda/sormas/backend/util/test.sql deleted file mode 100644 index 41489f99e15..00000000000 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/util/test.sql +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -select distinct new de.symeda.sormas.api.caze.CaseExportDto(generatedAlias0.id, generatedAlias1.id, generatedAlias2.id, generatedAlias3.id, generatedAlias4.id, generatedAlias5.id, generatedAlias6.id, generatedAlias0.uuid, generatedAlias0.epidNumber, generatedAlias0.disease, generatedAlias0.diseaseVariant, generatedAlias0.diseaseDetails, generatedAlias0.diseaseVariantDetails, generatedAlias1.uuid, generatedAlias1.firstName, generatedAlias1.lastName, generatedAlias1.salutation, generatedAlias1.otherSalutation, generatedAlias1.sex, generatedAlias0.pregnant, generatedAlias1.approximateAge, generatedAlias1.approximateAgeType, generatedAlias1.birthdateDD, generatedAlias1.birthdateMM, generatedAlias1.birthdateYYYY, generatedAlias0.reportDate, generatedAlias7.name, generatedAlias8.name, generatedAlias9.name, generatedAlias0.facilityType, generatedAlias10.name, generatedAlias10.uuid, generatedAlias0.healthFacilityDetails, generatedAlias11.name, generatedAlias11.uuid, generatedAlias0.pointOfEntryDetails, generatedAlias0.caseClassification, generatedAlias0.clinicalConfirmation, generatedAlias0.epidemiologicalConfirmation, generatedAlias0.laboratoryDiagnosticConfirmation, generatedAlias0.notACaseReasonNegativeTest, generatedAlias0.notACaseReasonPhysicianInformation, generatedAlias0.notACaseReasonDifferentPathogen, generatedAlias0.notACaseReasonOther, generatedAlias0.notACaseReasonDetails, generatedAlias0.investigationStatus, generatedAlias0.investigatedDate, generatedAlias0.outcome, generatedAlias0.outcomeDate, generatedAlias0.sequelae, generatedAlias0.sequelaeDetails, generatedAlias0.bloodOrganOrTissueDonated, generatedAlias0.followUpStatus, generatedAlias0.followUpUntil, generatedAlias0.nosocomialOutbreak, generatedAlias0.infectionSetting, generatedAlias0.prohibitionToWork, generatedAlias0.prohibitionToWorkFrom, generatedAlias0.prohibitionToWorkUntil, generatedAlias0.reInfection, generatedAlias0.previousInfectionDate, generatedAlias0.reinfectionStatus, generatedAlias0.reinfectionDetails, generatedAlias0.quarantine, generatedAlias0.quarantineTypeDetails, generatedAlias0.quarantineFrom, generatedAlias0.quarantineTo, generatedAlias0.quarantineHelpNeeded, generatedAlias0.quarantineOrderedVerbally, generatedAlias0.quarantineOrderedOfficialDocument, generatedAlias0.quarantineOrderedVerballyDate, generatedAlias0.quarantineOrderedOfficialDocumentDate, generatedAlias0.quarantineExtended, generatedAlias0.quarantineReduced, generatedAlias0.quarantineOfficialOrderSent, generatedAlias0.quarantineOfficialOrderSentDate, generatedAlias5.admittedToHealthFacility, generatedAlias5.admissionDate, generatedAlias5.dischargeDate, generatedAlias5.leftAgainstAdvice, generatedAlias1.presentCondition, generatedAlias1.deathDate, generatedAlias1.burialDate, generatedAlias1.burialConductor, generatedAlias1.burialPlaceDescription, generatedAlias12.name, generatedAlias13.name, generatedAlias14.name, generatedAlias2.city, generatedAlias2.street, generatedAlias2.houseNumber, generatedAlias2.additionalInformation, generatedAlias2.postalCode, generatedAlias15.name, generatedAlias15.uuid, generatedAlias2.facilityDetails, (select generatedAlias16.contactInformation from PersonContactDetail as generatedAlias16 where ( generatedAlias16.person=generatedAlias1 ) and ( generatedAlias16.primaryContact = true ) and ( generatedAlias16.personContactDetailType=:param0 )), (select case when generatedAlias17.thirdParty = true then generatedAlias17.thirdPartyName else 'This person' end from PersonContactDetail as generatedAlias17 where ( generatedAlias17.person=generatedAlias1 ) and ( generatedAlias17.primaryContact = true ) and ( generatedAlias17.personContactDetailType=:param1 )), (select generatedAlias18.contactInformation from PersonContactDetail as generatedAlias18 where ( generatedAlias18.person=generatedAlias1 ) and ( generatedAlias18.primaryContact = true ) and ( generatedAlias18.personContactDetailType=:param2 )), (select function('array_to_string', function('array_agg', case when generatedAlias19.personContactDetailType=:param3 then ((generatedAlias19.contactInformation || ' (') || (generatedAlias19.details || ')')) else ((generatedAlias19.contactInformation || ' (') || (generatedAlias19.personContactDetailType || ')')) end), ', ') from PersonContactDetail as generatedAlias19 where ( generatedAlias19.person=generatedAlias1 ) and ( ( generatedAlias19.primaryContact = false ) or ( generatedAlias19.personContactDetailType=:param4 ) )), generatedAlias1.educationType, generatedAlias1.educationDetails, generatedAlias1.occupationType, generatedAlias1.occupationDetails, generatedAlias1.armedForcesRelationType, generatedAlias3.contactWithSourceCaseKnown, generatedAlias0.vaccinationStatus, generatedAlias0.postpartum, generatedAlias0.trimester, (select count(distinct generatedAlias20.id) from EventParticipant as generatedAlias21 inner join generatedAlias21.event as generatedAlias20 inner join generatedAlias21.resultingCase as generatedAlias22 where ( generatedAlias22.id=generatedAlias0.id ) and ( generatedAlias20.deleted = false ) and ( generatedAlias20.archived = false ) and ( generatedAlias21.deleted = false )), generatedAlias0.externalID, generatedAlias0.externalToken, generatedAlias0.internalToken, generatedAlias1.birthName, generatedAlias23.isoCode, generatedAlias23.defaultName, generatedAlias24.isoCode, generatedAlias24.defaultName, generatedAlias0.caseIdentificationSource, generatedAlias0.screeningType, generatedAlias25.name, generatedAlias26.name, generatedAlias27.name, generatedAlias0.clinicianName, generatedAlias0.clinicianPhone, generatedAlias0.clinicianEmail, generatedAlias28.id, generatedAlias29.id, generatedAlias0.previousQuarantineTo, generatedAlias0.quarantineChangeComment, case when ( ( generatedAlias0.reportingUser is not null ) and ( generatedAlias0.reportingUser.id=15L ) ) or ( ( generatedAlias0.responsibleDistrict.id=11L ) or ( generatedAlias0.district.id=11L ) ) then true else false end) -from cases as generatedAlias0 - left join generatedAlias0.person as generatedAlias1 - left join generatedAlias1.address as generatedAlias2 - left join generatedAlias2.region as generatedAlias12 - left join generatedAlias2.district as generatedAlias13 - left join generatedAlias2.community as generatedAlias14 - left join generatedAlias1.address as generatedAlias30 - left join generatedAlias30.facility as generatedAlias15 - left join generatedAlias1.birthCountry as generatedAlias23 - left join generatedAlias1.citizenship as generatedAlias24 - left join generatedAlias1.address as generatedAlias31 - left join generatedAlias0.epiData as generatedAlias3 - left join generatedAlias0.symptoms as generatedAlias4 - left join generatedAlias0.hospitalization as generatedAlias5 - left join generatedAlias0.healthConditions as generatedAlias6 - left join generatedAlias0.region as generatedAlias7 - left join generatedAlias0.district as generatedAlias8 - left join generatedAlias0.community as generatedAlias9 - left join generatedAlias0.healthFacility as generatedAlias10 - left join generatedAlias0.pointOfEntry as generatedAlias11 - left join generatedAlias0.responsibleRegion as generatedAlias25 - left join generatedAlias0.responsibleDistrict as generatedAlias26 - left join generatedAlias0.responsibleCommunity as generatedAlias27 - left join generatedAlias0.reportingUser as generatedAlias28 - left join generatedAlias0.followUpStatusChangeUser as generatedAlias29 - left join generatedAlias0.contacts as generatedAlias32 -where (((((generatedAlias0.district.id = 11 L) or (generatedAlias0.responsibleDistrict.id = 11 L)) or - (((generatedAlias32.reportingUser = :param5) or (generatedAlias32.contactOfficer = :param6)) or - (generatedAlias32.district.id = 11 L))) or (generatedAlias0.sharedToCountry = true)) or - (((generatedAlias0.reportingUser.id = 15 L) or (generatedAlias0.surveillanceOfficer.id = 15 L)) or - (generatedAlias0.caseOfficer.id = 15 L))) - and (generatedAlias0.deleted = :param7) -order by generatedAlias0.reportDate desc, generatedAlias0.id desc \ No newline at end of file From 6e9e48ce62b2d089c5379d8ad4845f63b3235280 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Mon, 14 Feb 2022 09:43:03 +0100 Subject: [PATCH 122/253] Test scenario for event group --- .../events/EventDirectoryPage.java | 17 +++- .../events/EventDirectorySteps.java | 78 ++++++++++++++++++- .../features/sanity/web/Event.feature | 48 ++++++++++++ 3 files changed, 139 insertions(+), 4 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java index 5b4c5530647..45e6393b3ef 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java @@ -53,7 +53,22 @@ public class EventDirectoryPage { public static final By EVENT_CLUSTER = By.id("status-Cluster"); public static final By EVENT_DROPPED = By.id("status-Dropped"); public static final By CREATED_PARTICIPANT = By.cssSelector("[role='gridcell'] a"); - + public static final By EVENTS_RADIO_BUTTON = By.cssSelector(".v-radiobutton"); + public static final By LINK_EVENT_BUTTON = By.id("Link event"); + public static final By LINK_EVENT_BUTTON_EDIT_PAGE = By.id("Link event group"); + public static final By UNLINK_EVENT_BUTTON = By.id("unlink-event-0"); + public static final By ID_FIELD_FILTER = By.id("search"); + public static final By LINKED_EVENT_GROUP_ID = + By.xpath( + "/html/body/div[1]/div/div[2]/div/div[2]/div/div/div[3]/div/div/div/div/div[8]/div/div[2]/div/div/div/div/div/div/div[1]/div/div/div/div/div/div/div[2]/div/div[2]/div/div/div"); + public static final By SAVE_BUTTON_IN_LINK_FORM = + By.xpath("/html/body/div[2]/div[3]/div/div/div[3]/div/div/div[2]/div/div/div[3]/div"); + public static final By FILTERED_EVENT_LINK_EVENT_FORM = + By.xpath( + "//*[@id=\"sormasui-1655777373-overlays\"]/div[3]/div/div/div[3]/div/div/div[1]/div/div[2]/div/div/div[5]/div/div[3]/table/tbody/tr[1]/td[1]"); + public static final By FIRST_EVENT_GROUP = + By.xpath( + "/html/body/div[2]/div[3]/div/div/div[3]/div/div/div[1]/div/div[2]/div/div/div[7]/div/div[3]/table/tbody/tr[1]/td[1]"); /*public static By getByEventUuid(String eventUuid) { return By.cssSelector("a[title=" + eventUuid + "]"); }*/ diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index 5f67d338414..c350a5c2416 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -19,8 +19,33 @@ package org.sormas.e2etests.steps.web.application.events; import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_GRID_RESULTS_ROWS; -import static org.sormas.e2etests.pages.application.events.EditEventPage.*; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.*; +import static org.sormas.e2etests.pages.application.events.EditEventPage.EVENT_PARTICIPANTS_TAB; +import static org.sormas.e2etests.pages.application.events.EditEventPage.NEW_TASK_BUTTON; +import static org.sormas.e2etests.pages.application.events.EditEventPage.TITLE_INPUT; +import static org.sormas.e2etests.pages.application.events.EditEventPage.UUID_INPUT; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.APPLY_FILTER; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.CREATED_PARTICIPANT; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.CREATE_CASE_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENTS_RADIO_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_STATUS_FILTER_BUTTONS; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTERED_EVENT_LINK_EVENT_FORM; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_DISEASE; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_RISK_LEVEL; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_SOURCE_TYPE; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_TYPE_OF_PLACE; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FIRST_EVENT_GROUP; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FIRST_EVENT_ID_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.ID_FIELD_FILTER; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.LINKED_EVENT_GROUP_ID; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.LINK_EVENT_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.LINK_EVENT_BUTTON_EDIT_PAGE; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.RESET_FILTER; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.SAVE_BUTTON_IN_LINK_FORM; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.SEARCH_EVENT_BY_FREE_TEXT; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.SEARCH_EVENT_BY_FREE_TEXT_INPUT; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.TOTAL_EVENTS_COUNTER; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.UNLINK_EVENT_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.getByEventUuid; import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.APPLY_FILTERS_BUTTON; import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.RESET_FILTERS_BUTTON; @@ -28,8 +53,11 @@ import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.inject.Named; +import org.openqa.selenium.By; import org.sormas.e2etests.common.DataOperations; -import org.sormas.e2etests.enums.*; +import org.sormas.e2etests.enums.DiseasesValues; +import org.sormas.e2etests.enums.RiskLevelValues; +import org.sormas.e2etests.enums.SourceTypeValues; import org.sormas.e2etests.enums.cases.epidemiologicalData.TypeOfPlace; import org.sormas.e2etests.helpers.AssertHelpers; import org.sormas.e2etests.helpers.WebDriverHelpers; @@ -57,6 +85,50 @@ public EventDirectorySteps( dataOperations.getPartialUuidFromAssociatedLink(eventUuid)); }); + When( + "^I click on ([^\"]*) Radiobutton on Event Directory Page$", + (String buttonName) -> { + webDriverHelpers.clickWebElementByText(EVENTS_RADIO_BUTTON, buttonName); + webDriverHelpers.waitForPageLoaded(); + }); + + When( + "^I click on Link Event button on Event Directory Page$", + () -> webDriverHelpers.clickOnWebElementBySelector(LINK_EVENT_BUTTON)); + When( + "^I click on Link Event button on Edit Event Page$", + () -> webDriverHelpers.clickOnWebElementBySelector(LINK_EVENT_BUTTON_EDIT_PAGE)); + + When( + "^I click on Unlink Event button on Event Directory Page$", + () -> webDriverHelpers.clickOnWebElementBySelector(UNLINK_EVENT_BUTTON)); + + When( + "^I fill Id filter with Id of last created event in Link Event to group form$", + () -> + webDriverHelpers.fillInWebElement( + ID_FIELD_FILTER, apiState.getCreatedEvent().getUuid())); + When( + "^I click on filtered Event in Link Event to group form$", + () -> webDriverHelpers.clickOnWebElementBySelector(FILTERED_EVENT_LINK_EVENT_FORM)); + When( + "^I click on first Event Group on the list in Link Event form$", + () -> webDriverHelpers.clickOnWebElementBySelector(FIRST_EVENT_GROUP)); + + When( + "^I click on SAVE button in Link Event to group form$", + () -> webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON_IN_LINK_FORM)); + + When( + "^I click on Linked Group Id on Edit Event Page$", + () -> webDriverHelpers.clickOnWebElementBySelector(LINKED_EVENT_GROUP_ID)); + When( + "^I click on Group Id in Events result on Event Directory Page$", + () -> + webDriverHelpers.clickOnWebElementBySelector( + By.xpath( + "/html/body/div[1]/div/div[2]/div/div[2]/div/div/div/div[2]/div/div/div[3]/div/div[3]/table/tbody/tr/td[15]"))); + When( "I click on the NEW EVENT button", () -> diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature index c413a304440..317e91f9895 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature @@ -235,6 +235,54 @@ Feature: Create events And I select Dropped filter from quick filter And I click on the RESET FILTERS button + @issue=SORDEV-5571 + Scenario: Event group screen + Given API: I create a new event + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in with National User + And I click on the Events button from navbar + And I click on GROUPS Radiobutton on Event Directory Page + And I open the first event from events list + And I click on Link Event button on Event Directory Page + And I fill Id filter with Id of last created event in Link Event to group form + And I click on filtered Event in Link Event to group form + And I click on SAVE button in Link Event to group form + And I click on Unlink Event button on Event Directory Page + + @issue=SORDEV-5571 + Scenario: Event group screens + Given API: I create a new event + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in with National User + And I click on the Events button from navbar + And I fill EVENT ID filter by API + And I apply on the APPLY FILTERS button from Event + And I open the first event from events list + And I click on Link Event button on Edit Event Page + And I click on first Event Group on the list in Link Event form + And I click on SAVE button in Link Event to group form + And I click on Linked Group Id on Edit Event Page + And I click on Unlink Event button on Event Directory Page + + @issue=SORDEV-5571 + Scenario: Event group screenss + Given API: I create a new event + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in with National User + And I click on the Events button from navbar + And I fill EVENT ID filter by API + And I apply on the APPLY FILTERS button from Event + And I open the first event from events list + And I click on Link Event button on Edit Event Page + And I click on first Event Group on the list in Link Event form + And I click on SAVE button in Link Event to group form + And I click on the Events button from navbar + And I click on Group Id in Events result on Event Directory Page + And I click on Unlink Event button on Event Directory Page + @issue=SORDEV-5570 Scenario: Testing Event screen Impact Given API: I create a new event From 08f747b4cd6cf3e5314ab5d47059e98c80e97c46 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Tue, 15 Feb 2022 12:24:15 +0100 Subject: [PATCH 123/253] Test scenarios for event group screen --- .../events/EventDirectoryPage.java | 16 ++++------ .../webdriver/RemoteDriverFactory.java | 4 +-- .../events/EventDirectorySteps.java | 30 ++++++++----------- .../features/sanity/web/Event.feature | 6 ++-- 4 files changed, 24 insertions(+), 32 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java index 45e6393b3ef..9c1c2b621b1 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java @@ -59,19 +59,15 @@ public class EventDirectoryPage { public static final By UNLINK_EVENT_BUTTON = By.id("unlink-event-0"); public static final By ID_FIELD_FILTER = By.id("search"); public static final By LINKED_EVENT_GROUP_ID = - By.xpath( - "/html/body/div[1]/div/div[2]/div/div[2]/div/div/div[3]/div/div/div/div/div[8]/div/div[2]/div/div/div/div/div/div/div[1]/div/div/div/div/div/div/div[2]/div/div[2]/div/div/div"); - public static final By SAVE_BUTTON_IN_LINK_FORM = - By.xpath("/html/body/div[2]/div[3]/div/div/div[3]/div/div/div[2]/div/div/div[3]/div"); - public static final By FILTERED_EVENT_LINK_EVENT_FORM = - By.xpath( - "//*[@id=\"sormasui-1655777373-overlays\"]/div[3]/div/div/div[3]/div/div/div[1]/div/div[2]/div/div/div[5]/div/div[3]/table/tbody/tr[1]/td[1]"); - public static final By FIRST_EVENT_GROUP = - By.xpath( - "/html/body/div[2]/div[3]/div/div/div[3]/div/div/div[1]/div/div[2]/div/div/div[7]/div/div[3]/table/tbody/tr[1]/td[1]"); + By.xpath("//div[@location = 'event-groups']//div[contains(@class, 'v-slot')]//a"); + public static final By SAVE_BUTTON_IN_LINK_FORM = By.cssSelector(".popupContent #commit"); + public static final By FILTERED_EVENT_LINK_EVENT_FORM = By.xpath("//tr[@role='row']"); + public static final By FIRST_EVENT_GROUP = By.xpath("//tr[@role='row']"); /*public static By getByEventUuid(String eventUuid) { return By.cssSelector("a[title=" + eventUuid + "]"); }*/ + + public static final By EVENT_GROUP_ID_IN_GRID = By.xpath("//tr[@role='row']//td[15]/a"); public static final By FIRST_EVENT_ID_BUTTON = By.cssSelector(".v-grid-row-has-data a[title]"); public static final By CREATE_CASE_BUTTON = By.xpath("//td//span[contains(@class, 'v-icon-edit')]"); diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/RemoteDriverFactory.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/RemoteDriverFactory.java index 88350df2699..ba427b86a3f 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/RemoteDriverFactory.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/RemoteDriverFactory.java @@ -53,7 +53,7 @@ public RemoteDriverFactory( @Override public ChromeDriver getRemoteWebDriver() { log.info("Setting Chrome Driver's path"); - System.setProperty("webdriver.chrome.driver", "/usr/lib64/chromium-browser/chromedriver"); + System.setProperty("webdriver.chrome.driver", "C:\\chromedriver_win32\\chromedriver.exe"); log.info("Adding all chrome preferences"); final ChromeOptions options = new ChromeOptions(); final HashMap chromePreferences = new HashMap<>(); @@ -62,7 +62,7 @@ public ChromeDriver getRemoteWebDriver() { options.addArguments("--no-default-browser-check"); options.setUnhandledPromptBehaviour(UnexpectedAlertBehaviour.IGNORE); options.addArguments("disable-infobars"); - options.addArguments("--headless"); + // options.addArguments("--headless"); options.addArguments("enable-automation"); options.addArguments("--no-sandbox"); options.addArguments("--disable-browser-side-navigation"); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index c350a5c2416..f63d71f2b5b 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -27,6 +27,7 @@ import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.CREATED_PARTICIPANT; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.CREATE_CASE_BUTTON; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENTS_RADIO_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_GROUP_ID_IN_GRID; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_STATUS_FILTER_BUTTONS; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTERED_EVENT_LINK_EVENT_FORM; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_DISEASE; @@ -53,7 +54,6 @@ import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.inject.Named; -import org.openqa.selenium.By; import org.sormas.e2etests.common.DataOperations; import org.sormas.e2etests.enums.DiseasesValues; import org.sormas.e2etests.enums.RiskLevelValues; @@ -124,10 +124,7 @@ public EventDirectorySteps( () -> webDriverHelpers.clickOnWebElementBySelector(LINKED_EVENT_GROUP_ID)); When( "^I click on Group Id in Events result on Event Directory Page$", - () -> - webDriverHelpers.clickOnWebElementBySelector( - By.xpath( - "/html/body/div[1]/div/div[2]/div/div[2]/div/div/div/div[2]/div/div/div[3]/div/div[3]/table/tbody/tr/td[15]"))); + () -> webDriverHelpers.clickOnWebElementBySelector(EVENT_GROUP_ID_IN_GRID)); When( "I click on the NEW EVENT button", @@ -322,9 +319,8 @@ public EventDirectorySteps( When( "I click on the created event participant from the list", - () -> { - webDriverHelpers.clickOnWebElementBySelector(CREATED_PARTICIPANT); - }); + () -> + webDriverHelpers.clickOnWebElementBySelector(CREATED_PARTICIPANT)); When( "I click on New Task from event tab", @@ -338,15 +334,15 @@ public EventDirectorySteps( "I click Create Case for Event Participant", () -> webDriverHelpers.clickOnWebElementBySelector(CREATE_CASE_BUTTON)); - Then( - "I check that number of displayed Event results is {int}", - (Integer number) -> - assertHelpers.assertWithPoll20Second( - () -> - Assert.assertEquals( - webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), - number.intValue(), - "Number of displayed cases is not correct"))); + Then( + "I check that number of displayed Event results is {int}", + (Integer number) -> + assertHelpers.assertWithPoll20Second( + () -> + Assert.assertEquals( + webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), + number.intValue(), + "Number of displayed cases is not correct"))); Then( "I check the number of displayed Event results from All button is {int}", diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature index 317e91f9895..2cde902d6bb 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature @@ -236,7 +236,7 @@ Feature: Create events And I click on the RESET FILTERS button @issue=SORDEV-5571 - Scenario: Event group screen + Scenario: Event group screen from Event Directory Page Given API: I create a new event Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 @@ -251,7 +251,7 @@ Feature: Create events And I click on Unlink Event button on Event Directory Page @issue=SORDEV-5571 - Scenario: Event group screens + Scenario: Event group screen using Group Id on Edit Event Page Given API: I create a new event Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 @@ -267,7 +267,7 @@ Feature: Create events And I click on Unlink Event button on Event Directory Page @issue=SORDEV-5571 - Scenario: Event group screenss + Scenario: Event group screen using Group Id in grid Given API: I create a new event Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 From 4a3fe27b59e1592c26c3dac5fb4e69fd44128ae8 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Tue, 15 Feb 2022 12:31:41 +0100 Subject: [PATCH 124/253] remote driver fix --- .../org/sormas/e2etests/webdriver/RemoteDriverFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/RemoteDriverFactory.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/RemoteDriverFactory.java index ba427b86a3f..88350df2699 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/RemoteDriverFactory.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/webdriver/RemoteDriverFactory.java @@ -53,7 +53,7 @@ public RemoteDriverFactory( @Override public ChromeDriver getRemoteWebDriver() { log.info("Setting Chrome Driver's path"); - System.setProperty("webdriver.chrome.driver", "C:\\chromedriver_win32\\chromedriver.exe"); + System.setProperty("webdriver.chrome.driver", "/usr/lib64/chromium-browser/chromedriver"); log.info("Adding all chrome preferences"); final ChromeOptions options = new ChromeOptions(); final HashMap chromePreferences = new HashMap<>(); @@ -62,7 +62,7 @@ public ChromeDriver getRemoteWebDriver() { options.addArguments("--no-default-browser-check"); options.setUnhandledPromptBehaviour(UnexpectedAlertBehaviour.IGNORE); options.addArguments("disable-infobars"); - // options.addArguments("--headless"); + options.addArguments("--headless"); options.addArguments("enable-automation"); options.addArguments("--no-sandbox"); options.addArguments("--disable-browser-side-navigation"); From 950802e2853290b4c83b0c35e084babe61bab9d0 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Mon, 21 Feb 2022 13:43:43 +0100 Subject: [PATCH 125/253] Test scenario for Event directory impact --- .../events/EventDirectoryPage.java | 7 ++ .../events/EventDirectorySteps.java | 82 ++++++++++++++++++- .../features/sanity/web/Event.feature | 33 +++++++- 3 files changed, 118 insertions(+), 4 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java index 9c1c2b621b1..23a0a669e3f 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java @@ -72,6 +72,13 @@ public class EventDirectoryPage { public static final By CREATE_CASE_BUTTON = By.xpath("//td//span[contains(@class, 'v-icon-edit')]"); public static final By TOTAL_EVENTS_COUNTER = By.cssSelector(".badge"); + public static final By MORE_BUTTON_EVENT_DIRECTORY = By.id("more"); + public static final By ENTER_BULK_EDIT_MODE_EVENT_DIRECTORY = By.id("actionEnterBulkEditMode"); + public static final By FIRST_CHECKBOX_EVENT_DIRECTORY = + By.xpath("//th[@role='columnheader']//input[@type='checkbox']/../.."); + public static final By BULK_ACTIONS_EVENT_DIRECTORY = By.id("bulkActions-2"); + public static final By GROUP_EVENTS_EVENT_DIRECTORY = By.id("bulkActions-7"); + public static final By GROUP_ID_COLUMN = By.xpath("(//td//a)[2]"); public static By getByEventUuid(String eventUuid) { return By.xpath(String.format("//a[@title='%s']", eventUuid)); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index f63d71f2b5b..4afebde1231 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -24,8 +24,10 @@ import static org.sormas.e2etests.pages.application.events.EditEventPage.TITLE_INPUT; import static org.sormas.e2etests.pages.application.events.EditEventPage.UUID_INPUT; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.APPLY_FILTER; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.BULK_ACTIONS_EVENT_DIRECTORY; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.CREATED_PARTICIPANT; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.CREATE_CASE_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.ENTER_BULK_EDIT_MODE_EVENT_DIRECTORY; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENTS_RADIO_BUTTON; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_GROUP_ID_IN_GRID; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_STATUS_FILTER_BUTTONS; @@ -34,12 +36,16 @@ import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_RISK_LEVEL; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_SOURCE_TYPE; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_TYPE_OF_PLACE; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FIRST_CHECKBOX_EVENT_DIRECTORY; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FIRST_EVENT_GROUP; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FIRST_EVENT_ID_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.GROUP_EVENTS_EVENT_DIRECTORY; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.GROUP_ID_COLUMN; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.ID_FIELD_FILTER; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.LINKED_EVENT_GROUP_ID; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.LINK_EVENT_BUTTON; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.LINK_EVENT_BUTTON_EDIT_PAGE; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.MORE_BUTTON_EVENT_DIRECTORY; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.RESET_FILTER; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.SAVE_BUTTON_IN_LINK_FORM; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.SEARCH_EVENT_BY_FREE_TEXT; @@ -51,9 +57,11 @@ import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.RESET_FILTERS_BUTTON; import cucumber.api.java8.En; +import java.util.List; import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.inject.Named; +import org.openqa.selenium.By; import org.sormas.e2etests.common.DataOperations; import org.sormas.e2etests.enums.DiseasesValues; import org.sormas.e2etests.enums.RiskLevelValues; @@ -63,10 +71,14 @@ import org.sormas.e2etests.helpers.WebDriverHelpers; import org.sormas.e2etests.pages.application.NavBarPage; import org.sormas.e2etests.pages.application.events.EventDirectoryPage; +import org.sormas.e2etests.pojo.helpers.ComparisonHelper; +import org.sormas.e2etests.pojo.web.EventGroup; +import org.sormas.e2etests.services.EventGroupService; import org.sormas.e2etests.state.ApiState; import org.testng.Assert; public class EventDirectorySteps implements En { + private final WebDriverHelpers webDriverHelpers; @Inject public EventDirectorySteps( @@ -74,7 +86,9 @@ public EventDirectorySteps( ApiState apiState, DataOperations dataOperations, AssertHelpers assertHelpers, + EventGroupService eventGroupService, @Named("ENVIRONMENT_URL") String environmentUrl) { + this.webDriverHelpers = webDriverHelpers; When( "I fill EVENT ID filter by API", @@ -85,12 +99,46 @@ public EventDirectorySteps( dataOperations.getPartialUuidFromAssociatedLink(eventUuid)); }); + When( + "I click checkbox to choose all Event results", + () -> { + webDriverHelpers.clickOnWebElementBySelector(FIRST_CHECKBOX_EVENT_DIRECTORY); + webDriverHelpers.waitForPageLoaded(); + }); + And( + "I click on Bulk Actions combobox on Event Directory Page", + () -> webDriverHelpers.clickOnWebElementBySelector(BULK_ACTIONS_EVENT_DIRECTORY)); + + And( + "I click on Group Events from Bulk Actions combobox on Event Directory Page", + () -> webDriverHelpers.clickOnWebElementBySelector(GROUP_EVENTS_EVENT_DIRECTORY)); + When( + "I navigate to the last created Event page via URL", + () -> { + String createdEventUUID = CreateNewEventSteps.newEvent.getUuid(); + String LAST_CREATED_EVENT_PAGE_URL = + environmentUrl + "/sormas-webdriver/#!events/data/" + createdEventUUID; + webDriverHelpers.accessWebSite(LAST_CREATED_EVENT_PAGE_URL); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(UUID_INPUT, 50); + TimeUnit.SECONDS.sleep(5); + }); + When( "^I click on ([^\"]*) Radiobutton on Event Directory Page$", (String buttonName) -> { webDriverHelpers.clickWebElementByText(EVENTS_RADIO_BUTTON, buttonName); webDriverHelpers.waitForPageLoaded(); }); + When( + "I check that data of linked group is correct", + () -> { + EventGroup createdGroup = EditEventSteps.groupEvent; + EventGroup collectedGroup = collectEventGroup(); + ComparisonHelper.compareEqualFieldsOfEntities( + collectedGroup, createdGroup, List.of("name")); + webDriverHelpers.waitForPageLoaded(); + }); When( "^I click on Link Event button on Event Directory Page$", @@ -165,6 +213,13 @@ public EventDirectorySteps( webDriverHelpers.waitForPageLoaded(); webDriverHelpers.selectFromCombobox(FILTER_BY_DISEASE, disease); }); + When( + "I filter by last created group in Event Directory Page", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.fillInWebElement( + By.id("freeTextEventGroups"), EditEventSteps.groupEvent.getUuid()); + }); When( "I click on Show more filters in Events", @@ -306,6 +361,13 @@ public EventDirectorySteps( webDriverHelpers.clickOnWebElementBySelector(APPLY_FILTERS_BUTTON); TimeUnit.SECONDS.sleep(10); }); + When( + "I hover to Event Groups column of the Event result", + () -> { + webDriverHelpers.scrollToElement(GROUP_ID_COLUMN); + webDriverHelpers.hoverToElement(GROUP_ID_COLUMN); + TimeUnit.SECONDS.sleep(10); + }); When( "I click on the RESET FILTERS button from Event", @@ -318,9 +380,19 @@ public EventDirectorySteps( }); When( - "I click on the created event participant from the list", + "I click on the More button on Event directory page", () -> - webDriverHelpers.clickOnWebElementBySelector(CREATED_PARTICIPANT)); + webDriverHelpers.clickOnWebElementBySelector(MORE_BUTTON_EVENT_DIRECTORY) + ); + When( + "I click Enter Bulk Edit Mode on Event directory page", + () -> { + webDriverHelpers.clickOnWebElementBySelector(ENTER_BULK_EDIT_MODE_EVENT_DIRECTORY); + webDriverHelpers.waitForPageLoaded(); + }); + When( + "I click on the created event participant from the list", + () -> webDriverHelpers.clickOnWebElementBySelector(CREATED_PARTICIPANT)); When( "I click on New Task from event tab", @@ -355,4 +427,10 @@ public EventDirectorySteps( number.intValue(), "Number of displayed cases is not correct"))); } + + private EventGroup collectEventGroup() { + return EventGroup.builder() + .name(webDriverHelpers.getWebElement(GROUP_ID_COLUMN).getAttribute("title")) + .build(); + } } diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature index 2cde902d6bb..eb239489258 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature @@ -233,7 +233,7 @@ Feature: Create events And I select Screening filter from quick filter And I select Cluster filter from quick filter And I select Dropped filter from quick filter - And I click on the RESET FILTERS button + And I click on the RESET FILTERS button from Event @issue=SORDEV-5571 Scenario: Event group screen from Event Directory Page @@ -300,4 +300,33 @@ Feature: Create events And I click on Edit event group button from event groups box And I click on Edit event button for the first event in Events section And I click on the Navigate to event directory filtered on this event group - And I check the number of displayed Event results from All button is 1 \ No newline at end of file + And I check the number of displayed Event results from All button is 1 + + @issue=SORDEV-5572 + Scenario: Testing Event group adding for new event + Given API: I create a new event + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in as a Admin User + And I click on the Events button from navbar + Then I open the last created event via api + And I click on link event group + And I create a new event group + And I click on the Events button from navbar + And I fill EVENT ID filter by API + And I apply on the APPLY FILTERS button from Event + And I hover to Event Groups column of the Event result + And I click on the More button on Event directory page + And I click Enter Bulk Edit Mode on Event directory page + And I click checkbox to choose all Event results + And I click on Bulk Actions combobox on Event Directory Page + And I click on Group Events from Bulk Actions combobox on Event Directory Page + And I create a new event group + And I hover to Event Groups column of the Event result + And I filter by last created group in Event Directory Page + And I apply on the APPLY FILTERS button from Event + And I hover to Event Groups column of the Event result + And I check that data of linked group is correct + And I check the number of displayed Event results from All button is 1 + + From 34fe0bc585be1d26480477afca5a2dce96df4ebd Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Mon, 21 Feb 2022 13:50:50 +0100 Subject: [PATCH 126/253] Test scenario for Event directory impact --- .../features/sanity/web/Event.feature | 31 ------------------- 1 file changed, 31 deletions(-) diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature index eb239489258..04cc1caf937 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature @@ -235,37 +235,6 @@ Feature: Create events And I select Dropped filter from quick filter And I click on the RESET FILTERS button from Event - @issue=SORDEV-5571 - Scenario: Event group screen from Event Directory Page - Given API: I create a new event - Then API: I check that POST call body is "OK" - And API: I check that POST call status code is 200 - Given I log in with National User - And I click on the Events button from navbar - And I click on GROUPS Radiobutton on Event Directory Page - And I open the first event from events list - And I click on Link Event button on Event Directory Page - And I fill Id filter with Id of last created event in Link Event to group form - And I click on filtered Event in Link Event to group form - And I click on SAVE button in Link Event to group form - And I click on Unlink Event button on Event Directory Page - - @issue=SORDEV-5571 - Scenario: Event group screen using Group Id on Edit Event Page - Given API: I create a new event - Then API: I check that POST call body is "OK" - And API: I check that POST call status code is 200 - Given I log in with National User - And I click on the Events button from navbar - And I fill EVENT ID filter by API - And I apply on the APPLY FILTERS button from Event - And I open the first event from events list - And I click on Link Event button on Edit Event Page - And I click on first Event Group on the list in Link Event form - And I click on SAVE button in Link Event to group form - And I click on Linked Group Id on Edit Event Page - And I click on Unlink Event button on Event Directory Page - @issue=SORDEV-5571 Scenario: Event group screen using Group Id in grid Given API: I create a new event From 8c7d0edf73fe62526d9f9a9f9686b23791a68854 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Mon, 21 Feb 2022 13:53:36 +0100 Subject: [PATCH 127/253] Test scenario for Event directory impact --- .../resources/features/sanity/web/Event.feature | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature index 04cc1caf937..d8506559264 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature @@ -235,23 +235,6 @@ Feature: Create events And I select Dropped filter from quick filter And I click on the RESET FILTERS button from Event - @issue=SORDEV-5571 - Scenario: Event group screen using Group Id in grid - Given API: I create a new event - Then API: I check that POST call body is "OK" - And API: I check that POST call status code is 200 - Given I log in with National User - And I click on the Events button from navbar - And I fill EVENT ID filter by API - And I apply on the APPLY FILTERS button from Event - And I open the first event from events list - And I click on Link Event button on Edit Event Page - And I click on first Event Group on the list in Link Event form - And I click on SAVE button in Link Event to group form - And I click on the Events button from navbar - And I click on Group Id in Events result on Event Directory Page - And I click on Unlink Event button on Event Directory Page - @issue=SORDEV-5570 Scenario: Testing Event screen Impact Given API: I create a new event From cd9b1e7dca5a5d31d6caf81d821b580226b4c4fb Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Tue, 15 Feb 2022 08:14:13 +0100 Subject: [PATCH 128/253] test scenario for bulk edit --- .../application/cases/CaseDirectoryPage.java | 4 +++ .../application/cases/CaseDirectorySteps.java | 32 ++++++++++++++++++- .../features/sanity/web/Case.feature | 20 ++++++++++++ .../features/sanity/web/CaseFilters.feature | 2 +- 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java index a34e0de445d..03b56ae00ac 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java @@ -125,5 +125,9 @@ public class CaseDirectoryPage { public static final By INVESTIGATION_DISCARDED_BUTTON = By.id("Investigation discarded"); public static final By DATE_FROM_COMBOBOX = By.cssSelector("#dateFrom input"); public static final By DATE_TO_COMBOBOX = By.cssSelector("#dateTo input"); + public static final By MORE_BUTTON = By.id("more"); + public static final By ENTER_BULK_EDIT_MODE = By.id("actionEnterBulkEditMode"); + public static final By FIRST_CHECKBOX = + By.xpath("//th[@role='columnheader']//input[@type='checkbox']/../.."); // TODO refactor the other headers based on the last one added } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java index 7a852fa1119..5655dd8b1b9 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java @@ -82,6 +82,23 @@ public CaseDirectorySteps( By.xpath(String.format(RESULTS_GRID_HEADER, "Sex")), 20); webDriverHelpers.waitUntilANumberOfElementsAreVisibleAndClickable(GRID_HEADERS, 41); }); + When( + "I click on the More button on Case directory page", + () -> { + webDriverHelpers.clickOnWebElementBySelector(MORE_BUTTON); + }); + When( + "I click Enter Bulk Edit Mode on Case directory page", + () -> { + webDriverHelpers.clickOnWebElementBySelector(ENTER_BULK_EDIT_MODE); + webDriverHelpers.waitForPageLoaded(); + }); + When( + "I click checkbox to choose all Case results", + () -> { + webDriverHelpers.clickOnWebElementBySelector(FIRST_CHECKBOX); + webDriverHelpers.waitForPageLoaded(); + }); When( "I filter by CaseID on Case directory page", @@ -215,6 +232,7 @@ public CaseDirectorySteps( apiState.getLastCreatedPerson().getFirstName() + " " + apiState.getLastCreatedPerson().getLastName())); + And( "I apply mocked Person Id filter on Case directory page", () -> @@ -269,7 +287,7 @@ public CaseDirectorySteps( () -> { webDriverHelpers.clickOnWebElementBySelector( CASE_DIRECTORY_DETAILED_PAGE_APPLY_FILTER_BUTTON); - TimeUnit.SECONDS.sleep(3); // needed for table refresh + TimeUnit.SECONDS.sleep(5); // needed for table refresh }); Then( @@ -324,6 +342,18 @@ public CaseDirectorySteps( ZoneId.systemDefault()) .minusDays(number))); }); + And( + "I fill Cases from input to {int} days before mocked Cases created on Case directory page", + (Integer number) -> { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy"); + webDriverHelpers.fillInWebElement( + DATE_FROM_COMBOBOX, + formatter.format( + LocalDate.ofInstant( + apiState.getCreatedCases().get(0).getReportDate().toInstant(), + ZoneId.systemDefault()) + .minusDays(number))); + }); And( "I fill Cases from input to {int} days after before mocked Case created on Case directory page", (Integer number) -> { diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature index f8016bf558e..dd9f4d2af03 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature @@ -324,5 +324,25 @@ Feature: Case end to end tests Then I click on save Contact button And I check if Quarantine change comment field was saved correctly + @issue=SORDEV-7452 + Scenario: Bulk mode for linking/adding to Events + When API: I create a new person + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + When API: I create 10 new cases + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in as a Admin User + And I click on the Cases button from navbar + And I click SHOW MORE FILTERS button on Case directory page + And I apply Date type filter to "Case report date" on Case directory page + And I fill Cases from input to 1 days before mocked Cases created on Case directory page + And I apply last created api Person Id filter on Case directory page + And I click APPLY BUTTON in Case Directory Page + And I click on the More button on Case directory page + And I click Enter Bulk Edit Mode on Case directory page + And I click checkbox to choose all Case results + And I click on New Sample + diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature index d8242bc7f87..f002a5a4099 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature @@ -62,7 +62,7 @@ Feature: Case filter functionality Given API: I create a new case Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 - Given I log in with National User + Given I log in as a Admin User And I click on the Cases button from navbar And I apply Case origin "In-Country" on Case directory page And I filter by CaseID on Case directory page From 8e415f9f31347c0330ea437dc1f2dddaade89aac Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Fri, 18 Feb 2022 13:31:57 +0100 Subject: [PATCH 129/253] test scenario for bulk linking cases and contacts to event --- .../application/cases/CaseDirectoryPage.java | 3 ++ .../contacts/ContactDirectoryPage.java | 1 + .../e2etests/services/api/CaseApiService.java | 2 +- .../services/api/EventApiService.java | 2 +- .../application/cases/CaseDirectorySteps.java | 30 ++++++++++++ .../contacts/ContactDirectorySteps.java | 25 +++++++++- .../application/events/EditEventSteps.java | 14 ++++++ .../events/EventDirectorySteps.java | 40 ++++++++++++---- .../features/sanity/web/Case.feature | 41 ++++++++++++++-- .../features/sanity/web/Contacts.feature | 48 +++++++++++++++++++ 10 files changed, 191 insertions(+), 15 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java index 03b56ae00ac..5722a2d312b 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java @@ -34,6 +34,7 @@ public class CaseDirectoryPage { By.cssSelector("thead .v-grid-column-default-header-content"); public static final By CASE_DETAILED_TABLE_ROWS = By.cssSelector("div.v-grid-tablewrapper tbody tr"); + public static final By SAVE_BUTTON_IN_LINK_FORM = By.cssSelector(".popupContent #commit"); public static final By FIRST_CASE_ID_BUTTON = By.cssSelector(".v-grid-row-has-data a[title]"); public static final By NAME_UUID_EPID_NUMBER_LIKE_INPUT = By.cssSelector("input#caseLike"); public static final By PERSON_ID_NAME_CONTACT_INFORMATION_LIKE_INPUT = @@ -93,6 +94,8 @@ public class CaseDirectoryPage { By.cssSelector("[id='dateType'] [class='v-filterselect-button']"); public static final By CASE_DISPLAY_FILTER_COMBOBOX = By.cssSelector("[id='relevanceStatus'] [class='v-filterselect-button']"); + public static final By BULK_ACTIONS = By.id("bulkActions-2"); + public static final By BULK_ACTIONS_VALUES = By.id("bulkActions-10"); public static final By CASE_REPORTING_USER_FILTER = By.cssSelector("[id='reportingUserLike']"); public static final By CASE_YEAR_FILTER = By.cssSelector("[id='birthdateYYYY'] [class='v-filterselect-button']"); diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/ContactDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/ContactDirectoryPage.java index 7d083025ce0..5bd0ec2890e 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/ContactDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/contacts/ContactDirectoryPage.java @@ -82,4 +82,5 @@ public class ContactDirectoryPage { public static final By ACTIVE_CONTACT_BUTTON = By.id("status-Active contact"); public static final By CONVERTED_TO_CASE_BUTTON = By.id("status-Converted to case"); public static final By DROPPED_BUTTON = By.id("status-Dropped"); + public static final By BULK_ACTIONS_CONTACT_VALUES = By.id("bulkActions-9"); } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/CaseApiService.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/CaseApiService.java index ae17b538ef9..96c7806c69b 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/CaseApiService.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/CaseApiService.java @@ -37,7 +37,7 @@ public CaseApiService() {} public Case buildGeneratedCase(Person person) { return Case.builder() - .disease(DiseasesValues.getRandomDiseaseName()) + .disease(DiseasesValues.CORONAVIRUS.getDiseaseName()) .diseaseDetails("Test Disease") .pseudonymized(false) .uuid(UUID.randomUUID().toString()) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/EventApiService.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/EventApiService.java index a01f1c7a516..c2aef468c55 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/EventApiService.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/EventApiService.java @@ -35,7 +35,7 @@ public EventApiService() {} public Event buildGeneratedEvent() { return Event.builder() .uuid(UUID.randomUUID().toString()) - .disease(DiseasesValues.getRandomDiseaseName()) + .disease(DiseasesValues.CORONAVIRUS.getDiseaseName()) .reportingUser(ReportingUser.builder().uuid("QLW4AN-TGWLRA-3UQVEM-WCDFCIVM").build()) .eventStatus("SIGNAL") .srcType(SourceTypeValues.getRandomSourceTypeName()) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java index 5655dd8b1b9..6d33e4ac8db 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java @@ -99,6 +99,36 @@ public CaseDirectorySteps( webDriverHelpers.clickOnWebElementBySelector(FIRST_CHECKBOX); webDriverHelpers.waitForPageLoaded(); }); + And( + "I click on Bulk Actions combobox on Case Directory Page", + () -> webDriverHelpers.clickOnWebElementBySelector(BULK_ACTIONS)); + + And( + "I click on Link to Event from Bulk Actions combobox on Case Directory Page", + () -> webDriverHelpers.clickOnWebElementBySelector(BULK_ACTIONS_VALUES)); + + And( + "I click on New Event option in Link to Event Form", + () -> + webDriverHelpers.clickOnWebElementBySelector( + By.xpath( + "/html/body/div[2]/div[3]/div/div/div[3]/div/div/div[1]/div/div[2]/div/div/div[9]/div"))); + And( + "I fill Event Id filter with last created EventId on Link to Event form", + () -> { + String eventUuid = apiState.getCreatedEvent().getUuid(); + webDriverHelpers.fillInWebElement( + By.id("search"), dataOperations.getPartialUuidFromAssociatedLink(eventUuid)); + TimeUnit.SECONDS.sleep(5); + }); + And( + "I click first result in grid on Link to Event form", + () -> + webDriverHelpers.clickOnWebElementBySelector( + By.xpath("//div[contains(@class, 'popupContent')]//tr[@role='row']"))); + When( + "^I click on SAVE button in Link Event to group form$", + () -> webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON_IN_LINK_FORM)); When( "I filter by CaseID on Case directory page", diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/ContactDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/ContactDirectorySteps.java index ff4efead918..02d73fcc950 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/ContactDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/ContactDirectorySteps.java @@ -120,8 +120,31 @@ public ContactDirectorySteps( dataOperations.getPartialUuidFromAssociatedLink( apiState.getCreatedContact().getUuid()); webDriverHelpers.fillAndSubmitInWebElement( - CONTACT_DIRECTORY_DETAILED_PAGE_FILTER_INPUT, apiState.getCreatedContact().getUuid()); + CONTACT_DIRECTORY_DETAILED_PAGE_FILTER_INPUT, contactUuid); + }); + When( + "I click on the More button on Contact directory page", + () -> { + webDriverHelpers.clickOnWebElementBySelector(MORE_BUTTON); + }); + And( + "I click on Link to Event from Bulk Actions combobox on Contact Directory Page", + () -> webDriverHelpers.clickOnWebElementBySelector(BULK_ACTIONS_CONTACT_VALUES)); + When( + "I click Enter Bulk Edit Mode on Contact directory page", + () -> { + webDriverHelpers.clickOnWebElementBySelector(ENTER_BULK_EDIT_MODE); + webDriverHelpers.waitForPageLoaded(); }); + When( + "I click checkbox to choose all Contact results", + () -> { + webDriverHelpers.clickOnWebElementBySelector(FIRST_CHECKBOX); + webDriverHelpers.waitForPageLoaded(); + }); + And( + "I click on Bulk Actions combobox on Contact Directory Page", + () -> webDriverHelpers.clickOnWebElementBySelector(BULK_ACTIONS)); And( "I filter by mocked ContactID on Contact directory page", () -> { diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java index 92f27f47037..d046fe6086e 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java @@ -23,6 +23,7 @@ import static org.sormas.e2etests.pages.application.events.EditEventPage.*; import static org.sormas.e2etests.pages.application.events.EditEventPage.SAVE_BUTTON; import static org.sormas.e2etests.pages.application.events.EventActionsPage.CREATE_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.TOTAL_EVENTS_COUNTER; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.getByEventUuid; import static org.sormas.e2etests.pages.application.events.EventParticipantsPage.*; import static org.sormas.e2etests.pages.application.events.EventParticipantsPage.EVENT_PARTICIPANTS_TAB; @@ -372,6 +373,19 @@ public EditEventSteps( webDriverHelpers.clickOnWebElementBySelector(EditEventPage.CREATE_EVENT_HANDOUT_BUTTON); webDriverHelpers.clickOnWebElementBySelector(EditEventPage.CANCEL_EVENT_HANDOUT_BUTTON); }); + And( + "I check that number of displayed Event Participants is {int}", + (Integer number) -> { + webDriverHelpers.clickOnWebElementBySelector(EditEventPage.EVENT_PARTICIPANTS_TAB); + webDriverHelpers.waitForPageLoaded(); + assertHelpers.assertWithPoll20Second( + () -> + Assert.assertEquals( + Integer.parseInt( + webDriverHelpers.getTextFromPresentWebElement(TOTAL_EVENTS_COUNTER)), + number.intValue(), + "Number of displayed actions is not correct")); + }); And( "I check that number of actions in Edit Event Tab is {int}", (Integer number) -> diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index 5f67d338414..e90b0b054e6 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -21,6 +21,7 @@ import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_GRID_RESULTS_ROWS; import static org.sormas.e2etests.pages.application.events.EditEventPage.*; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.*; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.UUID_INPUT; import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.APPLY_FILTERS_BUTTON; import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.RESET_FILTERS_BUTTON; @@ -56,6 +57,27 @@ public EventDirectorySteps( SEARCH_EVENT_BY_FREE_TEXT, dataOperations.getPartialUuidFromAssociatedLink(eventUuid)); }); + When( + "I navigate to the last created Event page via URL", + () -> { + String createdEventUUID = CreateNewEventSteps.newEvent.getUuid(); + String LAST_CREATED_EVENT_PAGE_URL = + environmentUrl + "/sormas-webdriver/#!events/data/" + createdEventUUID; + webDriverHelpers.accessWebSite(LAST_CREATED_EVENT_PAGE_URL); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(UUID_INPUT, 50); + TimeUnit.SECONDS.sleep(5); + }); + When( + "I navigate to the last created through API Event page via URL", + () -> { + String createdEventUUID = apiState.getCreatedEvent().getUuid(); + String LAST_CREATED_EVENT_PAGE_URL = + environmentUrl + "/sormas-webdriver/#!events/data/" + createdEventUUID; + webDriverHelpers.accessWebSite(LAST_CREATED_EVENT_PAGE_URL); + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(UUID_INPUT, 50); + }); When( "I click on the NEW EVENT button", @@ -266,15 +288,15 @@ public EventDirectorySteps( "I click Create Case for Event Participant", () -> webDriverHelpers.clickOnWebElementBySelector(CREATE_CASE_BUTTON)); - Then( - "I check that number of displayed Event results is {int}", - (Integer number) -> - assertHelpers.assertWithPoll20Second( - () -> - Assert.assertEquals( - webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), - number.intValue(), - "Number of displayed cases is not correct"))); + Then( + "I check that number of displayed Event results is {int}", + (Integer number) -> + assertHelpers.assertWithPoll20Second( + () -> + Assert.assertEquals( + webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), + number.intValue(), + "Number of displayed cases is not correct"))); Then( "I check the number of displayed Event results from All button is {int}", diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature index dd9f4d2af03..8c2bd5680d5 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature @@ -325,11 +325,11 @@ Feature: Case end to end tests And I check if Quarantine change comment field was saved correctly @issue=SORDEV-7452 - Scenario: Bulk mode for linking/adding to Events + Scenario: Bulk mode for linking/adding cases to new Event When API: I create a new person Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 - When API: I create 10 new cases + When API: I create 2 new cases Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 Given I log in as a Admin User @@ -342,7 +342,42 @@ Feature: Case end to end tests And I click on the More button on Case directory page And I click Enter Bulk Edit Mode on Case directory page And I click checkbox to choose all Case results - And I click on New Sample + And I click on Bulk Actions combobox on Case Directory Page + And I click on Link to Event from Bulk Actions combobox on Case Directory Page + And I click on New Event option in Link to Event Form + And I click on SAVE button in Link Event to group form + And I create a new event with status CLUSTER + And I navigate to the last created Event page via URL + And I check that number of displayed Event Participants is 1 + + @issue=SORDEV-7452 + Scenario: Bulk mode for linking/adding case to existing Event + Given API: I create a new event + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + When API: I create a new person + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + When API: I create 2 new cases + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in as a Admin User + And I click on the Cases button from navbar + And I click SHOW MORE FILTERS button on Case directory page + And I apply Date type filter to "Case report date" on Case directory page + And I fill Cases from input to 1 days before mocked Cases created on Case directory page + And I apply last created api Person Id filter on Case directory page + And I click APPLY BUTTON in Case Directory Page + And I click on the More button on Case directory page + And I click Enter Bulk Edit Mode on Case directory page + And I click checkbox to choose all Case results + And I click on Bulk Actions combobox on Case Directory Page + And I click on Link to Event from Bulk Actions combobox on Case Directory Page + And I fill Event Id filter with last created EventId on Link to Event form + And I click first result in grid on Link to Event form + And I click on SAVE button in Link Event to group form + And I navigate to the last created through API Event page via URL + And I check that number of displayed Event Participants is 1 diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature index dd4128f8e80..c9fa8243545 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature @@ -241,3 +241,51 @@ Feature: Contacts end to end tests And I fill the specific data of visit with Set cleared to Unknown option to all symptoms Then I save the Visit data + @issue=SORDEV-7452 + Scenario: Bulk mode for linking/adding contacts to new Event + When API: I create a new person + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + When API: I create a new contact + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in as a Admin User + And I click on the Contacts button from navbar + And I apply Id of last api created Contact on Contact Directory Page + And I click APPLY BUTTON in Contact Directory Page + And I click on the More button on Contact directory page + And I click Enter Bulk Edit Mode on Contact directory page + And I click checkbox to choose all Contact results + And I click on Bulk Actions combobox on Contact Directory Page + And I click on Link to Event from Bulk Actions combobox on Contact Directory Page + And I click on New Event option in Link to Event Form + And I click on SAVE button in Link Event to group form + And I create a new event with status CLUSTER + And I navigate to the last created Event page via URL + And I check that number of displayed Event Participants is 1 + + @issue=SORDEV-7452 + Scenario: Bulk mode for linking/adding contacts to existing Event + Given API: I create a new event + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + When API: I create a new person + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + When API: I create a new contact + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in as a Admin User + And I click on the Contacts button from navbar + And I apply Id of last api created Contact on Contact Directory Page + And I click APPLY BUTTON in Contact Directory Page + And I click on the More button on Contact directory page + And I click Enter Bulk Edit Mode on Contact directory page + And I click checkbox to choose all Contact results + And I click on Bulk Actions combobox on Contact Directory Page + And I click on Link to Event from Bulk Actions combobox on Contact Directory Page + And I fill Event Id filter with last created EventId on Link to Event form + And I click first result in grid on Link to Event form + And I click on SAVE button in Link Event to group form + And I navigate to the last created through API Event page via URL + And I check that number of displayed Event Participants is 1 From b9296eea3eb4370747e58d638188f5a179f34d1b Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Mon, 21 Feb 2022 14:19:39 +0100 Subject: [PATCH 130/253] minor adjustements --- .../application/cases/CaseDirectoryPage.java | 3 ++ .../application/cases/CaseDirectorySteps.java | 9 ++---- .../persons/PersonDirectorySteps.java | 28 +++++++++---------- .../features/sanity/web/Case.feature | 2 ++ 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java index 5722a2d312b..4a1f8a5d19d 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java @@ -132,5 +132,8 @@ public class CaseDirectoryPage { public static final By ENTER_BULK_EDIT_MODE = By.id("actionEnterBulkEditMode"); public static final By FIRST_CHECKBOX = By.xpath("//th[@role='columnheader']//input[@type='checkbox']/../.."); + public static final By NEW_EVENT_CHECKBOX = By.xpath("//*[contains(text(),'New event')]/.."); + public static final By FIRST_RESULT_IN_GRID = + By.xpath("//div[contains(@class, 'popupContent')]//tr[@role='row']"); // TODO refactor the other headers based on the last one added } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java index 6d33e4ac8db..88a1469e145 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java @@ -109,10 +109,7 @@ public CaseDirectorySteps( And( "I click on New Event option in Link to Event Form", - () -> - webDriverHelpers.clickOnWebElementBySelector( - By.xpath( - "/html/body/div[2]/div[3]/div/div/div[3]/div/div/div[1]/div/div[2]/div/div/div[9]/div"))); + () -> webDriverHelpers.clickOnWebElementBySelector(NEW_EVENT_CHECKBOX)); And( "I fill Event Id filter with last created EventId on Link to Event form", () -> { @@ -123,9 +120,7 @@ public CaseDirectorySteps( }); And( "I click first result in grid on Link to Event form", - () -> - webDriverHelpers.clickOnWebElementBySelector( - By.xpath("//div[contains(@class, 'popupContent')]//tr[@role='row']"))); + () -> webDriverHelpers.clickOnWebElementBySelector(FIRST_RESULT_IN_GRID)); When( "^I click on SAVE button in Link Event to group form$", () -> webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON_IN_LINK_FORM)); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java index 8cbef9226d0..a634b8915ac 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java @@ -246,14 +246,14 @@ public PersonDirectorySteps( webDriverHelpers.clickOnWebElementBySelector(By.cssSelector("[role='gridcell'] a")); }); - When( - "I apply on the APPLY FILTERS button", - () -> { - webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable( - APPLY_FILTERS_BUTTON, 30); - webDriverHelpers.clickOnWebElementBySelector(APPLY_FILTERS_BUTTON); - TimeUnit.SECONDS.sleep(10); - }); + When( + "I apply on the APPLY FILTERS button", + () -> { + webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable( + APPLY_FILTERS_BUTTON, 30); + webDriverHelpers.clickOnWebElementBySelector(APPLY_FILTERS_BUTTON); + TimeUnit.SECONDS.sleep(10); + }); When( "I click on the RESET FILTERS button for Person", @@ -279,12 +279,12 @@ public PersonDirectorySteps( + " " + apiState.getLastCreatedPerson().getFirstName(); break; - case "phone number": - searchText = apiState.getLastCreatedPerson().getPhone(); - break; - case "email": - searchText = apiState.getLastCreatedPerson().getEmailAddress(); - break; + case "phone number": + searchText = apiState.getLastCreatedPerson().getPhone(); + break; + case "email": + searchText = apiState.getLastCreatedPerson().getEmailAddress(); + break; } webDriverHelpers.waitUntilElementIsVisibleAndClickable(APPLY_FILTERS_BUTTON); webDriverHelpers.clickOnWebElementBySelector(ALL_BUTTON); diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature index 8c2bd5680d5..138b042465d 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature @@ -339,6 +339,7 @@ Feature: Case end to end tests And I fill Cases from input to 1 days before mocked Cases created on Case directory page And I apply last created api Person Id filter on Case directory page And I click APPLY BUTTON in Case Directory Page + And I click SHOW MORE FILTERS button on Case directory page And I click on the More button on Case directory page And I click Enter Bulk Edit Mode on Case directory page And I click checkbox to choose all Case results @@ -368,6 +369,7 @@ Feature: Case end to end tests And I fill Cases from input to 1 days before mocked Cases created on Case directory page And I apply last created api Person Id filter on Case directory page And I click APPLY BUTTON in Case Directory Page + And I click SHOW MORE FILTERS button on Case directory page And I click on the More button on Case directory page And I click Enter Bulk Edit Mode on Case directory page And I click checkbox to choose all Case results From 7535c6045e2fd1b3aeb645d13d878722d8b9f286 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Mon, 21 Feb 2022 16:28:34 +0200 Subject: [PATCH 131/253] Feature 7451 travel entry directory (#8055) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * #7451 - add report date filters to travel entry directory * #7451 - add bulk actions -> bulk delete to travel entry directory * #7451 - update i18 strings Co-authored-by: Maté Strysewske --- .../de/symeda/sormas/api/i18n/Strings.java | 9 ++ .../api/travelentry/TravelEntryCriteria.java | 41 ++++++++- .../src/main/resources/strings.properties | 12 ++- .../services/TravelEntryService.java | 14 +++- .../ui/travelentry/TravelEntriesView.java | 83 ++++++++++++++++++ .../ui/travelentry/TravelEntryController.java | 32 ++++++- .../ui/travelentry/TravelEntryFilterForm.java | 84 +++++++++++++++++++ .../ui/travelentry/TravelEntryGrid.java | 34 +++++++- 8 files changed, 300 insertions(+), 9 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java index 069bf030abb..7f464edf4c1 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java @@ -125,6 +125,7 @@ public interface Strings { String confirmationDeletePrescriptions = "confirmationDeletePrescriptions"; String confirmationDeleteSamples = "confirmationDeleteSamples"; String confirmationDeleteTasks = "confirmationDeleteTasks"; + String confirmationDeleteTravelEntries = "confirmationDeleteTravelEntries"; String confirmationDeleteTreatments = "confirmationDeleteTreatments"; String confirmationDeleteVisits = "confirmationDeleteVisits"; String confirmationDisableAllLineListingNational = "confirmationDisableAllLineListingNational"; @@ -575,6 +576,7 @@ public interface Strings { String headingNoRowsSelected = "headingNoRowsSelected"; String headingNoSamplesSelected = "headingNoSamplesSelected"; String headingNoTasksSelected = "headingNoTasksSelected"; + String headingNoTravelEntriesSelected = "headingNoTravelEntriesSelected"; String headingNoTreatmentsSelected = "headingNoTreatmentsSelected"; String headingNoUsersSelected = "headingNoUsersSelected"; String headingNoVisitsSelected = "headingNoVisitsSelected"; @@ -643,6 +645,7 @@ public interface Strings { String headingTemplateNotAvailable = "headingTemplateNotAvailable"; String headingTests = "headingTests"; String headingTransferCase = "headingTransferCase"; + String headingTravelEntriesDeleted = "headingTravelEntriesDeleted"; String headingTravelEntryData = "headingTravelEntryData"; String headingTreatments = "headingTreatments"; String headingTreatmentsDeleted = "headingTreatmentsDeleted"; @@ -1068,6 +1071,7 @@ public interface Strings { String messageNoRowsSelected = "messageNoRowsSelected"; String messageNoSamplesSelected = "messageNoSamplesSelected"; String messageNoTasksSelected = "messageNoTasksSelected"; + String messageNoTravelEntriesSelected = "messageNoTravelEntriesSelected"; String messageNoTreatmentsSelected = "messageNoTreatmentsSelected"; String messageNoUsersSelected = "messageNoUsersSelected"; String messageNoVisitsSelected = "messageNoVisitsSelected"; @@ -1129,6 +1133,7 @@ public interface Strings { String messageTasksDeleted = "messageTasksDeleted"; String messageTasksEdited = "messageTasksEdited"; String messageTemplateNotAvailable = "messageTemplateNotAvailable"; + String messageTravelEntriesDeleted = "messageTravelEntriesDeleted"; String messageTravelEntryArchived = "messageTravelEntryArchived"; String messageTravelEntryDearchived = "messageTravelEntryDearchived"; String messageTravelEntryPOEFilledBySystem = "messageTravelEntryPOEFilledBySystem"; @@ -1311,6 +1316,10 @@ public interface Strings { String promptTaskEpiWeekFrom = "promptTaskEpiWeekFrom"; String promptTaskEpiWeekTo = "promptTaskEpiWeekTo"; String promptTaskSearchField = "promptTaskSearchField"; + String promptTravelEntryDateFrom = "promptTravelEntryDateFrom"; + String promptTravelEntryDateTo = "promptTravelEntryDateTo"; + String promptTravelEntryEpiWeekFrom = "promptTravelEntryEpiWeekFrom"; + String promptTravelEntryEpiWeekTo = "promptTravelEntryEpiWeekTo"; String promptTravelEntrySearchField = "promptTravelEntrySearchField"; String promptTreatmentTextFilter = "promptTreatmentTextFilter"; String promptTypeToAdd = "promptTypeToAdd"; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/travelentry/TravelEntryCriteria.java b/sormas-api/src/main/java/de/symeda/sormas/api/travelentry/TravelEntryCriteria.java index 73e27410e18..7bed58bd2df 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/travelentry/TravelEntryCriteria.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/travelentry/TravelEntryCriteria.java @@ -1,10 +1,12 @@ package de.symeda.sormas.api.travelentry; import java.io.Serializable; +import java.util.Date; -import de.symeda.sormas.api.caze.CaseReferenceDto; import de.symeda.sormas.api.EntityRelevanceStatus; +import de.symeda.sormas.api.caze.CaseReferenceDto; import de.symeda.sormas.api.person.PersonReferenceDto; +import de.symeda.sormas.api.utils.DateFilterOption; import de.symeda.sormas.api.utils.criteria.BaseCriteria; public class TravelEntryCriteria extends BaseCriteria implements Serializable, Cloneable { @@ -24,6 +26,9 @@ public class TravelEntryCriteria extends BaseCriteria implements Serializable, C private CaseReferenceDto caze; private Boolean deleted = Boolean.FALSE; private EntityRelevanceStatus relevanceStatus; + private Date reportDateFrom; + private Date reportDateTo; + private DateFilterOption dateFilterOption = DateFilterOption.DATE; public String getNameUuidExternalIDLike() { return nameUuidExternalIDLike; @@ -105,4 +110,38 @@ public EntityRelevanceStatus getRelevanceStatus() { public void relevanceStatus(EntityRelevanceStatus relevanceStatus) { this.relevanceStatus = relevanceStatus; } + + public Date getReportDateFrom() { + return reportDateFrom; + } + + public void setReportDateFrom(Date reportDateFrom) { + this.reportDateFrom = reportDateFrom; + } + + public Date getReportDateTo() { + return reportDateTo; + } + + public void setReportDateTo(Date reportDateTo) { + this.reportDateTo = reportDateTo; + } + + public DateFilterOption getDateFilterOption() { + return dateFilterOption; + } + + public void setDateFilterOption(DateFilterOption dateFilterOption) { + this.dateFilterOption = dateFilterOption; + } + + public TravelEntryCriteria reportDateBetween( + Date reportDateFrom, + Date reportDateTo, + DateFilterOption dateFilterOption) { + this.reportDateFrom = reportDateFrom; + this.reportDateTo = reportDateTo; + this.dateFilterOption = dateFilterOption; + return this; + } } diff --git a/sormas-api/src/main/resources/strings.properties b/sormas-api/src/main/resources/strings.properties index f08e46a5f6f..a87ad0aaf44 100644 --- a/sormas-api/src/main/resources/strings.properties +++ b/sormas-api/src/main/resources/strings.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Are you sure you want to delete all %d selected con confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Are you sure you want to delete all %d selected event participants? confirmationDeleteEvents = Are you sure you want to delete all %d selected events? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected pathogen tests? confirmationDeletePrescriptions = Are you sure you want to delete all %d selected prescriptions? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1350,6 +1355,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/TravelEntryService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/TravelEntryService.java index e5b0e434c86..ba910ed3406 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/TravelEntryService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/TravelEntryService.java @@ -18,9 +18,6 @@ import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; -import de.symeda.sormas.backend.event.Event; -import de.symeda.sormas.backend.event.EventQueryContext; -import de.symeda.sormas.backend.user.User; import org.apache.commons.collections4.CollectionUtils; import de.symeda.sormas.api.EntityRelevanceStatus; @@ -30,7 +27,6 @@ import de.symeda.sormas.api.travelentry.TravelEntryReferenceDto; import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.utils.DataHelper; -import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.api.utils.SortProperty; import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.common.AbstractDomainObject; @@ -45,6 +41,7 @@ import de.symeda.sormas.backend.travelentry.TravelEntryJoins; import de.symeda.sormas.backend.travelentry.TravelEntryQueryContext; import de.symeda.sormas.backend.travelentry.transformers.TravelEntryIndexDtoResultTransformer; +import de.symeda.sormas.backend.user.User; import de.symeda.sormas.backend.util.JurisdictionHelper; @Stateless @@ -276,6 +273,15 @@ private Predicate buildCriteriaFilter(TravelEntryCriteria criteria, TravelEntryQ } } + if (criteria.getReportDateFrom() != null && criteria.getReportDateTo() != null) { + filter = CriteriaBuilderHelper + .and(cb, filter, cb.between(from.get(TravelEntry.REPORT_DATE), criteria.getReportDateFrom(), criteria.getReportDateTo())); + } else if (criteria.getReportDateFrom() != null) { + filter = CriteriaBuilderHelper.and(cb, filter, cb.greaterThanOrEqualTo(from.get(TravelEntry.REPORT_DATE), criteria.getReportDateFrom())); + } else if (criteria.getReportDateTo() != null) { + filter = CriteriaBuilderHelper.and(cb, filter, cb.lessThanOrEqualTo(from.get(TravelEntry.REPORT_DATE), criteria.getReportDateTo())); + } + if (criteria.getDeleted() != null) { filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(TravelEntry.DELETED), criteria.getDeleted())); } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntriesView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntriesView.java index 58b7026b520..c18dbb6db4f 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntriesView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntriesView.java @@ -1,15 +1,20 @@ package de.symeda.sormas.ui.travelentry; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; import com.vaadin.icons.VaadinIcons; import com.vaadin.navigator.ViewChangeListener; import com.vaadin.shared.ui.ContentMode; import com.vaadin.ui.Alignment; +import com.vaadin.ui.Button; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.MenuBar; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window; +import com.vaadin.ui.themes.ValoTheme; import com.vaadin.v7.ui.ComboBox; import de.symeda.sormas.api.EntityRelevanceStatus; @@ -28,14 +33,18 @@ import de.symeda.sormas.ui.utils.ComboBoxHelper; import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.FilteredGrid; +import de.symeda.sormas.ui.utils.MenuBarHelper; import de.symeda.sormas.ui.utils.VaadinUiUtil; +import de.symeda.sormas.ui.utils.ViewConfiguration; import de.symeda.sormas.ui.utils.components.expandablebutton.ExpandableButton; +import de.symeda.sormas.ui.utils.components.popupmenu.PopupMenu; public class TravelEntriesView extends AbstractView { public static final String VIEW_NAME = "travelEntries"; private final TravelEntryCriteria criteria; + private ViewConfiguration viewConfiguration; private final FilteredGrid grid; private TravelEntryFilterForm filterForm; @@ -43,9 +52,14 @@ public class TravelEntriesView extends AbstractView { private Label relevanceStatusInfoLabel; private ComboBox relevanceStatusFilter; + // Bulk operations + private MenuBar bulkOperationsDropdown; + public TravelEntriesView() { super(VIEW_NAME); + viewConfiguration = ViewModelProviders.of(getClass()).get(ViewConfiguration.class); + criteria = ViewModelProviders.of(TravelEntriesView.class).get(TravelEntryCriteria.class); if (criteria.getRelevanceStatus() == null) { criteria.relevanceStatus(EntityRelevanceStatus.ACTIVE); @@ -80,6 +94,48 @@ public TravelEntriesView() { addHeaderComponent(createButton); } } + + final PopupMenu moreButton = new PopupMenu(I18nProperties.getCaption(Captions.moreActions)); + + if (UserProvider.getCurrent().hasUserRight(UserRight.TRAVEL_ENTRY_DELETE) + && UserProvider.getCurrent().hasUserRight(UserRight.PERFORM_BULK_OPERATIONS)) { + Button btnEnterBulkEditMode = ButtonHelper.createIconButton(Captions.actionEnterBulkEditMode, VaadinIcons.CHECK_SQUARE_O, null); + { + btnEnterBulkEditMode.setVisible(!viewConfiguration.isInEagerMode()); + btnEnterBulkEditMode.addStyleName(ValoTheme.BUTTON_PRIMARY); + + btnEnterBulkEditMode.setWidth(100, Unit.PERCENTAGE); + moreButton.addMenuEntry(btnEnterBulkEditMode); + } + + Button btnLeaveBulkEditMode = + ButtonHelper.createIconButton(Captions.actionLeaveBulkEditMode, VaadinIcons.CLOSE, null, ValoTheme.BUTTON_PRIMARY); + { + btnLeaveBulkEditMode.setVisible(viewConfiguration.isInEagerMode()); + btnLeaveBulkEditMode.setWidth(100, Unit.PERCENTAGE); + + moreButton.addMenuEntry(btnLeaveBulkEditMode); + } + + btnEnterBulkEditMode.addClickListener(e -> { + bulkOperationsDropdown.setVisible(true); + ViewModelProviders.of(TravelEntriesView.class).get(ViewConfiguration.class).setInEagerMode(true); + btnEnterBulkEditMode.setVisible(false); + btnLeaveBulkEditMode.setVisible(true); + ((TravelEntryGrid) grid).reload(); + }); + btnLeaveBulkEditMode.addClickListener(e -> { + bulkOperationsDropdown.setVisible(false); + ViewModelProviders.of(TravelEntriesView.class).get(ViewConfiguration.class).setInEagerMode(false); + btnLeaveBulkEditMode.setVisible(false); + btnEnterBulkEditMode.setVisible(true); + navigateTo(criteria); + }); + } + + if (moreButton.hasMenuEntries()) { + addHeaderComponent(moreButton); + } } @Override @@ -89,6 +145,12 @@ public void enter(ViewChangeListener.ViewChangeEvent event) { params = params.substring(1); criteria.fromUrlParams(params); } + + if (viewConfiguration.isInEagerMode()) { + TravelEntryGrid travelEntryGrid = (TravelEntryGrid) this.grid; + travelEntryGrid.setEagerDataProvider(); + } + updateFilterComponents(); } @@ -156,11 +218,13 @@ public HorizontalLayout createStatusFilterBar() { relevanceStatusFilter.setId("relevanceStatus"); relevanceStatusFilter.setWidth(140, Unit.PIXELS); relevanceStatusFilter.setNullSelectionAllowed(false); + relevanceStatusFilter.setTextInputAllowed(false); relevanceStatusFilter.addItems((Object[]) EntityRelevanceStatus.values()); relevanceStatusFilter.setItemCaption(EntityRelevanceStatus.ACTIVE, I18nProperties.getCaption(Captions.travelEntryActiveTravelEntries)); relevanceStatusFilter .setItemCaption(EntityRelevanceStatus.ARCHIVED, I18nProperties.getCaption(Captions.travelEntryArchivedTravelEntries)); relevanceStatusFilter.setItemCaption(EntityRelevanceStatus.ALL, I18nProperties.getCaption(Captions.travelEntryAllTravelEntries)); + relevanceStatusFilter.setCaption(""); relevanceStatusFilter.addValueChangeListener(e -> { relevanceStatusInfoLabel.setVisible(EntityRelevanceStatus.ARCHIVED.equals(e.getProperty().getValue())); criteria.relevanceStatus((EntityRelevanceStatus) e.getProperty().getValue()); @@ -172,6 +236,25 @@ public HorizontalLayout createStatusFilterBar() { statusFilterLayout.setComponentAlignment(actionButtonsLayout, Alignment.TOP_RIGHT); statusFilterLayout.setExpandRatio(actionButtonsLayout, 1); + // Bulk operation dropdown + if (UserProvider.getCurrent().hasUserRight(UserRight.TRAVEL_ENTRY_DELETE) + && UserProvider.getCurrent().hasUserRight(UserRight.PERFORM_BULK_OPERATIONS)) { + List bulkActions = new ArrayList<>(); + bulkActions.add( + new MenuBarHelper.MenuBarItem( + I18nProperties.getCaption(Captions.bulkDelete), + VaadinIcons.TRASH, + mi -> grid.bulkActionHandler( + items -> ControllerProvider.getTravelEntryController().deleteAllSelectedItems(items, () -> navigateTo(criteria)), + true))); + + bulkOperationsDropdown = MenuBarHelper.createDropDown(Captions.bulkActions, bulkActions); + + bulkOperationsDropdown.setVisible(viewConfiguration.isInEagerMode()); + bulkOperationsDropdown.setCaption(""); + actionButtonsLayout.addComponent(bulkOperationsDropdown); + } + return statusFilterLayout; } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryController.java index 7cd2657fc65..f07df81e471 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryController.java @@ -1,8 +1,11 @@ package de.symeda.sormas.ui.travelentry; +import java.util.Collection; + import org.apache.commons.lang3.StringUtils; import com.vaadin.navigator.Navigator; +import com.vaadin.server.Page; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; import com.vaadin.ui.Label; @@ -20,6 +23,7 @@ import de.symeda.sormas.api.person.PersonDto; import de.symeda.sormas.api.person.PersonReferenceDto; import de.symeda.sormas.api.travelentry.TravelEntryDto; +import de.symeda.sormas.api.travelentry.TravelEntryIndexDto; import de.symeda.sormas.api.travelentry.TravelEntryListCriteria; import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.utils.DataHelper; @@ -164,7 +168,7 @@ public CommitDiscardWrapperComponent getTravelEntryDataEdit boolean archived = FacadeProvider.getTravelEntryFacade().isArchived(travelEntryUuid); Button archiveTravelEntryButton = ButtonHelper.createButton(archived ? Captions.actionDearchive : Captions.actionArchive, e -> { editComponent.commit(); - archiveOrDearchiveTraveEntry(travelEntryUuid, !archived); + archiveOrDearchiveTravelEntry(travelEntryUuid, !archived); }, ValoTheme.BUTTON_LINK); editComponent.getButtonsPanel().addComponentAsFirst(archiveTravelEntryButton); @@ -198,7 +202,7 @@ public TitleLayout getTravelEntryViewTitleLayout(String uuid) { return titleLayout; } - private void archiveOrDearchiveTraveEntry(String travelEntryUuid, boolean archive) { + private void archiveOrDearchiveTravelEntry(String travelEntryUuid, boolean archive) { if (archive) { Label contentLabel = new Label( @@ -247,4 +251,28 @@ private void archiveOrDearchiveTraveEntry(String travelEntryUuid, boolean archiv }); } } + + public void deleteAllSelectedItems(Collection selectedRows, Runnable callback) { + if (selectedRows.size() == 0) { + new Notification( + I18nProperties.getString(Strings.headingNoTravelEntriesSelected), + I18nProperties.getString(Strings.messageNoTravelEntriesSelected), + Notification.Type.WARNING_MESSAGE, + false).show(Page.getCurrent()); + } else { + VaadinUiUtil.showDeleteConfirmationWindow( + String.format(I18nProperties.getString(Strings.confirmationDeleteTravelEntries), selectedRows.size()), + () -> { + for (TravelEntryIndexDto selectedRow : selectedRows) { + FacadeProvider.getTravelEntryFacade().deleteTravelEntry(selectedRow.getUuid()); + } + callback.run(); + new Notification( + I18nProperties.getString(Strings.headingTravelEntriesDeleted), + I18nProperties.getString(Strings.messageTravelEntriesDeleted), + Notification.Type.HUMANIZED_MESSAGE, + false).show(Page.getCurrent()); + }); + } + } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryFilterForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryFilterForm.java index 8e5f6c72469..45b6281cba7 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryFilterForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryFilterForm.java @@ -1,5 +1,11 @@ package de.symeda.sormas.ui.travelentry; +import static de.symeda.sormas.ui.utils.LayoutUtil.loc; + +import java.util.Date; + +import com.vaadin.ui.CustomLayout; +import com.vaadin.ui.HorizontalLayout; import com.vaadin.v7.ui.CheckBox; import com.vaadin.v7.ui.TextField; @@ -8,13 +14,18 @@ import de.symeda.sormas.api.i18n.Strings; import de.symeda.sormas.api.travelentry.TravelEntryCriteria; import de.symeda.sormas.api.travelentry.TravelEntryDto; +import de.symeda.sormas.api.utils.DateFilterOption; +import de.symeda.sormas.api.utils.DateHelper; +import de.symeda.sormas.api.utils.EpiWeek; import de.symeda.sormas.ui.utils.AbstractFilterForm; import de.symeda.sormas.ui.utils.CssStyles; +import de.symeda.sormas.ui.utils.EpiWeekAndDateFilterComponent; import de.symeda.sormas.ui.utils.FieldConfiguration; public class TravelEntryFilterForm extends AbstractFilterForm { private static final String CHECKBOX_STYLE = CssStyles.CHECKBOX_FILTER_INLINE + " " + CssStyles.VSPACE_3; + private static final String WEEK_AND_DATE_FILTER = "weekAndDateFilter"; protected TravelEntryFilterForm() { super(TravelEntryCriteria.class, TravelEntryDto.I18N_PREFIX); @@ -30,6 +41,11 @@ protected String[] getMainFilterLocators() { TravelEntryCriteria.ONLY_ENTRIES_CONVERTED_TO_CASE }; } + @Override + protected String createMoreFiltersHtmlLayout() { + return loc(WEEK_AND_DATE_FILTER); + } + @Override protected void addFields() { final TextField searchField = addField( @@ -71,4 +87,72 @@ protected void addFields() { CHECKBOX_STYLE), CheckBox.class); } + + @Override + public void addMoreFilters(CustomLayout moreFiltersContainer) { + moreFiltersContainer.addComponent(buildWeekAndDateFilter(), WEEK_AND_DATE_FILTER); + } + + private HorizontalLayout buildWeekAndDateFilter() { + + EpiWeekAndDateFilterComponent weekAndDateFilter = new EpiWeekAndDateFilterComponent<>(false, false, null, this); + + weekAndDateFilter.getWeekFromFilter().setInputPrompt(I18nProperties.getString(Strings.promptTravelEntryEpiWeekFrom)); + weekAndDateFilter.getWeekToFilter().setInputPrompt(I18nProperties.getString(Strings.promptTravelEntryEpiWeekTo)); + weekAndDateFilter.getDateFromFilter().setInputPrompt(I18nProperties.getString(Strings.promptTravelEntryDateFrom)); + weekAndDateFilter.getDateToFilter().setInputPrompt(I18nProperties.getString(Strings.promptTravelEntryDateTo)); + addApplyHandler(e -> onApplyClick(weekAndDateFilter)); + + HorizontalLayout dateFilterRowLayout = new HorizontalLayout(); + dateFilterRowLayout.setSpacing(true); + dateFilterRowLayout.setSizeUndefined(); + + dateFilterRowLayout.addComponent(weekAndDateFilter); + + return dateFilterRowLayout; + } + + private void onApplyClick(EpiWeekAndDateFilterComponent weekAndDateFilter) { + TravelEntryCriteria criteria = getValue(); + + DateFilterOption dateFilterOption = (DateFilterOption) weekAndDateFilter.getDateFilterOptionFilter().getValue(); + + Date fromDate, toDate; + if (dateFilterOption == DateFilterOption.DATE) { + Date dateFrom = weekAndDateFilter.getDateFromFilter().getValue(); + fromDate = dateFrom != null ? DateHelper.getStartOfDay(dateFrom) : null; + Date dateTo = weekAndDateFilter.getDateToFilter().getValue(); + toDate = dateTo != null ? DateHelper.getEndOfDay(dateTo) : null; + } else { + fromDate = DateHelper.getEpiWeekStart((EpiWeek) weekAndDateFilter.getWeekFromFilter().getValue()); + toDate = DateHelper.getEpiWeekEnd((EpiWeek) weekAndDateFilter.getWeekToFilter().getValue()); + } + + if ((fromDate != null && toDate != null) || (fromDate == null && toDate == null)) { + criteria.reportDateBetween(fromDate, toDate, dateFilterOption); + } else { + weekAndDateFilter.setNotificationsForMissingFilters(); + } + } + + @Override + protected void applyDependenciesOnNewValue(TravelEntryCriteria criteria) { + + final HorizontalLayout dateFilterLayout = (HorizontalLayout) getMoreFiltersContainer().getComponent(WEEK_AND_DATE_FILTER); + final EpiWeekAndDateFilterComponent weekAndDateFilter; + weekAndDateFilter = (EpiWeekAndDateFilterComponent) dateFilterLayout.getComponent(0); + + final DateFilterOption dateFilterOption = criteria.getDateFilterOption(); + final Date dateFrom = criteria.getReportDateFrom(); + final Date dateTo = criteria.getReportDateTo(); + weekAndDateFilter.getDateFilterOptionFilter().setValue(dateFilterOption); + + if (DateFilterOption.EPI_WEEK.equals(dateFilterOption)) { + weekAndDateFilter.getWeekFromFilter().setValue(dateFrom == null ? null : DateHelper.getEpiWeek(dateFrom)); + weekAndDateFilter.getWeekToFilter().setValue(dateTo == null ? null : DateHelper.getEpiWeek(dateTo)); + } else { + weekAndDateFilter.getDateFromFilter().setValue(dateFrom); + weekAndDateFilter.getDateToFilter().setValue(dateTo); + } + } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryGrid.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryGrid.java index 723e9af887b..82a34fa5e93 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryGrid.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryGrid.java @@ -4,6 +4,7 @@ import java.util.stream.Collectors; import com.vaadin.data.provider.DataProvider; +import com.vaadin.data.provider.ListDataProvider; import com.vaadin.shared.data.sort.SortDirection; import com.vaadin.ui.renderers.DateRenderer; @@ -14,19 +15,33 @@ import de.symeda.sormas.api.travelentry.TravelEntryIndexDto; import de.symeda.sormas.api.utils.SortProperty; import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.ViewModelProviders; +import de.symeda.sormas.ui.campaign.campaigns.CampaignsView; import de.symeda.sormas.ui.utils.BooleanRenderer; import de.symeda.sormas.ui.utils.DateFormatHelper; import de.symeda.sormas.ui.utils.FieldAccessColumnStyleGenerator; import de.symeda.sormas.ui.utils.FilteredGrid; import de.symeda.sormas.ui.utils.ShowDetailsListener; import de.symeda.sormas.ui.utils.UuidRenderer; +import de.symeda.sormas.ui.utils.ViewConfiguration; public class TravelEntryGrid extends FilteredGrid { public TravelEntryGrid(TravelEntryCriteria criteria) { super(TravelEntryIndexDto.class); setSizeFull(); - setLazyDataProvider(); + + ViewConfiguration viewConfiguration = ViewModelProviders.of(CampaignsView.class).get(ViewConfiguration.class); + setInEagerMode(viewConfiguration.isInEagerMode()); + + if (isInEagerMode()) { + setCriteria(criteria); + setEagerDataProvider(); + } else { + setLazyDataProvider(); + setCriteria(criteria); + } + setCriteria(criteria); initColumns(); addItemClickListener( @@ -80,7 +95,24 @@ public void setLazyDataProvider() { setSelectionMode(SelectionMode.NONE); } + + public void setEagerDataProvider() { + ListDataProvider dataProvider = + DataProvider.fromStream(FacadeProvider.getTravelEntryFacade().getIndexList(getCriteria(), null, null, null).stream()); + setDataProvider(dataProvider); + setSelectionMode(SelectionMode.MULTI); + } + public void reload() { + if (getSelectionModel().isUserSelectionAllowed()) { + deselectAll(); + } + + ViewConfiguration viewConfiguration = ViewModelProviders.of(TravelEntriesView.class).get(ViewConfiguration.class); + if (viewConfiguration.isInEagerMode()) { + setEagerDataProvider(); + } + getDataProvider().refreshAll(); } } From fc1fcfc097476cb990e7231cda5118b37846ffaf Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Mon, 21 Feb 2022 18:50:17 +0200 Subject: [PATCH 132/253] #6934-Update-Framework-To-Multiple-Environments : refactored and implemented multiple environments approach, updated tests to use specific environment, refactored user data usage --- .../org/sormas/e2etests/enums/UserRoles.java | 43 +++++++++++++++++++ .../e2etests/envconfig/dto/Environment.java | 2 +- .../envconfig/manager/EnvironmentManager.java | 16 +++---- .../entities/services/api/CaseApiService.java | 5 ++- .../services/api/ContactApiService.java | 5 ++- .../services/api/ImmunizationApiService.java | 3 +- .../e2etests/helpers/RestAssuredClient.java | 5 ++- .../org/sormas/e2etests/steps/BaseSteps.java | 2 +- .../steps/web/application/LoginSteps.java | 3 +- .../cases/CaseDetailedTableViewSteps.java | 3 +- .../ContactsDetailedTableViewSteps.java | 3 +- .../events/EventActionsTableSteps.java | 3 +- .../resources/features/sanity/api/Api.feature | 16 +++---- .../sanity/api/EntitiesCreation.feature | 4 +- .../PagesLoadMeasurements.feature | 18 ++++---- .../features/sanity/web/Case.feature | 24 +++++------ .../sanity/web/CaseClasification.feature | 4 +- .../features/sanity/web/CaseFilters.feature | 16 +++---- .../sanity/web/CaseFollowUpVisit.feature | 4 +- .../sanity/web/CaseHospitalization.feature | 2 +- .../features/sanity/web/CaseSymptoms.feature | 4 +- .../features/sanity/web/CaseViews.feature | 2 +- .../sanity/web/ContactFilters.feature | 6 +-- .../features/sanity/web/Contacts.feature | 26 +++++------ .../features/sanity/web/Dashboard.feature | 4 +- .../sanity/web/DocumentTemplate.feature | 10 ++--- .../features/sanity/web/EpiData.feature | 2 +- .../web/EpidemiologicalDataCase.feature | 4 +- .../features/sanity/web/Event.feature | 30 ++++++------- .../features/sanity/web/Immunization.feature | 2 +- .../features/sanity/web/LineListing.feature | 4 +- .../features/sanity/web/Login.feature | 2 +- .../features/sanity/web/Pathogen.feature | 14 +++--- .../features/sanity/web/Persons.feature | 6 +-- .../features/sanity/web/Reports.feature | 4 +- .../features/sanity/web/Sample.feature | 12 +++--- .../features/sanity/web/SampleFilters.feature | 4 +- .../features/sanity/web/Task.feature | 6 +-- .../sanity/web/TaskManagementFilter.feature | 4 +- .../features/sanity/web/User.feature | 4 +- 40 files changed, 191 insertions(+), 140 deletions(-) create mode 100644 sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/UserRoles.java diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/UserRoles.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/UserRoles.java new file mode 100644 index 00000000000..11f33807608 --- /dev/null +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/UserRoles.java @@ -0,0 +1,43 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.sormas.e2etests.enums; + +import lombok.Getter; + +@Getter +public enum UserRoles { + NationalUser("National User"), + ContactSupervisor("Contact Supervisor"), + SurveillanceOfficer("Surveillance Officer"), + LaboratoryOfficer("Laboratory Officer"), + POESupervisor("Point of Entry Supervisor"), + AdminUser("Admin User"), + RestUser("Rest AUTOMATION"); + + private final String role; + + UserRoles(String role) { + this.role = role; + } + + @Override + public String toString() { + return this.role; + } +} diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environment.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environment.java index dbc152743a7..db9cb04e158 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environment.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/dto/Environment.java @@ -31,7 +31,7 @@ public class Environment { String name; - String locale; + String identifier; String url; List users; } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/manager/EnvironmentManager.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/manager/EnvironmentManager.java index d8eafd5a715..3c153a69d76 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/manager/EnvironmentManager.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/envconfig/manager/EnvironmentManager.java @@ -40,22 +40,22 @@ public EnvironmentManager() { } @SneakyThrows - public String getEnvironmentUrlForMarket(String market) { + public String getEnvironmentUrlForMarket(String identifier) { try { return environments.getEnvironments().stream() - .filter(env -> env.getLocale().equalsIgnoreCase(market)) + .filter(env -> env.getIdentifier().equalsIgnoreCase(identifier)) .findFirst() .get() .getUrl(); } catch (NullPointerException e) { - throw new Exception(String.format("Unable to get Environment for market: %s", market)); + throw new Exception(String.format("Unable to get Environment for market: %s", identifier)); } } @SneakyThrows - public EnvUser getUserByRole(String market, String role) { + public EnvUser getUserByRole(String identifier, String role) { try { - List users = getEnvironment(market).getUsers(); + List users = getEnvironment(identifier).getUsers(); return users.stream() .filter(user -> user.getUserRole().equalsIgnoreCase(role)) .findFirst() @@ -63,13 +63,13 @@ public EnvUser getUserByRole(String market, String role) { } catch (NullPointerException e) { throw new Exception( String.format( - "Unable to get Environment User for market: %s, and role: %s", market, role)); + "Unable to get Environment User for market: %s, and role: %s", identifier, role)); } } - private Environment getEnvironment(String market) { + private Environment getEnvironment(String identifier) { return environments.getEnvironments().stream() - .filter(env -> env.getLocale().equalsIgnoreCase(market)) + .filter(env -> env.getIdentifier().equalsIgnoreCase(identifier)) .findFirst() .get(); } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/CaseApiService.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/CaseApiService.java index 301a11fff95..43453dea996 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/CaseApiService.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/CaseApiService.java @@ -45,6 +45,7 @@ import org.sormas.e2etests.enums.DiseasesValues; import org.sormas.e2etests.enums.DistrictsValues; import org.sormas.e2etests.enums.RegionsValues; +import org.sormas.e2etests.enums.UserRoles; import org.sormas.e2etests.envconfig.manager.EnvironmentManager; public class CaseApiService { @@ -65,7 +66,7 @@ public Case buildGeneratedCase(Person person) { .reportDate(new Date()) .reportingUser( ReportingUser.builder() - .uuid(environmentManager.getUserByRole(locale, "Rest AUTOMATION").getUuid()) + .uuid(environmentManager.getUserByRole(locale, UserRoles.RestUser.getRole()).getUuid()) .build()) .district( District.builder().uuid(DistrictsValues.VoreingestellterLandkreis.getUuid()).build()) @@ -110,7 +111,7 @@ public Case buildGeneratedCase(Person person) { .build()) .surveillanceOfficer( SurveillanceOfficer.builder() - .uuid(environmentManager.getUserByRole(locale, "Surveillance Officer").getUuid()) + .uuid(environmentManager.getUserByRole(locale, UserRoles.SurveillanceOfficer.getRole()).getUuid()) .build()) .healthFacilityDetails("Details") .caseOrigin("IN_COUNTRY") diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/ContactApiService.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/ContactApiService.java index ee2b218cf46..064b150954d 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/ContactApiService.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/ContactApiService.java @@ -34,6 +34,7 @@ import org.sormas.e2etests.enums.DiseasesValues; import org.sormas.e2etests.enums.DistrictsValues; import org.sormas.e2etests.enums.RegionsValues; +import org.sormas.e2etests.enums.UserRoles; import org.sormas.e2etests.envconfig.manager.EnvironmentManager; public class ContactApiService { @@ -55,7 +56,7 @@ public Contact buildGeneratedContact(Person person) { .reportDateTime(new Date()) .reportingUser( ReportingUser.builder() - .uuid(environmentManager.getUserByRole(locale, "Rest AUTOMATION").getUuid()) + .uuid(environmentManager.getUserByRole(locale, UserRoles.RestUser.getRole()).getUuid()) .build()) .district( District.builder() @@ -89,7 +90,7 @@ public Contact buildGeneratedContactWithLinkedCase(Person person, Case caze) { .reportDateTime(new Date()) .reportingUser( ReportingUser.builder() - .uuid(environmentManager.getUserByRole(locale, "Rest AUTOMATION").getUuid()) + .uuid(environmentManager.getUserByRole(locale, UserRoles.RestUser.getRole()).getUuid()) .build()) .district( District.builder() diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/ImmunizationApiService.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/ImmunizationApiService.java index 0ec7f5d2134..980c0578aaf 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/ImmunizationApiService.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/ImmunizationApiService.java @@ -30,6 +30,7 @@ import org.sormas.e2etests.enums.DiseasesValues; import org.sormas.e2etests.enums.DistrictsValues; import org.sormas.e2etests.enums.RegionsValues; +import org.sormas.e2etests.enums.UserRoles; import org.sormas.e2etests.enums.immunizations.ImmunizationManagementStatusValues; import org.sormas.e2etests.enums.immunizations.MeansOfImmunizationValues; import org.sormas.e2etests.enums.immunizations.StatusValues; @@ -59,7 +60,7 @@ public Immunization buildGeneratedImmunizationForPerson(Person person) { .startDate(Calendar.getInstance().getTimeInMillis()) .endDate(Calendar.getInstance().getTimeInMillis()) .externalId(faker.number().digits(9)) - .reportingUser(environmentManager.getUserByRole(locale, "National User").getUuid()) + .reportingUser(environmentManager.getUserByRole(locale, UserRoles.NationalUser.getRole()).getUuid()) .archived(false) .disease(DiseasesValues.getRandomDiseaseName()) .immunizationStatus(StatusValues.getRandomImmunizationStatus()) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/RestAssuredClient.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/RestAssuredClient.java index 0f45d9556d1..0d411e840da 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/RestAssuredClient.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/RestAssuredClient.java @@ -35,6 +35,7 @@ import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.sormas.e2etests.entities.pojo.api.Request; +import org.sormas.e2etests.enums.UserRoles; import org.sormas.e2etests.envconfig.manager.EnvironmentManager; import org.sormas.e2etests.state.ApiState; @@ -73,8 +74,8 @@ private RequestSpecification request() { .auth() .preemptive() .basic( - environmentManager.getUserByRole(locale, "Rest AUTOMATION").getUsername(), - environmentManager.getUserByRole(locale, "Rest AUTOMATION").getPassword()); + environmentManager.getUserByRole(locale, UserRoles.RestUser.getRole()).getUsername(), + environmentManager.getUserByRole(locale, UserRoles.RestUser.getRole()).getPassword()); return requestSpecification .config( diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java index 735422dfbec..8eb526e139c 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java @@ -100,7 +100,7 @@ private static boolean isNonApiScenario(Scenario scenario) { private void setLocale(Scenario scenario) { String localeTag = scenario.getSourceTagNames().stream() - .filter(value -> value.contains("Locale")) + .filter(value -> value.startsWith("@env")) .findFirst() .get(); int indexOfSubstring = localeTag.indexOf("_"); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/LoginSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/LoginSteps.java index 2c47de814be..bba25a27231 100755 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/LoginSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/LoginSteps.java @@ -24,6 +24,7 @@ import com.google.inject.Inject; import cucumber.api.java8.En; import org.openqa.selenium.NoSuchElementException; +import org.sormas.e2etests.enums.UserRoles; import org.sormas.e2etests.envconfig.dto.EnvUser; import org.sormas.e2etests.envconfig.manager.EnvironmentManager; import org.sormas.e2etests.helpers.WebDriverHelpers; @@ -61,7 +62,7 @@ public LoginSteps( And( "I log in with National User", () -> { - EnvUser user = environmentManager.getUserByRole(locale, "National User"); + EnvUser user = environmentManager.getUserByRole(locale, UserRoles.NationalUser.getRole()); webDriverHelpers.accessWebSite(environmentManager.getEnvironmentUrlForMarket(locale)); webDriverHelpers.waitForPageLoaded(); webDriverHelpers.waitUntilIdentifiedElementIsPresent(LoginPage.USER_NAME_INPUT); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java index 7b614111c06..a2a53d68c12 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java @@ -21,6 +21,7 @@ import org.sormas.e2etests.enums.DiseasesValues; import org.sormas.e2etests.enums.DistrictsValues; import org.sormas.e2etests.enums.RegionsValues; +import org.sormas.e2etests.enums.UserRoles; import org.sormas.e2etests.envconfig.manager.EnvironmentManager; import org.sormas.e2etests.helpers.WebDriverHelpers; import org.sormas.e2etests.state.ApiState; @@ -139,7 +140,7 @@ public CaseDetailedTableViewSteps( } softly.assertEquals( detailedCaseDTableRow.get(CaseDetailedTableViewHeaders.REPORTING_USER.toString()), - environmentManager.getUserByRole(locale, "Rest AUTOMATION").getUserRole(), + environmentManager.getUserByRole(locale, UserRoles.RestUser.getRole()).getUserRole(), "Reporting user is not correct"); softly.assertAll(); }); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/ContactsDetailedTableViewSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/ContactsDetailedTableViewSteps.java index ac1393b3f01..a67830e5c1a 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/ContactsDetailedTableViewSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/ContactsDetailedTableViewSteps.java @@ -14,6 +14,7 @@ import org.openqa.selenium.WebElement; import org.sormas.e2etests.common.DataOperations; import org.sormas.e2etests.enums.ContactOutcome; +import org.sormas.e2etests.enums.UserRoles; import org.sormas.e2etests.envconfig.manager.EnvironmentManager; import org.sormas.e2etests.helpers.WebDriverHelpers; import org.sormas.e2etests.state.ApiState; @@ -102,7 +103,7 @@ public ContactsDetailedTableViewSteps( softly.assertEquals( detailedContactDTableRow.get( ContactsDetailedTableViewHeaders.REPORTING_USER.toString()), - environmentManager.getUserByRole(locale, "Rest AUTOMATION").getUserRole(), + environmentManager.getUserByRole(locale, UserRoles.RestUser.getRole()).getUserRole(), "Reporting user is not correct"); softly.assertAll(); }); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventActionsTableSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventActionsTableSteps.java index 6bfc9d584d5..0b8ac0c5b05 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventActionsTableSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventActionsTableSteps.java @@ -31,6 +31,7 @@ import org.openqa.selenium.WebDriverException; import org.openqa.selenium.WebElement; import org.sormas.e2etests.entities.pojo.web.EventActionTableEntry; +import org.sormas.e2etests.enums.UserRoles; import org.sormas.e2etests.helpers.WebDriverHelpers; import org.sormas.e2etests.state.ApiState; import org.sormas.e2etests.steps.BaseSteps; @@ -90,7 +91,7 @@ public EventActionsTableSteps( "Priority is not correct"); softly.assertEquals( eventActionTableEntry.getActionLastModifiedBy(), - "National USER", + UserRoles.NationalUser.getRole(), "Last modified by user is not correct"); softly.assertAll(); }); diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/api/Api.feature b/sormas-e2e-tests/src/test/resources/features/sanity/api/Api.feature index 7da6efb9805..aaef2cb904d 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/api/Api.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/api/Api.feature @@ -1,13 +1,13 @@ @Sanity @API Feature: Check basic POSTs RestApi endpoints - @Locale_DE + @env_main Scenario: Create a new person Given API: I create a new person Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 - @Locale_DE + @env_main Scenario: Create new case Given API: I create a new person Then API: I check that POST call body is "OK" @@ -16,7 +16,7 @@ Feature: Check basic POSTs RestApi endpoints Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 - @Locale_DE + @env_main Scenario: Create a new contact Given API: I create a new person Then API: I check that POST call body is "OK" @@ -25,7 +25,7 @@ Feature: Check basic POSTs RestApi endpoints Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 - @Locale_DE + @env_main Scenario: Create a new contact linked to a case Given API: I create a new person Then API: I check that POST call body is "OK" @@ -37,13 +37,13 @@ Feature: Check basic POSTs RestApi endpoints Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 - @Locale_DE + @env_main Scenario: Create a new event Given API: I create a new event Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 - @Locale_DE + @env_main Scenario: Create a new sample Given API: I create a new person Then API: I check that POST call body is "OK" @@ -55,7 +55,7 @@ Feature: Check basic POSTs RestApi endpoints Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 - @Locale_DE + @env_main Scenario: Create a new task Given API: I create a new person Then API: I check that POST call body is "OK" @@ -67,7 +67,7 @@ Feature: Check basic POSTs RestApi endpoints Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 - @Locale_DE + @env_main Scenario Outline: Create Person and attach immunizations Given API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/api/EntitiesCreation.feature b/sormas-e2e-tests/src/test/resources/features/sanity/api/EntitiesCreation.feature index c09b612538e..6dc3cffd15e 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/api/EntitiesCreation.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/api/EntitiesCreation.feature @@ -11,7 +11,7 @@ Feature: Create person and attach immunizations via API requests Given API: I receive all contacts ids Given API: I receive all cases ids - @PersonsAndImmunizations @Locale_DE + @PersonsAndImmunizations @env_performance Scenario: Create multiple Person and attach immunizations to them When API: I create 100 persons Then API: I check that POST call body is "OK" @@ -20,7 +20,7 @@ Feature: Create person and attach immunizations via API requests Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 - @ContactsLinkedToCases @Locale_DE + @ContactsLinkedToCases @env_performance Scenario: Create multiple Cases and link 2 Contacts to each When API: I create 100 persons Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/pagesperformance/PagesLoadMeasurements.feature b/sormas-e2e-tests/src/test/resources/features/sanity/pagesperformance/PagesLoadMeasurements.feature index d96dd99668c..a818c01a23c 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/pagesperformance/PagesLoadMeasurements.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/pagesperformance/PagesLoadMeasurements.feature @@ -1,55 +1,55 @@ @UI @PagesMeasurements @PublishCustomReport Feature: Pages loading time - @Locale_DE + @env_performance Scenario: Check Tasks page loading time Given I log in with National User And I click on the Tasks button from navbar Then I wait for "Tasks" page to load and calculate elapsed time - @Locale_DE + @env_performance Scenario: Check Persons page loading time Given I log in with National User And I click on the Persons button from navbar Then I wait for "Persons" page to load and calculate elapsed time - @Locale_DE + @env_performance Scenario: Check Cases page loading time Given I log in with National User And I click on the Cases button from navbar Then I wait for "Cases" page to load and calculate elapsed time - @Locale_DE + @env_performance Scenario: Check Contacts page loading time Given I log in with National User And I click on the Contacts button from navbar Then I wait for "Contacts" page to load and calculate elapsed time - @Locale_DE + @env_performance Scenario: Check Events page loading time Given I log in with National User And I click on the Events button from navbar Then I wait for "Events" page to load and calculate elapsed time - @Locale_DE + @env_performance Scenario: Check Samples page loading time Given I log in with National User And I click on the Sample button from navbar Then I wait for "Samples" page to load and calculate elapsed time - @Locale_DE + @env_performance Scenario: Check Contacts Dashboard page loading time Given I log in with National User And I click on the Dashboard button from navbar and access Contacts Dashboard Then I wait for "Contacts Dashboard" page to load and calculate elapsed time - @Locale_DE + @env_performance Scenario: Check Immunizations page loading time Given I log in with National User And I click on the Immunizations button from navbar Then I wait for "Immunizations" page to load and calculate elapsed time - @Locale_DE + @env_performance Scenario: Check Surveillance Dashboard page loading time Given I log in with National User And I click on the Dashboard button from navbar and access Surveillance Dashboard diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature index 42482fe118f..87d4babe0f1 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature @@ -1,7 +1,7 @@ @UI @Sanity @Case Feature: Case end to end tests - @Locale_DE + @env_main Scenario: Check a new case data Given I log in with National User And I click on the Cases button from navbar @@ -10,7 +10,7 @@ Feature: Case end to end tests Then I check the created data is correctly displayed on Edit case page And I check the created data is correctly displayed on Edit case person page - @Locale_DE + @env_main Scenario: Check that double clicking NEW CASE button does not cause a redundant action Given I log in with National User And I click on the Cases button from navbar @@ -21,7 +21,7 @@ Feature: Case end to end tests Then I check the created data is correctly displayed on Edit case page And I check the created data is correctly displayed on Edit case person page - @Locale_DE + @env_main Scenario: Edit, save and check all fields of a new case Given I log in with National User And I click on the Cases button from navbar @@ -32,7 +32,7 @@ Feature: Case end to end tests And I open last edited case by link And I check the edited data is correctly displayed on Edit case page - @issue=SORDEV-7868 @Locale_DE + @issue=SORDEV-7868 @env_main Scenario: Fill the case tab Given I log in with National User And I click on the Cases button from navbar @@ -93,7 +93,7 @@ Feature: Case end to end tests And I click on save button from Edit Case page with current hospitalization Then I check if the specific data is correctly displayed - @Locale_DE + @env_main Scenario: Delete created case When API: I create a new person Then API: I check that POST call body is "OK" @@ -107,7 +107,7 @@ Feature: Case end to end tests And I delete the case Then I check that number of displayed cases results is 0 - @Locale_DE + @env_main Scenario: Edit all fields from Case Contacts tab Given API: I create a new person Then API: I check that POST call body is "OK" @@ -122,7 +122,7 @@ Feature: Case end to end tests And I open the Case Contacts tab of the created case via api And I verify that created contact from Case Contacts tab is correctly displayed - @Locale_DE + @env_main Scenario: Edit all fields from Symptoms tab Given API: I create a new person Then API: I check that POST call body is "OK" @@ -137,7 +137,7 @@ Feature: Case end to end tests When I am accessing the Symptoms tab using of created case via api And I check the created data is correctly displayed on Symptoms tab page -@issue=SORDEV-5496 @Locale_DE +@issue=SORDEV-5496 @env_main Scenario: Generate case document Given I log in with National User And I click on the Cases button from navbar @@ -146,7 +146,7 @@ Feature: Case end to end tests When I create a case document from template Then I verify that the case document is downloaded and correctly named - @issue=SORDEV-5527 @Locale_DE + @issue=SORDEV-5527 @env_main Scenario: Fill the therapy tab When API: I create a new person Then API: I check that POST call body is "OK" @@ -192,7 +192,7 @@ Feature: Case end to end tests Then I click on the popup Save button Then I check if created data is correctly displayed in Treatment section - @issue=SORDEV-5518 @Locale_DE + @issue=SORDEV-5518 @env_main Scenario: Fill the case person tab Given I log in with National User And I click on the Cases button from navbar @@ -209,7 +209,7 @@ Feature: Case end to end tests And I click on save button to Save Person data in Case Person Tab Then I check if saved Person data is correct - @issue=SORDEV-5529 @Locale_DE + @issue=SORDEV-5529 @env_main Scenario: Fill the clinical course tab When API: I create a new person Then API: I check that POST call body is "OK" @@ -270,7 +270,7 @@ Feature: Case end to end tests Then I click Save button on Clinical Course Tab And I check if Case saved popup appeared and close it - @issue=SORDEV-8412 @Locale_DE + @issue=SORDEV-8412 @env_main Scenario: Change of Isolation/Quarantine should be documented When API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseClasification.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseClasification.feature index b7ae5280c12..5c084d8c276 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseClasification.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseClasification.feature @@ -1,7 +1,7 @@ @UI @Sanity @Case @Classification Feature: Case Classification functionality - @Locale_DE + @env_main Scenario: Case Classification change from Not Yet Classified to Suspect Case by confirming Sore Throat Given API: I create a new person Then API: I check that POST call body is "OK" @@ -21,7 +21,7 @@ Feature: Case Classification functionality And I click on save button from Edit Case page Then For the current Case the Case Classification value should be "Suspect case" - @Locale_DE + @env_main Scenario: Case Classification change from Suspect Case to Not Yet Classified Given API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature index 108e795cca1..8e7454bf2a0 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature @@ -1,7 +1,7 @@ @UI @Sanity @Case @Filters Feature: Case filter functionality - @Locale_DE + @env_main Scenario: Check Cases on Sample page work as expected Given API: I create 10 new cases Then API: I check that POST call body is "OK" @@ -15,7 +15,7 @@ Feature: Case filter functionality Then I apply Disease filter "COVID-19" on Case directory page And I check that all displayed cases have "COVID-19" in grid Disease column - @issue=SORQA-30 @Locale_DE + @issue=SORQA-30 @env_main Scenario: Check Person related fields filter in Case directory page Given API: I create a new person Then API: I check that POST call body is "OK" @@ -55,7 +55,7 @@ Feature: Case filter functionality And I check that number of displayed cases results is 0 And I apply Present Condition filter on Case directory page to condition of last created person - @issue=SORQA-30 @Locale_DE + @issue=SORQA-30 @env_main Scenario: Check Case basic filters on Case directory page Given API: I create a new person Then API: I check that POST call body is "OK" @@ -98,7 +98,7 @@ Feature: Case filter functionality And I check that number of displayed cases results is 0 And I filter by CaseID on Case directory page - @issue=SORQA-30 @Locale_DE + @issue=SORQA-30 @env_main Scenario: Check Case region and facility related filters Given API: I create a new person Then API: I check that POST call body is "OK" @@ -139,7 +139,7 @@ Feature: Case filter functionality And I check that number of displayed cases results is 0 And I apply Facility filter to "Standard Einrichtung" on Case directory page - @issue=SORQA-30 @Locale_DE + @issue=SORQA-30 @env_main Scenario: Check checkboxes filters on Case directory page Given API: I create a new person Then API: I check that POST call body is "OK" @@ -194,7 +194,7 @@ Feature: Case filter functionality And I check that number of displayed cases results is 0 And I click "Only port health cases without a facility" checkbox on Case directory page - @issue=SORQA-30 @Locale_DE + @issue=SORQA-30 @env_main Scenario: Check aggregation buttons on Case directory page Given API: I create a new person Then API: I check that POST call body is "OK" @@ -218,7 +218,7 @@ Feature: Case filter functionality And I apply "Archived cases" to combobox on Case Directory Page And I check that number of displayed cases results is 0 - @issue=SORQA-30 @Locale_DE + @issue=SORQA-30 @env_main Scenario: Check Case report date filters on Case directory page Given API: I create a new person Then API: I check that POST call body is "OK" @@ -240,7 +240,7 @@ Feature: Case filter functionality And I check that number of displayed cases results is 0 And I fill Cases from input to 1 days before mocked Case created on Case directory page - @issue=SORQA-30 @Locale_DE + @issue=SORQA-30 @env_main Scenario: Check complex filters regarding responsibilities, vaccination, reinfection adn quarantine Given API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFollowUpVisit.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFollowUpVisit.feature index 281f95e6068..476886f9510 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFollowUpVisit.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFollowUpVisit.feature @@ -1,7 +1,7 @@ @UI @Sanity @Case @Visit Feature: Follow-up new visit functionality - @Locale_DE + @env_main Scenario: Create a new visit from case follow-up Given API: I create a new person Then API: I check that POST call body is "OK" @@ -18,7 +18,7 @@ Feature: Follow-up new visit functionality And I click on edit Visit button Then I validate all fields from Visit - @issue=SORDEV-5528 @Locale_DE + @issue=SORDEV-5528 @env_main Scenario: Fill the therapy tab When API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseHospitalization.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseHospitalization.feature index 5a840c409f7..90d295c579f 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseHospitalization.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseHospitalization.feature @@ -1,7 +1,7 @@ @UI @Sanity @Case @Hospitalization Feature: Case hospitalization tab e2e test cases - @Locale_DE + @env_main Scenario: Edit all fields from Hospitalization tab Given API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseSymptoms.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseSymptoms.feature index 3e6a3e5670b..f91cedcea77 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseSymptoms.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseSymptoms.feature @@ -1,7 +1,7 @@ @UI @Sanity @Case @Symptoms Feature: Case symptoms tab e2e test cases - @issue=SORDEV-5521 @Locale_DE + @issue=SORDEV-5521 @env_main Scenario: Fill the symptoms tab When API: I create a new person Then API: I check that POST call body is "OK" @@ -36,7 +36,7 @@ Feature: Case symptoms tab e2e test cases And I save data in Hospitalization Then I check if error in Hospitalization data is available - @issue=SORDEV-8350 @Locale_DE + @issue=SORDEV-8350 @env_main Scenario: Extend fever validation When API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseViews.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseViews.feature index 4614f408bde..660dae78c9d 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseViews.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseViews.feature @@ -1,7 +1,7 @@ @UI @Sanity @CaseView Feature: Case view tests - @Locale_DE + @env_main Scenario: Create a new Case and check details in Detailed view table Given API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/ContactFilters.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/ContactFilters.feature index 023626e23e5..60f76c4359c 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/ContactFilters.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/ContactFilters.feature @@ -1,7 +1,7 @@ @UI @Sanity @Contact @Filters Feature: Contact filter functionality - @issue=SORDEV-5692 @Locale_DE + @issue=SORDEV-5692 @env_main Scenario: Check Contact basic filters on Contact directory page Given API: I create a new person Then API: I check that POST call body is "OK" @@ -42,7 +42,7 @@ Feature: Contact filter functionality And I check that number of displayed contact results is 0 And I apply Follow-up status filter to "Completed follow-up" on Contact Directory Page - @issue=SORDEV-5692 @Locale_DE + @issue=SORDEV-5692 @env_main Scenario: Check checkbox filters on Contact directory page Given API: I create a new person Then API: I check that POST call body is "OK" @@ -92,7 +92,7 @@ Feature: Contact filter functionality And I check that number of displayed contact results is 0 And I click "Only contacts from other instances" checkbox on Contact directory page - @issue=SORDEV-5692 @Locale_DE + @issue=SORDEV-5692 @env_main Scenario: Check aggregation buttons on Contact directory page Given API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature index c284f79796b..55bcff8e6c2 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature @@ -1,7 +1,7 @@ @UI @Sanity @Contacts Feature: Contacts end to end tests - @Locale_DE + @env_main Scenario: Create simple contact Given I log in with National User And I click on the Contacts button from navbar @@ -12,7 +12,7 @@ Feature: Contacts end to end tests Then I open Contact Person tab And I check the created data is correctly displayed on Edit Contact Person page - @Locale_DE + @env_main Scenario: Delete created contact When API: I create a new person Then API: I check that POST call body is "OK" @@ -26,7 +26,7 @@ Feature: Contacts end to end tests Then I delete the contact And I check that number of displayed contact results is 0 - @Locale_DE + @env_main Scenario: Edit a created contact When API: I create a new person Then API: I check that POST call body is "OK" @@ -41,7 +41,7 @@ Feature: Contacts end to end tests And I navigate to the last created contact via the url Then I check the edited data is correctly displayed on Edit Contact page after editing - @issue=SORDEV-5476 @Locale_DE + @issue=SORDEV-5476 @env_main Scenario: Add a task from contact and verify the fields Given I log in with National User And I click on the Contacts button from navbar @@ -53,7 +53,7 @@ Feature: Contacts end to end tests And I open the last created UI Contact Then I check the created data is correctly displayed on Edit Contact page - @Locale_DE + @env_main Scenario: Source case selected for contact Given API: I create a new person Then API: I check that POST call body is "OK" @@ -77,7 +77,7 @@ Feature: Contacts end to end tests When I open the Case Contacts tab of the created case via api Then I check the linked contact information is correctly displayed - @Locale_DE + @env_main Scenario: Change the source case contact and then delete Given API: I create a new person Then API: I check that POST call body is "OK" @@ -116,7 +116,7 @@ Feature: Contacts end to end tests And I click yes on the CONFIRM REMOVAL popup from CONTACT page Then I check the CHOOSE SOURCE CASE BUTTON is displayed - @Locale_DE + @env_main Scenario: Create Contact and check details in Detailed view table Given API: I create a new person Then API: I check that POST call body is "OK" @@ -130,7 +130,7 @@ Feature: Contacts end to end tests And I filter by Contact uuid Then I am checking if all the fields are correctly displayed in the Contacts directory Detailed table - @Locale_DE + @env_main Scenario: Edit all fields from Follow-up visits tab When API: I create a new person Then API: I check that POST call body is "OK" @@ -152,7 +152,7 @@ Feature: Contacts end to end tests And I open Follow up Visits tab from contact directory Then I am validating the From and To dates displayed - @issue=SORDEV-5490 @Locale_DE + @issue=SORDEV-5490 @env_main Scenario: Create a contact and create a case for contact person Given I log in with National User When I click on the Contacts button from navbar @@ -165,7 +165,7 @@ Feature: Contacts end to end tests And I create a new case for contact with specific data And I check case created from created contact is correctly displayed on Edit Case page - @issue=SORDEV-5496 @Locale_DE + @issue=SORDEV-5496 @env_main Scenario: Generate contact document Given I log in with National User And I click on the Contacts button from navbar @@ -174,7 +174,7 @@ Feature: Contacts end to end tests When I create a contact document from template Then I verify that the contact document is downloaded and correctly named - @issue=SORDEV-5470 @Locale_DE + @issue=SORDEV-5470 @env_main Scenario: Create complex contact Given API: I create a new person Then API: I check that POST call body is "OK" @@ -195,7 +195,7 @@ Feature: Contacts end to end tests Then I open Contact Person tab And I check the created data is correctly displayed on Edit Contact Person page - @issue=SORDEV-5641 @Locale_DE + @issue=SORDEV-5641 @env_main Scenario: Fill the epidemiological data tab in Contacts When API: I create a new person Then API: I check that POST call body is "OK" @@ -220,7 +220,7 @@ Feature: Contacts end to end tests Then I am checking all Exposure data is saved and displayed in Contacts And I am checking if options in checkbox for Contact are displayed correctly - @issue=SORDEV-5670 @Locale_DE + @issue=SORDEV-5670 @env_main Scenario: Fill the follow-up tab Given API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Dashboard.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Dashboard.feature index 92b7301fae8..0d96ec48f09 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Dashboard.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Dashboard.feature @@ -1,7 +1,7 @@ @UI @Sanity @Dashboard @#7472 Feature: Dashboard counters - @Locale_DE + @env_main Scenario: Check disease and new cases counter in Surveillance Dashboard Given I log in with National User When I click on the Dashboard button from navbar and access Surveillance Dashboard @@ -18,7 +18,7 @@ Feature: Dashboard counters When I select "COVID-19" in TabSheet of Surveillance Dashboard Then I check that previous saved Surveillance Dashboard counters for COVID-19 have been increment - @Locale_DE + @env_main Scenario: Check contacts counter in Contacts Dashboard Given I log in with National User When I click on the Dashboard button from navbar and access Contacts Dashboard diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/DocumentTemplate.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/DocumentTemplate.feature index e2b4f646777..6d0e3609267 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/DocumentTemplate.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/DocumentTemplate.feature @@ -1,7 +1,7 @@ @UI @Sanity @DocumentTemplates Feature: Upload document template - @issue=SORDEV-5497 @Locale_DE + @issue=SORDEV-5497 @env_main Scenario: Upload Case Document Template Given I log in as a Admin User And I click on the Configuration button from navbar @@ -12,7 +12,7 @@ Feature: Upload document template And I confirm the document template overwrite popup Then I check that an upload success notification appears - @issue=SORDEV-5497 @Locale_DE + @issue=SORDEV-5497 @env_main Scenario: Upload Contact Document Template Given I log in as a Admin User And I click on the Configuration button from navbar @@ -23,7 +23,7 @@ Feature: Upload document template And I confirm the document template overwrite popup Then I check that an upload success notification appears - @issue=SORDEV-5497 @Locale_DE + @issue=SORDEV-5497 @env_main Scenario: Upload Event Participant Document Template Given I log in as a Admin User And I click on the Configuration button from navbar @@ -34,7 +34,7 @@ Feature: Upload document template And I confirm the document template overwrite popup Then I check that an upload success notification appears - @issue=SORDEV-5497 @Locale_DE + @issue=SORDEV-5497 @env_main Scenario: Upload Travel Entry Document Template Given I log in as a Admin User And I click on the Configuration button from navbar @@ -45,7 +45,7 @@ Feature: Upload document template And I confirm the document template overwrite popup Then I check that an upload success notification appears - @issue=SORDEV-5497 @Locale_DE + @issue=SORDEV-5497 @env_main Scenario: Upload Event Document Template Given I log in as a Admin User And I click on the Configuration button from navbar diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/EpiData.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/EpiData.feature index 6816615b436..1181271b101 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/EpiData.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/EpiData.feature @@ -1,7 +1,7 @@ @UI @Contacts @Epidata Feature: Cover Epidemiological data Tab from Contacts - @Locale_DE + @env_main Scenario: Cover Epidemiological data Tab from Contacts When API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/EpidemiologicalDataCase.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/EpidemiologicalDataCase.feature index b2fa17503f9..09de80327ac 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/EpidemiologicalDataCase.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/EpidemiologicalDataCase.feature @@ -1,7 +1,7 @@ @UI @Sanity @Case @EpidemiologicalData Feature: Epidemiological data coverage - @Locale_DE + @env_main Scenario: Edit all fields from Epidemiological data tab Given API: I create a new person Then API: I check that POST call body is "OK" @@ -21,7 +21,7 @@ Feature: Epidemiological data coverage And I open saved activity from Epidemiological Data Then I am checking all Activity data is saved and displayed - @issue=SORDEV-5522 @Locale_DE + @issue=SORDEV-5522 @env_main Scenario: Validate all fields are present and functional on Epidemiological page Given API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature index c69fc1b4001..cd6547e02db 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature @@ -1,14 +1,14 @@ @UI @Sanity @Event @UI Feature: Create events - @Locale_DE + @env_main Scenario: Create a new event Given I log in with National User And I click on the Events button from navbar And I click on the NEW EVENT button And I create a new event with status CLUSTER - @Locale_DE + @env_main Scenario: Create a new event and change its status multiple times Given I log in with National User And I click on the Events button from navbar @@ -34,7 +34,7 @@ Feature: Create events And I search for specific event in event directory Then I check if it appears under Dropped filter in event directory - @Locale_DE + @env_main Scenario: Create and check a new event data Given I log in with National User And I click on the Events button from navbar @@ -45,7 +45,7 @@ Feature: Create events And I click on the searched event Then I check the created data is correctly displayed in event edit page - @Locale_DE + @env_main Scenario: Add a participant to an event Given I log in with National User And I click on the Events button from navbar @@ -60,7 +60,7 @@ Feature: Create events And I navigate via URL to last Person created from edit Event page Then I check if event is available at person information - @issue=SORDEV-5475 @Locale_DE + @issue=SORDEV-5475 @env_main Scenario: Add a participant to an event Given I log in with National User And I click on the Events button from navbar @@ -85,7 +85,7 @@ Feature: Create events And I navigate via URL to last Person created from edit Event page Then I check if event is available at person information - @Locale_DE + @env_main Scenario: Create and edit a new event Given I log in with National User And I click on the Events button from navbar @@ -100,7 +100,7 @@ Feature: Create events And I click on the searched event Then I check the modified event data is correctly displayed - @Locale_DE + @env_main Scenario: Add a New action from event and verify the fields Given API: I create a new event Then API: I check that POST call body is "OK" @@ -114,7 +114,7 @@ Feature: Create events And I open the Action recently created from Event tab And I check that Action created from Event tab is correctly displayed in Event Actions tab - @issue=SORDEV-5520 @Locale_DE + @issue=SORDEV-5520 @env_main Scenario: Add a New action from Event Actions tab and verify the fields. Given API: I create a new event Then API: I check that POST call body is "OK" @@ -129,7 +129,7 @@ Feature: Create events Then I open the last created event via api And I check that number of actions in Edit Event Tab is 1 - @Locale_DE + @env_main Scenario: Add a New action for an Event and verify the Action in EventActions table Given API: I create a new event Then API: I check that POST call body is "OK" @@ -144,7 +144,7 @@ Feature: Create events And I collect the event actions from table view And I am checking if all the fields are correctly displayed in the Event directory Actions table - @issue=SORDEV-5476 @Locale_DE + @issue=SORDEV-5476 @env_main Scenario: Add a Task from event and verify the fields Given API: I create a new event Then API: I check that POST call body is "OK" @@ -158,7 +158,7 @@ Feature: Create events And I click on edit task icon of the first created task And I check the created task is correctly displayed on Edit task page - @Locale_DE + @env_main Scenario: Add a New Groups Event from event and verify the fields Given API: I create a new event Then API: I check that POST call body is "OK" @@ -170,7 +170,7 @@ Feature: Create events When I am accessing the event tab using the created event via api Then I am checking event group name and id is correctly displayed - @issue=SORDEV-5496 @Locale_DE + @issue=SORDEV-5496 @env_main Scenario: Generate event document Given I log in with National User And I click on the Events button from navbar @@ -179,7 +179,7 @@ Feature: Create events When I create an event document from template And I verify that the event document is downloaded and correctly named - @issue=SORDEV-5491 @Locale_DE + @issue=SORDEV-5491 @env_main Scenario: Add a participant to an event and create case Given I log in with National User And I click on the Events button from navbar @@ -195,7 +195,7 @@ Feature: Create events And I fill all fields for a new case created for event participant And I click on save case button - @issue=SORDEV-5915 @Locale_DE + @issue=SORDEV-5915 @env_main Scenario: Check all filters are work properly in Event directory Given API: I create a new event Then API: I check that POST call body is "OK" @@ -243,7 +243,7 @@ Feature: Create events And I select Dropped filter from quick filter And I click on the RESET FILTERS button - @issue=SORDEV-5570 @Locale_DE + @issue=SORDEV-5570 @env_main Scenario: Testing Event screen Impact Given API: I create a new event Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Immunization.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Immunization.feature index 57cee574c00..616822a824c 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Immunization.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Immunization.feature @@ -1,7 +1,7 @@ @UI @Sanity @Immunization Feature: Immunization end to end tests - @Locale_DE + @env_main Scenario:Check a new immunization data Given I log in as a Surveillance Officer And I click on the Immunizations button from navbar diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/LineListing.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/LineListing.feature index 68d7c78f9e2..7f7e88d8f3a 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/LineListing.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/LineListing.feature @@ -1,7 +1,7 @@ @UI @Sanity @Case Feature: Cases using Line Listing feature - @Locale_DE + @env_main Scenario: Create cases using Line Listing feature Given I log in with National User And I click on the Cases button from navbar @@ -11,7 +11,7 @@ Feature: Cases using Line Listing feature Then I click on the Cases button from navbar And I check that case created from Line Listing is saved and displayed in results grid - @Locale_DE + @env_main Scenario: Create contact using Line Listing feature Given I log in with National User When I click on the Contacts button from navbar diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Login.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Login.feature index 886ad4f2a1a..f0110da4211 100755 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Login.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Login.feature @@ -1,7 +1,7 @@ @UI @Sanity @Login Feature: Login with different type of users - @Locale_DE + @env_main Scenario Outline: Login with user Given I navigate to SORMAS login page Then I log in as a diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Pathogen.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Pathogen.feature index 0fdf563cb80..2576df39509 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Pathogen.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Pathogen.feature @@ -2,7 +2,7 @@ Feature: Pathogen Functionalities - @issue=SORDEV-5492 @Locale_DE + @issue=SORDEV-5492 @env_main Scenario: Add a Pathogen test from Samples with IgM test type and verify the fields Given API: I create a new person Then API: I check that POST call body is "OK" @@ -22,7 +22,7 @@ Feature: Pathogen Functionalities And I check that if Four Fold Increase Antibody Titer displayed And I delete the Pathogen test - @issue=SORDEV-5492 @Locale_DE + @issue=SORDEV-5492 @env_main Scenario: Add a Pathogen test from Samples with IgG test type and verify the fields Given API: I create a new person Then API: I check that POST call body is "OK" @@ -42,7 +42,7 @@ Feature: Pathogen Functionalities And I check that if Four Fold Increase Antibody Titer displayed And I delete the Pathogen test - @issue=SORDEV-5492 @Locale_DE + @issue=SORDEV-5492 @env_main Scenario: Add a Pathogen test from Samples with PCR RT PCR test type and verify the fields Given API: I create a new person Then API: I check that POST call body is "OK" @@ -62,7 +62,7 @@ Feature: Pathogen Functionalities And I check that if PCR RT PCR fields are correctly displayed And I delete the Pathogen test - @issue=SORDEV-5492 @Locale_DE + @issue=SORDEV-5492 @env_main Scenario: Add a Pathogen test from Samples with CQ Value Detection test type and verify the fields Given API: I create a new person Then API: I check that POST call body is "OK" @@ -82,7 +82,7 @@ Feature: Pathogen Functionalities And I check that if CQ CT Value field is correctly displayed And I delete the Pathogen test - @issue=SORDEV-5492 @Locale_DE + @issue=SORDEV-5492 @env_main Scenario: Add a Pathogen test from Samples with Sequencing test type and verify the fields Given API: I create a new person Then API: I check that POST call body is "OK" @@ -102,7 +102,7 @@ Feature: Pathogen Functionalities And I check that if Sequencing or DNA Microarray field is correctly displayed And I delete the Pathogen test - @issue=SORDEV-5492 @Locale_DE + @issue=SORDEV-5492 @env_main Scenario: Add a Pathogen test from Samples with DNA Microarray test type and verify the fields Given API: I create a new person Then API: I check that POST call body is "OK" @@ -122,7 +122,7 @@ Feature: Pathogen Functionalities And I check that if Sequencing or DNA Microarray field is correctly displayed And I delete the Pathogen test - @issue=SORDEV-5492 @Locale_DE + @issue=SORDEV-5492 @env_main Scenario: Add a Pathogen test from Samples with Other test type and verify the fields Given API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature index c07f95e4efd..717cdac1229 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature @@ -1,7 +1,7 @@ @UI @Sanity @Persons Feature: Edit Persons - @Locale_DE + @env_main Scenario: Edit existent person Given I log in with National User When I click on the Contacts button from navbar @@ -20,7 +20,7 @@ Feature: Edit Persons Then I click on save button from Edit Person page And I check that previous edited person is correctly displayed in Edit Person page - @issue=SORDEV-8466 @Locale_DE + @issue=SORDEV-8466 @env_main Scenario: Check Filters on Person page work as expected Given API: I create a new person Then API: I check that POST call body is "OK" @@ -86,7 +86,7 @@ Feature: Edit Persons And I apply on the APPLY FILTERS button And I click on the RESET FILTERS button for Person -@issue=SORDEV-8468 @Locale_DE +@issue=SORDEV-8468 @env_main Scenario: Edit existent person and provoke errors in the Edit Person page Given I log in with National User When I click on the Persons button from navbar diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Reports.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Reports.feature index 742198f550d..9de2c4309ea 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Reports.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Reports.feature @@ -1,7 +1,7 @@ @UI @Sanity @WeeklyReports Feature: Reports - @Locale_DE + @env_main Scenario: Reports directory layout Given I log in with National User When I click on the Reports button from navbar @@ -10,7 +10,7 @@ Feature: Reports Then I check that grid for weekly reports is shown Then I check that header names of grid for weekly reports are shown - @Locale_DE + @env_main Scenario: Reports filter work Given I log in with National User When I click on the Reports button from navbar diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Sample.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Sample.feature index 58eac416147..f3ea46fee98 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Sample.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Sample.feature @@ -1,7 +1,7 @@ @UI @Sanity @Sample Feature: Sample Functionalities - @Locale_DE + @env_main Scenario: Edit a new case Sample Given I log in with National User And I click on the Cases button from navbar @@ -18,7 +18,7 @@ Feature: Sample Functionalities When I change all Sample fields and save Then I check the edited Sample is correctly displayed on Edit Sample page - @issue=SORDEV-5471 @Locale_DE + @issue=SORDEV-5471 @env_main Scenario: Edit a new contact Sample Given I log in with National User And I click on the Contacts button from navbar @@ -36,7 +36,7 @@ Feature: Sample Functionalities When I change all Sample fields and save Then I check the edited Sample is correctly displayed on Edit Sample page - @issue=SORDEV-5471 @Locale_DE + @issue=SORDEV-5471 @env_main Scenario: Edit a new contact Sample with alternate purpose Given I log in with National User And I click on the Contacts button from navbar @@ -53,7 +53,7 @@ Feature: Sample Functionalities When I open created Sample Then I check the alternate Sample is correctly displayed on Edit Sample page - @issue=SORDEV-5471 @Locale_DE + @issue=SORDEV-5471 @env_main Scenario: Edit a new event participant Sample Given I log in with National User And I click on the Events button from navbar @@ -76,7 +76,7 @@ Feature: Sample Functionalities When I change all Sample fields and save Then I check the edited Sample is correctly displayed on Edit Sample page - @Locale_DE + @env_main Scenario: Add a Pathogen test from Samples and verify the fields Given API: I create a new person Then API: I check that POST call body is "OK" @@ -94,7 +94,7 @@ Feature: Sample Functionalities And I complete all fields from Pathogen test result popup and save Then I check that the created Pathogen is correctly displayed - @Locale_DE + @env_main Scenario: Delete created sample Given API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature index 6c23a0ff657..a0cf92ba87b 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature @@ -1,7 +1,7 @@ @UI @Sanity @Sample Feature: Sample filter functionality - @Locale_DE + @env_main Scenario: Check Filters on Sample page work as expected Given API: I create 10 new cases with a new sample foreach of them Then API: I check that POST call body is "OK" @@ -15,7 +15,7 @@ Feature: Sample filter functionality When I search for samples created with the API Then I check the displayed Laboratory filter dropdown - @issue=SORDEV-5981 @Locale_DE + @issue=SORDEV-5981 @env_main Scenario: Check all filters are work properly in Samples directory Given API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Task.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Task.feature index cfc7296f6e8..8b0a8370079 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Task.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Task.feature @@ -1,7 +1,7 @@ @UI @Sanity @Task Feature: Tasks functionalities - @Locale_DE + @env_main Scenario: Create and check a new task data Given I log in with National User And I click on the Tasks button from navbar @@ -10,7 +10,7 @@ Feature: Tasks functionalities And I open last created task Then I check the created task is correctly displayed on Edit task page - @issue=SORDEV-5476 @Locale_DE + @issue=SORDEV-5476 @env_main Scenario: Check the edit of task from Case Given I log in as a Surveillance Officer And I click on the Cases button from navbar @@ -29,7 +29,7 @@ Feature: Tasks functionalities When I click on first edit Task Then I check the created task is correctly displayed on Edit task page - @Locale_DE + @env_main Scenario: Check all fields from the created Task in the Task Management table Given API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/TaskManagementFilter.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/TaskManagementFilter.feature index 4de3faa368a..2f8c5a38e9b 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/TaskManagementFilter.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/TaskManagementFilter.feature @@ -1,7 +1,7 @@ @UI @Sanity @TaskManagementFilter Feature: Tasks functionalities - @issue=SORDEV-5688 @Locale_DE + @issue=SORDEV-5688 @env_main Scenario Outline: Check the filter of tasks context Given I log in with National User And I click on the Tasks button from navbar @@ -17,7 +17,7 @@ Feature: Tasks functionalities | Event | | General | - @issue=SORDEV-5688 @Locale_DE + @issue=SORDEV-5688 @env_main Scenario Outline: Check the filter of tasks status Given I log in with National User And I click on the Tasks button from navbar diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/User.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/User.feature index e6e2f5c6869..65bf8b2f64c 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/User.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/User.feature @@ -1,7 +1,7 @@ @UI @Sanity @Users Feature: Create user - @Locale_DE + @env_main Scenario Outline: Create a new user Given I log in as a Admin User And I click on the Users from navbar @@ -20,7 +20,7 @@ Feature: Create user | Sormas to Sormas Client | | National Clinician | - @Locale_DE + @env_main Scenario Outline: Edit user Given I log in as a Admin User And I click on the Users from navbar From d5e09be733224405767752ef39f4e7a3ede60fa6 Mon Sep 17 00:00:00 2001 From: Alexandru Caruntu Date: Mon, 21 Feb 2022 23:28:54 +0200 Subject: [PATCH 133/253] #8060 - Reset investigation dates when status is changed to pending --- .../src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java | 2 +- .../src/main/java/de/symeda/sormas/ui/events/EventDataForm.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java index e3a5e7ee468..1495a2c63c0 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java @@ -1046,7 +1046,7 @@ protected void addFields() { CaseDataDto.INVESTIGATED_DATE, CaseDataDto.INVESTIGATION_STATUS, Arrays.asList(InvestigationStatus.DONE, InvestigationStatus.DISCARDED), - false); + true); } setReadOnly( true, diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventDataForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventDataForm.java index 635c27abeef..abd13c52c65 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventDataForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventDataForm.java @@ -247,7 +247,7 @@ protected void addFields() { Arrays.asList(EventDto.EVENT_INVESTIGATION_START_DATE, EventDto.EVENT_INVESTIGATION_END_DATE), EventDto.EVENT_INVESTIGATION_STATUS, Arrays.asList(EventInvestigationStatus.ONGOING, EventInvestigationStatus.DONE, EventInvestigationStatus.DISCARDED), - false); + true); TextField title = addField(EventDto.EVENT_TITLE, TextField.class); title.addStyleName(CssStyles.SOFT_REQUIRED); From 4522160a2f5b35e7bda062bc28c5659c1be94ac1 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Tue, 22 Feb 2022 09:48:05 +0200 Subject: [PATCH 134/253] #6879 - separate each query into an executeRaw call --- .../de/symeda/sormas/app/backend/common/DatabaseHelper.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java index db41e10a650..7e0cca04d55 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java @@ -2945,10 +2945,8 @@ public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int case 331: currentVersion = 331; - getDao(Case.class).executeRaw( - "ALTER TABLE cases ADD COLUMN healthConditions_id BIGINT REFERENCES healthConditions(id);" + - "UPDATE cases c SET healthConditions_id = (SELECT cc.healthConditions_id from clinicalCourse cc where cc.id = c.clinicalCourse_id);"); - + getDao(Case.class).executeRaw("ALTER TABLE cases ADD COLUMN healthConditions_id BIGINT REFERENCES healthConditions(id);"); + getDao(Case.class).executeRaw("UPDATE cases c SET healthConditions_id = (SELECT cc.healthConditions_id from clinicalCourse cc where cc.id = c.clinicalCourse_id);"); // ATTENTION: break should only be done after last version break; From 7b363dd432762ce77d0997f45f18921c292b00bb Mon Sep 17 00:00:00 2001 From: Stefan Kock Date: Mon, 21 Feb 2022 16:53:29 +0100 Subject: [PATCH 135/253] #7786: Link to last commit in AboutView - Use git-commit-id-maven-plugin to get git related information --- sormas-api/pom.xml | 6 +++ .../symeda/sormas/api/utils/InfoProvider.java | 46 +++++++++++++++++++ .../sormas/api/utils/InfoProviderTest.java | 39 ++++++++++++++++ sormas-base/pom.xml | 28 +++++++++++ .../java/de/symeda/sormas/ui/AboutView.java | 13 ++++++ 5 files changed, 132 insertions(+) diff --git a/sormas-api/pom.xml b/sormas-api/pom.xml index 34ab0c6f590..a3c63912899 100644 --- a/sormas-api/pom.xml +++ b/sormas-api/pom.xml @@ -27,6 +27,12 @@ + + + io.github.git-commit-id + git-commit-id-maven-plugin + + diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/utils/InfoProvider.java b/sormas-api/src/main/java/de/symeda/sormas/api/utils/InfoProvider.java index d4467e0849d..36d690830bf 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/utils/InfoProvider.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/utils/InfoProvider.java @@ -19,12 +19,17 @@ import java.io.IOException; import java.io.InputStream; +import java.util.Properties; + +import org.jsoup.UncheckedIOException; public class InfoProvider { private static InfoProvider instance; private final String version; + private final String commitShortId; + private final String commitHistoryUrl; InfoProvider() { try { @@ -34,6 +39,16 @@ public class InfoProvider { } catch (IOException e) { throw new RuntimeException(e); } + + try (InputStream fis = InfoProvider.class.getResourceAsStream("/git.properties")) { + + Properties prop = new Properties(); + prop.load(fis); + this.commitShortId = prop.getProperty("git.commit.id.abbrev"); + this.commitHistoryUrl = prop.getProperty("git.remote.origin.url").replace(".git", "/commits/") + prop.getProperty("git.commit.id.full"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } } public static synchronized InfoProvider get() { @@ -67,6 +82,37 @@ public String getBaseVersion() { return version.substring(0, version.lastIndexOf(".")) + ".0"; } + /** + * @return The abbreviated id of the last commit. + */ + public String getLastCommitShortId() { + return commitShortId; + } + + /** + * @return The URL to the commit history starting at the last commit. + */ + public String getLastCommitHistoryUrl() { + return commitHistoryUrl; + } + + /** + * @return {@code true}, if this artifact was built from a SNAPSHOT version. + */ + public boolean isSnapshotVersion() { + return isSnapshot(version); + } + + /** + * @param versionString + * A {@code versionString} to check. + * @return {@code true}, if the artifact was built from a SNAPSHOT version. + */ + public boolean isSnapshot(String versionString) { + + return versionString.endsWith("SNAPSHOT"); + } + /** * Checks if the app version is compatible with the api version. This is true when the version is at least as high as the * MINIMUM_REQUIRED_VERSION and lower or equal to the version returned by getVersion(). diff --git a/sormas-api/src/test/java/de/symeda/sormas/api/utils/InfoProviderTest.java b/sormas-api/src/test/java/de/symeda/sormas/api/utils/InfoProviderTest.java index 4ace8b5814f..c8cc7b6905a 100644 --- a/sormas-api/src/test/java/de/symeda/sormas/api/utils/InfoProviderTest.java +++ b/sormas-api/src/test/java/de/symeda/sormas/api/utils/InfoProviderTest.java @@ -17,7 +17,14 @@ *******************************************************************************/ package de.symeda.sormas.api.utils; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasLength; +import static org.hamcrest.Matchers.startsWith; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.spy; @@ -75,4 +82,36 @@ public void testIsCompatibleToApiString() { } catch (IllegalArgumentException e) { } } + + @Test + public void testGetLastCommitShortId() { + + InfoProvider cut = InfoProvider.get(); + assertThat(cut.getLastCommitShortId(), hasLength(7)); + } + + @Test + public void testGetLastCommitHistoryUrl() { + + InfoProvider cut = InfoProvider.get(); + assertThat(cut.getLastCommitHistoryUrl(), startsWith("https://")); + assertThat(cut.getLastCommitHistoryUrl(), containsString(cut.getLastCommitShortId())); + } + + @Test + public void testIsSnapshotVersion() { + + InfoProvider cut = InfoProvider.get(); + assertThat(cut.isSnapshotVersion(), equalTo(cut.getVersion().endsWith("SNAPSHOT"))); + } + + @Test + public void testIsSnapshot() { + + InfoProvider cut = InfoProvider.get(); + assertTrue(cut.isSnapshot("1.69.0-SNAPSHOT")); + assertTrue(cut.isSnapshot("1.69.1-SNAPSHOT")); + assertFalse(cut.isSnapshot("1.69.0")); + assertFalse(cut.isSnapshot("1.69.1")); + } } diff --git a/sormas-base/pom.xml b/sormas-base/pom.xml index b1f97765205..f5dd10b65f7 100644 --- a/sormas-base/pom.xml +++ b/sormas-base/pom.xml @@ -1225,6 +1225,34 @@ + + io.github.git-commit-id + git-commit-id-maven-plugin + 5.0.0 + + + get-the-git-infos + + revision + + initialize + + + + ${project.basedir}/../.git + properties + true + ${project.build.outputDirectory}/git.properties + + ^git.build.time$ + ^git.build.version$ + ^git.commit.id.abbrev$ + ^git.commit.id.full$ + ^git.remote.origin.url$ + + full + + diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/AboutView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/AboutView.java index 0a73b5b0485..de4d8920196 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/AboutView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/AboutView.java @@ -133,6 +133,19 @@ private VerticalLayout createInfoSection() { CssStyles.style(versionLabel, CssStyles.VSPACE_3); infoLayout.addComponent(versionLabel); + if (InfoProvider.get().isSnapshotVersion()) { + Link commitLink = new Link( + String.format( + "%s (%s)", + versionLabel.getValue(), + InfoProvider.get() + .getLastCommitShortId()), + new ExternalResource(InfoProvider.get().getLastCommitHistoryUrl())); + commitLink.setTargetName("_blank"); + CssStyles.style(commitLink, CssStyles.VSPACE_3); + infoLayout.replaceComponent(versionLabel, commitLink); + } + if (FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.LAB_MESSAGES)) { addExternalServiceVersion( Captions.aboutLabMessageAdapter, From 8946af23d297d77d0d9305013234df7993c3d99a Mon Sep 17 00:00:00 2001 From: Stefan Kock Date: Mon, 21 Feb 2022 17:18:17 +0100 Subject: [PATCH 136/253] #7786: Removed version.txt approach, read version from git.properties --- sormas-api/pom.xml | 16 ---------------- .../de/symeda/sormas/api/utils/DataHelper.java | 16 ---------------- .../de/symeda/sormas/api/utils/InfoProvider.java | 13 +++---------- sormas-api/src/main/resources/version.txt | 1 - 4 files changed, 3 insertions(+), 43 deletions(-) delete mode 100644 sormas-api/src/main/resources/version.txt diff --git a/sormas-api/pom.xml b/sormas-api/pom.xml index a3c63912899..214eb0b788e 100644 --- a/sormas-api/pom.xml +++ b/sormas-api/pom.xml @@ -11,22 +11,6 @@ ${project.artifactId} - - - src/main/resources - true - - **/version.txt - - - - src/main/resources - false - - **/version.txt - - - io.github.git-commit-id diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/utils/DataHelper.java b/sormas-api/src/main/java/de/symeda/sormas/api/utils/DataHelper.java index f30a1aeca41..3015adece69 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/utils/DataHelper.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/utils/DataHelper.java @@ -215,22 +215,6 @@ public V getElement1() { } } - public static String convertStreamToString(InputStream is) throws IOException { - - BufferedReader reader = new BufferedReader(new InputStreamReader(is)); - StringBuilder sb = new StringBuilder(); - - String line = null; - try { - while ((line = reader.readLine()) != null) { - sb.append(line).append('\n'); - } - } finally { - is.close(); - } - return sb.toString(); - } - public static String capitalize(String input) { return input.substring(0, 1).toUpperCase() + input.substring(1); } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/utils/InfoProvider.java b/sormas-api/src/main/java/de/symeda/sormas/api/utils/InfoProvider.java index 36d690830bf..fdd36c3d652 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/utils/InfoProvider.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/utils/InfoProvider.java @@ -32,18 +32,12 @@ public class InfoProvider { private final String commitHistoryUrl; InfoProvider() { - try { - InputStream stream = InfoProvider.class.getResourceAsStream("/version.txt"); - String version = DataHelper.convertStreamToString(stream); - this.version = version.trim(); - } catch (IOException e) { - throw new RuntimeException(e); - } try (InputStream fis = InfoProvider.class.getResourceAsStream("/git.properties")) { Properties prop = new Properties(); prop.load(fis); + this.version = prop.getProperty("git.build.version"); this.commitShortId = prop.getProperty("git.commit.id.abbrev"); this.commitHistoryUrl = prop.getProperty("git.remote.origin.url").replace(".git", "/commits/") + prop.getProperty("git.commit.id.full"); } catch (IOException e) { @@ -68,15 +62,14 @@ public String getMinimumRequiredVersion() { } /** - * Reads the version from the version.txt where it is written by maven. - * We are doing it this way, because all other version information (manifest, pom) will be removed in the android app by gradle. + * Reads the current version. */ public String getVersion() { return version; } /** - * Reads the version from the version.txt where it is written by maven and replaces the last version number with a 0. + * Reads the current version and replaces the last version number with a 0. */ public String getBaseVersion() { return version.substring(0, version.lastIndexOf(".")) + ".0"; diff --git a/sormas-api/src/main/resources/version.txt b/sormas-api/src/main/resources/version.txt deleted file mode 100644 index f2ab45c3b0e..00000000000 --- a/sormas-api/src/main/resources/version.txt +++ /dev/null @@ -1 +0,0 @@ -${project.version} \ No newline at end of file From b177735f123e2263f64e2791c829dc06d961abe6 Mon Sep 17 00:00:00 2001 From: Levente Gal <62599627+leventegal-she@users.noreply.github.com> Date: Tue, 22 Feb 2022 10:53:56 +0200 Subject: [PATCH 137/253] #2805 Refactor email/sms notification system to work with future configurable user roles (#8024) --- .../de/symeda/sormas/api/i18n/Strings.java | 4 - .../sormas/api/user/NotificationType.java | 56 ++++ .../de/symeda/sormas/api/user/UserRole.java | 243 ++++++++++++++++-- sormas-api/src/main/resources/enum.properties | 1 - .../src/main/resources/strings.properties | 4 - .../sormas/backend/caze/CaseFacadeEjb.java | 146 +++++------ .../backend/common/NotificationService.java | 158 ++++++++++++ .../common/messaging/MessageContents.java | 4 - .../common/messaging/MessageSubject.java | 33 +-- .../common/messaging/MessagingService.java | 147 ++++++----- .../backend/event/EventGroupFacadeEjb.java | 29 +-- .../event/EventParticipantFacadeEjb.java | 21 +- .../backend/sample/PathogenTestFacadeEjb.java | 113 +++----- .../backend/sample/SampleFacadeEjb.java | 64 ++--- .../sormas/backend/task/TaskFacadeEjb.java | 190 +++++++------- .../sormas/backend/visit/VisitFacadeEjb.java | 27 +- .../symeda/sormas/backend/MockProducer.java | 5 +- .../common/NotificationServiceTest.java | 209 +++++++++++++++ 18 files changed, 982 insertions(+), 472 deletions(-) create mode 100644 sormas-api/src/main/java/de/symeda/sormas/api/user/NotificationType.java create mode 100644 sormas-backend/src/main/java/de/symeda/sormas/backend/common/NotificationService.java create mode 100644 sormas-backend/src/test/java/de/symeda/sormas/backend/common/NotificationServiceTest.java diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java index 7f464edf4c1..5dcd0b27db8 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java @@ -1187,10 +1187,6 @@ public interface Strings { String notificationLabResultArrivedContact = "notificationLabResultArrivedContact"; String notificationLabResultArrivedEventParticipant = "notificationLabResultArrivedEventParticipant"; String notificationLabResultArrivedEventParticipantNoDisease = "notificationLabResultArrivedEventParticipantNoDisease"; - String notificationLabResultSpecified = "notificationLabResultSpecified"; - String notificationLabResultSpecifiedContact = "notificationLabResultSpecifiedContact"; - String notificationLabResultSpecifiedEventParticipant = "notificationLabResultSpecifiedEventParticipant"; - String notificationLabResultSpecifiedEventParticipantNoDisease = "notificationLabResultSpecifiedEventParticipantNoDisease"; String notificationLabSampleShipped = "notificationLabSampleShipped"; String notificationLabSampleShippedShort = "notificationLabSampleShippedShort"; String notificationLabSampleShippedShortForContact = "notificationLabSampleShippedShortForContact"; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/user/NotificationType.java b/sormas-api/src/main/java/de/symeda/sormas/api/user/NotificationType.java new file mode 100644 index 00000000000..0d55c23e7cb --- /dev/null +++ b/sormas-api/src/main/java/de/symeda/sormas/api/user/NotificationType.java @@ -0,0 +1,56 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.api.user; + +import de.symeda.sormas.api.feature.FeatureType; + +public enum NotificationType { + + CASE_CLASSIFICATION_CHANGED, + CASE_INVESTIGATION_DONE, + EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED(FeatureType.EVENT_PARTICIPANT_CASE_CONFIRMED_NOTIFICATIONS), + EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS(FeatureType.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS_NOTIFICATIONS), + CASE_LAB_RESULT_ARRIVED, + CONTACT_LAB_RESULT_ARRIVED, + EVENT_PARTICIPANT_LAB_RESULT_ARRIVED, + LAB_SAMPLE_SHIPPED, + CONTACT_SYMPTOMATIC, + TASK_START(FeatureType.TASK_NOTIFICATIONS), + TASK_DUE(FeatureType.TASK_NOTIFICATIONS), + TASK_UPDATED_ASSIGNEE(FeatureType.TASK_NOTIFICATIONS), + VISIT_COMPLETED, + DISEASE_CHANGED, + EVENT_GROUP_CREATED(FeatureType.EVENT_GROUPS_MODIFICATION_NOTIFICATIONS), + EVENT_ADDED_TO_EVENT_GROUP(FeatureType.EVENT_GROUPS_MODIFICATION_NOTIFICATIONS), + EVENT_REMOVED_FROM_EVENT_GROUP(FeatureType.EVENT_GROUPS_MODIFICATION_NOTIFICATIONS); + + private final FeatureType relatedFeatureType; + + NotificationType() { + this.relatedFeatureType = FeatureType.OTHER_NOTIFICATIONS; + } + + NotificationType(FeatureType relatedFeatureType) { + this.relatedFeatureType = relatedFeatureType; + } + + public FeatureType getRelatedFeatureType() { + return relatedFeatureType; + } +} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRole.java b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRole.java index b9214402cb8..dbe126d145c 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRole.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRole.java @@ -18,7 +18,9 @@ package de.symeda.sormas.api.user; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Set; @@ -37,33 +39,179 @@ public enum UserRole implements StatisticsGroupingKey { - ADMIN(false, false, false, false, JurisdictionLevel.NONE), - NATIONAL_USER(false, false, false, false, JurisdictionLevel.NATION), - SURVEILLANCE_SUPERVISOR(true, false, false, false, JurisdictionLevel.REGION), - ADMIN_SUPERVISOR(true, false, false, false, JurisdictionLevel.REGION), // FIXME : remove this when user rights management is doable by users - SURVEILLANCE_OFFICER(false, true, false, false, JurisdictionLevel.DISTRICT), - HOSPITAL_INFORMANT(false, false, true, false, JurisdictionLevel.HEALTH_FACILITY), - COMMUNITY_OFFICER(false, true, false, false, JurisdictionLevel.COMMUNITY), - COMMUNITY_INFORMANT(false, false, true, false, JurisdictionLevel.COMMUNITY), - CASE_SUPERVISOR(true, false, false, false, JurisdictionLevel.REGION), - CASE_OFFICER(false, true, false, false, JurisdictionLevel.DISTRICT), - CONTACT_SUPERVISOR(true, false, false, false, JurisdictionLevel.REGION), - CONTACT_OFFICER(false, true, false, false, JurisdictionLevel.DISTRICT), - EVENT_OFFICER(true, false, false, false, JurisdictionLevel.REGION), - LAB_USER(false, false, false, false, JurisdictionLevel.LABORATORY), - EXTERNAL_LAB_USER(false, false, false, false, JurisdictionLevel.EXTERNAL_LABORATORY), - NATIONAL_OBSERVER(false, false, false, false, JurisdictionLevel.NATION), - STATE_OBSERVER(false, false, false, false, JurisdictionLevel.REGION), - DISTRICT_OBSERVER(false, false, false, false, JurisdictionLevel.DISTRICT), - NATIONAL_CLINICIAN(false, false, false, false, JurisdictionLevel.NATION), - POE_INFORMANT(false, false, false, true, JurisdictionLevel.POINT_OF_ENTRY), - POE_SUPERVISOR(true, false, false, true, JurisdictionLevel.REGION), - POE_NATIONAL_USER(false, false, false, true, JurisdictionLevel.NATION), - IMPORT_USER(false, false, false, false, JurisdictionLevel.NONE), - REST_EXTERNAL_VISITS_USER(false, false, false, false, JurisdictionLevel.NATION), - REST_USER(false, false, false, false, JurisdictionLevel.NONE), - SORMAS_TO_SORMAS_CLIENT(false, false, false, false, JurisdictionLevel.NATION), - BAG_USER(false, false, false, false, JurisdictionLevel.NONE); + ADMIN(false, false, false, false, JurisdictionLevel.NONE, Collections.emptyList(), Collections.emptyList()), + NATIONAL_USER(false, + false, + false, + false, + JurisdictionLevel.NATION, + Arrays.asList(NotificationType.TASK_START, NotificationType.TASK_DUE, NotificationType.TASK_UPDATED_ASSIGNEE), + Arrays.asList(NotificationType.TASK_START, NotificationType.TASK_DUE, NotificationType.TASK_UPDATED_ASSIGNEE)), + SURVEILLANCE_SUPERVISOR(true, + false, + false, + false, + JurisdictionLevel.REGION, + Arrays.asList( + NotificationType.CASE_CLASSIFICATION_CHANGED, + NotificationType.DISEASE_CHANGED, + NotificationType.CASE_INVESTIGATION_DONE, + NotificationType.CASE_LAB_RESULT_ARRIVED, + NotificationType.CONTACT_LAB_RESULT_ARRIVED, + NotificationType.TASK_START, + NotificationType.TASK_DUE, + NotificationType.TASK_UPDATED_ASSIGNEE, + NotificationType.VISIT_COMPLETED, + NotificationType.CONTACT_SYMPTOMATIC, + NotificationType.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED, + NotificationType.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS, + NotificationType.EVENT_GROUP_CREATED, + NotificationType.EVENT_ADDED_TO_EVENT_GROUP, + NotificationType.EVENT_REMOVED_FROM_EVENT_GROUP), + Arrays.asList( + NotificationType.CASE_CLASSIFICATION_CHANGED, + NotificationType.DISEASE_CHANGED, + NotificationType.CASE_INVESTIGATION_DONE, + NotificationType.CASE_LAB_RESULT_ARRIVED, + NotificationType.CONTACT_LAB_RESULT_ARRIVED, + NotificationType.TASK_START, + NotificationType.TASK_DUE, + NotificationType.TASK_UPDATED_ASSIGNEE, + NotificationType.VISIT_COMPLETED, + NotificationType.CONTACT_SYMPTOMATIC, + NotificationType.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED, + NotificationType.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS, + NotificationType.EVENT_GROUP_CREATED, + NotificationType.EVENT_ADDED_TO_EVENT_GROUP, + NotificationType.EVENT_REMOVED_FROM_EVENT_GROUP)), + ADMIN_SUPERVISOR(true, false, false, false, JurisdictionLevel.REGION, Collections.emptyList(), Collections.emptyList()), // FIXME : remove this when user rights management is doable by users + SURVEILLANCE_OFFICER(false, + true, + false, + false, + JurisdictionLevel.DISTRICT, + Arrays.asList( + NotificationType.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED, + NotificationType.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS, + NotificationType.EVENT_GROUP_CREATED, + NotificationType.EVENT_ADDED_TO_EVENT_GROUP, + NotificationType.EVENT_REMOVED_FROM_EVENT_GROUP), + Arrays.asList( + NotificationType.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED, + NotificationType.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS, + NotificationType.EVENT_GROUP_CREATED, + NotificationType.EVENT_ADDED_TO_EVENT_GROUP, + NotificationType.EVENT_REMOVED_FROM_EVENT_GROUP)), + HOSPITAL_INFORMANT(false, false, true, false, JurisdictionLevel.HEALTH_FACILITY, Collections.emptyList(), Collections.emptyList()), + COMMUNITY_OFFICER(false, true, false, false, JurisdictionLevel.COMMUNITY, Collections.emptyList(), Collections.emptyList()), + COMMUNITY_INFORMANT(false, false, true, false, JurisdictionLevel.COMMUNITY, Collections.emptyList(), Collections.emptyList()), + CASE_SUPERVISOR(true, + false, + false, + false, + JurisdictionLevel.REGION, + Arrays.asList( + NotificationType.CASE_CLASSIFICATION_CHANGED, + NotificationType.DISEASE_CHANGED, + NotificationType.CASE_INVESTIGATION_DONE, + NotificationType.CASE_LAB_RESULT_ARRIVED, + NotificationType.TASK_START, + NotificationType.TASK_DUE, + NotificationType.TASK_UPDATED_ASSIGNEE, + NotificationType.VISIT_COMPLETED, + NotificationType.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED), + Arrays.asList( + NotificationType.CASE_CLASSIFICATION_CHANGED, + NotificationType.DISEASE_CHANGED, + NotificationType.CASE_INVESTIGATION_DONE, + NotificationType.CASE_LAB_RESULT_ARRIVED, + NotificationType.TASK_START, + NotificationType.TASK_DUE, + NotificationType.TASK_UPDATED_ASSIGNEE, + NotificationType.VISIT_COMPLETED, + NotificationType.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED)), + CASE_OFFICER(false, true, false, false, JurisdictionLevel.DISTRICT, Collections.emptyList(), Collections.emptyList()), + CONTACT_SUPERVISOR(true, + false, + false, + false, + JurisdictionLevel.REGION, + Arrays.asList( + NotificationType.CASE_CLASSIFICATION_CHANGED, + NotificationType.DISEASE_CHANGED, + NotificationType.CONTACT_LAB_RESULT_ARRIVED, + NotificationType.TASK_START, + NotificationType.TASK_DUE, + NotificationType.TASK_UPDATED_ASSIGNEE, + NotificationType.VISIT_COMPLETED, + NotificationType.CONTACT_SYMPTOMATIC), + Arrays.asList( + NotificationType.CASE_CLASSIFICATION_CHANGED, + NotificationType.DISEASE_CHANGED, + NotificationType.CONTACT_LAB_RESULT_ARRIVED, + NotificationType.TASK_START, + NotificationType.TASK_DUE, + NotificationType.TASK_UPDATED_ASSIGNEE, + NotificationType.VISIT_COMPLETED, + NotificationType.CONTACT_SYMPTOMATIC)), + CONTACT_OFFICER(false, true, false, false, JurisdictionLevel.DISTRICT, Collections.emptyList(), Collections.emptyList()), + EVENT_OFFICER(true, + false, + false, + false, + JurisdictionLevel.REGION, + Arrays.asList( + NotificationType.EVENT_PARTICIPANT_LAB_RESULT_ARRIVED, + NotificationType.TASK_START, + NotificationType.TASK_DUE, + NotificationType.TASK_UPDATED_ASSIGNEE, + NotificationType.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED, + NotificationType.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS, + NotificationType.EVENT_GROUP_CREATED, + NotificationType.EVENT_ADDED_TO_EVENT_GROUP, + NotificationType.EVENT_REMOVED_FROM_EVENT_GROUP), + Arrays.asList( + NotificationType.EVENT_PARTICIPANT_LAB_RESULT_ARRIVED, + NotificationType.TASK_START, + NotificationType.TASK_DUE, + NotificationType.TASK_UPDATED_ASSIGNEE, + NotificationType.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED, + NotificationType.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS, + NotificationType.EVENT_GROUP_CREATED, + NotificationType.EVENT_ADDED_TO_EVENT_GROUP, + NotificationType.EVENT_REMOVED_FROM_EVENT_GROUP)), + LAB_USER(false, + false, + false, + false, + JurisdictionLevel.LABORATORY, + Collections.singletonList(NotificationType.LAB_SAMPLE_SHIPPED), + Collections.singletonList(NotificationType.LAB_SAMPLE_SHIPPED)), + EXTERNAL_LAB_USER(false, + false, + false, + false, + JurisdictionLevel.EXTERNAL_LABORATORY, + Collections.singletonList(NotificationType.LAB_SAMPLE_SHIPPED), + Collections.singletonList(NotificationType.LAB_SAMPLE_SHIPPED)), + NATIONAL_OBSERVER(false, false, false, false, JurisdictionLevel.NATION, Collections.emptyList(), Collections.emptyList()), + STATE_OBSERVER(false, false, false, false, JurisdictionLevel.REGION, Collections.emptyList(), Collections.emptyList()), + DISTRICT_OBSERVER(false, false, false, false, JurisdictionLevel.DISTRICT, Collections.emptyList(), Collections.emptyList()), + NATIONAL_CLINICIAN(false, false, false, false, JurisdictionLevel.NATION, Collections.emptyList(), Collections.emptyList()), + POE_INFORMANT(false, false, false, true, JurisdictionLevel.POINT_OF_ENTRY, Collections.emptyList(), Collections.emptyList()), + POE_SUPERVISOR(true, + false, + false, + true, + JurisdictionLevel.REGION, + Arrays.asList(NotificationType.TASK_START, NotificationType.TASK_DUE, NotificationType.TASK_UPDATED_ASSIGNEE), + Arrays.asList(NotificationType.TASK_START, NotificationType.TASK_DUE, NotificationType.TASK_UPDATED_ASSIGNEE)), + POE_NATIONAL_USER(false, false, false, true, JurisdictionLevel.NATION, Collections.emptyList(), Collections.emptyList()), + IMPORT_USER(false, false, false, false, JurisdictionLevel.NONE, Collections.emptyList(), Collections.emptyList()), + REST_EXTERNAL_VISITS_USER(false, false, false, false, JurisdictionLevel.NATION, Collections.emptyList(), Collections.emptyList()), + REST_USER(false, false, false, false, JurisdictionLevel.NONE, Collections.emptyList(), Collections.emptyList()), + SORMAS_TO_SORMAS_CLIENT(false, false, false, false, JurisdictionLevel.NATION, Collections.emptyList(), Collections.emptyList()), + BAG_USER(false, false, false, false, JurisdictionLevel.NONE, Collections.emptyList(), Collections.emptyList()); /* * Hint for SonarQube issues: @@ -106,18 +254,25 @@ public enum UserRole private final JurisdictionLevel jurisdictionLevel; + private final List emailNotifications; + private final List smsNotifications; + UserRole( boolean supervisor, boolean hasOptionalHealthFacility, boolean hasAssociatedOfficer, boolean portHealthUser, - JurisdictionLevel jurisdictionLevel) { + JurisdictionLevel jurisdictionLevel, + List emailNotifications, + List smsNotifications) { this.supervisor = supervisor; this.hasOptionalHealthFacility = hasOptionalHealthFacility; this.hasAssociatedOfficer = hasAssociatedOfficer; this.portHealthUser = portHealthUser; this.jurisdictionLevel = jurisdictionLevel; + this.emailNotifications = emailNotifications; + this.smsNotifications = smsNotifications; } public String toString() { @@ -140,6 +295,14 @@ public boolean isPortHealthUser() { return portHealthUser; } + public List getEmailNotifications() { + return emailNotifications; + } + + public List getSmsNotifications() { + return smsNotifications; + } + public Set getDefaultUserRights() { if (defaultUserRights == null) { @@ -369,4 +532,28 @@ public static List getWithJurisdictionLevels(JurisdictionLevel... juri return ret; } + + public static UserRole[] getWithEmailNotificationTypes(Set notificationTypes) { + List ret = new ArrayList<>(); + + for (UserRole role : UserRole.values()) { + if (role.emailNotifications.stream().anyMatch(notificationTypes::contains)) { + ret.add(role); + } + } + + return ret.toArray(new UserRole[] {}); + } + + public static UserRole[] getWithSmsNotificationTypes(Set notificationTypes) { + List ret = new ArrayList<>(); + + for (UserRole role : UserRole.values()) { + if (role.emailNotifications.stream().anyMatch(notificationTypes::contains)) { + ret.add(role); + } + } + + return ret.toArray(new UserRole[] {}); + } } diff --git a/sormas-api/src/main/resources/enum.properties b/sormas-api/src/main/resources/enum.properties index 28d9cd48fb4..9fd101a6a62 100644 --- a/sormas-api/src/main/resources/enum.properties +++ b/sormas-api/src/main/resources/enum.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/strings.properties b/sormas-api/src/main/resources/strings.properties index a87ad0aaf44..18de9109c38 100644 --- a/sormas-api/src/main/resources/strings.properties +++ b/sormas-api/src/main/resources/strings.properties @@ -1194,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type: %s. Tested disease: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type: %s. Tested disease: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type: %s. Tested disease: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type: %s. Tested disease: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type: %s. Tested disease: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type: %s. notificationLabSampleShipped = A new sample (sample code: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java index a27efbe60dd..1d4ea1a578c 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java @@ -123,7 +123,6 @@ import de.symeda.sormas.api.contact.ContactCriteria; import de.symeda.sormas.api.contact.ContactDto; import de.symeda.sormas.api.contact.ContactReferenceDto; -import de.symeda.sormas.api.deletionconfiguration.AutomaticDeletionInfoDto; import de.symeda.sormas.api.document.DocumentRelatedEntityType; import de.symeda.sormas.api.epidata.EpiDataDto; import de.symeda.sormas.api.epidata.EpiDataHelper; @@ -181,6 +180,7 @@ import de.symeda.sormas.api.therapy.TherapyReferenceDto; import de.symeda.sormas.api.therapy.TreatmentCriteria; import de.symeda.sormas.api.therapy.TreatmentDto; +import de.symeda.sormas.api.user.NotificationType; import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.user.UserRole; import de.symeda.sormas.api.utils.AccessDeniedException; @@ -214,6 +214,7 @@ import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; +import de.symeda.sormas.backend.common.NotificationService; import de.symeda.sormas.backend.common.messaging.ManualMessageLogService; import de.symeda.sormas.backend.common.messaging.MessageContents; import de.symeda.sormas.backend.common.messaging.MessageSubject; @@ -328,7 +329,7 @@ @Stateless(name = "CaseFacade") public class CaseFacadeEjb extends AbstractCoreFacadeEjb - implements CaseFacade { + implements CaseFacade { private static final int ARCHIVE_BATCH_SIZE = 1000; @@ -391,6 +392,8 @@ public class CaseFacadeEjb extends AbstractCoreFacadeEjb { - List messageRecipients = userService.getAllByRegionsAndUserRoles( - JurisdictionHelper.getCaseRegions(newCase), - UserRole.SURVEILLANCE_SUPERVISOR, - UserRole.ADMIN_SUPERVISOR, - UserRole.CASE_SUPERVISOR, - UserRole.CONTACT_SUPERVISOR); - final Map mapToReturn = new HashMap<>(); - messageRecipients.forEach( - user -> mapToReturn.put( - user, - String.format( - I18nProperties.getString(MessageContents.CONTENT_CASE_CLASSIFICATION_CHANGED), - DataHelper.getShortUuid(newCase.getUuid()), - newCase.getCaseClassification().toString()))); - return mapToReturn; - }, MessageSubject.CASE_CLASSIFICATION_CHANGED, MessageType.EMAIL, MessageType.SMS); + String message = String.format( + I18nProperties.getString(MessageContents.CONTENT_CASE_CLASSIFICATION_CHANGED), + DataHelper.getShortUuid(newCase.getUuid()), + newCase.getCaseClassification().toString()); + notificationService.sendNotifications( + NotificationType.CASE_CLASSIFICATION_CHANGED, + JurisdictionHelper.getCaseRegions(newCase), + null, + MessageSubject.CASE_CLASSIFICATION_CHANGED, + message); } catch (NotificationDeliveryFailedException e) { - logger.error( - String - .format("NotificationDeliveryFailedException when trying to notify supervisors about the change of a case classification. ")); + logger.error("NotificationDeliveryFailedException when trying to notify supervisors about the change of a case classification. "); } } @@ -1915,27 +1909,20 @@ public void onCaseChanged(CaseDataDto existingCase, Case newCase, boolean syncSh if (existingCase != null && existingCase.getDisease() == Disease.UNSPECIFIED_VHF && existingCase.getDisease() != newCase.getDisease()) { try { - messagingService.sendMessages(() -> { - List messageRecipients = userService.getAllByRegionsAndUserRoles( - JurisdictionHelper.getCaseRegions(newCase), - UserRole.SURVEILLANCE_SUPERVISOR, - UserRole.ADMIN_SUPERVISOR, - UserRole.CASE_SUPERVISOR, - UserRole.CONTACT_SUPERVISOR); - final Map mapToReturn = new HashMap<>(); - messageRecipients.forEach( - user -> mapToReturn.put( - user, - String.format( - I18nProperties.getString(MessageContents.CONTENT_DISEASE_CHANGED), - DataHelper.getShortUuid(newCase.getUuid()), - existingCase.getDisease().toString(), - newCase.getDisease().toString()))); - return mapToReturn; - }, MessageSubject.DISEASE_CHANGED, MessageType.EMAIL, MessageType.SMS); + String message = String.format( + I18nProperties.getString(MessageContents.CONTENT_DISEASE_CHANGED), + DataHelper.getShortUuid(newCase.getUuid()), + existingCase.getDisease().toString(), + newCase.getDisease().toString()); + + notificationService.sendNotifications( + NotificationType.DISEASE_CHANGED, + JurisdictionHelper.getCaseRegions(newCase), + null, + MessageSubject.DISEASE_CHANGED, + message); } catch (NotificationDeliveryFailedException e) { - logger.error( - String.format("NotificationDeliveryFailedException when trying to notify supervisors about the change of a case disease.")); + logger.error("NotificationDeliveryFailedException when trying to notify supervisors about the change of a case disease."); } } @@ -1996,29 +1983,29 @@ public boolean evaluateFulfilledCondition(CaseDataDto newCase, CaseClassificatio private void sendConfirmedCaseNotificationsForEvents(Case caze) { try { - messagingService.sendMessages(() -> { - final Date fromDate = Date.from(Instant.now().minus(Duration.ofDays(30))); - final Map responsibleUserByEventByEventUuid = - eventService.getAllEventUuidWithResponsibleUserByCaseAfterDateForNotification(caze, fromDate); - final Map mapToReturn = new HashMap<>(); - responsibleUserByEventByEventUuid.forEach( - (s, user) -> mapToReturn.put( - user, - String.format( - I18nProperties.getString(MessageContents.CONTENT_EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED), - DataHelper.getShortUuid(s), - caze.getDisease().getName(), - DataHelper.getShortUuid(caze.getUuid())))); - return mapToReturn; - }, + notificationService.sendNotifications( + NotificationType.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED, MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED, new Object[] { caze.getDisease().getName() }, - MessageType.EMAIL, - MessageType.SMS); + () -> { + final Date fromDate = Date.from(Instant.now().minus(Duration.ofDays(30))); + Map eventResponsibleUsers = + eventService.getAllEventUuidWithResponsibleUserByCaseAfterDateForNotification(caze, fromDate); + + return eventResponsibleUsers.keySet() + .stream() + .collect( + Collectors.toMap( + eventResponsibleUsers::get, + eventUuid -> String.format( + I18nProperties.getString(MessageContents.CONTENT_EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED), + DataHelper.getShortUuid(eventUuid), + caze.getDisease().getName(), + DataHelper.getShortUuid(caze.getUuid())))); + }); } catch (NotificationDeliveryFailedException e) { - logger.error( - String.format("NotificationDeliveryFailedException when trying to notify event responsible user about a newly confirmed case.")); + logger.error("NotificationDeliveryFailedException when trying to notify event responsible user about a newly confirmed case."); } } @@ -2365,7 +2352,7 @@ public void pseudonymizeDto(Case source, CaseDataDto dto, Pseudonymizer pseudony } } - public void restorePseudonymizedDto(CaseDataDto dto, CaseDataDto existingCaseDto, Case caze , Pseudonymizer pseudonymizer) { + public void restorePseudonymizedDto(CaseDataDto dto, CaseDataDto existingCaseDto, Case caze, Pseudonymizer pseudonymizer) { if (existingCaseDto != null) { boolean inJurisdiction = service.inJurisdictionOrOwned(caze); @@ -3108,25 +3095,16 @@ public int compare(Pair o1, Pair { - final List messageRecipients = userService.getAllByRegionsAndUserRoles( - JurisdictionHelper.getCaseRegions(caze), - UserRole.SURVEILLANCE_SUPERVISOR, - UserRole.ADMIN_SUPERVISOR, - UserRole.CASE_SUPERVISOR, - UserRole.CONTACT_SUPERVISOR); - final Map mapToReturn = new HashMap<>(); - messageRecipients.forEach( - user -> mapToReturn.put( - user, - String.format( - I18nProperties.getString(MessageContents.CONTENT_CASE_INVESTIGATION_DONE), - DataHelper.getShortUuid(caze.getUuid())))); - return mapToReturn; - }, MessageSubject.CASE_INVESTIGATION_DONE, MessageType.EMAIL, MessageType.SMS); + String message = + String.format(I18nProperties.getString(MessageContents.CONTENT_CASE_INVESTIGATION_DONE), DataHelper.getShortUuid(caze.getUuid())); + notificationService.sendNotifications( + NotificationType.CASE_INVESTIGATION_DONE, + JurisdictionHelper.getCaseRegions(caze), + null, + MessageSubject.CASE_INVESTIGATION_DONE, + message); } catch (NotificationDeliveryFailedException e) { - logger.error( - String.format("NotificationDeliveryFailedException when trying to notify supervisors about the completion of a case investigation.")); + logger.error("NotificationDeliveryFailedException when trying to notify supervisors about the completion of a case investigation."); } } @@ -3479,8 +3457,8 @@ public List getCaseFollowUpList( caze.get(Case.DISEASE), JurisdictionHelper.booleanSelector(cb, service.inJurisdictionOrOwned(caseQueryContext))); - Predicate filter = CriteriaBuilderHelper - .and(cb, service.createUserFilter(cb, cq, caze), service.createCriteriaFilter(caseCriteria, caseQueryContext)); + Predicate filter = + CriteriaBuilderHelper.and(cb, service.createUserFilter(cb, cq, caze), service.createCriteriaFilter(caseCriteria, caseQueryContext)); if (filter != null) { cq.where(filter); @@ -3590,7 +3568,7 @@ public void sendMessage(List caseUuids, String subject, String messageCo final Person person = aCase.getPerson(); try { - messagingService.sendMessage(person, subject, messageContent, messageTypes); + messagingService.sendManualMessage(person, subject, messageContent, messageTypes); } catch (NotificationDeliveryFailedException e) { logger.error( String.format( @@ -3806,7 +3784,7 @@ public List getDuplicates(@Valid CasePersonDto casePerson) { @Override public List getByPersonUuids(List personUuids) { - return service.getByPersonUuids(personUuids).stream().map(c->toDto(c)).collect(Collectors.toList()); + return service.getByPersonUuids(personUuids).stream().map(c -> toDto(c)).collect(Collectors.toList()); } @Override diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/NotificationService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/NotificationService.java new file mode 100644 index 00000000000..7e968008520 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/NotificationService.java @@ -0,0 +1,158 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.common; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import javax.ejb.EJB; +import javax.ejb.LocalBean; +import javax.ejb.Stateless; + +import de.symeda.sormas.api.user.NotificationType; +import de.symeda.sormas.api.user.UserRole; +import de.symeda.sormas.backend.common.messaging.MessageSubject; +import de.symeda.sormas.backend.common.messaging.MessagingService; +import de.symeda.sormas.backend.common.messaging.NotificationDeliveryFailedException; +import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal; +import de.symeda.sormas.backend.infrastructure.region.Region; +import de.symeda.sormas.backend.user.User; +import de.symeda.sormas.backend.user.UserService; + +@Stateless(name = "NotificationService") +@LocalBean +public class NotificationService { + + @EJB + private MessagingService messagingService; + + @EJB + private UserService userService; + + @EJB + private FeatureConfigurationFacadeEjbLocal featureConfigurationFacade; + + public void sendNotifications( + NotificationType notificationType, + List regions, + List additionalUsers, + MessageSubject subject, + String message) + throws NotificationDeliveryFailedException { + sendNotifications(Collections.singleton(notificationType), regions, additionalUsers, subject, message); + } + + public void sendNotifications( + Set notificationTypes, + List regions, + List additionalUsers, + MessageSubject subject, + String message) + throws NotificationDeliveryFailedException { + Set allowedNotificationTypes = getAllowedNotificationTypes(notificationTypes); + + sendNotifications( + allowedNotificationTypes, + subject, + new Object[] {}, + () -> buildUserMessages(regions, additionalUsers, message, UserRole.getWithEmailNotificationTypes(allowedNotificationTypes)), + () -> buildUserMessages(regions, additionalUsers, message, UserRole.getWithSmsNotificationTypes(allowedNotificationTypes))); + } + + public void sendNotifications(NotificationType notificationType, MessageSubject subject, Supplier> userMessagesSupplier) + throws NotificationDeliveryFailedException { + sendNotifications(notificationType, subject, new Object[] {}, userMessagesSupplier); + } + + public void sendNotifications( + NotificationType notificationType, + MessageSubject subject, + Object[] subjectParams, + Supplier> userMessagesSupplier) + throws NotificationDeliveryFailedException { + + Map cachedUserMessages = new HashMap<>(); + Supplier> cachedUserMessagesSupplier = () -> { + if (cachedUserMessages.isEmpty()) { + cachedUserMessages.putAll(userMessagesSupplier.get()); + } + + return cachedUserMessages; + }; + + sendNotifications(Collections.singleton(notificationType), subject, subjectParams, cachedUserMessagesSupplier, cachedUserMessagesSupplier); + } + + private void sendNotifications( + Set notificationTypes, + MessageSubject subject, + Object[] subjectParams, + Supplier> emailUserMessagesSupplier, + Supplier> smsUserMessagesSupplier) + throws NotificationDeliveryFailedException { + + Set allowedNotificationTypes = getAllowedNotificationTypes(notificationTypes); + + if (!allowedNotificationTypes.isEmpty()) { + messagingService.sendEmail( + filterUserMessagesByRoles(emailUserMessagesSupplier.get(), UserRole.getWithEmailNotificationTypes(allowedNotificationTypes)), + subject, + subjectParams); + messagingService.sendSms( + filterUserMessagesByRoles(smsUserMessagesSupplier.get(), UserRole.getWithSmsNotificationTypes(allowedNotificationTypes)), + subject, + subjectParams); + } + } + + private Map buildUserMessages(List regions, List additionalUsers, String message, UserRole[] userRoles) { + List recipients = new ArrayList<>(); + if (regions != null) { + recipients.addAll(userService.getAllByRegionsAndUserRoles(regions, userRoles)); + } + + if (additionalUsers != null) { + recipients + .addAll(additionalUsers.stream().filter(u -> !recipients.contains(u) && u.hasAnyUserRole(userRoles)).collect(Collectors.toList())); + } + + return recipients.stream().collect(Collectors.toMap(Function.identity(), (u) -> message)); + } + + private Map filterUserMessagesByRoles(Map userStringMap, UserRole[] userRoles) { + return userStringMap.entrySet() + .stream() + .filter(e -> e.getKey().hasAnyUserRole(userRoles)) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + + private Set getAllowedNotificationTypes(Set notificationTypes) { + return notificationTypes.stream() + .filter(nt -> featureConfigurationFacade.isFeatureEnabled(nt.getRelatedFeatureType())) + .collect(Collectors.toSet()); + } + +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/messaging/MessageContents.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/messaging/MessageContents.java index 73868ae8e0c..95d8a149c45 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/messaging/MessageContents.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/messaging/MessageContents.java @@ -28,10 +28,6 @@ public final class MessageContents { public static final String CONTENT_LAB_RESULT_ARRIVED_CONTACT = "notificationLabResultArrivedContact"; public static final String CONTENT_LAB_RESULT_ARRIVED_EVENT_PARTICIPANT = "notificationLabResultArrivedEventParticipant"; public static final String CONTENT_LAB_RESULT_ARRIVED_EVENT_PARTICIPANT_NO_DISEASE = "notificationLabResultArrivedEventParticipantNoDisease"; - public static final String CONTENT_LAB_RESULT_SPECIFIED = "notificationLabResultSpecified"; - public static final String CONTENT_LAB_RESULT_SPECIFIED_CONTACT = "notificationLabResultSpecifiedContact"; - public static final String CONTENT_LAB_RESULT_SPECIFIED_EVENT_PARTICIPANT = "notificationLabResultSpecifiedEventParticipant"; - public static final String CONTENT_LAB_RESULT_SPECIFIED_EVENT_PARTICIPANT_NO_DISEASE = "notificationLabResultSpecifiedEventParticipantNoDisease"; public static final String CONTENT_LAB_SAMPLE_SHIPPED = "notificationLabSampleShipped"; public static final String CONTENT_LAB_SAMPLE_SHIPPED_SHORT = "notificationLabSampleShippedShort"; public static final String CONTENT_LAB_SAMPLE_SHIPPED_SHORT_FOR_CONTACT = "notificationLabSampleShippedShortForContact"; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/messaging/MessageSubject.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/messaging/MessageSubject.java index df72d92873b..be7458cf65e 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/messaging/MessageSubject.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/messaging/MessageSubject.java @@ -1,37 +1,20 @@ package de.symeda.sormas.backend.common.messaging; -import de.symeda.sormas.api.feature.FeatureType; - public enum MessageSubject { CASE_CLASSIFICATION_CHANGED, CASE_INVESTIGATION_DONE, - EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED(FeatureType.EVENT_PARTICIPANT_CASE_CONFIRMED_NOTIFICATIONS), - EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS(FeatureType.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS_NOTIFICATIONS), + EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED, + EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS, LAB_RESULT_ARRIVED, - LAB_RESULT_SPECIFIED, LAB_SAMPLE_SHIPPED, CONTACT_SYMPTOMATIC, - TASK_START(FeatureType.TASK_NOTIFICATIONS), - TASK_DUE(FeatureType.TASK_NOTIFICATIONS), - TASK_UPDATED_ASSIGNEE(FeatureType.TASK_NOTIFICATIONS), + TASK_START, + TASK_DUE, + TASK_UPDATED_ASSIGNEE, VISIT_COMPLETED, DISEASE_CHANGED, - EVENT_GROUP_CREATED(FeatureType.EVENT_GROUPS_MODIFICATION_NOTIFICATIONS), - EVENT_ADDED_TO_EVENT_GROUP(FeatureType.EVENT_GROUPS_MODIFICATION_NOTIFICATIONS), - EVENT_REMOVED_FROM_EVENT_GROUP(FeatureType.EVENT_GROUPS_MODIFICATION_NOTIFICATIONS); - - private final FeatureType relatedFeatureType; - - MessageSubject() { - this.relatedFeatureType = FeatureType.OTHER_NOTIFICATIONS; - } - - MessageSubject(FeatureType relatedFeatureType) { - this.relatedFeatureType = relatedFeatureType; - } - - public FeatureType getRelatedFeatureType() { - return relatedFeatureType; - } + EVENT_GROUP_CREATED, + EVENT_ADDED_TO_EVENT_GROUP, + EVENT_REMOVED_FROM_EVENT_GROUP; } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/messaging/MessagingService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/messaging/MessagingService.java index e24d8d471c8..7601be56b60 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/messaging/MessagingService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/messaging/MessagingService.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.util.Date; import java.util.Map; +import java.util.function.Function; import java.util.function.Supplier; import javax.ejb.EJB; @@ -32,12 +33,10 @@ import com.nexmo.client.NexmoClientException; -import de.symeda.sormas.api.feature.FeatureType; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.messaging.MessageType; import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.backend.common.ConfigFacadeEjb; -import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb; import de.symeda.sormas.backend.person.Person; import de.symeda.sormas.backend.user.User; import de.symeda.sormas.backend.user.UserService; @@ -62,62 +61,34 @@ public class MessagingService { @EJB private ManualMessageLogService manualMessageLogService; @EJB - private FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal featureConfigurationFacade; - @EJB private ConfigFacadeEjb.ConfigFacadeEjbLocal configFacade; - public void sendMessages(Supplier> userMessagesSupplier, MessageSubject subject, MessageType... messageTypes) + public void sendEmail(Map userMessages, MessageSubject subject, Object[] subjectParameters) throws NotificationDeliveryFailedException { - if (relatedFeatureEnabled(subject.getRelatedFeatureType())) { - for (Map.Entry entry : userMessagesSupplier.get().entrySet()) { - final User user = entry.getKey(); - final String messageContent = entry.getValue(); - sendMessage(user, I18nProperties.getEnumCaption(subject), messageContent, messageTypes); - } - } + sendMessage(userMessages, subject, subjectParameters, User::getUserEmail, this::sendEmail); } - public void sendMessages( - Supplier> userMessagesSupplier, - MessageSubject subject, - Object[] subjectParameters, - MessageType... messageTypes) + public void sendSms(Map userMessages, MessageSubject subject, Object[] subjectParameters) throws NotificationDeliveryFailedException { - if (relatedFeatureEnabled(subject.getRelatedFeatureType())) { - for (Map.Entry entry : userMessagesSupplier.get().entrySet()) { - final User user = entry.getKey(); - final String messageContent = entry.getValue(); - sendMessage(user, String.format(I18nProperties.getEnumCaption(subject), subjectParameters), messageContent, messageTypes); - } - } - } - - private boolean relatedFeatureEnabled(FeatureType relatedFeatureType) { - return featureConfigurationFacade.isFeatureEnabled(relatedFeatureType); + sendMessage(userMessages, subject, subjectParameters, User::getPhone, this::sendSms); } - private void sendMessage(User recipient, String subject, String messageContent, MessageType... messageTypes) - throws NotificationDeliveryFailedException { - // Don't send notifications to users that initiated an action - if (recipient.equals(userService.getCurrentUser()) || !recipient.isActive()) { - return; - } - - final String emailAddress = recipient.getUserEmail(); - final String phoneNumber = recipient.getPhone(); - final String recipientUuid = recipient.getUuid(); - sendMessage(subject, messageContent, emailAddress, phoneNumber, recipientUuid, "user", messageTypes); - } - - public void sendMessage(Person recipient, String subject, String messageContent, MessageType... messageTypes) + public void sendManualMessage(Person recipient, String subject, String messageContent, MessageType... messageTypes) throws NotificationDeliveryFailedException { final String emailAddress = recipient.getEmailAddress(); final String phoneNumber = recipient.getPhone(); final String recipientUuid = recipient.getUuid(); + final String recipientType = "person"; + for (MessageType messageType : messageTypes) { - sendMessage(subject, messageContent, emailAddress, phoneNumber, recipientUuid, "person", messageType); + if (messageType == MessageType.EMAIL) { + sendEmail(subject, messageContent, emailAddress, recipientUuid, recipientType); + } else if (messageType == MessageType.SMS) { + sendSms(subject, messageContent, phoneNumber, recipientUuid, recipientType); + } + final ManualMessageLog manualMessageLog = new ManualMessageLog(); manualMessageLog.setMessageType(messageType); manualMessageLog.setRecipientPerson(recipient); @@ -128,38 +99,66 @@ public void sendMessage(Person recipient, String subject, String messageContent, } private void sendMessage( - String subject, - String messageContent, - String emailAddress, - String phoneNumber, - String recipientUuid, - final String recipientType, - MessageType... messageTypes) + Map userMessages, + MessageSubject subject, + Object[] subjectParameters, + Function contactInfoSupplier, + Messenger messenger) + throws NotificationDeliveryFailedException { + + for (Map.Entry entry : userMessages.entrySet()) { + final User recipient = entry.getKey(); + final String messageContent = entry.getValue(); + + // Don't send notifications to users that initiated an action + if (recipient.equals(userService.getCurrentUser()) || !recipient.isActive()) { + return; + } + + final String recipientUuid = recipient.getUuid(); + + messenger.send( + String.format(I18nProperties.getEnumCaption(subject), subjectParameters), + messageContent, + contactInfoSupplier.apply(recipient), + recipientUuid, + "user"); + } + } + + private void sendEmail(String subject, String messageContent, String emailAddress, String recipientUuid, final String recipientType) + throws NotificationDeliveryFailedException { + + if (DataHelper.isNullOrEmpty(emailAddress)) { + logger.info(String.format("Tried to send an email to a %s without an email address (UUID: %s).", recipientType, recipientUuid)); + } else { + try { + emailService.sendEmail(emailAddress, subject, messageContent); + } catch (MessagingException e) { + logError(recipientUuid, recipientType, MessageType.EMAIL); + throw new NotificationDeliveryFailedException("Email could not be sent due to an unexpected error.", MessageType.EMAIL, e); + } + } + } + + private void sendSms(String subject, String messageContent, String phoneNumber, String recipientUuid, final String recipientType) throws NotificationDeliveryFailedException { boolean isSmsServiceSetUp = configFacade.isSmsServiceSetUp(); - for (MessageType messageType : messageTypes) { - if (messageType == MessageType.EMAIL && DataHelper.isNullOrEmpty(emailAddress)) { - logger.info(String.format("Tried to send an email to a %s without an email address (UUID: %s).", recipientType, recipientUuid)); - } else if (isSmsServiceSetUp && messageType == MessageType.SMS && DataHelper.isNullOrEmpty(phoneNumber)) { - logger.info(String.format("Tried to send an SMS to a %s without a phone number (UUID: %s).", recipientType, recipientUuid)); - } else { - try { - if (messageType == MessageType.EMAIL) { - emailService.sendEmail(emailAddress, subject, messageContent); - } else if (isSmsServiceSetUp && messageType == MessageType.SMS) { - smsService.sendSms(phoneNumber, messageContent); - } - } catch (MessagingException e) { - logError(recipientUuid, recipientType, messageType); - throw new NotificationDeliveryFailedException("Email could not be sent due to an unexpected error.", MessageType.EMAIL, e); - } catch (IOException | NexmoClientException e) { - logError(recipientUuid, recipientType, messageType); - throw new NotificationDeliveryFailedException("SMS could not be sent due to an unexpected error.", MessageType.SMS, e); - } catch (InvalidPhoneNumberException e) { - logError(recipientUuid, recipientType, messageType); - throw new NotificationDeliveryFailedException("SMS could not be sent because of an invalid phone number.", MessageType.SMS, e); + + if (isSmsServiceSetUp && DataHelper.isNullOrEmpty(phoneNumber)) { + logger.info(String.format("Tried to send an SMS to a %s without a phone number (UUID: %s).", recipientType, recipientUuid)); + } else { + try { + if (isSmsServiceSetUp) { + smsService.sendSms(phoneNumber, messageContent); } + } catch (IOException | NexmoClientException e) { + logError(recipientUuid, recipientType, MessageType.SMS); + throw new NotificationDeliveryFailedException("SMS could not be sent due to an unexpected error.", MessageType.SMS, e); + } catch (InvalidPhoneNumberException e) { + logError(recipientUuid, recipientType, MessageType.SMS); + throw new NotificationDeliveryFailedException("SMS could not be sent because of an invalid phone number.", MessageType.SMS, e); } } } @@ -167,4 +166,10 @@ private void sendMessage( private void logError(String recipientUuid, String recipientType, MessageType messageType) { logger.error(String.format("Failed to send %s to %s with UUID %s.", messageType, recipientType, recipientUuid)); } + + interface Messenger { + + void send(String subject, String messageContent, String contactInfo, String recipientUuid, String recipientType) + throws NotificationDeliveryFailedException; + } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventGroupFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventGroupFacadeEjb.java index 3ee0de45e50..e7d6d02eba9 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventGroupFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventGroupFacadeEjb.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; import javax.ejb.EJB; @@ -60,16 +61,16 @@ import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Strings; import de.symeda.sormas.api.infrastructure.region.RegionReferenceDto; -import de.symeda.sormas.api.messaging.MessageType; import de.symeda.sormas.api.user.JurisdictionLevel; +import de.symeda.sormas.api.user.NotificationType; import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.api.utils.SortProperty; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; +import de.symeda.sormas.backend.common.NotificationService; import de.symeda.sormas.backend.common.messaging.MessageContents; import de.symeda.sormas.backend.common.messaging.MessageSubject; -import de.symeda.sormas.backend.common.messaging.MessagingService; import de.symeda.sormas.backend.common.messaging.NotificationDeliveryFailedException; import de.symeda.sormas.backend.infrastructure.region.Region; import de.symeda.sormas.backend.location.Location; @@ -94,7 +95,7 @@ public class EventGroupFacadeEjb implements EventGroupFacade { @EJB private UserService userService; @EJB - private MessagingService messagingService; + private NotificationService notificationService; @Override public EventGroupReferenceDto getReferenceByUuid(String uuid) { @@ -460,6 +461,7 @@ public void notifyEventEventGroupCreated(EventGroupReferenceDto eventGroupRefere notifyModificationOfEventGroup( eventGroupReference, Collections.emptyList(), + NotificationType.EVENT_GROUP_CREATED, MessageSubject.EVENT_GROUP_CREATED, MessageContents.CONTENT_EVENT_GROUP_CREATED); } @@ -469,6 +471,7 @@ public void notifyEventAddedToEventGroup(EventGroupReferenceDto eventGroupRefere notifyModificationOfEventGroup( eventGroupReference, eventReferences, + NotificationType.EVENT_ADDED_TO_EVENT_GROUP, MessageSubject.EVENT_ADDED_TO_EVENT_GROUP, MessageContents.CONTENT_EVENT_ADDED_TO_EVENT_GROUP); } @@ -478,6 +481,7 @@ public void notifyEventRemovedFromEventGroup(EventGroupReferenceDto eventGroupRe notifyModificationOfEventGroup( eventGroupReference, eventReferences, + NotificationType.EVENT_REMOVED_FROM_EVENT_GROUP, MessageSubject.EVENT_REMOVED_FROM_EVENT_GROUP, MessageContents.CONTENT_EVENT_REMOVED_FROM_EVENT_GROUP); } @@ -485,6 +489,7 @@ public void notifyEventRemovedFromEventGroup(EventGroupReferenceDto eventGroupRe private void notifyModificationOfEventGroup( EventGroupReferenceDto eventGroupReference, List impactedEventReferences, + NotificationType notificationType, MessageSubject subject, String contentTemplate) { EventGroup eventGroup = eventGroupService.getByUuid(eventGroupReference.getUuid()); @@ -495,7 +500,7 @@ private void notifyModificationOfEventGroup( User currentUser = userService.getCurrentUser(); try { - messagingService.sendMessages(() -> { + notificationService.sendNotifications(notificationType, subject, () -> { final Set allRemainingEventUuids = getEventReferencesByEventGroupUuid(eventGroupReference.getUuid()).stream() .map(EventReferenceDto::getUuid) @@ -509,6 +514,7 @@ private void notifyModificationOfEventGroup( final Map responsibleUserByImpactedEventUuid = Maps.filterKeys(responsibleUserByEventUuid, impactedEventUuids::contains); final String message; + if (impactedEventReferences.isEmpty()) { message = String.format( I18nProperties.getString(contentTemplate), @@ -526,19 +532,10 @@ private void notifyModificationOfEventGroup( buildEventGroupSummaryForNotification(responsibleUserByRemainingEventUuid)); } - final Map mapToReturn = new HashMap<>(); - responsibleUserByEventUuid.values().forEach(user -> { - if (!(user == null || user.equals(currentUser))) { - mapToReturn.put(user, message); - } - }); - return mapToReturn; - - }, subject, MessageType.EMAIL, MessageType.SMS); + return responsibleUserByEventUuid.values().stream().collect(Collectors.toMap(Function.identity(), (u) -> message)); + }); } catch (NotificationDeliveryFailedException e) { - logger.error( - String.format( - "NotificationDeliveryFailedException when trying to notify event responsible user about a modification on an EventGroup.")); + logger.error("NotificationDeliveryFailedException when trying to notify event responsible user about a modification on an EventGroup."); } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java index 4abaad61ffc..d0cdcc749bc 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantFacadeEjb.java @@ -15,6 +15,8 @@ package de.symeda.sormas.backend.event; +import de.symeda.sormas.api.user.NotificationType; +import de.symeda.sormas.backend.common.NotificationService; import java.time.Duration; import java.time.Instant; import java.util.ArrayList; @@ -57,7 +59,6 @@ import de.symeda.sormas.api.caze.CaseExportDto; import de.symeda.sormas.api.caze.EmbeddedSampleExportDto; import de.symeda.sormas.api.common.Page; -import de.symeda.sormas.api.deletionconfiguration.AutomaticDeletionInfoDto; import de.symeda.sormas.api.event.EventDto; import de.symeda.sormas.api.event.EventParticipantCriteria; import de.symeda.sormas.api.event.EventParticipantDto; @@ -78,7 +79,6 @@ import de.symeda.sormas.api.infrastructure.facility.FacilityHelper; import de.symeda.sormas.api.infrastructure.region.RegionReferenceDto; import de.symeda.sormas.api.location.LocationDto; -import de.symeda.sormas.api.messaging.MessageType; import de.symeda.sormas.api.person.PersonDto; import de.symeda.sormas.api.person.PersonReferenceDto; import de.symeda.sormas.api.user.UserRight; @@ -95,7 +95,6 @@ import de.symeda.sormas.backend.common.DeletableAdo; import de.symeda.sormas.backend.common.messaging.MessageContents; import de.symeda.sormas.backend.common.messaging.MessageSubject; -import de.symeda.sormas.backend.common.messaging.MessagingService; import de.symeda.sormas.backend.common.messaging.NotificationDeliveryFailedException; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.contact.ContactService; @@ -157,7 +156,7 @@ public class EventParticipantFacadeEjb @EJB private DistrictService districtService; @EJB - private MessagingService messagingService; + private NotificationService notificationService; @EJB private SormasToSormasOriginInfoFacadeEjb.SormasToSormasOriginInfoFacadeEjbLocal sormasToSormasOriginInfoFacade; @EJB @@ -324,7 +323,8 @@ public void onEventParticipantChanged( private void notifyEventResponsibleUsersOfCommonEventParticipant(EventParticipant eventParticipant, Event event) { try { - messagingService.sendMessages(() -> { + + notificationService.sendNotifications(NotificationType.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS, MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS, () -> { final Date fromDate = Date.from(Instant.now().minus(Duration.ofDays(30))); final Map> responsibleUserByEventUuid = @@ -340,20 +340,21 @@ private void notifyEventResponsibleUsersOfCommonEventParticipant(EventParticipan final Map mapToReturn = new HashMap<>(); for (Map.Entry> entry : responsibleUserByEventUuid.entrySet()) { entry.getValue().filter(user -> StringUtils.isNotEmpty(user.getUserEmail())).ifPresent(user -> { - mapToReturn.put( - user, - String.format( + String message = String.format( I18nProperties.getString(MessageContents.CONTENT_EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS), DataHelper.getShortUuid(eventParticipant.getPerson().getUuid()), DataHelper.getShortUuid(eventParticipant.getUuid()), DataHelper.getShortUuid(event.getUuid()), User.buildCaptionForNotification(event.getResponsibleUser()), User.buildCaptionForNotification(userService.getCurrentUser()), - buildEventListContentForNotification(responsibleUserByEventUuid))); + buildEventListContentForNotification(responsibleUserByEventUuid)); + mapToReturn.put( + user, + message); }); } return mapToReturn; - }, MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS, MessageType.EMAIL, MessageType.SMS); + }); } catch (NotificationDeliveryFailedException e) { logger.error( String.format( diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java index 160ffbd1435..6fdbddf8876 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/PathogenTestFacadeEjb.java @@ -20,9 +20,10 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Date; -import java.util.HashMap; +import java.util.HashSet; import java.util.List; -import java.util.Map; +import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; import javax.ejb.EJB; @@ -45,12 +46,12 @@ import de.symeda.sormas.api.common.Page; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Validations; -import de.symeda.sormas.api.messaging.MessageType; import de.symeda.sormas.api.sample.PathogenTestCriteria; import de.symeda.sormas.api.sample.PathogenTestDto; import de.symeda.sormas.api.sample.PathogenTestFacade; import de.symeda.sormas.api.sample.PathogenTestResultType; import de.symeda.sormas.api.sample.SampleReferenceDto; +import de.symeda.sormas.api.user.NotificationType; import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.user.UserRole; import de.symeda.sormas.api.utils.DataHelper; @@ -58,9 +59,9 @@ import de.symeda.sormas.api.utils.ValidationRuntimeException; import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.caze.CaseFacadeEjb.CaseFacadeEjbLocal; +import de.symeda.sormas.backend.common.NotificationService; import de.symeda.sormas.backend.common.messaging.MessageContents; import de.symeda.sormas.backend.common.messaging.MessageSubject; -import de.symeda.sormas.backend.common.messaging.MessagingService; import de.symeda.sormas.backend.common.messaging.NotificationDeliveryFailedException; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.contact.ContactFacadeEjb.ContactFacadeEjbLocal; @@ -105,7 +106,7 @@ public class PathogenTestFacadeEjb implements PathogenTestFacade { @EJB private UserService userService; @EJB - private MessagingService messagingService; + private NotificationService notificationService; @EJB private UserRoleConfigFacadeEjbLocal userRoleConfigFacade; @@ -268,7 +269,7 @@ private void handleAssotiatedObjectChanges(PathogenTest pathogenTest, boolean sy if (associatedEventParticipant != null) { eventParticipantFacade.onEventParticipantChanged( eventFacade.toDto(associatedEventParticipant.getEvent()), - eventParticipantFacade.toDto(associatedEventParticipant), + eventParticipantFacade.toDto(associatedEventParticipant), associatedEventParticipant, syncShares); } @@ -471,48 +472,36 @@ private void onPathogenTestChanged(PathogenTestDto existingPathogenTest, Pathoge final Case caze = sample.getAssociatedCase(); final Contact contact = sample.getAssociatedContact(); final EventParticipant eventParticipant = sample.getAssociatedEventParticipant(); - final List messageRecipients = new ArrayList<>(); + Disease disease = null; + Set notificationTypes = new HashSet<>(); + List regions = new ArrayList<>(); if (caze != null) { disease = caze.getDisease(); - messageRecipients.addAll( - userService.getAllByRegionsAndUserRoles( - JurisdictionHelper.getCaseRegions(caze), - UserRole.SURVEILLANCE_SUPERVISOR, - UserRole.CASE_SUPERVISOR)); - + notificationTypes.add(NotificationType.CASE_LAB_RESULT_ARRIVED); + regions.addAll(JurisdictionHelper.getCaseRegions(caze)); } if (contact != null) { disease = contact.getDisease() != null ? contact.getDisease() : contact.getCaze().getDisease(); - messageRecipients.addAll( - userService - .getAllByRegionsAndUserRoles( - JurisdictionHelper.getContactRegions(contact), - UserRole.SURVEILLANCE_SUPERVISOR, - UserRole.CONTACT_SUPERVISOR) - .stream() - .filter(user -> !messageRecipients.contains(user)) - .collect(Collectors.toList())); + notificationTypes.add(NotificationType.CONTACT_LAB_RESULT_ARRIVED); + regions.addAll(JurisdictionHelper.getContactRegions(contact)); } if (eventParticipant != null) { - final Region region = eventParticipant.getEvent().getEventLocation().getRegion(); disease = eventParticipant.getEvent().getDisease(); - messageRecipients.addAll( - userService.getAllByRegionAndUserRoles(region, UserRole.EVENT_OFFICER) - .stream() - .filter(user -> !messageRecipients.contains(user)) - .collect(Collectors.toList())); + notificationTypes.add(NotificationType.EVENT_PARTICIPANT_LAB_RESULT_ARRIVED); + regions.add(eventParticipant.getEvent().getEventLocation().getRegion()); + if (disease == null) { sendMessageOnPathogenTestChanged( existingPathogenTest, newPathogenTest, null, - messageRecipients, + notificationTypes, + regions, MessageContents.CONTENT_LAB_RESULT_ARRIVED_EVENT_PARTICIPANT_NO_DISEASE, - MessageContents.CONTENT_LAB_RESULT_SPECIFIED_EVENT_PARTICIPANT_NO_DISEASE, DataHelper.getShortUuid(eventParticipant.getUuid())); } } @@ -522,20 +511,15 @@ private void onPathogenTestChanged(PathogenTestDto existingPathogenTest, Pathoge ? MessageContents.CONTENT_LAB_RESULT_ARRIVED : contact != null ? MessageContents.CONTENT_LAB_RESULT_ARRIVED_CONTACT : MessageContents.CONTENT_LAB_RESULT_ARRIVED_EVENT_PARTICIPANT; - final String contentLabResultSpecified = caze != null - ? MessageContents.CONTENT_LAB_RESULT_SPECIFIED - : contact != null - ? MessageContents.CONTENT_LAB_RESULT_SPECIFIED_CONTACT - : MessageContents.CONTENT_LAB_RESULT_SPECIFIED_EVENT_PARTICIPANT; final String shortUuid = DataHelper.getShortUuid(caze != null ? caze.getUuid() : contact != null ? contact.getUuid() : eventParticipant.getUuid()); sendMessageOnPathogenTestChanged( existingPathogenTest, newPathogenTest, disease, - messageRecipients, + notificationTypes, + regions, contentLabResultArrived, - contentLabResultSpecified, shortUuid); } } @@ -544,50 +528,27 @@ private void sendMessageOnPathogenTestChanged( PathogenTestDto existingPathogenTest, PathogenTest newPathogenTest, Disease disease, - List messageRecipients, + Set notificationTypes, + List regions, String contentLabResultArrived, - String contentLabResultSpecified, String shortUuid) { - if (existingPathogenTest == null && newPathogenTest.getTestResult() != PathogenTestResultType.PENDING) { - try { - messagingService.sendMessages(() -> { - final Map mapToReturn = new HashMap<>(); - messageRecipients.forEach( - user -> mapToReturn.put( - user, - String.format( - I18nProperties.getString(contentLabResultArrived), - newPathogenTest.getTestResult().toString(), - disease, - shortUuid, - newPathogenTest.getTestType(), - newPathogenTest.getTestedDisease()))); - return mapToReturn; - }, MessageSubject.LAB_RESULT_ARRIVED, MessageType.EMAIL, MessageType.SMS); - } catch (NotificationDeliveryFailedException e) { - logger.error(String.format("EmailDeliveryFailedException when trying to notify supervisors " + "about the arrival of a lab result.")); - } - } else if (existingPathogenTest != null + boolean isNewTestWithResult = existingPathogenTest == null && newPathogenTest.getTestResult() != PathogenTestResultType.PENDING; + boolean testResultChanged = existingPathogenTest != null && existingPathogenTest.getTestResult() == PathogenTestResultType.PENDING - && newPathogenTest.getTestResult() != PathogenTestResultType.PENDING) { + && newPathogenTest.getTestResult() != PathogenTestResultType.PENDING; + if (newPathogenTest.getTestResult() != null && isNewTestWithResult || testResultChanged) { try { - messagingService.sendMessages(() -> { - final Map mapToReturn = new HashMap<>(); - messageRecipients.forEach( - user -> mapToReturn.put( - user, - String.format( - I18nProperties.getString(contentLabResultSpecified), - disease, - shortUuid, - newPathogenTest.getTestResult().toString(), - newPathogenTest.getTestType(), - newPathogenTest.getTestedDisease()))); - return mapToReturn; - }, MessageSubject.LAB_RESULT_SPECIFIED, MessageType.EMAIL, MessageType.SMS); + String message = String.format( + I18nProperties.getString(contentLabResultArrived), + newPathogenTest.getTestResult().toString(), + disease, + shortUuid, + newPathogenTest.getTestType(), + newPathogenTest.getTestedDisease()); + + notificationService.sendNotifications(notificationTypes, regions, null, MessageSubject.LAB_RESULT_ARRIVED, message); } catch (NotificationDeliveryFailedException e) { - logger.error( - String.format("EmailDeliveryFailedException when trying to notify supervisors " + "about the specification of a lab result")); + logger.error("EmailDeliveryFailedException when trying to notify supervisors " + "about the arrival of a lab result."); } } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java index b1fc1fc1dfd..666431a7c76 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java @@ -14,11 +14,11 @@ */ package de.symeda.sormas.backend.sample; +import de.symeda.sormas.backend.event.EventFacadeEjb; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Function; @@ -37,7 +37,6 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; -import de.symeda.sormas.backend.event.EventFacadeEjb; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -54,7 +53,6 @@ import de.symeda.sormas.api.i18n.Validations; import de.symeda.sormas.api.infrastructure.facility.FacilityDto; import de.symeda.sormas.api.infrastructure.facility.FacilityHelper; -import de.symeda.sormas.api.messaging.MessageType; import de.symeda.sormas.api.sample.PathogenTestResultType; import de.symeda.sormas.api.sample.SampleCriteria; import de.symeda.sormas.api.sample.SampleDto; @@ -66,6 +64,7 @@ import de.symeda.sormas.api.sample.SampleMaterial; import de.symeda.sormas.api.sample.SampleReferenceDto; import de.symeda.sormas.api.sample.SampleSimilarityCriteria; +import de.symeda.sormas.api.user.NotificationType; import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.user.UserRole; import de.symeda.sormas.api.utils.AccessDeniedException; @@ -81,9 +80,9 @@ import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.CoreAdo; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; +import de.symeda.sormas.backend.common.NotificationService; import de.symeda.sormas.backend.common.messaging.MessageContents; import de.symeda.sormas.backend.common.messaging.MessageSubject; -import de.symeda.sormas.backend.common.messaging.MessagingService; import de.symeda.sormas.backend.common.messaging.NotificationDeliveryFailedException; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.contact.ContactFacadeEjb; @@ -161,7 +160,7 @@ public class SampleFacadeEjb implements SampleFacade { @EJB private EventFacadeEjb.EventFacadeEjbLocal eventFacade; @EJB - private MessagingService messagingService; + private NotificationService notificationService; @EJB private UserRoleConfigFacadeEjbLocal userRoleConfigFacade; @EJB @@ -948,36 +947,41 @@ private void onSampleChanged(SampleDto existingSample, Sample newSample, boolean && (existingSample == null || !existingSample.isShipped()) && !StringUtils.equals(newSample.getLab().getUuid(), FacilityDto.OTHER_FACILITY_UUID)) { try { - - messagingService.sendMessages(() -> { - final String messageContent; - if (newSample.getAssociatedCase() != null) { - messageContent = String.format( - I18nProperties.getString(MessageContents.CONTENT_LAB_SAMPLE_SHIPPED_SHORT), - DataHelper.getShortUuid(newSample.getAssociatedCase().getUuid())); - } else if (newSample.getAssociatedContact() != null) { - messageContent = String.format( - I18nProperties.getString(MessageContents.CONTENT_LAB_SAMPLE_SHIPPED_SHORT_FOR_CONTACT), - DataHelper.getShortUuid(newSample.getAssociatedContact().getUuid())); - } else if (newSample.getAssociatedEventParticipant() != null) { - messageContent = String.format( - I18nProperties.getString(MessageContents.CONTENT_LAB_SAMPLE_SHIPPED_SHORT_FOR_EVENT_PARTICIPANT), - DataHelper.getShortUuid(newSample.getAssociatedEventParticipant().getUuid())); - } else { - messageContent = null; - } - final Map mapToReturn = new HashMap<>(); - userService.getLabUsersOfLab(newSample.getLab()).forEach(user -> mapToReturn.put(user, messageContent)); - return mapToReturn; - }, MessageSubject.LAB_SAMPLE_SHIPPED, MessageType.EMAIL, MessageType.SMS); - + final String messageContent = getSampleShippedNotificationMessage(newSample); + notificationService.sendNotifications( + NotificationType.LAB_SAMPLE_SHIPPED, + MessageSubject.LAB_SAMPLE_SHIPPED, + () -> userService.getLabUsersOfLab(newSample.getLab()) + .stream() + .collect(Collectors.toMap(Function.identity(), (e) -> messageContent))); } catch (NotificationDeliveryFailedException e) { - logger - .error(String.format("EmailDeliveryFailedException when trying to notify supervisors about " + "the shipment of a lab sample.")); + logger.error("EmailDeliveryFailedException when trying to notify supervisors about " + "the shipment of a lab sample."); } } } + private String getSampleShippedNotificationMessage(Sample newSample) { + final String messageContent; + + if (newSample.getAssociatedCase() != null) { + messageContent = String.format( + I18nProperties.getString(MessageContents.CONTENT_LAB_SAMPLE_SHIPPED_SHORT), + DataHelper.getShortUuid(newSample.getAssociatedCase().getUuid())); + } else if (newSample.getAssociatedContact() != null) { + messageContent = String.format( + I18nProperties.getString(MessageContents.CONTENT_LAB_SAMPLE_SHIPPED_SHORT_FOR_CONTACT), + DataHelper.getShortUuid(newSample.getAssociatedContact().getUuid())); + } else if (newSample.getAssociatedEventParticipant() != null) { + messageContent = String.format( + I18nProperties.getString(MessageContents.CONTENT_LAB_SAMPLE_SHIPPED_SHORT_FOR_EVENT_PARTICIPANT), + DataHelper.getShortUuid(newSample.getAssociatedEventParticipant().getUuid())); + } else { + messageContent = null; + } + + return messageContent; + } + private void handleAssotiatedObjectChanges(Sample newSample, boolean syncShares) { if (newSample.getAssociatedCase() != null) { caseFacade.onCaseChanged(caseFacade.toDto(newSample.getAssociatedCase()), newSample.getAssociatedCase(), syncShares); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/task/TaskFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/task/TaskFacadeEjb.java index 761990afa75..d0f8369110b 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/task/TaskFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/task/TaskFacadeEjb.java @@ -29,6 +29,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.function.Supplier; import java.util.stream.Collectors; import javax.ejb.EJB; @@ -61,7 +62,6 @@ import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Validations; import de.symeda.sormas.api.infrastructure.district.DistrictReferenceDto; -import de.symeda.sormas.api.messaging.MessageType; import de.symeda.sormas.api.task.TaskContext; import de.symeda.sormas.api.task.TaskCriteria; import de.symeda.sormas.api.task.TaskDto; @@ -72,9 +72,9 @@ import de.symeda.sormas.api.task.TaskStatus; import de.symeda.sormas.api.task.TaskType; import de.symeda.sormas.api.travelentry.TravelEntryReferenceDto; +import de.symeda.sormas.api.user.NotificationType; import de.symeda.sormas.api.user.UserReferenceDto; import de.symeda.sormas.api.user.UserRight; -import de.symeda.sormas.api.user.UserRole; import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.api.utils.SortProperty; import de.symeda.sormas.api.utils.ValidationRuntimeException; @@ -84,6 +84,7 @@ import de.symeda.sormas.backend.caze.CaseQueryContext; import de.symeda.sormas.backend.caze.CaseService; import de.symeda.sormas.backend.common.AbstractDomainObject; +import de.symeda.sormas.backend.common.NotificationService; import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.common.CronService; @@ -147,6 +148,8 @@ public class TaskFacadeEjb implements TaskFacade { private TravelEntryService travelEntryService; @EJB private TravelEntryFacadeEjb.TravelEntryFacadeEjbLocal travelEntryFacade; + @EJB + private NotificationService notificationService; public Task fromDto(TaskDto source, boolean checkChangeDate) { @@ -312,30 +315,19 @@ public TaskDto saveTask(@Valid TaskDto dto) { if (ado.getTaskType() == TaskType.CONTACT_FOLLOW_UP && ado.getTaskStatus() == TaskStatus.DONE && ado.getContact() != null) { try { - messagingService.sendMessages(() -> { - final List messageRecipients = new ArrayList<>( - userService.getAllByRegionsAndUserRoles( - JurisdictionHelper.getContactRegions(ado.getContact()), - UserRole.SURVEILLANCE_SUPERVISOR, - UserRole.CASE_SUPERVISOR, - UserRole.CONTACT_SUPERVISOR)); - if (ado.getObserverUsers() != null) { - messageRecipients.addAll(ado.getObserverUsers()); - } - final Map mapToReturn = new HashMap<>(); - messageRecipients.forEach( - user -> mapToReturn.put( - user, - String.format( - I18nProperties.getString(MessageContents.CONTENT_VISIT_COMPLETED), - DataHelper.getShortUuid(ado.getContact().getUuid()), - DataHelper.getShortUuid(ado.getAssigneeUser().getUuid())))); - return mapToReturn; - }, MessageSubject.VISIT_COMPLETED, MessageType.EMAIL, MessageType.SMS); + String message = String.format( + I18nProperties.getString(MessageContents.CONTENT_VISIT_COMPLETED), + DataHelper.getShortUuid(ado.getContact().getUuid()), + DataHelper.getShortUuid(ado.getAssigneeUser().getUuid())); + + notificationService.sendNotifications( + NotificationType.VISIT_COMPLETED, + JurisdictionHelper.getContactRegions(ado.getContact()), + ado.getObserverUsers(), + MessageSubject.VISIT_COMPLETED, + message); } catch (NotificationDeliveryFailedException e) { - logger.error( - String - .format("NotificationDeliveryFailedException when trying to notify supervisors about the completion of a follow-up visit.")); + logger.error("NotificationDeliveryFailedException when trying to notify supervisors about the completion of a follow-up visit."); } } @@ -349,32 +341,45 @@ private void notifyAboutNewAssignee(Task task, User newAssignee, User oldAssigne } try { - messagingService.sendMessages(() -> { - final Map mapToReturn = new HashMap<>(); - final TaskContext context = task.getTaskContext(); - final AbstractDomainObject associatedEntity = context == TaskContext.CASE - ? task.getCaze() - : context == TaskContext.CONTACT ? task.getContact() : context == TaskContext.EVENT ? task.getEvent() : null; - - String oldAssigneeMessage = context == TaskContext.GENERAL - ? String.format(I18nProperties.getString(MessageContents.CONTENT_TASK_GENERAL_UPDATED_ASSIGNEE_SOURCE), task.getTaskType().toString()) - : buildSpecificTaskMessage(MessageContents.CONTENT_TASK_SPECIFIC_UPDATED_ASSIGNEE_SOURCE, task.getTaskType(), context, associatedEntity); - mapToReturn.put(oldAssignee, oldAssigneeMessage); - - if (newAssignee != null) { - String newAssigneeMessage = context == TaskContext.GENERAL - ? String.format(I18nProperties.getString(MessageContents.CONTENT_TASK_GENERAL_UPDATED_ASSIGNEE_TARGET), task.getTaskType().toString()) - : buildSpecificTaskMessage(MessageContents.CONTENT_TASK_SPECIFIC_UPDATED_ASSIGNEE_TARGET, task.getTaskType(), context, associatedEntity); - mapToReturn.put(newAssignee, newAssigneeMessage); - } - - return mapToReturn; - }, MessageSubject.TASK_UPDATED_ASSIGNEE, MessageType.EMAIL, MessageType.SMS); + final TaskContext context = task.getTaskContext(); + final AbstractDomainObject associatedEntity = context == TaskContext.CASE + ? task.getCaze() + : context == TaskContext.CONTACT ? task.getContact() : context == TaskContext.EVENT ? task.getEvent() : null; + + Map userMessages = new HashMap<>(); + userMessages.put( + oldAssignee, + getTaskNotificationMessage( + task, + associatedEntity, + MessageContents.CONTENT_TASK_GENERAL_UPDATED_ASSIGNEE_SOURCE, + MessageContents.CONTENT_TASK_SPECIFIC_UPDATED_ASSIGNEE_SOURCE)); + if (newAssignee != null) { + userMessages.put( + newAssignee, + getTaskNotificationMessage( + task, + associatedEntity, + MessageContents.CONTENT_TASK_GENERAL_UPDATED_ASSIGNEE_TARGET, + MessageContents.CONTENT_TASK_SPECIFIC_UPDATED_ASSIGNEE_TARGET)); + } + notificationService.sendNotifications( + NotificationType.TASK_UPDATED_ASSIGNEE, + MessageSubject.TASK_UPDATED_ASSIGNEE, + () -> userMessages); } catch (NotificationDeliveryFailedException e) { logger.error(String.format("EmailDeliveryFailedException when trying to notify a user about an updated task assignee.")); } } + private String getTaskNotificationMessage(Task task, AbstractDomainObject associatedEntity, String generalMessageTag, String specificMessageTag) { + TaskContext context = task.getTaskContext(); + + return context == TaskContext.GENERAL + ? String.format(I18nProperties.getString(generalMessageTag), task.getTaskType().toString()) + : buildSpecificTaskMessage(specificMessageTag, task.getTaskType(), context, associatedEntity); + } + @Override public List getAllActiveUuids() { @@ -887,63 +892,52 @@ public void sendNewAndDueTaskMessages() { final Date before = calendar.getTime(); try { - messagingService.sendMessages(() -> { - final Map mapToReturn = new HashMap<>(); - final List startingTasks = - taskService.findBy(new TaskCriteria().taskStatus(TaskStatus.PENDING).startDateBetween(before, now), true); - for (Task task : startingTasks) { - final TaskContext context = task.getTaskContext(); - final AbstractDomainObject associatedEntity = context == TaskContext.CASE - ? task.getCaze() - : context == TaskContext.CONTACT ? task.getContact() : context == TaskContext.EVENT ? task.getEvent() : null; - String message = context == TaskContext.GENERAL - ? String.format(I18nProperties.getString(MessageContents.CONTENT_TASK_START_GENERAL), task.getTaskType().toString()) - : buildSpecificTaskMessage(MessageContents.CONTENT_TASK_START_SPECIFIC, task.getTaskType(), context, associatedEntity); - if (task.getAssigneeUser() != null) { - mapToReturn.put(task.getAssigneeUser(), message); - } - if (task.getObserverUsers() != null) { - String observerUserMessage = I18nProperties.getString(MessageContents.CONTENT_TASK_OBSERVER_INFORMATION) + "\n\n" + message; - for (User observerUser : task.getObserverUsers()) { - mapToReturn.put(observerUser, observerUserMessage); - } - } - } - return mapToReturn; - }, MessageSubject.TASK_START, MessageType.EMAIL, MessageType.SMS); + notificationService.sendNotifications(NotificationType.TASK_START, MessageSubject.TASK_START, () -> buildTaskUserMessages( + taskService.findBy(new TaskCriteria().taskStatus(TaskStatus.PENDING).startDateBetween(before, now), true), + MessageContents.CONTENT_TASK_START_GENERAL, + MessageContents.CONTENT_TASK_START_SPECIFIC)); } catch (NotificationDeliveryFailedException e) { - logger.error(String.format("EmailDeliveryFailedException when trying to notify a user about a starting task.")); + logger.error("EmailDeliveryFailedException when trying to notify a user about a starting task."); } try { - messagingService.sendMessages(() -> { - final Map mapToReturn = new HashMap<>(); - final List dueTasks = taskService.findBy(new TaskCriteria().taskStatus(TaskStatus.PENDING).dueDateBetween(before, now), true); - for (Task task : dueTasks) { - final TaskContext context = task.getTaskContext(); - final AbstractDomainObject associatedEntity = context == TaskContext.CASE - ? task.getCaze() - : context == TaskContext.CONTACT ? task.getContact() : context == TaskContext.EVENT ? task.getEvent() : null; - String message = context == TaskContext.GENERAL - ? String.format(I18nProperties.getString(MessageContents.CONTENT_TASK_DUE_GENERAL), task.getTaskType().toString()) - : buildSpecificTaskMessage(MessageContents.CONTENT_TASK_DUE_SPECIFIC, task.getTaskType(), context, associatedEntity); - if (task.getAssigneeUser() != null) { - mapToReturn.put(task.getAssigneeUser(), message); - } - if (task.getObserverUsers() != null) { - String observerUserMessage = I18nProperties.getString(MessageContents.CONTENT_TASK_OBSERVER_INFORMATION) + "\n\n" + message; - for (User observerUser : task.getObserverUsers()) { - mapToReturn.put(observerUser, observerUserMessage); - } - } - } - return mapToReturn; - }, MessageSubject.TASK_START, MessageType.EMAIL, MessageType.SMS); + Supplier> userMessageSupplier = () -> buildTaskUserMessages( + taskService.findBy(new TaskCriteria().taskStatus(TaskStatus.PENDING).dueDateBetween(before, now), true), + MessageContents.CONTENT_TASK_DUE_GENERAL, + MessageContents.CONTENT_TASK_DUE_SPECIFIC); + + notificationService.sendNotifications(NotificationType.TASK_DUE, MessageSubject.TASK_DUE, userMessageSupplier); } catch (NotificationDeliveryFailedException e) { - logger.error(String.format("EmailDeliveryFailedException when trying to notify a user about a due task.")); + logger.error("EmailDeliveryFailedException when trying to notify a user about a due task."); } } + private Map buildTaskUserMessages(List tasks, String generalMessageTag, String specificMessageTag) { + final Map messages = new HashMap<>(); + + for (Task task : tasks) { + final TaskContext context = task.getTaskContext(); + final AbstractDomainObject associatedEntity = context == TaskContext.CASE + ? task.getCaze() + : context == TaskContext.CONTACT ? task.getContact() : context == TaskContext.EVENT ? task.getEvent() : null; + + String message = getTaskNotificationMessage(task, associatedEntity, generalMessageTag, specificMessageTag); + + if (task.getAssigneeUser() != null) { + messages.put(task.getAssigneeUser(), message); + } + + if (task.getObserverUsers() != null) { + String observerUserMessage = I18nProperties.getString(MessageContents.CONTENT_TASK_OBSERVER_INFORMATION) + "\n\n" + message; + for (User observerUser : task.getObserverUsers()) { + messages.put(observerUser, observerUserMessage); + } + } + } + + return messages; + } + private void validate(TaskDto task) throws ValidationRuntimeException { if (task.getTaskContext() == TaskContext.CASE && task.getCaze() == null) { @@ -1014,11 +1008,7 @@ public List getArchivedUuidsSince(Date since) { private String buildSpecificTaskMessage(String messageTemplate, TaskType taskType, TaskContext taskContext, AbstractDomainObject entity) { String entityReference = buildAssociatedEntityReference(taskContext, entity); String linkContent = buildAssociatedEntityLinkContent(taskContext, entity); - return String.format( - I18nProperties.getString(messageTemplate) + "%s", - taskType, - entityReference, - linkContent); + return String.format(I18nProperties.getString(messageTemplate) + "%s", taskType, entityReference, linkContent); } private String buildAssociatedEntityReference(TaskContext taskContext, AbstractDomainObject entity) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/visit/VisitFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/visit/VisitFacadeEjb.java index ae8df4cd3b7..955f442584d 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/visit/VisitFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/visit/VisitFacadeEjb.java @@ -22,7 +22,6 @@ import java.util.Collections; import java.util.Comparator; import java.util.Date; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -61,13 +60,12 @@ import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Validations; import de.symeda.sormas.api.importexport.ExportConfigurationDto; -import de.symeda.sormas.api.messaging.MessageType; import de.symeda.sormas.api.person.PersonReferenceDto; import de.symeda.sormas.api.symptoms.SymptomsDto; import de.symeda.sormas.api.symptoms.SymptomsHelper; +import de.symeda.sormas.api.user.NotificationType; import de.symeda.sormas.api.user.UserReferenceDto; import de.symeda.sormas.api.user.UserRight; -import de.symeda.sormas.api.user.UserRole; import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.api.utils.SortProperty; import de.symeda.sormas.api.utils.ValidationRuntimeException; @@ -84,10 +82,10 @@ import de.symeda.sormas.backend.caze.CaseFacadeEjb.CaseFacadeEjbLocal; import de.symeda.sormas.backend.caze.CaseQueryContext; import de.symeda.sormas.backend.caze.CaseService; +import de.symeda.sormas.backend.common.NotificationService; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.common.messaging.MessageContents; import de.symeda.sormas.backend.common.messaging.MessageSubject; -import de.symeda.sormas.backend.common.messaging.MessagingService; import de.symeda.sormas.backend.common.messaging.NotificationDeliveryFailedException; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.contact.ContactQueryContext; @@ -130,7 +128,7 @@ public class VisitFacadeEjb implements VisitFacade { @EJB private SymptomsFacadeEjbLocal symptomsFacade; @EJB - private MessagingService messagingService; + private NotificationService notificationService; @Override public List getAllActiveUuids() { @@ -601,19 +599,14 @@ private void onVisitChanged(VisitDto existingVisit, Visit newVisit) { DataHelper.getShortUuid(contact.getUuid())); } - messagingService.sendMessages(() -> { - final Map mapToReturn = new HashMap<>(); - userService - .getAllByRegionsAndUserRoles( - JurisdictionHelper.getContactRegions(contact), - UserRole.SURVEILLANCE_SUPERVISOR, - UserRole.CONTACT_SUPERVISOR) - .forEach(user -> mapToReturn.put(user, messageContent)); - return mapToReturn; - }, MessageSubject.CONTACT_SYMPTOMATIC, MessageType.EMAIL, MessageType.SMS); + notificationService.sendNotifications( + NotificationType.CONTACT_SYMPTOMATIC, + JurisdictionHelper.getContactRegions(contact), + null, + MessageSubject.CONTACT_SYMPTOMATIC, + messageContent); } catch (NotificationDeliveryFailedException e) { - logger.error( - String.format("EmailDeliveryFailedException when trying to notify supervisors about a contact that has become symptomatic.")); + logger.error("EmailDeliveryFailedException when trying to notify supervisors about a contact that has become symptomatic."); } } } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/MockProducer.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/MockProducer.java index 21538778ff6..88193eab9db 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/MockProducer.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/MockProducer.java @@ -21,6 +21,7 @@ import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.withSettings; import java.io.File; import java.lang.reflect.Field; @@ -55,8 +56,8 @@ public class MockProducer { private static final String TMP_PATH = "target/tmp"; - private static SessionContext sessionContext = mock(SessionContext.class); - private static Principal principal = mock(Principal.class); + private static SessionContext sessionContext = mock(SessionContext.class, withSettings().lenient()); + private static Principal principal = mock(Principal.class, withSettings().lenient()); private static Topic topic = mock(Topic.class); private static ConnectionFactory connectionFactory = mock(ConnectionFactory.class); private static TimerService timerService = mock(TimerService.class); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/common/NotificationServiceTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/common/NotificationServiceTest.java new file mode 100644 index 00000000000..63437888d79 --- /dev/null +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/common/NotificationServiceTest.java @@ -0,0 +1,209 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package de.symeda.sormas.backend.common; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.mockito.ArgumentMatchers.any; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; + +import de.symeda.sormas.api.feature.FeatureType; +import de.symeda.sormas.api.user.NotificationType; +import de.symeda.sormas.api.user.UserDto; +import de.symeda.sormas.api.user.UserRole; +import de.symeda.sormas.backend.AbstractBeanTest; +import de.symeda.sormas.backend.TestDataCreator; +import de.symeda.sormas.backend.common.messaging.MessageSubject; +import de.symeda.sormas.backend.common.messaging.MessagingService; +import de.symeda.sormas.backend.common.messaging.NotificationDeliveryFailedException; +import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal; +import de.symeda.sormas.backend.infrastructure.region.Region; +import de.symeda.sormas.backend.user.User; +import de.symeda.sormas.backend.user.UserService; + +@RunWith(MockitoJUnitRunner.class) +public class NotificationServiceTest extends AbstractBeanTest { + + @Mock + private FeatureConfigurationFacadeEjbLocal configurationFacade; + + @Mock + private MessagingService messagingService; + + @Mock + private UserService userService; + + @InjectMocks + private NotificationService notificationService; + + public void init() { + super.init(); + + Mockito.when(configurationFacade.isFeatureEnabled(any())).thenReturn(true); + } + + @Test + public void testSendNotifications() throws NotificationDeliveryFailedException { + notificationService + .sendNotifications(NotificationType.CASE_LAB_RESULT_ARRIVED, null, null, MessageSubject.CASE_CLASSIFICATION_CHANGED, "Test message"); + + Mockito.verify(messagingService, Mockito.times(1)).sendEmail(any(), any(), any()); + Mockito.verify(messagingService, Mockito.times(1)).sendSms(any(), any(), any()); + } + + @Test + public void testSendNotifications_loadUsersByRoles() throws NotificationDeliveryFailedException { + TestDataCreator.RDCF rdcf = creator.createRDCF(); + Region region = getRegionService().getByReferenceDto(rdcf.region); + + UserDto survSup = creator.createUser(rdcf, "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); + UserDto caseSup = creator.createUser(rdcf, "Case", "Sup", UserRole.CASE_SUPERVISOR); + + Mockito.when(userService.getAllByRegionsAndUserRoles(any(), any())).then(invocation -> { + return getUserService().getAllByRegionsAndUserRoles( + (List) invocation.getArgument(0), + (UserRole) invocation.getArgument(1), + (UserRole) invocation.getArgument(2)); + }); + Mockito.doAnswer(invocation -> { + Map userMessages = (Map) invocation.getArgument(0); + + assertThat(userMessages.size(), is(2)); + assertThat(userMessages.get(getUserService().getByReferenceDto(survSup.toReference())), is("Test message")); + assertThat(userMessages.get(getUserService().getByReferenceDto(caseSup.toReference())), is("Test message")); + + return null; + }).when(messagingService).sendEmail(any(), any(), any()); + + notificationService.sendNotifications( + NotificationType.CASE_LAB_RESULT_ARRIVED, + Collections.singletonList(region), + null, + MessageSubject.LAB_RESULT_ARRIVED, + "Test message"); + + Mockito.verify(messagingService, Mockito.times(1)).sendEmail(any(), any(), any()); + Mockito.verify(messagingService, Mockito.times(1)).sendSms(any(), any(), any()); + } + + @Test + public void testSendNotifications_additionalUsers() throws NotificationDeliveryFailedException { + TestDataCreator.RDCF rdcf = creator.createRDCF(); + Region region = getRegionService().getByReferenceDto(rdcf.region); + + UserDto survSup = creator.createUser(rdcf, "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); + UserDto caseSup = creator.createUser(rdcf, "Case", "Sup", UserRole.CASE_SUPERVISOR); + + User caseSupUser = getUserService().getByReferenceDto(caseSup.toReference()); + + Mockito.when(userService.getAllByRegionsAndUserRoles(any(), any())).then(invocation -> { + // load only for SURVEILLANCE_SUPERVISOR, so the additional CASE_SUPERVISOR user will be added in the notification service + return getUserService().getAllByRegionsAndUserRoles( + (List) invocation.getArgument(0), + UserRole.SURVEILLANCE_SUPERVISOR); + }); + Mockito.doAnswer(invocation -> { + Map userMessages = (Map) invocation.getArgument(0); + + assertThat(userMessages.size(), is(2)); + assertThat(userMessages.get(getUserService().getByReferenceDto(survSup.toReference())), is("Test message")); + assertThat(userMessages.get(getUserService().getByReferenceDto(caseSup.toReference())), is("Test message")); + + return null; + }).when(messagingService).sendEmail(any(), any(), any()); + + notificationService.sendNotifications( + NotificationType.VISIT_COMPLETED, + Collections.singletonList(region), + Collections.singletonList(caseSupUser), + MessageSubject.VISIT_COMPLETED, + "Test message"); + + Mockito.verify(messagingService, Mockito.times(1)).sendEmail(any(), any(), any()); + Mockito.verify(messagingService, Mockito.times(1)).sendSms(any(), any(), any()); + } + + @Test + public void testSendNotifications_filterUserMessagesByroles() throws NotificationDeliveryFailedException { + TestDataCreator.RDCF rdcf = creator.createRDCF(); + + UserDto survSup = creator.createUser(rdcf, "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); + UserDto caseSup = creator.createUser(rdcf, "Case", "Sup", UserRole.CASE_SUPERVISOR); + UserDto contSup = creator.createUser(rdcf, "Cont", "Sup", UserRole.CONTACT_SUPERVISOR); + + User survSupUser = getUserService().getByReferenceDto(survSup.toReference()); + User survOffUser = getUserService().getByReferenceDto(caseSup.toReference()); + User contSupUser = getUserService().getByReferenceDto(contSup.toReference()); + + Mockito.doAnswer(invocation -> { + Map userMessages = (Map) invocation.getArgument(0); + + assertThat(userMessages.size(), is(2)); + assertThat(userMessages.get(survSupUser), is("Test message SS")); + assertThat(userMessages.get(survOffUser), is("Test message SO")); + + return null; + }).when(messagingService).sendEmail(any(), any(), any()); + + notificationService.sendNotifications(NotificationType.CASE_LAB_RESULT_ARRIVED, MessageSubject.LAB_RESULT_ARRIVED, () -> { + Map userMessages = new HashMap<>(); + userMessages.put(survOffUser, "Test message SO"); + userMessages.put(survSupUser, "Test message SS"); + userMessages.put(contSupUser, "Test message CS"); + + return userMessages; + }); + + Mockito.verify(messagingService, Mockito.times(1)).sendEmail(any(), any(), any()); + Mockito.verify(messagingService, Mockito.times(1)).sendSms(any(), any(), any()); + } + + @Test + public void testSendNotifications_notificationFeatureNotAllowed() throws NotificationDeliveryFailedException { + TestDataCreator.RDCF rdcf = creator.createRDCF(); + + UserDto survSup = creator.createUser(rdcf, "Surv", "Sup", UserRole.SURVEILLANCE_SUPERVISOR); + + User survSupUser = getUserService().getByReferenceDto(survSup.toReference()); + + Mockito.when(configurationFacade.isFeatureEnabled(FeatureType.TASK_NOTIFICATIONS)).thenReturn(false); + + notificationService.sendNotifications(NotificationType.TASK_START, MessageSubject.TASK_START, () -> { + Map userMessages = new HashMap<>(); + userMessages.put(survSupUser, "Test message"); + + return userMessages; + }); + + Mockito.verify(messagingService, Mockito.times(0)).sendEmail(any(), any(), any()); + Mockito.verify(messagingService, Mockito.times(0)).sendSms(any(), any(), any()); + } +} From 1c05a245fb93e0f6889d8d113fe1d9db006a36e8 Mon Sep 17 00:00:00 2001 From: Levente Gal Date: Tue, 22 Feb 2022 11:10:24 +0200 Subject: [PATCH 138/253] #2805 Refactor email/sms notification system to work with future configurable user roles - fix mockito runner import --- .../symeda/sormas/backend/common/NotificationServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/common/NotificationServiceTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/common/NotificationServiceTest.java index 63437888d79..e01eeea97d4 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/common/NotificationServiceTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/common/NotificationServiceTest.java @@ -33,7 +33,7 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import de.symeda.sormas.api.feature.FeatureType; import de.symeda.sormas.api.user.NotificationType; From 141b8b76901b3147ee8dfdf011c42c1c78058bbd Mon Sep 17 00:00:00 2001 From: sergiupacurariu <62688603+sergiupacurariu@users.noreply.github.com> Date: Tue, 22 Feb 2022 11:42:46 +0200 Subject: [PATCH 139/253] #7247 - CoreAdo: Introduce "end of processing date" --- .../sormas/ui/utils/ArchivingController.java | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchivingController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchivingController.java index 0d1212058e2..9552230fae3 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchivingController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchivingController.java @@ -1,7 +1,6 @@ package de.symeda.sormas.ui.utils; import java.util.Collections; -import java.util.Date; import java.util.List; import com.vaadin.server.Page; @@ -18,9 +17,6 @@ import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Strings; -import de.symeda.sormas.ui.SormasUI; -import de.symeda.sormas.ui.caze.AbstractCaseView; -import de.symeda.sormas.ui.events.EventDataView; public class ArchivingController { @@ -210,23 +206,4 @@ public void dearchiveSelectedItems( }); } } - - public void navigateToView(String viewName, String caseUuid, ViewMode viewMode) { - navigateToView(viewName, caseUuid, viewMode, false); - } - - public void navigateToView(String viewName, String caseUuid, ViewMode viewMode, boolean openTab) { - - String navigationState = viewName + "/" + caseUuid; - if (viewMode == ViewMode.NORMAL) { - // pass full view mode as param so it's also used for other views when switching - navigationState += "?" + AbstractCaseView.VIEW_MODE_URL_PREFIX + "=" + viewMode; - } - - if (openTab) { - SormasUI.get().getPage().open(SormasUI.get().getPage().getLocation().getRawPath() + "#!" + navigationState, "_blank", false); - } else { - SormasUI.get().getNavigator().navigateTo(navigationState); - } - } } From 172f0d2a2fb482e32719fcf60895754d6396b980 Mon Sep 17 00:00:00 2001 From: alexcaruntu-vita <76100512+alexcaruntu-vita@users.noreply.github.com> Date: Tue, 22 Feb 2022 13:25:22 +0200 Subject: [PATCH 140/253] #8044 - Reset community field when region is changed (#8088) --- .../java/de/symeda/sormas/ui/person/PersonFilterForm.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonFilterForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonFilterForm.java index d32201eb9f5..2c800d4b396 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonFilterForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonFilterForm.java @@ -6,7 +6,6 @@ import com.vaadin.v7.ui.TextField; import de.symeda.sormas.api.FacadeProvider; -import de.symeda.sormas.api.caze.CaseDataDto; import de.symeda.sormas.api.i18n.Descriptions; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Strings; @@ -71,7 +70,7 @@ protected void addFields() { UserDto user = currentUserDto(); ComboBox regionField = null; if (user.getRegion() == null) { - regionField = addField(getContent(), FieldConfiguration.pixelSized(CaseDataDto.REGION, 140)); + regionField = addField(getContent(), FieldConfiguration.pixelSized(PersonCriteria.REGION, 140)); regionField.addItems(FacadeProvider.getRegionFacade().getAllActiveByServerCountry()); } @@ -112,6 +111,7 @@ protected void applyDependenciesOnFieldChange(String propertyId, Property.ValueC districtFilter.removeAllItems(); districtFilter.clear(); } + clearAndDisableFields(communityFilter); break; case PersonCriteria.DISTRICT: DistrictReferenceDto district = (DistrictReferenceDto) event.getProperty().getValue(); From f044ec5e7052718b8d7dd28d23e6689f3900ae4d Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Tue, 22 Feb 2022 13:54:28 +0200 Subject: [PATCH 141/253] #6879 - fix migration query on android + move healthconditions section after symptoms --- .../de/symeda/sormas/app/backend/common/DatabaseHelper.java | 2 +- .../src/main/java/de/symeda/sormas/app/caze/CaseSection.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java index 7e0cca04d55..6b1d47bdef6 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java @@ -2946,7 +2946,7 @@ public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int case 331: currentVersion = 331; getDao(Case.class).executeRaw("ALTER TABLE cases ADD COLUMN healthConditions_id BIGINT REFERENCES healthConditions(id);"); - getDao(Case.class).executeRaw("UPDATE cases c SET healthConditions_id = (SELECT cc.healthConditions_id from clinicalCourse cc where cc.id = c.clinicalCourse_id);"); + getDao(Case.class).executeRaw("UPDATE cases SET healthConditions_id = (SELECT healthConditions_id from clinicalCourse where clinicalCourse.id = cases.clinicalCourse_id);"); // ATTENTION: break should only be done after last version break; diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseSection.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseSection.java index db3d6e3ab60..21b557e6792 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseSection.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseSection.java @@ -30,12 +30,12 @@ public enum CaseSection HOSPITALIZATION(R.string.caption_case_hospitalization, R.drawable.ic_local_hospital_black_24dp), PORT_HEALTH_INFO(R.string.caption_case_port_health_info, R.drawable.ic_transfer_case_24dp), SYMPTOMS(R.string.caption_symptoms, R.drawable.ic_healing_black_24dp), + HEALTH_CONDITIONS(R.string.caption_case_health_conditions, R.drawable.ic_dvr_black_24dp), EPIDEMIOLOGICAL_DATA(R.string.caption_case_epidemiological_data, R.drawable.ic_pets_black_24dp), SAMPLES(R.string.caption_case_samples, R.drawable.ic_drawer_sample_blue_24dp), CONTACTS(R.string.caption_case_contacts, R.drawable.ic_drawer_contact_blue_24dp), PRESCRIPTIONS(R.string.caption_case_prescriptions, R.drawable.ic_receipt_black_24dp), TREATMENTS(R.string.caption_case_treatments, R.drawable.ic_pan_tool_black_24dp), - HEALTH_CONDITIONS(R.string.caption_case_health_conditions, R.drawable.ic_dvr_black_24dp), CLINICAL_VISITS(R.string.caption_case_clinical_visits, R.drawable.ic_add_alarm_black_24dp), TASKS(R.string.caption_case_tasks, R.drawable.ic_drawer_user_task_blue_24dp), EVENTS(R.string.caption_case_events, R.drawable.ic_event_available_black_24dp), From 4f29cfcc469da6111f177cfda238749022bcdc2b Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Tue, 22 Feb 2022 16:15:12 +0200 Subject: [PATCH 142/253] #6934-Update-Framework-To-Multiple-Environments : updated readme --- sormas-e2e-tests/README.md | 12 +++++++++--- sormas-e2e-tests/images/configFIle.JPG | Bin 0 -> 58325 bytes sormas-e2e-tests/scripts/runTests.sh | 2 +- .../entities/services/api/CaseApiService.java | 10 ++++++++-- .../services/api/ContactApiService.java | 10 ++++++++-- .../services/api/ImmunizationApiService.java | 3 ++- .../e2etests/helpers/RestAssuredClient.java | 8 ++++++-- .../events/EventActionsTableSteps.java | 2 +- .../sanity/api/EntitiesCreation.feature | 3 +-- .../PagesLoadMeasurements.feature | 4 +--- .../resources/features/sanity/web/Login.feature | 5 +---- 11 files changed, 38 insertions(+), 21 deletions(-) create mode 100644 sormas-e2e-tests/images/configFIle.JPG diff --git a/sormas-e2e-tests/README.md b/sormas-e2e-tests/README.md index 9a14a5dc122..d05a5f57598 100644 --- a/sormas-e2e-tests/README.md +++ b/sormas-e2e-tests/README.md @@ -77,8 +77,14 @@ LOG_RESTASSURED=false * Change REMOTE_DRIVER value to false to run the tests from your local machine (optional HEADLESS to false to enable UI execution, and LOG_RESTASSURED to true to enable json logging) -* To change testing environment, open: resources/configuration/properties/environment/test-performance.properties -And update ENVIRONMENT_URL value (can be a local dev environments as well) +* Pass Environment data json file as argument in order to provide all available environments and users. This can be set in IDE VM options or directly in CLI. + +Argument = envConfig + +Value = ./path/envData.json + +![config](./images/configFIle.JPG) + ## Test case design A design pattern is implemented based on a behavior-driven development style. @@ -115,7 +121,7 @@ This file a build configuration script defines a project and its tasks. ````gradle -gradlew clean startTests -Dcucumber.tags="@Login" -Denvironment=performance +gradlew clean startTests -Dcucumber.tags="@Login" -Dheadless=true -Dcourgette.threads=9 -DenvConfig=C:/Users/MyUser/Desktop/envData.json ```` diff --git a/sormas-e2e-tests/images/configFIle.JPG b/sormas-e2e-tests/images/configFIle.JPG new file mode 100644 index 0000000000000000000000000000000000000000..0f9c706a1e49b07d7e4ccff560805fa1ef6271a5 GIT binary patch literal 58325 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Π4{TZ+SOQG~KakbrsoE%x3yD+D|jTNx&*967+ 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 literal 0 HcmV?d00001 diff --git a/sormas-e2e-tests/scripts/runTests.sh b/sormas-e2e-tests/scripts/runTests.sh index fa7f7eacb70..526c706daf4 100644 --- a/sormas-e2e-tests/scripts/runTests.sh +++ b/sormas-e2e-tests/scripts/runTests.sh @@ -25,7 +25,7 @@ rm -rf ./allureReports echo "Executing gradle clean..." ./gradlew clean goJF echo "Starting all BDD tests under @$1 tag..." -./gradlew startTests -Dcucumber.tags=\"@$1\" -Dheadless=true -Dcourgette.threads=9 -DenvConfig=C:/Users/Zack/Desktop/data.json +./gradlew startTests -Dcucumber.tags=\"@$1\" -Dheadless=true -Dcourgette.threads=9 -DenvConfig=C:/Users/Zack/Desktop/envData.json echo "Deleting test downloads folder..." rm -rf ./downloads diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/CaseApiService.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/CaseApiService.java index 43453dea996..c08091179f8 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/CaseApiService.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/CaseApiService.java @@ -66,7 +66,10 @@ public Case buildGeneratedCase(Person person) { .reportDate(new Date()) .reportingUser( ReportingUser.builder() - .uuid(environmentManager.getUserByRole(locale, UserRoles.RestUser.getRole()).getUuid()) + .uuid( + environmentManager + .getUserByRole(locale, UserRoles.RestUser.getRole()) + .getUuid()) .build()) .district( District.builder().uuid(DistrictsValues.VoreingestellterLandkreis.getUuid()).build()) @@ -111,7 +114,10 @@ public Case buildGeneratedCase(Person person) { .build()) .surveillanceOfficer( SurveillanceOfficer.builder() - .uuid(environmentManager.getUserByRole(locale, UserRoles.SurveillanceOfficer.getRole()).getUuid()) + .uuid( + environmentManager + .getUserByRole(locale, UserRoles.SurveillanceOfficer.getRole()) + .getUuid()) .build()) .healthFacilityDetails("Details") .caseOrigin("IN_COUNTRY") diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/ContactApiService.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/ContactApiService.java index 064b150954d..b940ec824d0 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/ContactApiService.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/ContactApiService.java @@ -56,7 +56,10 @@ public Contact buildGeneratedContact(Person person) { .reportDateTime(new Date()) .reportingUser( ReportingUser.builder() - .uuid(environmentManager.getUserByRole(locale, UserRoles.RestUser.getRole()).getUuid()) + .uuid( + environmentManager + .getUserByRole(locale, UserRoles.RestUser.getRole()) + .getUuid()) .build()) .district( District.builder() @@ -90,7 +93,10 @@ public Contact buildGeneratedContactWithLinkedCase(Person person, Case caze) { .reportDateTime(new Date()) .reportingUser( ReportingUser.builder() - .uuid(environmentManager.getUserByRole(locale, UserRoles.RestUser.getRole()).getUuid()) + .uuid( + environmentManager + .getUserByRole(locale, UserRoles.RestUser.getRole()) + .getUuid()) .build()) .district( District.builder() diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/ImmunizationApiService.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/ImmunizationApiService.java index 980c0578aaf..f15d6b1b789 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/ImmunizationApiService.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/ImmunizationApiService.java @@ -60,7 +60,8 @@ public Immunization buildGeneratedImmunizationForPerson(Person person) { .startDate(Calendar.getInstance().getTimeInMillis()) .endDate(Calendar.getInstance().getTimeInMillis()) .externalId(faker.number().digits(9)) - .reportingUser(environmentManager.getUserByRole(locale, UserRoles.NationalUser.getRole()).getUuid()) + .reportingUser( + environmentManager.getUserByRole(locale, UserRoles.NationalUser.getRole()).getUuid()) .archived(false) .disease(DiseasesValues.getRandomDiseaseName()) .immunizationStatus(StatusValues.getRandomImmunizationStatus()) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/RestAssuredClient.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/RestAssuredClient.java index 0d411e840da..dd18fa660cf 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/RestAssuredClient.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/RestAssuredClient.java @@ -74,8 +74,12 @@ private RequestSpecification request() { .auth() .preemptive() .basic( - environmentManager.getUserByRole(locale, UserRoles.RestUser.getRole()).getUsername(), - environmentManager.getUserByRole(locale, UserRoles.RestUser.getRole()).getPassword()); + environmentManager + .getUserByRole(locale, UserRoles.RestUser.getRole()) + .getUsername(), + environmentManager + .getUserByRole(locale, UserRoles.RestUser.getRole()) + .getPassword()); return requestSpecification .config( diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventActionsTableSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventActionsTableSteps.java index 0b8ac0c5b05..01671c972c1 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventActionsTableSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventActionsTableSteps.java @@ -91,7 +91,7 @@ public EventActionsTableSteps( "Priority is not correct"); softly.assertEquals( eventActionTableEntry.getActionLastModifiedBy(), - UserRoles.NationalUser.getRole(), + UserRoles.NationalUser.getRole(), "Last modified by user is not correct"); softly.assertAll(); }); diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/api/EntitiesCreation.feature b/sormas-e2e-tests/src/test/resources/features/sanity/api/EntitiesCreation.feature index 6dc3cffd15e..e8a66353d62 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/api/EntitiesCreation.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/api/EntitiesCreation.feature @@ -30,5 +30,4 @@ Feature: Create person and attach immunizations via API requests And API: I check that POST call status code is 200 Then API: I create and link 2 Contacts to each case from previous created cases Then API: I check that POST call body is "OK" - And API: I check that POST call status code is 200 - + And API: I check that POST call status code is 200 \ No newline at end of file diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/pagesperformance/PagesLoadMeasurements.feature b/sormas-e2e-tests/src/test/resources/features/sanity/pagesperformance/PagesLoadMeasurements.feature index a818c01a23c..2a944aa0de4 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/pagesperformance/PagesLoadMeasurements.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/pagesperformance/PagesLoadMeasurements.feature @@ -53,6 +53,4 @@ Feature: Pages loading time Scenario: Check Surveillance Dashboard page loading time Given I log in with National User And I click on the Dashboard button from navbar and access Surveillance Dashboard - Then I wait for "Surveillance Dashboard" page to load and calculate elapsed time - - + Then I wait for "Surveillance Dashboard" page to load and calculate elapsed time \ No newline at end of file diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Login.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Login.feature index f0110da4211..f7cfb37f59c 100755 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Login.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Login.feature @@ -13,7 +13,4 @@ Feature: Login with different type of users | Contact Supervisor | | Laboratory Officer | | Point of Entry Supervisor | - | Surveillance Officer | - - - + | Surveillance Officer | \ No newline at end of file From d9f317c3fe4271b8f9d6c5260ec82e2aba715e3a Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Tue, 22 Feb 2022 17:24:32 +0200 Subject: [PATCH 143/253] #6879 - remove healthconditions_id from clinical course on android --- .../clinicalcourse/ClinicalCourse.java | 13 ------------- .../app/backend/common/DatabaseHelper.java | 19 ++++++++++++++++--- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/clinicalcourse/ClinicalCourse.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/clinicalcourse/ClinicalCourse.java index f106b88c8e7..e83b42ac8a8 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/clinicalcourse/ClinicalCourse.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/clinicalcourse/ClinicalCourse.java @@ -15,7 +15,6 @@ package de.symeda.sormas.app.backend.clinicalcourse; -import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; import javax.persistence.Entity; @@ -33,18 +32,6 @@ public class ClinicalCourse extends AbstractDomainObject { public static final String TABLE_NAME = "clinicalCourse"; public static final String I18N_PREFIX = "ClinicalCourse"; - @Deprecated - @DatabaseField(foreign = true, foreignAutoRefresh = true) - private HealthConditions healthConditions; - - public HealthConditions getHealthConditions() { - return healthConditions; - } - - public void setHealthConditions(HealthConditions healthConditions) { - this.healthConditions = healthConditions; - } - @Override public String getI18nPrefix() { return I18N_PREFIX; diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java index 6b1d47bdef6..5ea0e91946c 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java @@ -183,7 +183,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { public static final String DATABASE_NAME = "sormas.db"; // any time you make changes to your database objects, you may have to increase the database version - public static final int DATABASE_VERSION = 332; + public static final int DATABASE_VERSION = 333; private static DatabaseHelper instance = null; @@ -2947,8 +2947,21 @@ public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int currentVersion = 331; getDao(Case.class).executeRaw("ALTER TABLE cases ADD COLUMN healthConditions_id BIGINT REFERENCES healthConditions(id);"); getDao(Case.class).executeRaw("UPDATE cases SET healthConditions_id = (SELECT healthConditions_id from clinicalCourse where clinicalCourse.id = cases.clinicalCourse_id);"); - // ATTENTION: break should only be done after last version - break; + case 332: + currentVersion = 332; + getDao(ClinicalCourse.class).executeRaw("ALTER TABLE clinicalCourse RENAME TO tmp_clinicalCourse"); + getDao(ClinicalCourse.class).executeRaw( + "CREATE TABLE clinicalCourse(" + "id integer primary key autoincrement," + "uuid varchar(36) not null," + + "changeDate timestamp not null," + "creationDate timestamp not null," + "lastOpenedDate timestamp," + + "localChangeDate timestamp not null," + "modified integer," + "snapshot integer," + "UNIQUE(snapshot, uuid));"); + getDao(ClinicalCourse.class).executeRaw( + "INSERT INTO clinicalCourse(id, uuid, changeDate, creationDate, lastOpenedDate, " + + "localChangeDate, modified, snapshot) " + + "SELECT id, uuid, changeDate, creationDate, lastOpenedDate, localChangeDate, modified, snapshot FROM tmp_clinicalCourse"); + getDao(ClinicalCourse.class).executeRaw("DROP TABLE tmp_clinicalCourse;"); + + // ATTENTION: break should only be done after last version + break; default: throw new IllegalStateException("onUpgrade() with unknown oldVersion " + oldVersion); From a8b9a3f51053be000c625643749d4eb4545ba252 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Tue, 22 Feb 2022 17:03:26 +0100 Subject: [PATCH 144/253] Filters for Event Directory --- .../events/EventDirectoryPage.java | 10 ++ .../org/sormas/e2etests/pojo/api/Event.java | 2 + .../e2etests/pojo/api/EventLocation.java | 3 + .../services/api/EventApiService.java | 28 +++- .../events/EventDirectorySteps.java | 130 +++++++++++++++-- .../features/sanity/web/EventFilters.feature | 132 ++++++++++++++++++ 6 files changed, 291 insertions(+), 14 deletions(-) create mode 100644 sormas-e2e-tests/src/test/resources/features/sanity/web/EventFilters.feature diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java index 5b4c5530647..7c760fdf16c 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java @@ -38,6 +38,14 @@ public class EventDirectoryPage { public static final By SEARCH_EVENT_BY_FREE_TEXT = By.id("freeText"); public static final By FILTER_BY_RISK_LEVEL = By.cssSelector("[id='riskLevel'] [class='v-filterselect-button']"); + public static final By FILTER_BY_REPORTING_USER = + By.cssSelector("[id='reportingUserRole'] [class='v-filterselect-button']"); + public static final By EVENT_MANAGEMENT_FILTER = + By.cssSelector("[id='eventManagementStatus'] [class='v-filterselect-button']"); + public static final By EVENT_INVESTIGATION_STATUS = + By.cssSelector("[id='eventInvestigationStatus'] [class='v-filterselect-button']"); + public static final By EVENT_DISPLAY_COMBOBOX = + By.cssSelector("[id='relevanceStatusFilter'] [class='v-filterselect-button']"); public static final By FILTER_BY_DISEASE = By.cssSelector("[id='disease'] [class='v-filterselect-button']"); public static final By DISTRICT_COMBOBOX = @@ -53,6 +61,8 @@ public class EventDirectoryPage { public static final By EVENT_CLUSTER = By.id("status-Cluster"); public static final By EVENT_DROPPED = By.id("status-Dropped"); public static final By CREATED_PARTICIPANT = By.cssSelector("[role='gridcell'] a"); + public static final By EVENT_PARTICIPANT = By.id("freeTextEventParticipants"); + public static final By EVENT_GROUP = By.id("freeTextEventGroups"); /*public static By getByEventUuid(String eventUuid) { return By.cssSelector("a[title=" + eventUuid + "]"); diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pojo/api/Event.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pojo/api/Event.java index 7379de7d0dd..f6cbb28b337 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pojo/api/Event.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pojo/api/Event.java @@ -41,4 +41,6 @@ public class Event { String uuid; Date startDate; Boolean multiDayEvent; + String responsibleUser; + String eventManagementStatus; } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pojo/api/EventLocation.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pojo/api/EventLocation.java index 092ca67f884..405e5bcc24d 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pojo/api/EventLocation.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pojo/api/EventLocation.java @@ -27,4 +27,7 @@ @JsonInclude(JsonInclude.Include.NON_NULL) public class EventLocation { String uuid; + Region region; + District district; + Community community; } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/EventApiService.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/EventApiService.java index a01f1c7a516..496fd55aa2b 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/EventApiService.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/EventApiService.java @@ -21,11 +21,19 @@ import com.google.inject.Inject; import java.util.Date; import java.util.UUID; +import org.sormas.e2etests.enums.CommunityValues; import org.sormas.e2etests.enums.DiseasesValues; +import org.sormas.e2etests.enums.DistrictsValues; +import org.sormas.e2etests.enums.RegionsValues; import org.sormas.e2etests.enums.RiskLevelValues; import org.sormas.e2etests.enums.SourceTypeValues; import org.sormas.e2etests.enums.cases.epidemiologicalData.TypeOfPlace; -import org.sormas.e2etests.pojo.api.*; +import org.sormas.e2etests.pojo.api.Community; +import org.sormas.e2etests.pojo.api.District; +import org.sormas.e2etests.pojo.api.Event; +import org.sormas.e2etests.pojo.api.EventLocation; +import org.sormas.e2etests.pojo.api.Region; +import org.sormas.e2etests.pojo.api.ReportingUser; public class EventApiService { @@ -43,9 +51,25 @@ public Event buildGeneratedEvent() { .eventTitle(String.valueOf(System.currentTimeMillis())) .startDate(new Date()) .reportDateTime(new Date()) - .eventLocation(EventLocation.builder().uuid(UUID.randomUUID().toString()).build()) .riskLevel(RiskLevelValues.getRandomRiskLevelName()) .typeOfPlace(TypeOfPlace.getRandomTypeOfPlace()) + .eventManagementStatus("ONGOING") + .eventLocation( + EventLocation.builder() + .uuid(UUID.randomUUID().toString()) + .community( + Community.builder() + .uuid(CommunityValues.VoreingestellteGemeinde.getUuid()) + .build()) + .region( + Region.builder() + .uuid(RegionsValues.VoreingestellteBundeslander.getUuid()) + .build()) + .district( + District.builder() + .uuid(DistrictsValues.VoreingestellterLandkreis.getUuid()) + .build()) + .build()) .build(); } } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index 5f67d338414..a7cc1e36a84 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -18,13 +18,24 @@ package org.sormas.e2etests.steps.web.application.events; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_COMMUNITY_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_DATA_TYPE_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_DISTRICT_FILTER_COMBOBOX; import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_GRID_RESULTS_ROWS; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_REGION_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.DATE_FROM_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.DATE_TO_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.PERSON_ID_NAME_CONTACT_INFORMATION_LIKE_INPUT; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.SHOW_MORE_LESS_FILTERS; import static org.sormas.e2etests.pages.application.events.EditEventPage.*; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.*; import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.APPLY_FILTERS_BUTTON; import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.RESET_FILTERS_BUTTON; import cucumber.api.java8.En; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.inject.Named; @@ -57,12 +68,82 @@ public EventDirectorySteps( dataOperations.getPartialUuidFromAssociatedLink(eventUuid)); }); + When( + "I fill Event Group Id filter to one assigned to created event on Event Directory Page", + () -> { + String eventGroupId = EditEventSteps.groupEvent.getUuid(); + webDriverHelpers.fillInWebElement( + EVENT_GROUP, dataOperations.getPartialUuidFromAssociatedLink(eventGroupId)); + }); + When( "I click on the NEW EVENT button", () -> webDriverHelpers.clickWhileOtherButtonIsDisplayed( EventDirectoryPage.NEW_EVENT_BUTTON, TITLE_INPUT)); + And( + "I apply {string} to combobox on Event Directory Page", + (String eventParameter) -> { + webDriverHelpers.selectFromCombobox(EVENT_DISPLAY_COMBOBOX, eventParameter); + webDriverHelpers.waitForPageLoaded(); + }); + And( + "I apply Date type filter to {string} on Event directory page", + (String dataType) -> + webDriverHelpers.selectFromCombobox(CASE_DATA_TYPE_FILTER_COMBOBOX, dataType)); + And( + "I fill Event to input to {int} days after mocked Event created on Event directory page", + (Integer number) -> { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy"); + webDriverHelpers.fillInWebElement( + DATE_TO_COMBOBOX, + formatter.format( + LocalDate.ofInstant( + apiState.getCreatedEvent().getReportDateTime().toInstant(), + ZoneId.systemDefault()) + .plusDays(number))); + }); + And( + "I fill Event from input to {int} days before mocked Event created on Event directory page", + (Integer number) -> { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy"); + webDriverHelpers.fillInWebElement( + DATE_FROM_COMBOBOX, + formatter.format( + LocalDate.ofInstant( + apiState.getCreatedEvent().getReportDateTime().toInstant(), + ZoneId.systemDefault()) + .minusDays(number))); + }); + And( + "I fill Event from input to {int} days after before mocked Event created on Event directory page", + (Integer number) -> { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy"); + webDriverHelpers.fillInWebElement( + DATE_FROM_COMBOBOX, formatter.format(LocalDate.now().plusDays(number))); + }); + And( + "I click SHOW MORE FILTERS button on Event directory page", + () -> webDriverHelpers.clickOnWebElementBySelector(SHOW_MORE_LESS_FILTERS)); + And( + "I apply mocked Person Id filter on Event directory page", + () -> + webDriverHelpers.fillAndSubmitInWebElement( + PERSON_ID_NAME_CONTACT_INFORMATION_LIKE_INPUT, "TestName TestSurname")); + And( + "I filter by mocked EventId on Event directory page", + () -> { + String partialUuid = + dataOperations.getPartialUuidFromAssociatedLink( + "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"); + webDriverHelpers.fillAndSubmitInWebElement(SEARCH_EVENT_BY_FREE_TEXT, partialUuid); + }); + And( + "I filter by mocked EventGroupId on Event directory page", + () -> + webDriverHelpers.fillAndSubmitInWebElement(EVENT_GROUP, "TestName TestSurname") + ); When( "I select random Risk level filter among the filter options from API", () -> { @@ -71,6 +152,32 @@ public EventDirectorySteps( webDriverHelpers.selectFromCombobox( FILTER_BY_RISK_LEVEL, RiskLevelValues.getCaptionForName(riskLevel)); }); + When( + "I fill Reporting User filter to {string} on Event Directory Page", + (String reportingUser) -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox(FILTER_BY_REPORTING_USER, reportingUser); + }); + And( + "I apply Region filter to {string} on Event directory page", + (String region) -> + webDriverHelpers.selectFromCombobox(CASE_REGION_FILTER_COMBOBOX, region)); + And( + "I apply District filter to {string} on Event directory page", + (String district) -> + webDriverHelpers.selectFromCombobox(CASE_DISTRICT_FILTER_COMBOBOX, district)); + And( + "I apply Event Management Status filter to {string} on Event directory page", + (String managementStatus) -> + webDriverHelpers.selectFromCombobox(EVENT_MANAGEMENT_FILTER, managementStatus)); + And( + "I apply Event Investigation Status filter to {string} on Event directory page", + (String investigationStatus) -> + webDriverHelpers.selectFromCombobox(EVENT_INVESTIGATION_STATUS, investigationStatus)); + Then( + "I apply Community filter to {string} on Event directory page", + (String community) -> + webDriverHelpers.selectFromCombobox(CASE_COMMUNITY_FILTER_COMBOBOX, community)); When( "I select random Risk level filter among the filter options", @@ -250,9 +357,8 @@ public EventDirectorySteps( When( "I click on the created event participant from the list", - () -> { - webDriverHelpers.clickOnWebElementBySelector(CREATED_PARTICIPANT); - }); + () -> + webDriverHelpers.clickOnWebElementBySelector(CREATED_PARTICIPANT)); When( "I click on New Task from event tab", @@ -266,15 +372,15 @@ public EventDirectorySteps( "I click Create Case for Event Participant", () -> webDriverHelpers.clickOnWebElementBySelector(CREATE_CASE_BUTTON)); - Then( - "I check that number of displayed Event results is {int}", - (Integer number) -> - assertHelpers.assertWithPoll20Second( - () -> - Assert.assertEquals( - webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), - number.intValue(), - "Number of displayed cases is not correct"))); + Then( + "I check that number of displayed Event results is {int}", + (Integer number) -> + assertHelpers.assertWithPoll20Second( + () -> + Assert.assertEquals( + webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), + number.intValue(), + "Number of displayed cases is not correct"))); Then( "I check the number of displayed Event results from All button is {int}", diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/EventFilters.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/EventFilters.feature new file mode 100644 index 00000000000..f312fd69744 --- /dev/null +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/EventFilters.feature @@ -0,0 +1,132 @@ +@UI @Sanity @Event @UI +Feature: Filters in Event Directory + + @issue=SORDEV-5915 + Scenario: Check all filters are working properly in Event directory + Given API: I create a new event + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + When I log in with National User + And I click on the Events button from navbar + Then I select random Risk level filter among the filter options from API + And I fill EVENT ID filter by API + And I apply on the APPLY FILTERS button from Event + And I check that number of displayed Event results is 1 + Then I select random Risk level filter among the filter options + And I apply on the APPLY FILTERS button from Event + And I check that number of displayed Event results is 0 + And I click on the RESET FILTERS button from Event + Then I select random Disease filter among the filter options from API + And I fill EVENT ID filter by API + And I apply on the APPLY FILTERS button from Event + And I check that number of displayed Event results is 1 + Then I select random Disease filter among the filter options + And I apply on the APPLY FILTERS button from Event + And I check that number of displayed Event results is 0 + And I click on the RESET FILTERS button from Event + Then I click on Show more filters in Events + Then I select Source Type among the filter options from API + And I fill EVENT ID filter by API + And I apply on the APPLY FILTERS button from Event + And I check that number of displayed Event results is 1 + Then I select random Source Type among the filter options + And I apply on the APPLY FILTERS button from Event + And I check the number of displayed Event results from All button is 0 + And I click on the RESET FILTERS button from Event + Then I click on Show more filters in Events + Then I select Type of Place field among the filter options from API + And I fill EVENT ID filter by API + And I apply on the APPLY FILTERS button from Event + And I check that number of displayed Event results is 1 + Then I select random Type of Place field among the filter options + And I apply on the APPLY FILTERS button from Event + And I check the number of displayed Event results from All button is 0 + And I click on the RESET FILTERS button from Event + + @issue=SORQA-77 + Scenario: Filters in Event Directory + Given API: I create a new person + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + When API: I create a new event + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + When I log in with National User + And I click on the Events button from navbar + And I open the last created event via api + And I add a participant to the event + And I open the last created event via api + And I click on link event group + And I create a new event group + And I click on the Events button from navbar + And I fill EVENT ID filter by API + And I fill Event Group Id filter to one assigned to created event on Event Directory Page + And I fill Reporting User filter to "ReST User" on Event Directory Page + And I click SHOW MORE FILTERS button on Event directory page + And I apply Region filter to "Voreingestellte Bundesländer" on Event directory page + And I apply District filter to "Voreingestellter Landkreis" on Event directory page + And I apply Community filter to "Voreingestellte Gemeinde" on Event directory page + And I apply Event Investigation Status filter to "Investigation pending" on Event directory page + And I apply Event Management Status filter to "Ongoing" on Event directory page + And I apply on the APPLY FILTERS button from Event + And I check the number of displayed Event results from All button is 1 + And I filter by mocked EventId on Event directory page + And I apply on the APPLY FILTERS button from Event + And I check the number of displayed Event results from All button is 0 + And I fill EVENT ID filter by API + And I filter by mocked EventGroupId on Event directory page + And I apply on the APPLY FILTERS button from Event + And I check the number of displayed Event results from All button is 0 + And I fill Event Group Id filter to one assigned to created event on Event Directory Page + And I fill Reporting User filter to "Surveillance Supervisor" on Event Directory Page + And I apply on the APPLY FILTERS button from Event + And I check the number of displayed Event results from All button is 0 + And I fill Reporting User filter to "ReST User" on Event Directory Page + And I apply Region filter to "Bayern" on Event directory page + And I apply on the APPLY FILTERS button from Event + And I check the number of displayed Event results from All button is 0 + And I apply Region filter to "Voreingestellte Bundesländer" on Event directory page + And I apply District filter to "Voreingestellter Landkreis" on Event directory page + And I apply Community filter to "Voreingestellte Gemeinde" on Event directory page + And I apply Event Investigation Status filter to "Investigation done" on Event directory page + And I apply on the APPLY FILTERS button from Event + And I check the number of displayed Event results from All button is 0 + And I apply Event Investigation Status filter to "Investigation pending" on Event directory page + And I apply Event Management Status filter to "Done" on Event directory page + And I apply on the APPLY FILTERS button from Event + And I check the number of displayed Event results from All button is 0 + + @issue=SORQA-77 + Scenario: Date filters and aggregation buttons in Event Directory + Given API: I create a new event + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + When I log in with National User + And I click on the Events button from navbar + And I fill EVENT ID filter by API + And I click SHOW MORE FILTERS button on Event directory page + And I apply Date type filter to "Report date" on Event directory page + And I fill Event from input to 2 days before mocked Event created on Event directory page + And I fill Event to input to 5 days after mocked Event created on Event directory page + And I apply on the APPLY FILTERS button from Event + And I check the number of displayed Event results from All button is 1 + And I fill Event from input to 2 days after before mocked Event created on Event directory page + And I apply on the APPLY FILTERS button from Event + And I check the number of displayed Event results from All button is 0 + And I fill Event from input to 2 days before mocked Event created on Event directory page + And I apply on the APPLY FILTERS button from Event + Then I select Signal filter from quick filter + And I check the number of displayed Event results from All button is 1 + And I select Event filter from quick filter + And I check the number of displayed Event results from All button is 0 + And I select Screening filter from quick filter + And I check the number of displayed Event results from All button is 0 + And I select Cluster filter from quick filter + And I check the number of displayed Event results from All button is 0 + And I select Dropped filter from quick filter + And I check the number of displayed Event results from All button is 0 + Then I select Signal filter from quick filter + And I check the number of displayed Event results from All button is 1 + And I apply "Archived events" to combobox on Event Directory Page + And I check the number of displayed Event results from All button is 0 + From ab119a4742b65c81439be28f50b9cf9809e28177 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Tue, 22 Feb 2022 17:06:36 +0100 Subject: [PATCH 145/253] refactor --- .../features/sanity/web/Event.feature | 48 ------------------- 1 file changed, 48 deletions(-) diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature index c413a304440..11fd033dc24 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature @@ -187,54 +187,6 @@ Feature: Create events And I fill all fields for a new case created for event participant And I click on save case button - @issue=SORDEV-5915 - Scenario: Check all filters are work properly in Event directory - Given API: I create a new event - Then API: I check that POST call body is "OK" - And API: I check that POST call status code is 200 - When I log in with National User - And I click on the Events button from navbar - Then I select random Risk level filter among the filter options from API - And I fill EVENT ID filter by API - And I apply on the APPLY FILTERS button from Event - And I check that number of displayed Event results is 1 - Then I select random Risk level filter among the filter options - And I apply on the APPLY FILTERS button from Event - And I check that number of displayed Event results is 0 - And I click on the RESET FILTERS button from Event - Then I select random Disease filter among the filter options from API - And I fill EVENT ID filter by API - And I apply on the APPLY FILTERS button from Event - And I check that number of displayed Event results is 1 - Then I select random Disease filter among the filter options - And I apply on the APPLY FILTERS button from Event - And I check that number of displayed Event results is 0 - And I click on the RESET FILTERS button from Event - Then I click on Show more filters in Events - Then I select Source Type among the filter options from API - And I fill EVENT ID filter by API - And I apply on the APPLY FILTERS button from Event - And I check that number of displayed Event results is 1 - Then I select random Source Type among the filter options - And I apply on the APPLY FILTERS button from Event - And I check that number of displayed Event results is 0 - And I click on the RESET FILTERS button from Event - Then I click on Show more filters in Events - Then I select Type of Place field among the filter options from API - And I fill EVENT ID filter by API - And I apply on the APPLY FILTERS button from Event - And I check that number of displayed Event results is 1 - Then I select random Type of Place field among the filter options - And I apply on the APPLY FILTERS button from Event - And I check that number of displayed Event results is 0 - And I click on the RESET FILTERS button from Event - Then I select Signal filter from quick filter - And I select Event filter from quick filter - And I select Screening filter from quick filter - And I select Cluster filter from quick filter - And I select Dropped filter from quick filter - And I click on the RESET FILTERS button - @issue=SORDEV-5570 Scenario: Testing Event screen Impact Given API: I create a new event From b98b98420c5fc39b36c50203a5d622100f356ab8 Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Tue, 22 Feb 2022 18:34:34 +0200 Subject: [PATCH 146/253] #6934-Update-Framework-To-Multiple-Environments : removed paths from scripts --- sormas-e2e-tests/scripts/runCreatePerformanceData.sh | 2 +- sormas-e2e-tests/scripts/runPagesMeasurements.sh | 2 +- sormas-e2e-tests/scripts/runTests.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sormas-e2e-tests/scripts/runCreatePerformanceData.sh b/sormas-e2e-tests/scripts/runCreatePerformanceData.sh index 64d04820868..0455925c3a7 100644 --- a/sormas-e2e-tests/scripts/runCreatePerformanceData.sh +++ b/sormas-e2e-tests/scripts/runCreatePerformanceData.sh @@ -32,7 +32,7 @@ for ((i = 1; i <= $1; ++i)); do echo "Run: $i " echo "Started at:" date +"%T" - ./gradlew startTests -Dcucumber.tags="@PersonsAndImmunizations" -Dheadless=true -Dcourgette.threads=9 -DenvConfig=........./data.json + ./gradlew startTests -Dcucumber.tags="@PersonsAndImmunizations" -Dheadless=true -Dcourgette.threads=9 -DenvConfig= echo "Finished at:" date +"%T" done diff --git a/sormas-e2e-tests/scripts/runPagesMeasurements.sh b/sormas-e2e-tests/scripts/runPagesMeasurements.sh index 3b44a206dab..7ef513953b8 100644 --- a/sormas-e2e-tests/scripts/runPagesMeasurements.sh +++ b/sormas-e2e-tests/scripts/runPagesMeasurements.sh @@ -33,4 +33,4 @@ cat /dev/null > ./customReports/data/results.txt echo "Executing gradle clean..." ./gradlew clean goJF echo "Starting all BDD tests under @PagesMeasurements tag..." -./gradlew startTests -Dcucumber.tags="@PagesMeasurements" -Dheadless=true -Dcourgette.threads=9 -DenvConfig=........../data.json \ No newline at end of file +./gradlew startTests -Dcucumber.tags="@PagesMeasurements" -Dheadless=true -Dcourgette.threads=9 -DenvConfig= \ No newline at end of file diff --git a/sormas-e2e-tests/scripts/runTests.sh b/sormas-e2e-tests/scripts/runTests.sh index 526c706daf4..e3e7f3b15ab 100644 --- a/sormas-e2e-tests/scripts/runTests.sh +++ b/sormas-e2e-tests/scripts/runTests.sh @@ -25,7 +25,7 @@ rm -rf ./allureReports echo "Executing gradle clean..." ./gradlew clean goJF echo "Starting all BDD tests under @$1 tag..." -./gradlew startTests -Dcucumber.tags=\"@$1\" -Dheadless=true -Dcourgette.threads=9 -DenvConfig=C:/Users/Zack/Desktop/envData.json +./gradlew startTests -Dcucumber.tags=\"@$1\" -Dheadless=true -Dcourgette.threads=9 -DenvConfig= echo "Deleting test downloads folder..." rm -rf ./downloads From 7425505eb74ff8d4a0fb3ccd3430c467eb88327b Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Tue, 22 Feb 2022 17:55:01 +0100 Subject: [PATCH 147/253] removed redundant step --- .../web/application/events/EventDirectorySteps.java | 11 ++--------- .../features/sanity/web/EventFilters.feature | 4 ++-- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index a7cc1e36a84..5020bbc9f76 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -26,7 +26,6 @@ import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.DATE_FROM_COMBOBOX; import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.DATE_TO_COMBOBOX; import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.PERSON_ID_NAME_CONTACT_INFORMATION_LIKE_INPUT; -import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.SHOW_MORE_LESS_FILTERS; import static org.sormas.e2etests.pages.application.events.EditEventPage.*; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.*; import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.APPLY_FILTERS_BUTTON; @@ -123,9 +122,6 @@ public EventDirectorySteps( DATE_FROM_COMBOBOX, formatter.format(LocalDate.now().plusDays(number))); }); - And( - "I click SHOW MORE FILTERS button on Event directory page", - () -> webDriverHelpers.clickOnWebElementBySelector(SHOW_MORE_LESS_FILTERS)); And( "I apply mocked Person Id filter on Event directory page", () -> @@ -141,9 +137,7 @@ public EventDirectorySteps( }); And( "I filter by mocked EventGroupId on Event directory page", - () -> - webDriverHelpers.fillAndSubmitInWebElement(EVENT_GROUP, "TestName TestSurname") - ); + () -> webDriverHelpers.fillAndSubmitInWebElement(EVENT_GROUP, "TestName TestSurname")); When( "I select random Risk level filter among the filter options from API", () -> { @@ -357,8 +351,7 @@ public EventDirectorySteps( When( "I click on the created event participant from the list", - () -> - webDriverHelpers.clickOnWebElementBySelector(CREATED_PARTICIPANT)); + () -> webDriverHelpers.clickOnWebElementBySelector(CREATED_PARTICIPANT)); When( "I click on New Task from event tab", diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/EventFilters.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/EventFilters.feature index f312fd69744..1d88e2240f4 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/EventFilters.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/EventFilters.feature @@ -62,7 +62,7 @@ Feature: Filters in Event Directory And I fill EVENT ID filter by API And I fill Event Group Id filter to one assigned to created event on Event Directory Page And I fill Reporting User filter to "ReST User" on Event Directory Page - And I click SHOW MORE FILTERS button on Event directory page + And I click on Show more filters in Events And I apply Region filter to "Voreingestellte Bundesländer" on Event directory page And I apply District filter to "Voreingestellter Landkreis" on Event directory page And I apply Community filter to "Voreingestellte Gemeinde" on Event directory page @@ -104,7 +104,7 @@ Feature: Filters in Event Directory When I log in with National User And I click on the Events button from navbar And I fill EVENT ID filter by API - And I click SHOW MORE FILTERS button on Event directory page + And I click on Show more filters in Events And I apply Date type filter to "Report date" on Event directory page And I fill Event from input to 2 days before mocked Event created on Event directory page And I fill Event to input to 5 days after mocked Event created on Event directory page From 1bd79d1ed0d562754bfa99abe192644dd7bc143f Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Tue, 22 Feb 2022 20:08:52 +0200 Subject: [PATCH 148/253] #6879 - fix test --- .../androidTest/java/de/symeda/sormas/app/CaseBackendTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/CaseBackendTest.java b/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/CaseBackendTest.java index 63180339285..741b2e19ddf 100644 --- a/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/CaseBackendTest.java +++ b/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/CaseBackendTest.java @@ -153,7 +153,6 @@ public void shouldMergeAsExpected() throws DaoException { mergeCase.getClinicalCourse().setId(null); mergeCase.getPortHealthInfo().setId(null); mergeCase.getTherapy().setId(null); - mergeCase.getClinicalCourse().getHealthConditions().setId(null); mergeCase.getHealthConditions().setId(null); mergeCase.getMaternalHistory().setId(null); @@ -254,7 +253,6 @@ public void shouldCreateSyncLogEntry() throws DaoException { mergeCase.getClinicalCourse().setId(null); mergeCase.getPortHealthInfo().setId(null); mergeCase.getTherapy().setId(null); - mergeCase.getClinicalCourse().getHealthConditions().setId(null); mergeCase.getHealthConditions().setId(null); mergeCase.getMaternalHistory().setId(null); mergeCase.setEpidNumber("ServerEpidNumber"); From c94e93e3d2278e51fd54b709d37f0574778f5add Mon Sep 17 00:00:00 2001 From: Frank Hautpmann Date: Wed, 23 Feb 2022 09:48:04 +0100 Subject: [PATCH 149/253] New Crowdin updates (#8083) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * New translations validations.properties (Czech) * New translations strings.properties (Dari) * New translations strings.properties (Pashto) * New translations strings.properties (Spanish, Cuba) * New translations strings.properties (English, Afghanistan) * New translations strings.properties (English, Nigeria) * New translations strings.properties (English, Ghana) * New translations validations.properties (Romanian) * New translations validations.properties (French) * New translations validations.properties (Spanish) * New translations validations.properties (German) * New translations strings.properties (French, Switzerland) * New translations validations.properties (Finnish) * New translations validations.properties (Italian) * New translations validations.properties (Japanese) * New translations validations.properties (Dutch) * New translations validations.properties (Norwegian) * New translations validations.properties (Polish) * New translations validations.properties (Portuguese) * New translations validations.properties (Russian) * New translations validations.properties (Swedish) * New translations validations.properties (Turkish) * New translations strings.properties (Italian, Switzerland) * New translations strings.properties (German, Switzerland) * New translations strings.properties (German) * New translations strings.properties (Portuguese) * New translations validations.properties (Urdu (Pakistan)) * New translations strings.properties (Romanian) * New translations strings.properties (Spanish) * New translations strings.properties (Czech) * New translations strings.properties (Finnish) * New translations strings.properties (Italian) * New translations strings.properties (Japanese) * New translations strings.properties (Dutch) * New translations strings.properties (Norwegian) * New translations strings.properties (Polish) * New translations strings.properties (Russian) * New translations strings.properties (Swahili) * New translations strings.properties (Swedish) * New translations strings.properties (Turkish) * New translations strings.properties (Ukrainian) * New translations strings.properties (Chinese Simplified) * New translations strings.properties (Urdu (Pakistan)) * New translations strings.properties (Spanish, Ecuador) * New translations strings.properties (Croatian) * New translations strings.properties (Hindi) * New translations strings.properties (Filipino) * New translations strings.properties (Fijian) * New translations validations.properties (Ukrainian) * New translations validations.properties (Chinese Simplified) * New translations validations.properties (Spanish, Ecuador) * New translations validations.properties (Croatian) * New translations validations.properties (Hindi) * New translations validations.properties (Filipino) * New translations validations.properties (Fijian) * New translations validations.properties (Swahili) * New translations validations.properties (German, Switzerland) * New translations validations.properties (French, Switzerland) * New translations validations.properties (Italian, Switzerland) * New translations validations.properties (Dari) * New translations validations.properties (Pashto) * New translations validations.properties (Spanish, Cuba) * New translations validations.properties (English, Afghanistan) * New translations validations.properties (English, Nigeria) * New translations validations.properties (English, Ghana) * New translations strings.properties (French) * New translations enum.properties (French) * New translations strings.properties (German, Switzerland) * New translations strings.properties (Spanish, Cuba) * New translations captions.properties (Norwegian) * New translations captions.properties (Romanian) * New translations captions.properties (French) * New translations captions.properties (Spanish) * New translations captions.properties (Czech) * New translations captions.properties (Finnish) * New translations captions.properties (Italian) * New translations captions.properties (Japanese) * New translations captions.properties (Dutch) * New translations captions.properties (German) * New translations captions.properties (Dari) * New translations captions.properties (German, Switzerland) * New translations captions.properties (French, Switzerland) * New translations captions.properties (Italian, Switzerland) * New translations captions.properties (Urdu (Pakistan)) * New translations captions.properties (Pashto) * New translations captions.properties (Spanish, Cuba) * New translations captions.properties (English, Afghanistan) * New translations captions.properties (English, Nigeria) * New translations captions.properties (Fijian) * New translations captions.properties (Swahili) * New translations captions.properties (Ukrainian) * New translations captions.properties (Filipino) * New translations captions.properties (Hindi) * New translations captions.properties (Croatian) * New translations captions.properties (Spanish, Ecuador) * New translations captions.properties (Chinese Simplified) * New translations captions.properties (Turkish) * New translations captions.properties (Swedish) * New translations captions.properties (Russian) * New translations captions.properties (Portuguese) * New translations captions.properties (Polish) * New translations captions.properties (English, Ghana) * New translations captions.properties (Urdu (Pakistan)) * New translations captions.properties (German) * New translations captions.properties (Czech) * New translations captions.properties (German, Switzerland) * New translations captions.properties (Spanish, Cuba) * New translations enum.properties (French) * New translations enum.properties (Urdu (Pakistan)) * New translations enum.properties (English, Nigeria) * New translations enum.properties (English, Afghanistan) * New translations enum.properties (Spanish, Cuba) * New translations enum.properties (Pashto) * New translations enum.properties (Dari) * New translations enum.properties (Italian, Switzerland) * New translations enum.properties (French, Switzerland) * New translations enum.properties (German, Switzerland) * New translations enum.properties (Swahili) * New translations enum.properties (Fijian) * New translations enum.properties (Filipino) * New translations enum.properties (Hindi) * New translations enum.properties (Croatian) * New translations enum.properties (Spanish, Ecuador) * New translations enum.properties (Chinese Simplified) * New translations enum.properties (German) * New translations enum.properties (Ukrainian) * New translations enum.properties (Turkish) * New translations enum.properties (Swedish) * New translations enum.properties (Russian) * New translations enum.properties (Portuguese) * New translations enum.properties (Polish) * New translations enum.properties (Norwegian) * New translations enum.properties (Dutch) * New translations enum.properties (Japanese) * New translations enum.properties (Italian) * New translations enum.properties (Finnish) * New translations enum.properties (Czech) * New translations enum.properties (Spanish) * New translations enum.properties (Romanian) * New translations enum.properties (English, Ghana) * New translations strings.properties (French) * New translations strings.properties (Pashto) * New translations strings.properties (Filipino) * New translations strings.properties (Fijian) * New translations strings.properties (Swahili) * New translations strings.properties (German, Switzerland) * New translations strings.properties (French, Switzerland) * New translations strings.properties (Italian, Switzerland) * New translations strings.properties (Dari) * New translations strings.properties (Spanish, Cuba) * New translations strings.properties (Croatian) * New translations strings.properties (English, Afghanistan) * New translations strings.properties (English, Nigeria) * New translations strings.properties (English, Ghana) * New translations captions.properties (Czech) * New translations validations.properties (Czech) * New translations enum.properties (Czech) * New translations enum.properties (Urdu (Pakistan)) * New translations strings.properties (Hindi) * New translations strings.properties (Spanish, Ecuador) * New translations strings.properties (German) * New translations strings.properties (Japanese) * New translations enum.properties (French) * New translations enum.properties (German) * New translations strings.properties (Romanian) * New translations strings.properties (Spanish) * New translations strings.properties (Czech) * New translations strings.properties (Finnish) * New translations strings.properties (Italian) * New translations strings.properties (Dutch) * New translations strings.properties (Urdu (Pakistan)) * New translations strings.properties (Norwegian) * New translations strings.properties (Polish) * New translations strings.properties (Portuguese) * New translations strings.properties (Russian) * New translations strings.properties (Swedish) * New translations strings.properties (Turkish) * New translations strings.properties (Ukrainian) * New translations strings.properties (Chinese Simplified) * New translations enum.properties (German, Switzerland) * New translations strings.properties (French) * New translations enum.properties (Spanish) * New translations strings.properties (Italian, Switzerland) * New translations strings.properties (Dari) * New translations strings.properties (Pashto) * New translations strings.properties (Spanish, Cuba) * New translations strings.properties (English, Afghanistan) * New translations strings.properties (English, Nigeria) * New translations strings.properties (English, Ghana) * New translations captions.properties (German) * New translations enum.properties (Romanian) * New translations enum.properties (Czech) * New translations strings.properties (German, Switzerland) * New translations enum.properties (Finnish) * New translations enum.properties (Italian) * New translations enum.properties (Japanese) * New translations enum.properties (Dutch) * New translations enum.properties (Norwegian) * New translations enum.properties (Polish) * New translations enum.properties (Portuguese) * New translations enum.properties (Russian) * New translations enum.properties (Swedish) * New translations enum.properties (Turkish) * New translations strings.properties (French, Switzerland) * New translations strings.properties (Swahili) * New translations strings.properties (German) * New translations strings.properties (Polish) * New translations enum.properties (French) * New translations enum.properties (German) * New translations strings.properties (Romanian) * New translations strings.properties (Spanish) * New translations strings.properties (Czech) * New translations strings.properties (Finnish) * New translations strings.properties (Italian) * New translations strings.properties (Japanese) * New translations strings.properties (Dutch) * New translations strings.properties (Norwegian) * New translations strings.properties (Portuguese) * New translations strings.properties (Fijian) * New translations strings.properties (Russian) * New translations strings.properties (Swedish) * New translations strings.properties (Turkish) * New translations strings.properties (Ukrainian) * New translations strings.properties (Chinese Simplified) * New translations strings.properties (Urdu (Pakistan)) * New translations strings.properties (Spanish, Ecuador) * New translations strings.properties (Croatian) * New translations strings.properties (Hindi) * New translations strings.properties (Filipino) * New translations enum.properties (Ukrainian) * New translations enum.properties (Chinese Simplified) * New translations enum.properties (French, Switzerland) * New translations enum.properties (English, Nigeria) * New translations enum.properties (English, Afghanistan) * New translations enum.properties (Spanish, Cuba) * New translations enum.properties (Pashto) * New translations enum.properties (Dari) * New translations enum.properties (Italian, Switzerland) * New translations enum.properties (German, Switzerland) * New translations enum.properties (Urdu (Pakistan)) * New translations enum.properties (Swahili) * New translations enum.properties (Fijian) * New translations enum.properties (Filipino) * New translations enum.properties (Hindi) * New translations enum.properties (Croatian) * New translations enum.properties (Spanish, Ecuador) * New translations enum.properties (English, Ghana) Co-authored-by: Maté Strysewske --- .../main/resources/captions_cs-CZ.properties | 34 +++++++++---------- .../main/resources/captions_de-DE.properties | 6 ++-- .../src/main/resources/enum_cs-CZ.properties | 7 ++-- .../src/main/resources/enum_de-CH.properties | 15 ++++---- .../src/main/resources/enum_de-DE.properties | 15 ++++---- .../src/main/resources/enum_en-AF.properties | 1 - .../src/main/resources/enum_en-GH.properties | 1 - .../src/main/resources/enum_en-NG.properties | 1 - .../src/main/resources/enum_es-CU.properties | 15 ++++---- .../src/main/resources/enum_es-EC.properties | 1 - .../src/main/resources/enum_es-ES.properties | 1 - .../src/main/resources/enum_fa-AF.properties | 1 - .../src/main/resources/enum_fi-FI.properties | 1 - .../src/main/resources/enum_fil-PH.properties | 1 - .../src/main/resources/enum_fj-FJ.properties | 1 - .../src/main/resources/enum_fr-CH.properties | 1 - .../src/main/resources/enum_fr-FR.properties | 15 ++++---- .../src/main/resources/enum_hi-IN.properties | 1 - .../src/main/resources/enum_hr-HR.properties | 1 - .../src/main/resources/enum_it-CH.properties | 1 - .../src/main/resources/enum_it-IT.properties | 1 - .../src/main/resources/enum_ja-JP.properties | 1 - .../src/main/resources/enum_nl-NL.properties | 1 - .../src/main/resources/enum_no-NO.properties | 1 - .../src/main/resources/enum_pl-PL.properties | 1 - .../src/main/resources/enum_ps-AF.properties | 1 - .../src/main/resources/enum_pt-PT.properties | 1 - .../src/main/resources/enum_ro-RO.properties | 1 - .../src/main/resources/enum_ru-RU.properties | 1 - .../src/main/resources/enum_sv-SE.properties | 1 - .../src/main/resources/enum_sw-KE.properties | 1 - .../src/main/resources/enum_tr-TR.properties | 1 - .../src/main/resources/enum_uk-UA.properties | 1 - .../src/main/resources/enum_ur-PK.properties | 15 ++++---- .../src/main/resources/enum_zh-CN.properties | 1 - .../main/resources/strings_cs-CZ.properties | 28 +++++++++------ .../main/resources/strings_de-CH.properties | 16 ++++++--- .../main/resources/strings_de-DE.properties | 16 ++++++--- .../main/resources/strings_en-AF.properties | 16 ++++++--- .../main/resources/strings_en-GH.properties | 16 ++++++--- .../main/resources/strings_en-NG.properties | 16 ++++++--- .../main/resources/strings_es-CU.properties | 16 ++++++--- .../main/resources/strings_es-EC.properties | 16 ++++++--- .../main/resources/strings_es-ES.properties | 16 ++++++--- .../main/resources/strings_fa-AF.properties | 16 ++++++--- .../main/resources/strings_fi-FI.properties | 16 ++++++--- .../main/resources/strings_fil-PH.properties | 16 ++++++--- .../main/resources/strings_fj-FJ.properties | 16 ++++++--- .../main/resources/strings_fr-CH.properties | 16 ++++++--- .../main/resources/strings_fr-FR.properties | 16 ++++++--- .../main/resources/strings_hi-IN.properties | 16 ++++++--- .../main/resources/strings_hr-HR.properties | 16 ++++++--- .../main/resources/strings_it-CH.properties | 16 ++++++--- .../main/resources/strings_it-IT.properties | 16 ++++++--- .../main/resources/strings_ja-JP.properties | 16 ++++++--- .../main/resources/strings_nl-NL.properties | 16 ++++++--- .../main/resources/strings_no-NO.properties | 16 ++++++--- .../main/resources/strings_pl-PL.properties | 16 ++++++--- .../main/resources/strings_ps-AF.properties | 16 ++++++--- .../main/resources/strings_pt-PT.properties | 16 ++++++--- .../main/resources/strings_ro-RO.properties | 16 ++++++--- .../main/resources/strings_ru-RU.properties | 16 ++++++--- .../main/resources/strings_sv-SE.properties | 16 ++++++--- .../main/resources/strings_sw-KE.properties | 16 ++++++--- .../main/resources/strings_tr-TR.properties | 16 ++++++--- .../main/resources/strings_uk-UA.properties | 16 ++++++--- .../main/resources/strings_ur-PK.properties | 16 ++++++--- .../main/resources/strings_zh-CN.properties | 16 ++++++--- .../resources/validations_cs-CZ.properties | 2 +- 69 files changed, 428 insertions(+), 263 deletions(-) diff --git a/sormas-api/src/main/resources/captions_cs-CZ.properties b/sormas-api/src/main/resources/captions_cs-CZ.properties index 417dd9f63c7..23d095bae83 100644 --- a/sormas-api/src/main/resources/captions_cs-CZ.properties +++ b/sormas-api/src/main/resources/captions_cs-CZ.properties @@ -1351,7 +1351,7 @@ Facility.CONFIGURED_FACILITY=Konfigurované zařízení Facility.NO_FACILITY=Domov nebo jiné místo Facility.OTHER_FACILITY=Ostatní zařízení -Facility=Facility +Facility=Zařízení Facility.additionalInformation=Další informace Facility.archived=Archivováno Facility.areaType=Typ oblasti (městská/venkov) @@ -1409,10 +1409,10 @@ HealthConditions.otherConditions=Další relevantní již existující podmínky HealthConditions.immunodeficiencyOtherThanHiv=Selhání imunity jiné než HIV HealthConditions.cardiovascularDiseaseIncludingHypertension=Kardiovaskulární onemocnění včetně hypertenze HealthConditions.obesity=Obezita -HealthConditions.currentSmoker=Current smoker -HealthConditions.formerSmoker=Former smoker +HealthConditions.currentSmoker=Aktivní kuřák +HealthConditions.formerSmoker=Bývalý kuřák HealthConditions.asthma=Astma -HealthConditions.sickleCellDisease=Sickle cell disease +HealthConditions.sickleCellDisease=Srpkovitá anémie HealthConditions.immunodeficiencyIncludingHiv=Selhání imunity včetně HIV # Import @@ -1469,7 +1469,7 @@ LabMessage.assignee=Přiřazený labMessageFetch=Načíst zprávy laboratoře labMessageProcess=Proces -labMessageNoDisease=No tested disease found +labMessageNoDisease=Nenalezena žádná testovaná nákaza labMessageNoNewMessages=Žádné nové zprávy nejsou k dispozici labMessageForwardedMessageFound=Byla nalezena související přeposlaná zpráva (zprávy) labMessageLabMessagesList=Seznam zpráv laboratoře @@ -1724,7 +1724,7 @@ personContactDetailOwnerName = Jméno vlastníka personContactDetailThisPerson = Tato osoba personContactDetailThirdParty = Shromažďovat kontaktní údaje jiné osoby nebo zařízení -PersonContactDetail = Person contact detail +PersonContactDetail = Detail kontaktu osoby PersonContactDetail.person = Osoba PersonContactDetail.primaryContact = Hlavní kontaktní údaje PersonContactDetail.personContactDetailType = Typ kontaktních údajů @@ -1745,7 +1745,7 @@ PointOfEntry.OTHER_SEAPORT=Ostatní námořní přístav PointOfEntry.OTHER_GROUND_CROSSING=Ostatní pozemní přejezdy PointOfEntry.OTHER_POE=Ostatní vstupní místo -PointOfEntry=Point of entry +PointOfEntry=Místo vstupu PointOfEntry.pointOfEntryType=Typ vstupního místa PointOfEntry.active=Aktivní? PointOfEntry.latitude=Zeměpisná šířka @@ -1783,7 +1783,7 @@ PortHealthInfo.details=Údaje o vstupním místě # Prescription prescriptionNewPrescription=Nový předpis -Prescription=Prescription +Prescription=Předpis Prescription.additionalNotes=Doplňkové poznámky Prescription.dose=Dávka Prescription.drugIntakeDetails=Název léku @@ -1808,7 +1808,7 @@ continentActiveContinents=Aktivní kontinenty continentArchivedContinents=Archivované kontinenty continentAllContinents=Všechny kontinenty -Continent=Continent +Continent=Kontinent Continent.archived=Archivováno Continent.externalId=Externí ID Continent.defaultName=Výchozí název @@ -1819,7 +1819,7 @@ subcontinentActiveSubcontinents=Aktivní subkontinenty subcontinentArchivedSubcontinents=Archivované subkontinenty subcontinentAllSubcontinents=Všechny subkontinenty -Subcontinent=Subcontinent +Subcontinent=Subkontinent Subcontinent.archived=Archivováno Subcontinent.externalId=Externí ID Subcontinent.defaultName=Výchozí název @@ -1831,7 +1831,7 @@ countryActiveCountries=Aktivní země countryArchivedCountries=Archivované země countryAllCountries=Všechny země -Country=Country +Country=Země Country.archived=Archivováno Country.externalId=Externí ID Country.defaultName=Výchozí název @@ -1845,7 +1845,7 @@ regionActiveRegions=Aktivní regiony regionArchivedRegions=Archivované regiony regionAllRegions=Všechny regiony -Region=Region +Region=Oblast Region.archived=Archivováno Region.epidCode=Epid kód Region.growthRate=Míra růstu @@ -2040,7 +2040,7 @@ Immunization.responsibleDistrict = Odpovědný okres Immunization.responsibleCommunity = Odpovědná komunita Immunization.immunizationPeriod = Doba imunizace immunizationImmunizationsList = Seznam imunizací -linkImmunizationToCaseButton=Link case +linkImmunizationToCaseButton=Odkaz na Případ openLinkedCaseToImmunizationButton = Otevřít případ immunizationNewImmunization = Nová imunizace immunizationKeepImmunization = Zachovat existující informace a zrušit novou imunizaci @@ -2299,7 +2299,7 @@ Task.taskPriority=Priorita úkolu Task.travelEntry=Travel entry # TestReport -TestReport=Test report +TestReport=Zkušební protokol TestReport.testDateTime=Datum a čas výsledku TestReport.testLabCity=Město laboratoře TestReport.testLabExternalId=Externí ID laboratoře @@ -2314,7 +2314,7 @@ travelEntryOnlyRecoveredEntries=Pouze obnovené položky travelEntryOnlyVaccinatedEntries=Pouze očkované položky travelEntryOnlyEntriesTestedNegative=Pouze negativně testované položky travelEntryOnlyEntriesConvertedToCase=Pouze položky převedeny na případ -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=Otevřít případ tohoto cestovního vstupu travelEntryActiveTravelEntries=Aktivní cestovní vstupy travelEntryArchivedTravelEntries=Archivované cestovní vstupy travelEntryAllTravelEntries=Všechny cestovní vstupy @@ -2365,7 +2365,7 @@ treatmentCreateTreatment=Vytvořit léčbu treatmentNewTreatment=Nová léčba treatmentOpenPrescription=Otevřít předpis -Treatment=Treatment +Treatment=Léčba Treatment.additionalNotes=Doplňkové poznámky Treatment.dose=Dávka Treatment.drugIntakeDetails=Název léku @@ -2638,7 +2638,7 @@ ExternalSurveillanceToolGateway.unableToSend=Nelze odeslat ExternalSurveillanceToolGateway.confirmSend=Potvrdit odeslání ExternalSurveillanceToolGateway.notTransferred=Dosud neodesláno do nástroje hlášení ExternalSurveillanceToolGateway.confirmDelete=Potvrdit odstranění -ExternalSurveillanceToolGateway.excludeAndSend=Send %d of %d +ExternalSurveillanceToolGateway.excludeAndSend=Poslat %d z %d patientDiaryRegistrationError=Nelze zaregistrovat osobu v deníku pacienta. patientDiaryCancelError=Nelze zrušit externí deník sledování diff --git a/sormas-api/src/main/resources/captions_de-DE.properties b/sormas-api/src/main/resources/captions_de-DE.properties index 35f93d4cabd..e3f3fdc92c9 100644 --- a/sormas-api/src/main/resources/captions_de-DE.properties +++ b/sormas-api/src/main/resources/captions_de-DE.properties @@ -142,8 +142,8 @@ actionPick=Auswählen actionDismiss=Abbrechen actionCompare=Vergleichen actionHide=Ausblenden -actionEnterBulkEditMode=Massenbearbeitungsmodus aktivieren -actionLeaveBulkEditMode=Massenbearbeitungsmodus deaktivieren +actionEnterBulkEditMode=Massenbearbeitung aktivieren +actionLeaveBulkEditMode=Massenbearbeitung deaktivieren actionDiscardChanges=Änderungen verwerfen actionSaveChanges=Änderungen speichern actionAdjustChanges=Änderungen anpassen @@ -1412,7 +1412,7 @@ HealthConditions.obesity=Adipositas HealthConditions.currentSmoker=Aktuell Raucher HealthConditions.formerSmoker=Ehemaliger Raucher HealthConditions.asthma=Asthma bronchiale -HealthConditions.sickleCellDisease=Sickle cell disease +HealthConditions.sickleCellDisease=Sichelzellenanämie HealthConditions.immunodeficiencyIncludingHiv=Immunschwäche, einschließlich HIV # Import diff --git a/sormas-api/src/main/resources/enum_cs-CZ.properties b/sormas-api/src/main/resources/enum_cs-CZ.properties index d43e8672a36..8069dabff37 100644 --- a/sormas-api/src/main/resources/enum_cs-CZ.properties +++ b/sormas-api/src/main/resources/enum_cs-CZ.properties @@ -797,12 +797,11 @@ MessageSubject.CASE_INVESTIGATION_DONE = Vyšetřování případů dokončeno MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Účastník události identifikován jako potvrzený případ %s MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Účastník události související s jinými událostmi MessageSubject.LAB_RESULT_ARRIVED = Výsledek laboratoře dorazil -MessageSubject.LAB_RESULT_SPECIFIED = Výsledek laboratoře zadán MessageSubject.LAB_SAMPLE_SHIPPED = Vzorek laboratoře dodán MessageSubject.CONTACT_SYMPTOMATIC = Kontakt se stal symptomatickým MessageSubject.TASK_START = Úkol byl spuštěn MessageSubject.TASK_DUE = Úkol po termínu -MessageSubject.TASK_UPDATED_ASSIGNEE = Updated task assignee +MessageSubject.TASK_UPDATED_ASSIGNEE = Aktualizovaná pověřená osoba úkolu MessageSubject.VISIT_COMPLETED = Následná návštěva dokončena MessageSubject.DISEASE_CHANGED = Nemoc případu se změnila MessageSubject.EVENT_GROUP_CREATED = Skupina událostí vytvořena @@ -1283,7 +1282,7 @@ UserRight.CONTACT_EDIT = Upravit existující kontakty UserRight.CONTACT_EXPORT = Exportovat kontakty ze SORMAS UserRight.CONTACT_SEE_ARCHIVED = Zobrazit archivované kontakty UserRight.CONTACT_VIEW = Zobrazit existující kontakty -UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Přístup k ovládacínu panelu kontaktního orgánu UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard UserRight.DATABASE_EXPORT_ACCESS = Exportovat celou databázi UserRight.EVENT_ARCHIVE = Archivovat události @@ -1415,7 +1414,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Exportovat data o ochraně údajů -UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_VIEW = Zobrazit ohniska # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Vyšetřování případů diff --git a/sormas-api/src/main/resources/enum_de-CH.properties b/sormas-api/src/main/resources/enum_de-CH.properties index 1eb86d076b3..a934850f52f 100644 --- a/sormas-api/src/main/resources/enum_de-CH.properties +++ b/sormas-api/src/main/resources/enum_de-CH.properties @@ -580,8 +580,8 @@ ExportGroupType.LOCATION = Ortsdaten ExportGroupType.EVENT = Ereignisdaten ExportGroupType.EVENT_GROUP = Ereignisgruppendaten ExportGroupType.EVENT_SOURCE = Ereignis-Quelldaten -ExportGroupType.CLINICAL_COURSE = Clinical Course Data -ExportGroupType.THERAPY = Therapy Data +ExportGroupType.CLINICAL_COURSE = Klinischer Verlauf Daten +ExportGroupType.THERAPY = Therapie Daten EventSourceType.NOT_APPLICABLE = Nicht zutreffend EventSourceType.MEDIA_NEWS = Medien/Neuigkeiten @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Falluntersuchung erledigt MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Ereignisteilnehmer als bestätigten Fall %s identifiziert MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Ereignisteilnehmer im Zusammenhang mit anderen Ereignissen MessageSubject.LAB_RESULT_ARRIVED = Laborergebnis angekommen -MessageSubject.LAB_RESULT_SPECIFIED = Laborergebnis angegeben MessageSubject.LAB_SAMPLE_SHIPPED = Laborprobe versendet MessageSubject.CONTACT_SYMPTOMATIC = Kontakt ist symptomatisch geworden MessageSubject.TASK_START = Zu startende Aufgabe @@ -1283,8 +1282,8 @@ UserRight.CONTACT_EDIT = Bestehende Kontakte bearbeiten UserRight.CONTACT_EXPORT = Kontakte von SORMAS exportieren UserRight.CONTACT_SEE_ARCHIVED = Archivierte Kontakte anzeigen UserRight.CONTACT_VIEW = Bestehende Kontakte anzeigen -UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Zugriff auf die Kontaktleitungs-Übersicht +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Zugriff auf die Überwachungsleitungs-Übersicht UserRight.DATABASE_EXPORT_ACCESS = Die gesamte Datenbank exportieren UserRight.EVENT_ARCHIVE = Ereignisse archivieren UserRight.EVENT_CREATE = Neue Ereignisse erstellen @@ -1354,8 +1353,8 @@ UserRight.INFRASTRUCTURE_EXPORT = Infrastrukturdaten von SORMAS exportieren UserRight.INFRASTRUCTURE_IMPORT = Infrastrukturdaten importieren UserRight.INFRASTRUCTURE_ARCHIVE = Infrastrukturdaten archivieren UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = Kontaktübertragungsketten auf dem Dashboard einsehen -UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard -UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Zugriff auf Kampagnen Dashboard +UserRight.CASE_CLINICIAN_VIEW = Zugriff auf Fall-Bereiche im Zusammenhang mit der Fallverwaltung UserRight.THERAPY_VIEW = Vorhandene Therapien einsehen UserRight.PRESCRIPTION_CREATE = Neue Verschreibungen erstellen UserRight.PRESCRIPTION_EDIT = Vorhandene Verschreibungen bearbeiten @@ -1415,7 +1414,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Vorhandene Einreisen bearbeiten UserRight.TRAVEL_ENTRY_DELETE = Einreisen aus dem System löschen UserRight.TRAVEL_ENTRY_ARCHIVE = Einreisen archivieren UserRight.EXPORT_DATA_PROTECTION_DATA = Datenschutz-Daten exportieren -UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_VIEW = Ausbrüche anzeigen # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Falluntersuchung diff --git a/sormas-api/src/main/resources/enum_de-DE.properties b/sormas-api/src/main/resources/enum_de-DE.properties index 2ae2235e8d8..dc0cf6df524 100644 --- a/sormas-api/src/main/resources/enum_de-DE.properties +++ b/sormas-api/src/main/resources/enum_de-DE.properties @@ -580,8 +580,8 @@ ExportGroupType.LOCATION = Ortsdaten ExportGroupType.EVENT = Ereignisdaten ExportGroupType.EVENT_GROUP = Ereignisgruppendaten ExportGroupType.EVENT_SOURCE = Ereignis-Quelldaten -ExportGroupType.CLINICAL_COURSE = Clinical Course Data -ExportGroupType.THERAPY = Therapy Data +ExportGroupType.CLINICAL_COURSE = Klinischer Verlauf Daten +ExportGroupType.THERAPY = Therapie Daten EventSourceType.NOT_APPLICABLE = Nicht erhoben EventSourceType.MEDIA_NEWS = Medien/ Nachrichten @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Falluntersuchung erledigt MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Ereignisteilnehmer als bestätigten Fall %s identifiziert MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Ereignisteilnehmer im Zusammenhang mit anderen Ereignissen MessageSubject.LAB_RESULT_ARRIVED = Laborergebnis angekommen -MessageSubject.LAB_RESULT_SPECIFIED = Laborergebnis angegeben MessageSubject.LAB_SAMPLE_SHIPPED = Laborprobe versendet MessageSubject.CONTACT_SYMPTOMATIC = Kontakt ist symptomatisch geworden MessageSubject.TASK_START = Zu startende Aufgabe @@ -1283,8 +1282,8 @@ UserRight.CONTACT_EDIT = Bestehende Kontakte bearbeiten UserRight.CONTACT_EXPORT = Kontakte von SORMAS exportieren UserRight.CONTACT_SEE_ARCHIVED = Archivierte Kontakte anzeigen UserRight.CONTACT_VIEW = Bestehende Kontakte anzeigen -UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Zugriff auf die Kontaktleitungs-Übersicht +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Zugriff auf die Überwachungsleitungs-Übersicht UserRight.DATABASE_EXPORT_ACCESS = Die gesamte Datenbank exportieren UserRight.EVENT_ARCHIVE = Ereignisse archivieren UserRight.EVENT_CREATE = Neue Ereignisse erstellen @@ -1354,8 +1353,8 @@ UserRight.INFRASTRUCTURE_EXPORT = Infrastrukturdaten von SORMAS exportieren UserRight.INFRASTRUCTURE_IMPORT = Infrastrukturdaten importieren UserRight.INFRASTRUCTURE_ARCHIVE = Infrastrukturdaten archivieren UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = Kontaktübertragungsketten auf dem Dashboard einsehen -UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard -UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Zugriff auf Kampagnen Dashboard +UserRight.CASE_CLINICIAN_VIEW = Zugriff auf Fall-Bereiche im Zusammenhang mit der Fallverwaltung UserRight.THERAPY_VIEW = Vorhandene Therapien einsehen UserRight.PRESCRIPTION_CREATE = Neue Verschreibungen erstellen UserRight.PRESCRIPTION_EDIT = Vorhandene Verschreibungen bearbeiten @@ -1415,7 +1414,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Vorhandene Einreisen bearbeiten UserRight.TRAVEL_ENTRY_DELETE = Einreisen aus dem System löschen UserRight.TRAVEL_ENTRY_ARCHIVE = Einreisen archivieren UserRight.EXPORT_DATA_PROTECTION_DATA = Datenschutz-Daten exportieren -UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_VIEW = Ausbrüche anzeigen # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Falluntersuchung diff --git a/sormas-api/src/main/resources/enum_en-AF.properties b/sormas-api/src/main/resources/enum_en-AF.properties index c05627d2a11..465fb992a04 100644 --- a/sormas-api/src/main/resources/enum_en-AF.properties +++ b/sormas-api/src/main/resources/enum_en-AF.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_en-GH.properties b/sormas-api/src/main/resources/enum_en-GH.properties index d75b061e3f6..0352fead6fc 100644 --- a/sormas-api/src/main/resources/enum_en-GH.properties +++ b/sormas-api/src/main/resources/enum_en-GH.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_en-NG.properties b/sormas-api/src/main/resources/enum_en-NG.properties index c12df24d20c..96b852ad890 100644 --- a/sormas-api/src/main/resources/enum_en-NG.properties +++ b/sormas-api/src/main/resources/enum_en-NG.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_es-CU.properties b/sormas-api/src/main/resources/enum_es-CU.properties index e507fefccb0..e1d3dc4053f 100644 --- a/sormas-api/src/main/resources/enum_es-CU.properties +++ b/sormas-api/src/main/resources/enum_es-CU.properties @@ -580,8 +580,8 @@ ExportGroupType.LOCATION = Datos de ubicación ExportGroupType.EVENT = Datos de evento ExportGroupType.EVENT_GROUP = Datos de grupo de eventos ExportGroupType.EVENT_SOURCE = Datos fuente del evento -ExportGroupType.CLINICAL_COURSE = Clinical Course Data -ExportGroupType.THERAPY = Therapy Data +ExportGroupType.CLINICAL_COURSE = Datos de curso clínico +ExportGroupType.THERAPY = Datos de terapia EventSourceType.NOT_APPLICABLE = No aplicable EventSourceType.MEDIA_NEWS = Medios/Noticias @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Investigación del caso realizada MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Participante de evento identificado como un caso de %s confirmado MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Participante de evento relacionado con otros eventos MessageSubject.LAB_RESULT_ARRIVED = Resultado de laboratorio recibido -MessageSubject.LAB_RESULT_SPECIFIED = Resultado de laboratorio especificado MessageSubject.LAB_SAMPLE_SHIPPED = Muestra de laboratorio enviada MessageSubject.CONTACT_SYMPTOMATIC = El contacto se ha vuelto sintomático MessageSubject.TASK_START = Tarea a iniciar @@ -1283,8 +1282,8 @@ UserRight.CONTACT_EDIT = Editar contactos existentes UserRight.CONTACT_EXPORT = Exportar contactos de SORMAS UserRight.CONTACT_SEE_ARCHIVED = Ver contactos archivados UserRight.CONTACT_VIEW = Ver contactos existentes -UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Acceder al tablero de control de supervisor de contactos +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Acceder al tablero de control de supervisor de vigilancia UserRight.DATABASE_EXPORT_ACCESS = Exportar toda la base de datos UserRight.EVENT_ARCHIVE = Archivar eventos UserRight.EVENT_CREATE = Crear nuevos eventos @@ -1354,8 +1353,8 @@ UserRight.INFRASTRUCTURE_EXPORT = Exportar datos de infraestructura de SORMAS UserRight.INFRASTRUCTURE_IMPORT = Importar datos de infraestructura UserRight.INFRASTRUCTURE_ARCHIVE = Archivar datos de infraestructura UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = Ver cadenas de transmisión de contactos en el tablero de control -UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard -UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Acceder a tablero de control de campañas +UserRight.CASE_CLINICIAN_VIEW = Acceder a secciones de casos relacionadas con el médico UserRight.THERAPY_VIEW = Ver terapias existentes UserRight.PRESCRIPTION_CREATE = Crear nuevas prescripciones UserRight.PRESCRIPTION_EDIT = Editar prescripciones existentes @@ -1415,7 +1414,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Editar entradas de viaje existentes UserRight.TRAVEL_ENTRY_DELETE = Eliminar entradas de viaje del sistema UserRight.TRAVEL_ENTRY_ARCHIVE = Archivar entradas de viaje UserRight.EXPORT_DATA_PROTECTION_DATA = Exportar datos de protección de datos -UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_VIEW = Ver brotes # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Investigación de caso diff --git a/sormas-api/src/main/resources/enum_es-EC.properties b/sormas-api/src/main/resources/enum_es-EC.properties index 29ca9fa68e7..4e4f0b60b82 100644 --- a/sormas-api/src/main/resources/enum_es-EC.properties +++ b/sormas-api/src/main/resources/enum_es-EC.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_es-ES.properties b/sormas-api/src/main/resources/enum_es-ES.properties index c12df24d20c..96b852ad890 100644 --- a/sormas-api/src/main/resources/enum_es-ES.properties +++ b/sormas-api/src/main/resources/enum_es-ES.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_fa-AF.properties b/sormas-api/src/main/resources/enum_fa-AF.properties index 46253b11430..4c963925628 100644 --- a/sormas-api/src/main/resources/enum_fa-AF.properties +++ b/sormas-api/src/main/resources/enum_fa-AF.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_fi-FI.properties b/sormas-api/src/main/resources/enum_fi-FI.properties index b632fe4161e..04b553858d5 100644 --- a/sormas-api/src/main/resources/enum_fi-FI.properties +++ b/sormas-api/src/main/resources/enum_fi-FI.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_fil-PH.properties b/sormas-api/src/main/resources/enum_fil-PH.properties index c12df24d20c..96b852ad890 100644 --- a/sormas-api/src/main/resources/enum_fil-PH.properties +++ b/sormas-api/src/main/resources/enum_fil-PH.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_fj-FJ.properties b/sormas-api/src/main/resources/enum_fj-FJ.properties index c12df24d20c..96b852ad890 100644 --- a/sormas-api/src/main/resources/enum_fj-FJ.properties +++ b/sormas-api/src/main/resources/enum_fj-FJ.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_fr-CH.properties b/sormas-api/src/main/resources/enum_fr-CH.properties index 48155de569e..45a2fa06bc8 100644 --- a/sormas-api/src/main/resources/enum_fr-CH.properties +++ b/sormas-api/src/main/resources/enum_fr-CH.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Enquête de cas effectuée MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Résultat du laboratoire arrivé -MessageSubject.LAB_RESULT_SPECIFIED = Résultat du laboratoire spécifié MessageSubject.LAB_SAMPLE_SHIPPED = Échantillon de laboratoire expédié MessageSubject.CONTACT_SYMPTOMATIC = Le contact est devenu symptomatique MessageSubject.TASK_START = Tâche à démarrer diff --git a/sormas-api/src/main/resources/enum_fr-FR.properties b/sormas-api/src/main/resources/enum_fr-FR.properties index 9603db23f0a..18ffd099ece 100644 --- a/sormas-api/src/main/resources/enum_fr-FR.properties +++ b/sormas-api/src/main/resources/enum_fr-FR.properties @@ -580,8 +580,8 @@ ExportGroupType.LOCATION = Données de localisation ExportGroupType.EVENT = Données de l'événement ExportGroupType.EVENT_GROUP = Données du groupe d'événements ExportGroupType.EVENT_SOURCE = Données de la source de l'événement -ExportGroupType.CLINICAL_COURSE = Clinical Course Data -ExportGroupType.THERAPY = Therapy Data +ExportGroupType.CLINICAL_COURSE = Données clinique +ExportGroupType.THERAPY = Données thérapeutiques EventSourceType.NOT_APPLICABLE = Non applicable EventSourceType.MEDIA_NEWS = Médias/Nouvelles @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Enquête de cas effectuée MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Participant à l'événement identifié comme un cas confirmé %s MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Participant à l'événement lié à d'autres événements MessageSubject.LAB_RESULT_ARRIVED = Résultat du laboratoire arrivé -MessageSubject.LAB_RESULT_SPECIFIED = Résultat du laboratoire spécifié MessageSubject.LAB_SAMPLE_SHIPPED = Échantillon de laboratoire expédié MessageSubject.CONTACT_SYMPTOMATIC = Le contact est devenu symptomatique MessageSubject.TASK_START = Tâche à démarrer @@ -1283,8 +1282,8 @@ UserRight.CONTACT_EDIT = Modifier les contacts existants UserRight.CONTACT_EXPORT = Exporter les contacts de SORMAS UserRight.CONTACT_SEE_ARCHIVED = Voir les contacts archivés UserRight.CONTACT_VIEW = Voir les contacts existants -UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = Accéder au tableau de bord du superviseur de contacts +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Accéder au tableau de bord du superviseur de surveillance UserRight.DATABASE_EXPORT_ACCESS = Exporter toute la base de données UserRight.EVENT_ARCHIVE = Archiver les événements UserRight.EVENT_CREATE = Créer un nouvel évènement @@ -1354,8 +1353,8 @@ UserRight.INFRASTRUCTURE_EXPORT = Exporter les données d'infrastructure depuis UserRight.INFRASTRUCTURE_IMPORT = Importer des données d'infrastructure UserRight.INFRASTRUCTURE_ARCHIVE = Archiver les données d'infrastructure UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = Afficher les chaînes de transmission des contacts sur le tableau de bord -UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard -UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Accéder au tableau de bord des campagnes +UserRight.CASE_CLINICIAN_VIEW = Accéder aux sections de cas concernées par le clinicien UserRight.THERAPY_VIEW = Voir les thérapies existantes UserRight.PRESCRIPTION_CREATE = Créer de nouvelles ordonnances UserRight.PRESCRIPTION_EDIT = Modifier les ordonnances existantes @@ -1415,7 +1414,7 @@ UserRight.TRAVEL_ENTRY_EDIT = Edit existing travel entries UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Exporter les données de protection des données -UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_VIEW = Voir les éclosions # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Enquête de cas diff --git a/sormas-api/src/main/resources/enum_hi-IN.properties b/sormas-api/src/main/resources/enum_hi-IN.properties index c12df24d20c..96b852ad890 100644 --- a/sormas-api/src/main/resources/enum_hi-IN.properties +++ b/sormas-api/src/main/resources/enum_hi-IN.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_hr-HR.properties b/sormas-api/src/main/resources/enum_hr-HR.properties index c12df24d20c..96b852ad890 100644 --- a/sormas-api/src/main/resources/enum_hr-HR.properties +++ b/sormas-api/src/main/resources/enum_hr-HR.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_it-CH.properties b/sormas-api/src/main/resources/enum_it-CH.properties index 5ed14f84229..60747efd0bd 100644 --- a/sormas-api/src/main/resources/enum_it-CH.properties +++ b/sormas-api/src/main/resources/enum_it-CH.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_it-IT.properties b/sormas-api/src/main/resources/enum_it-IT.properties index 5f43a3ec514..95c049d8b9d 100644 --- a/sormas-api/src/main/resources/enum_it-IT.properties +++ b/sormas-api/src/main/resources/enum_it-IT.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_ja-JP.properties b/sormas-api/src/main/resources/enum_ja-JP.properties index c12df24d20c..96b852ad890 100644 --- a/sormas-api/src/main/resources/enum_ja-JP.properties +++ b/sormas-api/src/main/resources/enum_ja-JP.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_nl-NL.properties b/sormas-api/src/main/resources/enum_nl-NL.properties index c12df24d20c..96b852ad890 100644 --- a/sormas-api/src/main/resources/enum_nl-NL.properties +++ b/sormas-api/src/main/resources/enum_nl-NL.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_no-NO.properties b/sormas-api/src/main/resources/enum_no-NO.properties index c12df24d20c..96b852ad890 100644 --- a/sormas-api/src/main/resources/enum_no-NO.properties +++ b/sormas-api/src/main/resources/enum_no-NO.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_pl-PL.properties b/sormas-api/src/main/resources/enum_pl-PL.properties index c12df24d20c..96b852ad890 100644 --- a/sormas-api/src/main/resources/enum_pl-PL.properties +++ b/sormas-api/src/main/resources/enum_pl-PL.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_ps-AF.properties b/sormas-api/src/main/resources/enum_ps-AF.properties index 46253b11430..4c963925628 100644 --- a/sormas-api/src/main/resources/enum_ps-AF.properties +++ b/sormas-api/src/main/resources/enum_ps-AF.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_pt-PT.properties b/sormas-api/src/main/resources/enum_pt-PT.properties index c12df24d20c..96b852ad890 100644 --- a/sormas-api/src/main/resources/enum_pt-PT.properties +++ b/sormas-api/src/main/resources/enum_pt-PT.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_ro-RO.properties b/sormas-api/src/main/resources/enum_ro-RO.properties index c12df24d20c..96b852ad890 100644 --- a/sormas-api/src/main/resources/enum_ro-RO.properties +++ b/sormas-api/src/main/resources/enum_ro-RO.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_ru-RU.properties b/sormas-api/src/main/resources/enum_ru-RU.properties index f2a7db808e3..7b85a5bdf0e 100644 --- a/sormas-api/src/main/resources/enum_ru-RU.properties +++ b/sormas-api/src/main/resources/enum_ru-RU.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_sv-SE.properties b/sormas-api/src/main/resources/enum_sv-SE.properties index c12df24d20c..96b852ad890 100644 --- a/sormas-api/src/main/resources/enum_sv-SE.properties +++ b/sormas-api/src/main/resources/enum_sv-SE.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_sw-KE.properties b/sormas-api/src/main/resources/enum_sw-KE.properties index c12df24d20c..96b852ad890 100644 --- a/sormas-api/src/main/resources/enum_sw-KE.properties +++ b/sormas-api/src/main/resources/enum_sw-KE.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_tr-TR.properties b/sormas-api/src/main/resources/enum_tr-TR.properties index c12df24d20c..96b852ad890 100644 --- a/sormas-api/src/main/resources/enum_tr-TR.properties +++ b/sormas-api/src/main/resources/enum_tr-TR.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_uk-UA.properties b/sormas-api/src/main/resources/enum_uk-UA.properties index c12df24d20c..96b852ad890 100644 --- a/sormas-api/src/main/resources/enum_uk-UA.properties +++ b/sormas-api/src/main/resources/enum_uk-UA.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/enum_ur-PK.properties b/sormas-api/src/main/resources/enum_ur-PK.properties index 3e1a1000454..37c23d3146b 100644 --- a/sormas-api/src/main/resources/enum_ur-PK.properties +++ b/sormas-api/src/main/resources/enum_ur-PK.properties @@ -580,8 +580,8 @@ ExportGroupType.LOCATION = پتے کا ڈیٹا ExportGroupType.EVENT = تقریب کا ڈیٹا ExportGroupType.EVENT_GROUP = تقریب گروپ ڈیٹا ExportGroupType.EVENT_SOURCE = تقریب سورس ڈیٹا -ExportGroupType.CLINICAL_COURSE = Clinical Course Data -ExportGroupType.THERAPY = Therapy Data +ExportGroupType.CLINICAL_COURSE = طبی کورس محفوظ کر لیا +ExportGroupType.THERAPY = تھراپی ڈیٹا EventSourceType.NOT_APPLICABLE = قابل اطلاق نہیں EventSourceType.MEDIA_NEWS = میڈیا/نیوز @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = کیس کی تفتیش مکمل MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = تقریب کے شریک کی شناخت تصدیق شدہ %s کیس کے طور پر ہوئی MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = تقریب میں شریک فرد، دیگر تقریبات سے متعلق ہے MessageSubject.LAB_RESULT_ARRIVED = لیبارٹری کا نتیجہ آگیا -MessageSubject.LAB_RESULT_SPECIFIED = لیبارٹری کا نتیجہ بیان کیا گیا MessageSubject.LAB_SAMPLE_SHIPPED = لیب کا نمونہ بھیج دیا گیا MessageSubject.CONTACT_SYMPTOMATIC = رابطہ علامتی شکل اختیار کر گیا ہے MessageSubject.TASK_START = کام شروع کرنا ہے @@ -1283,8 +1282,8 @@ UserRight.CONTACT_EDIT = موجودہ روابط میں ترمیم کریں UserRight.CONTACT_EXPORT = سورماس سے روابط ايکسپورٹ کریں UserRight.CONTACT_SEE_ARCHIVED = محفوظ شدہ روابط دیکھیں UserRight.CONTACT_VIEW = موجودہ روابط دیکھیں -UserRight.DASHBOARD_CONTACT_VIEW = Access the contact supervisor dashboard -UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_CONTACT_VIEW = رابطہ سپروائزر ڈیش بورڈ تک رسائی حاصل کریں +UserRight.DASHBOARD_SURVEILLANCE_VIEW = نگران سپروائزر ڈیش بورڈ تک رسائی حاصل کریں UserRight.DATABASE_EXPORT_ACCESS = پورا ڈیٹا بیس ايکسپورٹ کریں UserRight.EVENT_ARCHIVE = تقریبات کو آرکائیو کریں UserRight.EVENT_CREATE = نئے تقریبات بنائیں @@ -1354,8 +1353,8 @@ UserRight.INFRASTRUCTURE_EXPORT = سورماس سے انفراسٹرکچر ڈی UserRight.INFRASTRUCTURE_IMPORT = انفراسٹرکچر ڈیٹا امپورٹ کریں UserRight.INFRASTRUCTURE_ARCHIVE = انفراسٹرکچر ڈیٹا آرکائیو کریں UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = ڈیش بورڈ پر کونٹيکٹ ٹرانسمیشن چینز دیکھیں -UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard -UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician +UserRight.DASHBOARD_CAMPAIGNS_VIEW = مہمات کے ڈیش بورڈ تک رسائی حاصل کریں +UserRight.CASE_CLINICIAN_VIEW = معالج سے متعلق کیس کے حصوں تک رسائی حاصل کریں UserRight.THERAPY_VIEW = موجودہ تھراپیزدیکھیں UserRight.PRESCRIPTION_CREATE = نئے نسخے بنائیں UserRight.PRESCRIPTION_EDIT = موجودہ نسخوں میں ترمیم کریں @@ -1415,7 +1414,7 @@ UserRight.TRAVEL_ENTRY_EDIT = موجودہ سفری اندراجات میں تر UserRight.TRAVEL_ENTRY_DELETE = سسٹم سے سفری اندراجات کو مٹا دیں UserRight.TRAVEL_ENTRY_ARCHIVE = آرکائیو سفری اندراجات UserRight.EXPORT_DATA_PROTECTION_DATA = ڈیٹا پروٹیکشن ڈیٹا ایکسپورٹ کریں -UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_VIEW = پھیلاؤ دیکھیں # UserRightGroup UserRightGroup.CASE_INVESTIGATION = کیس کی تفتیش diff --git a/sormas-api/src/main/resources/enum_zh-CN.properties b/sormas-api/src/main/resources/enum_zh-CN.properties index 56364e0de79..a2d5881713f 100644 --- a/sormas-api/src/main/resources/enum_zh-CN.properties +++ b/sormas-api/src/main/resources/enum_zh-CN.properties @@ -797,7 +797,6 @@ MessageSubject.CASE_INVESTIGATION_DONE = Case investigation done MessageSubject.EVENT_PARTICIPANT_CASE_CLASSIFICATION_CONFIRMED = Event participant identified as a confirmed %s case MessageSubject.EVENT_PARTICIPANT_RELATED_TO_OTHER_EVENTS = Event Participant related to other Events MessageSubject.LAB_RESULT_ARRIVED = Lab result arrived -MessageSubject.LAB_RESULT_SPECIFIED = Lab result specified MessageSubject.LAB_SAMPLE_SHIPPED = Lab sample shipped MessageSubject.CONTACT_SYMPTOMATIC = Contact has become symptomatic MessageSubject.TASK_START = Task to be started diff --git a/sormas-api/src/main/resources/strings_cs-CZ.properties b/sormas-api/src/main/resources/strings_cs-CZ.properties index 85e860de3aa..b280a8e3fd9 100644 --- a/sormas-api/src/main/resources/strings_cs-CZ.properties +++ b/sormas-api/src/main/resources/strings_cs-CZ.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Jste si jisti, že chcete odstranit všech %d vybra confirmationDeleteEntity = Opravdu chcete odstranit %s? Tuto akci nelze vrátit zpět. confirmationDeleteEventParticipants = Opravdu chcete odstranit všech %d vybraných účastníků události? confirmationDeleteEvents = Opravdu chcete smazat všech %d vybraných událostí? +confirmationDeleteTravelEntries = Opravdu chcete smazat všech %d vybraných cestovních vstupů? confirmationDeleteFile = Opravdu chcete smazat %s? confirmationDeletePathogenTests = Opravdu chcete smazat všech %d vybraných patogenních testy? confirmationDeletePrescriptions = Opravdu chcete smazat všech %d vybraných předpisů? @@ -383,7 +384,7 @@ headingCasesDeleted = Případy odstraněny headingCaseConversion = Převod na případ headingChangeCaseDisease = Změnit onemocnění případu headingCasesGuide = Příručka\: Adresář případů -headingCasesSentToExternalSurveillanceTool=Cases sent to the reporting tool +headingCasesSentToExternalSurveillanceTool=Případy zaslané do nástroje pro podávání zpráv headingChangePathogenTestResult = Upravit výsledek testu patogenu headingClinicalMeasurements = Klinická měření headingClinicalVisitsDeleted = Klinická hodnocení smazána @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = Nebyla vybrána žádná klinická hodnocení headingNoContactsSelected = Nebyly vybrány žádné kontakty headingNoEventParticipantsSelected = Nejsou vybráni žádní účastníci události headingNoEventsSelected = Nebyly vybrány žádné události +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = Žádný soubor headingNoPathogenTestsSelected = Nebyly vybrány žádné patogeny headingNoPrescriptionsSelected = Nevybrány žádné recepty @@ -576,7 +578,8 @@ headingTasksDeleted = Úkoly odstraněny headingTemplateNotAvailable = Šablona není k dispozici headingTests = Testy patogenů headingTransferCase = Případ přenosu -headingTravelEntryData= Data o cestovním vstupu +headingTravelEntryData = Data o cestovním vstupu +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Viz případ z místa vstupu headingTreatments = Provedená léčba headingTreatmentsDeleted = Léčba odstraněna @@ -871,7 +874,7 @@ infoPlaceOfStayInHospital = Vyberte prosím nemocnici jako místo pobytu. Pokud infoMoreDetailsAboutHospitalization = Chcete-li přidat další podrobnosti o hospitalizaci, přejděte na záložku hospitalizace. infoCountryNotEditableEventParticipantsWithoutJurisdiction = Změna země není povolena, protože alespoň jeden účastník této události nemá nastavený odpovědný region a/nebo odpovědný okres. infoContactAlreadyConvertedToCase = Tento kontakt již byl převeden na případ. Prosím, přidejte nové návštěvy k případu. -infoSearchPersonOnDependentForm = Search for another person +infoSearchPersonOnDependentForm = Hledat jinou osobu # Messages messageActivateAccount = Účet musí být aktivován @@ -905,7 +908,7 @@ messageCasesDearchived = Všechny vybrané případy byly vyjmuty z archivu messageCasesDeleted = Všechny vybrané případy byly odstraněny messageCasesEdited = Všechny případy byly editovány messageCasesMerged = Případy sloučeny a duplicitní případ odstraněn. -messageCasesSentToExternalSurveillanceTool = All selected cases have been sent to the reporting tool +messageCasesSentToExternalSurveillanceTool = Všechny vybrané případy byly odeslány do nástroje pro hlášení messageCasesNotDeletedReasonExternalSurveillanceTool = Některé případy nebyly odstraněny, protože komunikace s nástrojem pro hlášení selhala. messageChangePathogenTestResult = Výsledek testu tohoto patogenu se liší od současného celkového výsledku testu patogenu vzorku. Chcete aktualizovat výsledek na %s? messageCheckInputData = Zkontrolujte prosím vstupní data @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = Nevybrali jste soubor, který chcete nahr messageNoDocumentUploadFile = Nevybrali jste soubor, který chcete nahrát. Vyberte soubor, který chcete importovat z vašeho počítače. messageNoEventParticipantsSelected = Nevybrali jste žádné účastníky události messageNoEventsSelected = Nevybrali jste žádné události +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = Nevybrali jste žádné testy patogenu messageNoPrescriptionsSelected = Nevybrali jste žádné předpisy messageNoSamplesSelected = Nevybrali jste žádné vzorky @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Zadané údaje o cestování uloženy messageTravelEntryArchived = Místo vstupu bylo archivováno messageTravelEntryDearchived = Místo vstupu bylo vyjmuto z archivu messageTravelEntryPOEFilledBySystem = [System] Automaticky vyplněný vstupní bod +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Léčba vytvořena messageTreatmentSaved = Léčba uložena messageTreatmentsDeleted = Všechny vybrané léčby byly odstraněny @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s výsledek testu patogenu dorazil pro %s příp notificationLabResultArrivedContact = %s výsledek testu patogenu dorazil na %s kontaktu %s. Typ testu\: %s. Testovaná choroba\: %s. notificationLabResultArrivedEventParticipant = Výsledky testu patogenu %s dorazily pro %s účastníka události %s. Typ testu\: %s. Testovaná choroba\: %s. notificationLabResultArrivedEventParticipantNoDisease = Výsledek testu patogenu %s dorazil pro %s účastníka události %s. Typ testu\: %s. -notificationLabResultSpecified = Výsledek testu patogenu pro %s případ %s byl zadán na %s. Typ testu\: %s. Testovaná choroba\: %s. -notificationLabResultSpecifiedContact = Výsledek testu patogenu pro %s kontakt %s byl zadán na %s. Typ testu\: %s. Testovaná choroba\: %s. -notificationLabResultSpecifiedEventParticipant = Výsledek testu patogenu pro účastníka události %s %s byl zadán na %s. Typ testu\: %s. Testovaná choroba\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = Výsledek testu patogenu pro účastníka události %s %s byl zadán pro %s. Typ testu\: %s. notificationLabSampleShipped = Nový vzorek (kód vzorku\: %s) pro případ %s je odesílán do vaší laboratoře. notificationLabSampleShippedShort = Do vaší laboratoře je odesílán nový vzorek pro případ %s. notificationLabSampleShippedShortForContact = Do vaší laboratoře je odesílán nový vzorek pro kontakt %s. @@ -1208,9 +1209,9 @@ notificationTaskAssociatedContactLink = Odkaz na související kontakt\: %s notificationTaskAssociatedEventLink = Odkaz na související událost\: %s notificationTaskAssociatedTravelEntryLink = Odkaz na související cestovní záznam\: %s notificationTaskGeneralUpdatedAssigneeUserSource = Your %s task has been assigned to another user. You are no longer in charge of this task. -notificationTaskGeneralUpdatedAssigneeUserTarget = A(n) %s task has been assigned to you. -notificationTaskSpecificUpdatedAssigneeUserSource = Your %s task for %s has been assigned to another user. You are no longer in charge of this task. -notificationTaskSpecificUpdatedAssigneeUserTarget = A(n) %s task for %s has been assigned to you. +notificationTaskGeneralUpdatedAssigneeUserTarget = %s úkol byl přiřazen na vás. +notificationTaskSpecificUpdatedAssigneeUserSource = Váš %s úkol pro %s byl přiřazen jinému uživateli. Již nemáte na starosti tento úkol. +notificationTaskSpecificUpdatedAssigneeUserTarget = %s úkol pro %s vám byl přidělen. notificationVisitCompleted = Následná návštěva kontaktu %s přiděleného uživateli %s byla dokončena. notificationEventParticipantRelatedToOtherEvents = Osoba %s nově přidaná jako účastník %s k události %s (odpovědný uživatel\: %s) %s se také vztahuje k těmto událostem\:\n%s notificationEventWithResponsibleUserLine = Událost %s (zodpovědný uživatel\: %s) @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Datum zahájení imunizace... promptImmunizationPositiveTestResultDateFrom = Datum pozitivního výsledku testu imunizace od... promptImmunizationRecoveryDateFrom = Datum obnovení imunizace od... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... do +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... do epi týdne + # Unsaved changes unsavedChanges.warningTitle = Potvrdit navigaci unsavedChanges.warningMessage = V tomto formuláři máte neuložené změny. diff --git a/sormas-api/src/main/resources/strings_de-CH.properties b/sormas-api/src/main/resources/strings_de-CH.properties index c464194e011..e23d430f3d8 100644 --- a/sormas-api/src/main/resources/strings_de-CH.properties +++ b/sormas-api/src/main/resources/strings_de-CH.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Sind Sie sicher, dass Sie alle %d ausgewählten Kon confirmationDeleteEntity = Sind Sie sicher, dass Sie %s löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden. confirmationDeleteEventParticipants = Sind Sie sicher, dass Sie alle %d ausgewählten Ereignisteilnehmer*innen löschen möchten? confirmationDeleteEvents = Sind Sie sicher, dass Sie alle %d ausgewählten Ereignisse löschen möchten? +confirmationDeleteTravelEntries = Sind Sie sicher, dass Sie alle %d ausgewählten Einreisen löschen möchten? confirmationDeleteFile = Sind Sie sicher, dass Sie %s löschen möchten? confirmationDeletePathogenTests = Sind Sie sicher, dass Sie alle %d ausgewählten Erregertests löschen möchten? confirmationDeletePrescriptions = Sind Sie sicher, dass Sie alle %d ausgewählten Rezepte löschen möchten? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = Keine klinischen Bewertungen ausgewählt headingNoContactsSelected = Keine Kontakte ausgewählt headingNoEventParticipantsSelected = Keine Ereignisteilnehmenden ausgewählt headingNoEventsSelected = Keine Ereignisse ausgewählt +headingNoTravelEntriesSelected = Keine Einreisen ausgewählt headingNoFile = Die Datei ist nicht vorhanden headingNoPathogenTestsSelected = Keine Erregertests ausgewählt headingNoPrescriptionsSelected = Keine Rezepte ausgewählt @@ -576,7 +578,8 @@ headingTasksDeleted = Aufgaben gelöscht headingTemplateNotAvailable = Vorlage nicht verfügbar headingTests = Erregertests headingTransferCase = Fall übertragen -headingTravelEntryData= Einreisedaten +headingTravelEntryData = Einreisedaten +headingTravelEntriesDeleted = Einreisen gelöscht headingReferCaseFromPointOfEntry = Fall vom Einreiseort weiterleiten headingTreatments = Ausgeführte Behandlungen headingTreatmentsDeleted = Behandlungen gelöscht @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = Sie haben keine Datei zum Hochladen ausgew messageNoDocumentUploadFile = Sie haben keine Datei zum Hochladen ausgewählt. Bitte wählen Sie eine Datei aus, die Sie von Ihrem Computer importieren möchten. messageNoEventParticipantsSelected = Sie haben keine Teilnehmer*innen ausgewählt messageNoEventsSelected = Sie haben keine Ereignisse ausgewählt +messageNoTravelEntriesSelected = Sie haben keine Einreisen ausgewählt messageNoPathogenTestsSelected = Sie haben keine Erregertests ausgewählt messageNoPrescriptionsSelected = Sie haben keine Rezepte ausgewählt messageNoSamplesSelected = Sie haben keine Proben ausgewählt @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Einreisedaten gespeichert messageTravelEntryArchived = Einreise wurde archiviert messageTravelEntryDearchived = Einreise wurde dearchiviert messageTravelEntryPOEFilledBySystem = [System] Automatisch befüllter Einreiseort +messageTravelEntriesDeleted = Alle ausgewählten Einreisen wurden gelöscht messageTreatmentCreated = Behandlung erstellt messageTreatmentSaved = Behandlung gespeichert messageTreatmentsDeleted = Alle ausgewählten Behandlungen wurden gelöscht @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s Erregertestergebnisse sind eingetroffen für % notificationLabResultArrivedContact = %s Erreger-Testergebnis ist für %s Kontakt %seingetroffen. Testtyp\: %s. Getestete Krankheit\: %s. notificationLabResultArrivedEventParticipant = %s Erregertest ist für %s Ereignisteilnehmer %s eingetroffen. Test-Typ\: %s. Getestete Krankheit\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s Erregertestergenbis ist für %s Ereignisteilnehmer %s eingetroffen. Test-Typ\: %s. -notificationLabResultSpecified = Ein Erregertestergebnis für den Fall %s %s wurde auf %s spezifiziert. Testtyp\: %s. Getestete Krankheit\: %s. -notificationLabResultSpecifiedContact = Ein Erregertestergebnis für %s Kontakt %s wurde auf %s spezifiziert. Testtyp\: %s. Getestete Krankheit\: %s. -notificationLabResultSpecifiedEventParticipant = Ein Erregertest für %s Ereignisteilnehmer %s wurde spezifiziert für %s. Test-Typ\: %s. Getestete Krankheit\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = Ein Erregertest für %s Eventteilnehmer %s wurde spezifiziert für %s. Test-Typ\: %s. notificationLabSampleShipped = Eine neue Probe (Probencode\: %s) für den Fall %s wird an Ihr Labor versandt. notificationLabSampleShippedShort = Eine neue Probe für den Fall %s wird an Ihr Labor versandt. notificationLabSampleShippedShortForContact = Eine neue Probe für Kontakt %s wird an Ihr Labor versendet. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunisierungsbeginn vom... promptImmunizationPositiveTestResultDateFrom = Positive Testergebnis der Immunisierung vom... promptImmunizationRecoveryDateFrom = Genesungsdatum der Immunisierung vom... +promptTravelEntryDateFrom = Meldedatum der Einreise von... +promptTravelEntryDateTo = ... bis +promptTravelEntryEpiWeekFrom = Einreise von epi Woche... +promptTravelEntryEpiWeekTo = ... bis Epi Woche + # Unsaved changes unsavedChanges.warningTitle = Änderungen bestätigen unsavedChanges.warningMessage = Sie haben ungespeicherte Änderungen auf diesem Formular. diff --git a/sormas-api/src/main/resources/strings_de-DE.properties b/sormas-api/src/main/resources/strings_de-DE.properties index 8423dc6d79e..08f3c4e737d 100644 --- a/sormas-api/src/main/resources/strings_de-DE.properties +++ b/sormas-api/src/main/resources/strings_de-DE.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Sind Sie sicher, dass Sie alle %d ausgewählten Kon confirmationDeleteEntity = Sind Sie sicher, dass Sie %s löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden. confirmationDeleteEventParticipants = Sind Sie sicher, dass Sie alle %d ausgewählten Ereignisteilnehmer*innen löschen möchten? confirmationDeleteEvents = Sind Sie sicher, dass Sie alle %d ausgewählten Ereignisse löschen möchten? +confirmationDeleteTravelEntries = Sind Sie sicher, dass Sie alle %d ausgewählten Einreisen löschen möchten? confirmationDeleteFile = Sind Sie sicher, dass Sie %s löschen möchten? confirmationDeletePathogenTests = Sind Sie sicher, dass Sie alle %d ausgewählten Erregertests löschen möchten? confirmationDeletePrescriptions = Sind Sie sicher, dass Sie alle %d ausgewählten Verschreibungen löschen möchten? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = Keine klinischen Bewertungen ausgewählt headingNoContactsSelected = Keine Kontakte ausgewählt headingNoEventParticipantsSelected = Keine Ereignisteilnehmenden ausgewählt headingNoEventsSelected = Keine Ereignisse ausgewählt +headingNoTravelEntriesSelected = Keine Einreisen ausgewählt headingNoFile = Die Datei ist nicht vorhanden headingNoPathogenTestsSelected = Keine Erregertests ausgewählt headingNoPrescriptionsSelected = Keine Verschreibungen ausgewählt @@ -576,7 +578,8 @@ headingTasksDeleted = Aufgaben gelöscht headingTemplateNotAvailable = Vorlage nicht verfügbar headingTests = Erregertests headingTransferCase = Fall übertragen -headingTravelEntryData= Einreisedaten +headingTravelEntryData = Einreisedaten +headingTravelEntriesDeleted = Einreisen gelöscht headingReferCaseFromPointOfEntry = Fall vom Einreiseort weiterleiten headingTreatments = Ausgeführte Behandlungen headingTreatmentsDeleted = Behandlungen gelöscht @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = Sie haben keine Datei zum Hochladen ausgew messageNoDocumentUploadFile = Sie haben keine Datei zum Hochladen ausgewählt. Bitte wählen Sie eine Datei aus, die Sie von Ihrem Computer importieren möchten. messageNoEventParticipantsSelected = Sie haben keine Teilnehmer*innen ausgewählt messageNoEventsSelected = Sie haben keine Ereignisse ausgewählt +messageNoTravelEntriesSelected = Sie haben keine Einreisen ausgewählt messageNoPathogenTestsSelected = Sie haben keine Erregertests ausgewählt messageNoPrescriptionsSelected = Sie haben keine Verschreibungen ausgewählt messageNoSamplesSelected = Sie haben keine Proben ausgewählt @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Einreisedaten gespeichert messageTravelEntryArchived = Einreise wurde archiviert messageTravelEntryDearchived = Einreise wurde dearchiviert messageTravelEntryPOEFilledBySystem = [System] Automatisch befüllter Einreiseort +messageTravelEntriesDeleted = Alle ausgewählten Einreisen wurden gelöscht messageTreatmentCreated = Behandlung erstellt messageTreatmentSaved = Behandlung gespeichert messageTreatmentsDeleted = Alle ausgewählten Behandlungen wurden gelöscht @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s Erregertestergebnisse sind eingetroffen für % notificationLabResultArrivedContact = %s Erreger-Testergebnis ist für %s Kontakt %seingetroffen. Testtyp\: %s. Getestete Krankheit\: %s. notificationLabResultArrivedEventParticipant = %s Das Erreger-Testresultat ist für den %s Ereignisteilnehmer %s eingetroffen. Test-Typ\: %s. Getestete Krankheit\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s Ein Erregertest ist für %s Ereignisteilnehmer %s eingetroffen. Test-Typ\: %s. -notificationLabResultSpecified = Ein Erregertestergebnis für den Fall %s %s wurde auf %s spezifiziert. Testtyp\: %s. Getestete Krankheit\: %s. -notificationLabResultSpecifiedContact = Ein Erregungstestergebnis für %s Kontakt %s wurde auf %s spezifiziert. Testtyp\: %s. Getestete Krankheit\: %s. -notificationLabResultSpecifiedEventParticipant = Ein Erregertest für %s Eventteilnehmer %s wurde spezifiziert für %s. Test-Typ\: %s. Getestete Krankheit\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = Ein Erregertest für %s Eventteilnehmer %s wurde spezifiziert für %s. Test-Typ\: %s. notificationLabSampleShipped = Eine neue Probe (Proben-Code\: %s) für den Fall %s wird an Ihr Labor versandt. notificationLabSampleShippedShort = Eine neue Probe für den Fall %s wird an Ihr Labor versandt. notificationLabSampleShippedShortForContact = Eine neue Probe für Kontakt %s wird ans Labor versendet. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunisierungsbeginn vom... promptImmunizationPositiveTestResultDateFrom = Positive Testergebnis der Immunisierung vom... promptImmunizationRecoveryDateFrom = Genesungsdatum der Immunisierung vom... +promptTravelEntryDateFrom = Meldedatum der Einreise von... +promptTravelEntryDateTo = ... bis +promptTravelEntryEpiWeekFrom = Einreise von epi Woche... +promptTravelEntryEpiWeekTo = ... bis Epi Woche + # Unsaved changes unsavedChanges.warningTitle = Änderungen bestätigen unsavedChanges.warningMessage = Sie haben ungespeicherte Änderungen auf diesem Formular. diff --git a/sormas-api/src/main/resources/strings_en-AF.properties b/sormas-api/src/main/resources/strings_en-AF.properties index ea447d4b31b..7a8a4530c79 100644 --- a/sormas-api/src/main/resources/strings_en-AF.properties +++ b/sormas-api/src/main/resources/strings_en-AF.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Are you sure you want to delete all %d selected con confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Are you sure you want to delete all %d selected event participants? confirmationDeleteEvents = Are you sure you want to delete all %d selected events? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected pathogen tests? confirmationDeletePrescriptions = Are you sure you want to delete all %d selected prescriptions? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = A new sample (sample code\: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_en-GH.properties b/sormas-api/src/main/resources/strings_en-GH.properties index 2e09eb76ada..2a951541123 100644 --- a/sormas-api/src/main/resources/strings_en-GH.properties +++ b/sormas-api/src/main/resources/strings_en-GH.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Are you sure you want to delete all %d selected con confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Are you sure you want to delete all %d selected event participants? confirmationDeleteEvents = Are you sure you want to delete all %d selected events? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected pathogen tests? confirmationDeletePrescriptions = Are you sure you want to delete all %d selected prescriptions? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = A new sample (sample code\: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_en-NG.properties b/sormas-api/src/main/resources/strings_en-NG.properties index 6ada606fc38..9f04e55b369 100644 --- a/sormas-api/src/main/resources/strings_en-NG.properties +++ b/sormas-api/src/main/resources/strings_en-NG.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Are you sure you want to delete all %d selected con confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Are you sure you want to delete all %d selected event participants? confirmationDeleteEvents = Are you sure you want to delete all %d selected events? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected pathogen tests? confirmationDeletePrescriptions = Are you sure you want to delete all %d selected prescriptions? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = A new sample (sample code\: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_es-CU.properties b/sormas-api/src/main/resources/strings_es-CU.properties index 8395037d821..d8bd141e6e9 100644 --- a/sormas-api/src/main/resources/strings_es-CU.properties +++ b/sormas-api/src/main/resources/strings_es-CU.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = ¿Está seguro de que desea eliminar todos los %d c confirmationDeleteEntity = ¿Está seguro de que desea eliminar esta %s? Esta acción no se puede revertir. confirmationDeleteEventParticipants = ¿Está seguro de que desea eliminar todos los %d participantes del evento seleccionados? confirmationDeleteEvents = ¿Está seguro de que desea eliminar todos los %d eventos seleccionados? +confirmationDeleteTravelEntries = ¿Está seguro de que desea eliminar las %d entradas de viaje seleccionadas? confirmationDeleteFile = ¿Está seguro de que desea eliminar "%s"? confirmationDeletePathogenTests = ¿Está seguro de que desea eliminar todas las %d pruebas de patógeno seleccionadas? confirmationDeletePrescriptions = ¿Está seguro de que desea eliminar todas las %d prescripciones seleccionadas? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No hay evaluaciones clínicas seleccionadas headingNoContactsSelected = No hay contactos seleccionados headingNoEventParticipantsSelected = No hay participantes del evento seleccionados headingNoEventsSelected = No hay eventos seleccionados +headingNoTravelEntriesSelected = No hay entradas de viaje seleccionadas headingNoFile = Ningún archivo headingNoPathogenTestsSelected = No hay pruebas de patógeno seleccionadas headingNoPrescriptionsSelected = No hay prescripciones seleccionadas @@ -576,7 +578,8 @@ headingTasksDeleted = Tareas eliminadas headingTemplateNotAvailable = Plantilla no disponible headingTests = Pruebas de patógeno headingTransferCase = Transferir caso -headingTravelEntryData= Datos de entrada de viaje +headingTravelEntryData = Datos de entrada de viaje +headingTravelEntriesDeleted = Entradas de viaje eliminadas headingReferCaseFromPointOfEntry = Referir el caso desde un punto de entrada headingTreatments = Tratamientos ejecutados headingTreatmentsDeleted = Tratamientos eliminados @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = No ha seleccionado un archivo para cargar. messageNoDocumentUploadFile = No ha seleccionado un archivo para cargar. Por favor, seleccione un archivo que desee importar desde su computadora. messageNoEventParticipantsSelected = No ha seleccionado ningún participante del evento messageNoEventsSelected = No ha seleccionado ningún evento +messageNoTravelEntriesSelected = No ha seleccionado ninguna entrada de viaje messageNoPathogenTestsSelected = No ha seleccionado ninguna prueba de patógeno messageNoPrescriptionsSelected = No ha seleccionado ninguna prescripción messageNoSamplesSelected = No ha seleccionado ninguna muestra @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Datos de entrada de viaje guardados messageTravelEntryArchived = La entrada de viaje fue archivada messageTravelEntryDearchived = La entrada de viaje fue desarchivada messageTravelEntryPOEFilledBySystem = [System] Punto de entrada rellenado automáticamente +messageTravelEntriesDeleted = Todas las entradas de viaje seleccionadas han sido eliminadas messageTreatmentCreated = Tratamiento creado messageTreatmentSaved = Tratamiento guardado messageTreatmentsDeleted = Todos los tratamientos seleccionados fueron eliminados @@ -1189,10 +1194,6 @@ notificationLabResultArrived = Llegó el resultado de la prueba de patógeno %s notificationLabResultArrivedContact = Llegó el resultado de la prueba de patógeno %s para %s contacto %s. Tipo de prueba\: %s. Enfermedad probada\: %s. notificationLabResultArrivedEventParticipant = Llegó el resultado de la prueba de patógeno %s para %s participante de evento %s. Tipo de prueba\: %s. Enfermedad probada\: %s. notificationLabResultArrivedEventParticipantNoDisease = Llegó el resultado de la prueba de patógeno %s para %s participante de evento %s. Tipo de prueba\: %s. -notificationLabResultSpecified = Un resultado de prueba de patógeno para %s caso %s se especificó como %s. Tipo de prueba\: %s. Enfermedad probada\: %s. -notificationLabResultSpecifiedContact = Un resultado de prueba de patógeno para %s contacto %s se especificó como %s. Tipo de prueba\: %s. Enfermedad probada\: %s. -notificationLabResultSpecifiedEventParticipant = Un resultado de prueba de patógeno para %s participante de evento %s se especificó como %s. Tipo de prueba\: %s. Enfermedad probada\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = Un resultado de prueba de patógeno para %s participante de evento %s se especificó como %s. Tipo de prueba\: %s. notificationLabSampleShipped = Una nueva muestra (código de muestra\: %s) para el caso %s está siendo enviada a su laboratorio. notificationLabSampleShippedShort = Una nueva muestra para el caso %s está siendo enviada a su laboratorio. notificationLabSampleShippedShortForContact = Una nueva muestra para el contacto %s está siendo enviada a su laboratorio. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Fecha de inicio de inmunización desde... promptImmunizationPositiveTestResultDateFrom = Fecha de resultado de prueba positivo desde... promptImmunizationRecoveryDateFrom = Fecha de recuperación de inmunización desde... +promptTravelEntryDateFrom = Fecha de informe de entrada de viaje desde... +promptTravelEntryDateTo = ... hasta +promptTravelEntryEpiWeekFrom = Entrada de viaje desde la semana epi... +promptTravelEntryEpiWeekTo = ... hasta la semana epi + # Unsaved changes unsavedChanges.warningTitle = Confirmar navegación unsavedChanges.warningMessage = Tiene cambios sin guardar en este formulario. diff --git a/sormas-api/src/main/resources/strings_es-EC.properties b/sormas-api/src/main/resources/strings_es-EC.properties index 389d43f8e04..8d873d788b5 100644 --- a/sormas-api/src/main/resources/strings_es-EC.properties +++ b/sormas-api/src/main/resources/strings_es-EC.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = ¿Está seguro de que desea eliminar los %d contact confirmationDeleteEntity = ¿Estás seguro de que deseas eliminar este %s? Esta acción no se puede revertir. confirmationDeleteEventParticipants = ¿Está seguro de que desea eliminar todos los %d participantes del evento seleccionado? confirmationDeleteEvents = ¿Está seguro de que desea eliminar todos los %d eventos seleccionado? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = ¿Está seguro de que desea eliminar todas las %d pruebas de patógenos seleccionadas? confirmationDeletePrescriptions = ¿Está seguro de que desea eliminar todas las %d prescripciones seleccionadas? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No hay evaluaciones clínicas seleccionadas headingNoContactsSelected = Ningún contacto seleccionado headingNoEventParticipantsSelected = Ningún participante de evento seleccionado headingNoEventsSelected = Ningún evento seleccionado +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = Ningún archivo headingNoPathogenTestsSelected = No hay pruebas de patógenos seleccionadas headingNoPrescriptionsSelected = Ninguna prescripción seleccionada @@ -576,7 +578,8 @@ headingTasksDeleted = Tareas eliminadas headingTemplateNotAvailable = Plantilla no disponible headingTests = Pruebas de patógenos headingTransferCase = Transferir caso -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Caso referido desde un punto de ingreso headingTreatments = Tratamientos ejecutados headingTreatmentsDeleted = Tratamientos eliminados @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = No ha seleccionado ningún participante de evento messageNoEventsSelected = No ha seleccionado ningún evento +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = No ha seleccionado ninguna prueba de patógeno messageNoPrescriptionsSelected = No ha seleccionado ninguna prescripción messageNoSamplesSelected = No ha seleccionado ninguna muestra @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Tratamiento creado messageTreatmentSaved = Tratamiento guardado messageTreatmentsDeleted = Todos los tratamientos seleccionados han sido eliminados @@ -1189,10 +1194,6 @@ notificationLabResultArrived = El resultado de la prueba de patógeno %s ha lleg notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = Un resultado de una prueba de patógeno para %s caso %s se ha especificado a %s. Tipo de prueba\: %s. Enfermedad probada\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = Una nueva muestra (código de muestra\: %s) para el caso %s está siendo enviada a su laboratorio. notificationLabSampleShippedShort = Una nueva muestra para el caso %s se está enviando a su laboratorio. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_es-ES.properties b/sormas-api/src/main/resources/strings_es-ES.properties index 395653a1f96..e2aba1b50c7 100644 --- a/sormas-api/src/main/resources/strings_es-ES.properties +++ b/sormas-api/src/main/resources/strings_es-ES.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Are you sure you want to delete all %d selected con confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Are you sure you want to delete all %d selected event participants? confirmationDeleteEvents = Are you sure you want to delete all %d selected events? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected pathogen tests? confirmationDeletePrescriptions = Are you sure you want to delete all %d selected prescriptions? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = A new sample (sample code\: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_fa-AF.properties b/sormas-api/src/main/resources/strings_fa-AF.properties index 395653a1f96..e2aba1b50c7 100644 --- a/sormas-api/src/main/resources/strings_fa-AF.properties +++ b/sormas-api/src/main/resources/strings_fa-AF.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Are you sure you want to delete all %d selected con confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Are you sure you want to delete all %d selected event participants? confirmationDeleteEvents = Are you sure you want to delete all %d selected events? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected pathogen tests? confirmationDeletePrescriptions = Are you sure you want to delete all %d selected prescriptions? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = A new sample (sample code\: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_fi-FI.properties b/sormas-api/src/main/resources/strings_fi-FI.properties index c3b8cf2da22..cb73c9419a3 100644 --- a/sormas-api/src/main/resources/strings_fi-FI.properties +++ b/sormas-api/src/main/resources/strings_fi-FI.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Haluatko varmasti poistaa kaikki %d valittua kontak confirmationDeleteEntity = Haluatko varmasti poistaa entiteetin %s? Tätä toimintoa ei voi kumota. confirmationDeleteEventParticipants = Haluatko varmasti poistaa kaikki %d valitun tapahtuman osallistujaa? confirmationDeleteEvents = Haluatko varmasti poistaa kaikki %d valittua tapahtumaa? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Haluatko varmasti poistaa kaikki %d valittua patogeenitestiä? confirmationDeletePrescriptions = Haluatko varmasti poistaa kaikki %d valittua lääkemääräystä? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = Ei valittuja kliinisiä arvioita headingNoContactsSelected = Ei valittuja kontakteja headingNoEventParticipantsSelected = Ei valittuja tapahtuman osallistujia headingNoEventsSelected = Ei valittuja tapahtumia +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = Ei tiedostoa headingNoPathogenTestsSelected = Ei valittuja patogeenitestejä headingNoPrescriptionsSelected = Ei valittuja lääkemääräyksiä @@ -576,7 +578,8 @@ headingTasksDeleted = Tehtävät poistettu headingTemplateNotAvailable = Mallia ei saatavilla headingTests = Patogeenitestit headingTransferCase = Siirrä potilas -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Lähetä potilas eteenpäin maahantulopaikasta headingTreatments = Annetut hoidot headingTreatmentsDeleted = Hoidot poistettu @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = Et ole valinnut yhtään tapahtumaan osallistujaa messageNoEventsSelected = Et ole valinnut yhtään tapahtumaa +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = Et ole valinnut yhtään patogeenitestiä messageNoPrescriptionsSelected = Et ole valinnut yhtään lääkemääräystä messageNoSamplesSelected = Et ole valinnut yhtään näytettä @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Hoito luotu messageTreatmentSaved = Hoito tallennettu messageTreatmentsDeleted = Kaikki valitut hoidot on poistettu @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s patogeenitestin tulos on saapunut %s potilaall notificationLabResultArrivedContact = %s patogeenitestin tulos on saapunut %s kontaktille %s. Testityyppi\: %s. Testattu sairaus\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = Patogeenitestin tuloksen %s potilaalle %s on määritetty olevan %s. Testityyppi\: %s. Testattu sairaus\: %s. -notificationLabResultSpecifiedContact = Patogeenitestin tuloksen %s kontaktille %s on määritetty olevan %s. Testityyppi\: %s. Testattu sairaus\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = Uusi näyte (näytekoodi\: %s) potilaalle %s lähetetään laboratoriiosi. notificationLabSampleShippedShort = Uusi näyte potilaalle %s lähetetään laboratorioosi. notificationLabSampleShippedShortForContact = Uusi näyte kontaktille %s lähetetään laboratorioosi. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_fil-PH.properties b/sormas-api/src/main/resources/strings_fil-PH.properties index 395653a1f96..e2aba1b50c7 100644 --- a/sormas-api/src/main/resources/strings_fil-PH.properties +++ b/sormas-api/src/main/resources/strings_fil-PH.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Are you sure you want to delete all %d selected con confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Are you sure you want to delete all %d selected event participants? confirmationDeleteEvents = Are you sure you want to delete all %d selected events? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected pathogen tests? confirmationDeletePrescriptions = Are you sure you want to delete all %d selected prescriptions? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = A new sample (sample code\: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_fj-FJ.properties b/sormas-api/src/main/resources/strings_fj-FJ.properties index 395653a1f96..e2aba1b50c7 100644 --- a/sormas-api/src/main/resources/strings_fj-FJ.properties +++ b/sormas-api/src/main/resources/strings_fj-FJ.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Are you sure you want to delete all %d selected con confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Are you sure you want to delete all %d selected event participants? confirmationDeleteEvents = Are you sure you want to delete all %d selected events? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected pathogen tests? confirmationDeletePrescriptions = Are you sure you want to delete all %d selected prescriptions? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = A new sample (sample code\: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_fr-CH.properties b/sormas-api/src/main/resources/strings_fr-CH.properties index 27ef8bae807..c24e449dc5e 100644 --- a/sormas-api/src/main/resources/strings_fr-CH.properties +++ b/sormas-api/src/main/resources/strings_fr-CH.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Êtes-vous sûr de vouloir supprimer tous les %d co confirmationDeleteEntity = Are you sure you want to delete this %d? This action can not be reversed. confirmationDeleteEventParticipants = Êtes-vous sûr de vouloir supprimer tous les %d participants sélectionnés à l'événement? confirmationDeleteEvents = Êtes-vous sûr de vouloir supprimer tous les %d événements sélectionnés ? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Êtes-vous sûr de vouloir supprimer "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected sample tests? confirmationDeletePrescriptions = Êtes-vous sûr de vouloir supprimer toutes les %d prescriptions sélectionnées? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical visits selected headingNoContactsSelected = Aucun contact sélectionné headingNoEventParticipantsSelected = Aucun participant à l'événement sélectionné headingNoEventsSelected = Aucun événement sélectionné +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = Aucun fichier headingNoPathogenTestsSelected = No sample tests selected headingNoPrescriptionsSelected = Aucune ordonnance sélectionnée @@ -576,7 +578,8 @@ headingTasksDeleted = Tâches supprimées headingTemplateNotAvailable = Modèle non disponible headingTests = Tests headingTransferCase = Transfert le cas -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Référez le cas du point d'entrée headingTreatments = Traitements exécutés headingTreatmentsDeleted = Traitement supprimé @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = Vous n'avez pas sélectionné de fichier messageNoDocumentUploadFile = Vous n'avez pas sélectionné de fichier à télécharger. Veuillez sélectionner un fichier que vous souhaitez importer depuis votre ordinateur. messageNoEventParticipantsSelected = Vous n'avez sélectionné aucun participant à l'événement messageNoEventsSelected = Vous n'avez sélectionné aucun événement +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any sample tests messageNoPrescriptionsSelected = Vous n'avez sélectionné aucune ordonnance messageNoSamplesSelected = Vous n'avez sélectionné aucun échantillon @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Traitement créé messageTreatmentSaved = Traitement enregistré messageTreatmentsDeleted = Tous les traitements sélectionnés ont été supprimés @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s le résultat du test pathogène est arrivé po notificationLabResultArrivedContact = %s le résultat du test d'agent pathogène est arrivé pour %s contact %s. Type de test \: %s. Maladie testée \: %s. notificationLabResultArrivedEventParticipant = %s résultats de test d'agent pathogène est arrivé pour %s participant à l'événement %s. Type de test \: %s. Maladie testée \: %s. notificationLabResultArrivedEventParticipantNoDisease = %s résultats de test pathogène est arrivé pour %s participant à l'événement %s. Type de test \: %s. -notificationLabResultSpecified = Un résultat de test pathogène pour %s la case %s a été spécifié à %s. Type de test \: %s. Maladie testée \: %s. -notificationLabResultSpecifiedContact = Un résultat de test de pathogène pour %s contact %s a été spécifié à %s. Type de test \: %s. Maladie testée \: %s. -notificationLabResultSpecifiedEventParticipant = Un résultat de test pathogène pour %s participant à l'événement %s a été spécifié à %s. Type de test \: %s. Maladie testée \: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = Un résultat de test pathogène pour %s participant à l'événement %s a été spécifié à %s. Type de test \: %s. notificationLabSampleShipped = Un nouvel échantillon (code d'échantillon\: %s) pour le cas %s est en cours d'expédition vers votre laboratoire. notificationLabSampleShippedShort = Un nouvel échantillon pour le cas %s est expédié à votre laboratoire. notificationLabSampleShippedShortForContact = Un nouvel échantillon de contact %s est en cours d'expédition vers votre laboratoire. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirmer la navigation unsavedChanges.warningMessage = Vous avez des modifications non enregistrées sur ce formulaire. diff --git a/sormas-api/src/main/resources/strings_fr-FR.properties b/sormas-api/src/main/resources/strings_fr-FR.properties index 5beae6c7337..e90342a1e7e 100644 --- a/sormas-api/src/main/resources/strings_fr-FR.properties +++ b/sormas-api/src/main/resources/strings_fr-FR.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Êtes-vous sûr de vouloir supprimer les %d contact confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Êtes-vous sûr de vouloir supprimer les %d participants sélectionnés à l'événement? confirmationDeleteEvents = Êtes-vous sûr de vouloir supprimer les %d événements sélectionnés ? +confirmationDeleteTravelEntries = Êtes-vous sûr de vouloir supprimer toutes les %d entrées de voyage sélectionnées ? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Êtes-vous sûr de vouloir supprimer les %d tests sélectionnés? confirmationDeletePrescriptions = Êtes-vous sûr de vouloir supprimer les %d prescriptions sélectionnées? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = Aucune visite médicale sélectionnée headingNoContactsSelected = Aucun contact sélectionné headingNoEventParticipantsSelected = Aucun participant à l'événement sélectionné headingNoEventsSelected = Aucun événement sélectionné +headingNoTravelEntriesSelected = Aucune entrée de voyage sélectionnée headingNoFile = Aucun fichier headingNoPathogenTestsSelected = No sample tests selected headingNoPrescriptionsSelected = Aucune ordonnance sélectionnée @@ -576,7 +578,8 @@ headingTasksDeleted = Tâches supprimées headingTemplateNotAvailable = Modèle non disponible headingTests = Tests headingTransferCase = Transfert le cas -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Entrées de voyage supprimées headingReferCaseFromPointOfEntry = Référez le cas du point d'entrée headingTreatments = Traitements exécutés headingTreatmentsDeleted = Traitement supprimé @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = Vous n'avez pas sélectionné de fichier à télécharger. Veuillez sélectionner un fichier que vous souhaitez importer depuis votre ordinateur. messageNoEventParticipantsSelected = Vous n'avez sélectionné aucun participant à l'événement messageNoEventsSelected = Vous n'avez sélectionné aucun événement +messageNoTravelEntriesSelected = Vous n'avez sélectionné aucune entrée de voyage messageNoPathogenTestsSelected = You have not selected any sample tests messageNoPrescriptionsSelected = Vous n'avez sélectionné aucune ordonnance messageNoSamplesSelected = Vous n'avez sélectionné aucun échantillon @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = Toutes les entrées de voyage sélectionnées ont été supprimées messageTreatmentCreated = Traitement créé messageTreatmentSaved = Traitement enregistré messageTreatmentsDeleted = Tous les traitements sélectionnés ont été supprimés @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s le résultat du test pathogène est arrivé po notificationLabResultArrivedContact = %s le résultat du test d'agent pathogène est arrivé pour %s contact %s. Type de test \: %s. Maladie testée \: %s. notificationLabResultArrivedEventParticipant = %s résultats de test d'agent pathogène est arrivé pour %s participant à l'événement %s. Type de test \: %s. Maladie testée \: %s. notificationLabResultArrivedEventParticipantNoDisease = %s résultats de test pathogène est arrivé pour %s participant à l'événement %s. Type de test \: %s. -notificationLabResultSpecified = Un résultat de test pathogène pour %s la case %s a été spécifié à %s. Type de test \: %s. Maladie testée \: %s. -notificationLabResultSpecifiedContact = Un résultat de test de pathogène pour %s contact %s a été spécifié à %s. Type de test \: %s. Maladie testée \: %s. -notificationLabResultSpecifiedEventParticipant = Un résultat de test pathogène pour %s participant à l'événement %s a été spécifié à %s. Type de test \: %s. Maladie testée \: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = Un résultat de test pathogène pour %s participant à l'événement %s a été spécifié à %s. Type de test \: %s. notificationLabSampleShipped = Un nouvel échantillon (code d'échantillon\: %s) pour le cas %s est en cours d'expédition vers votre laboratoire. notificationLabSampleShippedShort = Un nouvel échantillon pour le cas %s est expédié à votre laboratoire. notificationLabSampleShippedShortForContact = Un nouvel échantillon de contact %s est en cours d'expédition vers votre laboratoire. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Date de début d'immunisation depuis... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Date d'entrée de voyage depuis... +promptTravelEntryDateTo = ... à +promptTravelEntryEpiWeekFrom = Entrée de voyage depuis la semaine de l'Epi... +promptTravelEntryEpiWeekTo = ... à la semaine épi + # Unsaved changes unsavedChanges.warningTitle = Confirmer la navigation unsavedChanges.warningMessage = Vous avez des modifications non enregistrées sur ce formulaire. diff --git a/sormas-api/src/main/resources/strings_hi-IN.properties b/sormas-api/src/main/resources/strings_hi-IN.properties index 395653a1f96..e2aba1b50c7 100644 --- a/sormas-api/src/main/resources/strings_hi-IN.properties +++ b/sormas-api/src/main/resources/strings_hi-IN.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Are you sure you want to delete all %d selected con confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Are you sure you want to delete all %d selected event participants? confirmationDeleteEvents = Are you sure you want to delete all %d selected events? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected pathogen tests? confirmationDeletePrescriptions = Are you sure you want to delete all %d selected prescriptions? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = A new sample (sample code\: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_hr-HR.properties b/sormas-api/src/main/resources/strings_hr-HR.properties index 395653a1f96..e2aba1b50c7 100644 --- a/sormas-api/src/main/resources/strings_hr-HR.properties +++ b/sormas-api/src/main/resources/strings_hr-HR.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Are you sure you want to delete all %d selected con confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Are you sure you want to delete all %d selected event participants? confirmationDeleteEvents = Are you sure you want to delete all %d selected events? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected pathogen tests? confirmationDeletePrescriptions = Are you sure you want to delete all %d selected prescriptions? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = A new sample (sample code\: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_it-CH.properties b/sormas-api/src/main/resources/strings_it-CH.properties index ba6b04faaf8..a16750d1be7 100644 --- a/sormas-api/src/main/resources/strings_it-CH.properties +++ b/sormas-api/src/main/resources/strings_it-CH.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Sei sicuro di voler eliminare tutti i %d contatti s confirmationDeleteEntity = Sei sicuro di voler eliminare questo %s? Questa azione non potrà essere annullata. confirmationDeleteEventParticipants = Sei sicuro di voler eliminare tutti i %d partecipanti all'evento selezionati? confirmationDeleteEvents = Sei sicuro di voler eliminare tutti i %d eventi selezionati? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Sei sicuro di voler eliminare tutti i %d test patogeni selezionati? confirmationDeletePrescriptions = Sei sicuro di voler eliminare tutte le %d prescrizioni selezionate? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = Nessuna valutazione clinica selezionata headingNoContactsSelected = Nessun contatto selezionato headingNoEventParticipantsSelected = Nessun partecipante all'evento selezionato headingNoEventsSelected = Nessun evento selezionato +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = Nessun file headingNoPathogenTestsSelected = Nessun test patogeno selezionato headingNoPrescriptionsSelected = Nessuna prescrizione selezionata @@ -576,7 +578,8 @@ headingTasksDeleted = Compiti eliminati headingTemplateNotAvailable = Modello non disponibile headingTests = Test patogeni headingTransferCase = Trasferisci caso -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Trasferisci caso dal punto di entrata headingTreatments = Trattamenti eseguiti headingTreatmentsDeleted = Trattamenti eliminati @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = Non hai selezionato nessun partecipante all'evento messageNoEventsSelected = Non hai selezionato nessun evento +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = Non hai selezionato nessun test patogeno messageNoPrescriptionsSelected = Non hai selezionato nessuna prescrizione messageNoSamplesSelected = Non hai selezionato nessun campione @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Trattamento creato messageTreatmentSaved = Trattamento salvato messageTreatmentsDeleted = Tutti i trattamenti selezionati sono stati eliminati @@ -1189,10 +1194,6 @@ notificationLabResultArrived = Il risultato del test patogeno %s per il %s caso notificationLabResultArrivedContact = Il risultato del test patogeno %s per il %s contatto %s è arrivato. Tipo di test\: %s. Malattia testata\: %s. notificationLabResultArrivedEventParticipant = Il risultato del test patogeno %s per il %s contatto %s è arrivato. Tipo di test\: %s. Malattia testata\: %s. notificationLabResultArrivedEventParticipantNoDisease = Il risultato del test patogeno %s per il %s contatto %s è arrivato. Tipo di test\: %s. -notificationLabResultSpecified = Un risultato di test patogeno per il %s caso %s è stato specificato in %s. Tipo di test\: %s. Malattia testata\: %s. -notificationLabResultSpecifiedContact = Un risultato di test patogeno per il %s contatto %s è stato specificato in %s. Tipo di test\: %s. Malattia testata\: %s. -notificationLabResultSpecifiedEventParticipant = Un risultato di test patogeno per il %s contatto %s è stato specificato in %s. Tipo di test\: %s. Malattia testata\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = Un risultato del test patogeno per %s partecipante all'evento %s è stato specificato a %s. Tipo di test\: %s. notificationLabSampleShipped = Un nuovo campione (codice campione\: %s) per il caso %s viene spedito al tuo laboratorio. notificationLabSampleShippedShort = Un nuovo campione per il caso %s viene spedito al tuo laboratorio. notificationLabSampleShippedShortForContact = Un nuovo campione per il contatto %s viene spedito al tuo laboratorio. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Conferma navigazione unsavedChanges.warningMessage = Sono state apportate modifiche non salvate in questo modulo. diff --git a/sormas-api/src/main/resources/strings_it-IT.properties b/sormas-api/src/main/resources/strings_it-IT.properties index 4118e481c42..7aafc6f8f32 100644 --- a/sormas-api/src/main/resources/strings_it-IT.properties +++ b/sormas-api/src/main/resources/strings_it-IT.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Sei sicuro di voler eliminare tutti i %d contatti s confirmationDeleteEntity = Sei sicuro di voler eliminare questo %s? Questa azione non potrà essere annullata. confirmationDeleteEventParticipants = Sei sicuro di voler eliminare tutti i %d partecipanti all'evento selezionati? confirmationDeleteEvents = Sei sicuro di voler eliminare tutti i %d eventi selezionati? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Sei sicuro di voler eliminare tutti i %d test patogeni selezionati? confirmationDeletePrescriptions = Sei sicuro di voler eliminare tutte le %d prescrizioni selezionate? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = Nessuna valutazione clinica selezionata headingNoContactsSelected = Nessun contatto selezionato headingNoEventParticipantsSelected = Nessun partecipante all'evento selezionato headingNoEventsSelected = Nessun evento selezionato +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = Nessun file headingNoPathogenTestsSelected = Nessun test patogeno selezionato headingNoPrescriptionsSelected = Nessuna prescrizione selezionata @@ -576,7 +578,8 @@ headingTasksDeleted = Compiti eliminati headingTemplateNotAvailable = Modello non disponibile headingTests = Test patogeni headingTransferCase = Trasferisci caso -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Trasferisci caso dal punto di entrata headingTreatments = Trattamenti eseguiti headingTreatmentsDeleted = Trattamenti eliminati @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = Non hai selezionato nessun partecipante all'evento messageNoEventsSelected = Non hai selezionato nessun evento +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = Non hai selezionato nessun test patogeno messageNoPrescriptionsSelected = Non hai selezionato nessuna prescrizione messageNoSamplesSelected = Non hai selezionato nessun campione @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Trattamento creato messageTreatmentSaved = Trattamento salvato messageTreatmentsDeleted = Tutti i trattamenti selezionati sono stati eliminati @@ -1189,10 +1194,6 @@ notificationLabResultArrived = Il risultato del test patogeno %s per il %s caso notificationLabResultArrivedContact = Il risultato del test patogeno %s per il %s contatto %s è arrivato. Tipo di test\: %s. Malattia testata\: %s. notificationLabResultArrivedEventParticipant = Il risultato del test patogeno %s per il %s contatto %s è arrivato. Tipo di test\: %s. Malattia testata\: %s. notificationLabResultArrivedEventParticipantNoDisease = Il risultato del test patogeno %s per il %s contatto %s è arrivato. Tipo di test\: %s. -notificationLabResultSpecified = Un risultato di test patogeno per il %s caso %s è stato specificato in %s. Tipo di test\: %s. Malattia testata\: %s. -notificationLabResultSpecifiedContact = Un risultato di test patogeno per il %s contatto %s è stato specificato in %s. Tipo di test\: %s. Malattia testata\: %s. -notificationLabResultSpecifiedEventParticipant = Un risultato di test patogeno per il %s contatto %s è stato specificato in %s. Tipo di test\: %s. Malattia testata\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = Un risultato del test patogeno per %s partecipante all'evento %s è stato specificato a %s. Tipo di test\: %s. notificationLabSampleShipped = Un nuovo campione (codice campione\: %s) per il caso %s viene spedito al tuo laboratorio. notificationLabSampleShippedShort = Un nuovo campione per il caso %s viene spedito al tuo laboratorio. notificationLabSampleShippedShortForContact = Un nuovo campione per il contatto %s viene spedito al tuo laboratorio. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_ja-JP.properties b/sormas-api/src/main/resources/strings_ja-JP.properties index 395653a1f96..e2aba1b50c7 100644 --- a/sormas-api/src/main/resources/strings_ja-JP.properties +++ b/sormas-api/src/main/resources/strings_ja-JP.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Are you sure you want to delete all %d selected con confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Are you sure you want to delete all %d selected event participants? confirmationDeleteEvents = Are you sure you want to delete all %d selected events? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected pathogen tests? confirmationDeletePrescriptions = Are you sure you want to delete all %d selected prescriptions? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = A new sample (sample code\: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_nl-NL.properties b/sormas-api/src/main/resources/strings_nl-NL.properties index 395653a1f96..e2aba1b50c7 100644 --- a/sormas-api/src/main/resources/strings_nl-NL.properties +++ b/sormas-api/src/main/resources/strings_nl-NL.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Are you sure you want to delete all %d selected con confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Are you sure you want to delete all %d selected event participants? confirmationDeleteEvents = Are you sure you want to delete all %d selected events? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected pathogen tests? confirmationDeletePrescriptions = Are you sure you want to delete all %d selected prescriptions? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = A new sample (sample code\: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_no-NO.properties b/sormas-api/src/main/resources/strings_no-NO.properties index 395653a1f96..e2aba1b50c7 100644 --- a/sormas-api/src/main/resources/strings_no-NO.properties +++ b/sormas-api/src/main/resources/strings_no-NO.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Are you sure you want to delete all %d selected con confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Are you sure you want to delete all %d selected event participants? confirmationDeleteEvents = Are you sure you want to delete all %d selected events? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected pathogen tests? confirmationDeletePrescriptions = Are you sure you want to delete all %d selected prescriptions? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = A new sample (sample code\: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_pl-PL.properties b/sormas-api/src/main/resources/strings_pl-PL.properties index 395653a1f96..e2aba1b50c7 100644 --- a/sormas-api/src/main/resources/strings_pl-PL.properties +++ b/sormas-api/src/main/resources/strings_pl-PL.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Are you sure you want to delete all %d selected con confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Are you sure you want to delete all %d selected event participants? confirmationDeleteEvents = Are you sure you want to delete all %d selected events? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected pathogen tests? confirmationDeletePrescriptions = Are you sure you want to delete all %d selected prescriptions? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = A new sample (sample code\: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_ps-AF.properties b/sormas-api/src/main/resources/strings_ps-AF.properties index de8ad9df933..3d6fe026b4e 100644 --- a/sormas-api/src/main/resources/strings_ps-AF.properties +++ b/sormas-api/src/main/resources/strings_ps-AF.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Are you sure you want to delete all %d selected con confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Are you sure you want to delete all %d selected event participants? confirmationDeleteEvents = Are you sure you want to delete all %d selected events? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected pathogen tests? confirmationDeletePrescriptions = Are you sure you want to delete all %d selected prescriptions? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = A new sample (sample code\: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_pt-PT.properties b/sormas-api/src/main/resources/strings_pt-PT.properties index 395653a1f96..e2aba1b50c7 100644 --- a/sormas-api/src/main/resources/strings_pt-PT.properties +++ b/sormas-api/src/main/resources/strings_pt-PT.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Are you sure you want to delete all %d selected con confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Are you sure you want to delete all %d selected event participants? confirmationDeleteEvents = Are you sure you want to delete all %d selected events? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected pathogen tests? confirmationDeletePrescriptions = Are you sure you want to delete all %d selected prescriptions? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = A new sample (sample code\: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_ro-RO.properties b/sormas-api/src/main/resources/strings_ro-RO.properties index 395653a1f96..e2aba1b50c7 100644 --- a/sormas-api/src/main/resources/strings_ro-RO.properties +++ b/sormas-api/src/main/resources/strings_ro-RO.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Are you sure you want to delete all %d selected con confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Are you sure you want to delete all %d selected event participants? confirmationDeleteEvents = Are you sure you want to delete all %d selected events? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected pathogen tests? confirmationDeletePrescriptions = Are you sure you want to delete all %d selected prescriptions? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = A new sample (sample code\: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_ru-RU.properties b/sormas-api/src/main/resources/strings_ru-RU.properties index 82595eb150e..abbd125f68f 100644 --- a/sormas-api/src/main/resources/strings_ru-RU.properties +++ b/sormas-api/src/main/resources/strings_ru-RU.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Are you sure you want to delete all %d selected con confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Are you sure you want to delete all %d selected event participants? confirmationDeleteEvents = Are you sure you want to delete all %d selected events? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected pathogen tests? confirmationDeletePrescriptions = Are you sure you want to delete all %d selected prescriptions? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = A new sample (sample code\: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_sv-SE.properties b/sormas-api/src/main/resources/strings_sv-SE.properties index 395653a1f96..e2aba1b50c7 100644 --- a/sormas-api/src/main/resources/strings_sv-SE.properties +++ b/sormas-api/src/main/resources/strings_sv-SE.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Are you sure you want to delete all %d selected con confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Are you sure you want to delete all %d selected event participants? confirmationDeleteEvents = Are you sure you want to delete all %d selected events? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected pathogen tests? confirmationDeletePrescriptions = Are you sure you want to delete all %d selected prescriptions? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = A new sample (sample code\: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_sw-KE.properties b/sormas-api/src/main/resources/strings_sw-KE.properties index 395653a1f96..e2aba1b50c7 100644 --- a/sormas-api/src/main/resources/strings_sw-KE.properties +++ b/sormas-api/src/main/resources/strings_sw-KE.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Are you sure you want to delete all %d selected con confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Are you sure you want to delete all %d selected event participants? confirmationDeleteEvents = Are you sure you want to delete all %d selected events? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected pathogen tests? confirmationDeletePrescriptions = Are you sure you want to delete all %d selected prescriptions? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = A new sample (sample code\: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_tr-TR.properties b/sormas-api/src/main/resources/strings_tr-TR.properties index 395653a1f96..e2aba1b50c7 100644 --- a/sormas-api/src/main/resources/strings_tr-TR.properties +++ b/sormas-api/src/main/resources/strings_tr-TR.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Are you sure you want to delete all %d selected con confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Are you sure you want to delete all %d selected event participants? confirmationDeleteEvents = Are you sure you want to delete all %d selected events? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected pathogen tests? confirmationDeletePrescriptions = Are you sure you want to delete all %d selected prescriptions? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = A new sample (sample code\: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_uk-UA.properties b/sormas-api/src/main/resources/strings_uk-UA.properties index 395653a1f96..e2aba1b50c7 100644 --- a/sormas-api/src/main/resources/strings_uk-UA.properties +++ b/sormas-api/src/main/resources/strings_uk-UA.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = Are you sure you want to delete all %d selected con confirmationDeleteEntity = Are you sure you want to delete this %s? This action can not be reversed. confirmationDeleteEventParticipants = Are you sure you want to delete all %d selected event participants? confirmationDeleteEvents = Are you sure you want to delete all %d selected events? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = Are you sure you want to delete "%s"? confirmationDeletePathogenTests = Are you sure you want to delete all %d selected pathogen tests? confirmationDeletePrescriptions = Are you sure you want to delete all %d selected prescriptions? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = A new sample (sample code\: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/strings_ur-PK.properties b/sormas-api/src/main/resources/strings_ur-PK.properties index be76f408a05..cc57f5291bf 100644 --- a/sormas-api/src/main/resources/strings_ur-PK.properties +++ b/sormas-api/src/main/resources/strings_ur-PK.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = کیا آپ واقعی تمام %d منتخب رو confirmationDeleteEntity = کیا آپ واقعی اس %s کو مٹانا چاہتے ہیں؟ اس عمل کو واپس نہیں لیا جا سکتا۔ confirmationDeleteEventParticipants = کیا آپ واقعی تمام %d منتخب تقریب کے شرکاء کو مٹانا چاہتے ہیں؟ confirmationDeleteEvents = کیا آپ واقعی تمام %d منتخب تقریبات کو مٹانا چاہتے ہیں؟ +confirmationDeleteTravelEntries = کیا آپ واقعی تمام %d منتخب سفری اندراجات کو مٹانا چاہتے ہیں؟ confirmationDeleteFile = کیا آپ واقعی "%s" کو مٹانا چاہتے ہیں؟ confirmationDeletePathogenTests = کیا آپ واقعی تمام %d منتخب پیتھوجین ٹیسٹ کو مٹانا چاہتے ہیں؟ confirmationDeletePrescriptions = کیا آپ واقعی تمام %d منتخب نسخے کو مٹانا چاہتے ہیں؟ @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = کوئی طبی تشخیص منتخب نہیں headingNoContactsSelected = کوئی رابطے منتخب نہیں کیے گئے headingNoEventParticipantsSelected = تقریب کے کسی شرکاء کو منتخب نہیں کیا گیا headingNoEventsSelected = کوئی تقریبات منتخب نہیں کی گیئ +headingNoTravelEntriesSelected = کوئی سفری اندراج منتخب نہیں کیا گیا headingNoFile = کوئی فائل نہیں headingNoPathogenTestsSelected = کوئی پیتھوجین ٹیسٹ منتخب نہیں کۓ گۓ headingNoPrescriptionsSelected = کوئی نسخے منتخب نہیں کۓ گۓ @@ -576,7 +578,8 @@ headingTasksDeleted = کاموں کو مٹا دیا گیا headingTemplateNotAvailable = ٹیمپلیٹ دستیاب نہیں ہے headingTests = پیتھوجین ٹیسٹس headingTransferCase = کیس کی منتقلی -headingTravelEntryData= سفر کے اندراج کا ڈیٹا +headingTravelEntryData = سفر کے اندراج کا ڈیٹا +headingTravelEntriesDeleted = سفری اندراجات مٹا دیے گئے headingReferCaseFromPointOfEntry = داخلے کا جگہ سے کیس کا حوالہ دیں headingTreatments = عمل شدہ علاج headingTreatmentsDeleted = علاج مٹا دیے گیے @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = آپ نے اپ لوڈ کرنے کے لیے messageNoDocumentUploadFile = آپ نے اپ لوڈ کرنے کے لیے فائل کا انتخاب نہیں کیا ہے۔ براہ کرم ایک فائل منتخب کریں جسے آپ اپنے کمپیوٹر سے امپورٹ کرنا چاہتے ہیں۔ messageNoEventParticipantsSelected = آپ نے کسی بھی تقریب کے شرکاء کا انتخاب نہیں کیا ہے messageNoEventsSelected = آپ نے کوئی تقریبات منتخب نہیں کی۔ +messageNoTravelEntriesSelected = آپ نے کوئی سفری اندراج منتخب نہیں کیا ہے messageNoPathogenTestsSelected = آپ نے کوئی پیتھوجین ٹیسٹس منتخب نہیں کیے messageNoPrescriptionsSelected = آپ نے کوئی نسخے منتخب نہیں کیے messageNoSamplesSelected = آپ نے کوئی نمونے منتخب نہیں کیے @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = سفر کے اندراج کا ڈیٹا محفوظ ہو messageTravelEntryArchived = سفری اندراج کو آرکائیو کر دیا گیا ہے messageTravelEntryDearchived = سفری اندراج کو ڈی آرکائیو کر دیا گیا ہے messageTravelEntryPOEFilledBySystem = [System] داخلے کی جگہ خود بخود پرہو گئی +messageTravelEntriesDeleted = تمام منتخب سفری اندراجات کو مٹا دیا گیا ہے messageTreatmentCreated = علاج بنایا messageTreatmentSaved = علاج محفوظ کر لیا messageTreatmentsDeleted = تمام منتخب تقریبات کو مٹا دیا گیا ہے @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s پیتھوجین ٹیسٹ کا نتیجہ %s notificationLabResultArrivedContact = %s پیتھوجین ٹیسٹ کا نتیجہ %s رابطہ %s کے لیے آ گیا ہے۔ ٹیسٹ کی قسم\: %s۔ ٹیسٹڈ بیماری\: %s۔ notificationLabResultArrivedEventParticipant = %s پیتھوجین ٹیسٹ کا نتیجہ %s تقریب کے شریک %s کے لیے آ گیا ہے۔ ٹیسٹ کی قسم\: %s۔ ٹیسٹڈ بیماری\: %s۔ notificationLabResultArrivedEventParticipantNoDisease = %s پیتھوجین ٹیسٹ کا نتیجہ %s تقریب کے شریک %s کے لیے آ گیا ہے۔ ٹیسٹ کی قسم\: %s۔ -notificationLabResultSpecified = %s کیس %s کے لیے پیتھوجین ٹیسٹ کا نتیجہ %s کے لیے مخصوص کیا گیا ہے۔ ٹیسٹ کی قسم\: %s۔ ٹیسٹڈ بیماری\: %s۔ -notificationLabResultSpecifiedContact = %s رابطہ %s کے لیے ایک پیتھوجین ٹیسٹ کا نتیجہ %s پر بیان کیا گیا ہے۔ ٹیسٹ کی قسم\: %s۔ ٹیسٹڈ بیماری\: %s۔ -notificationLabResultSpecifiedEventParticipant = %s تقریب کے شریک %s کے لیے ایک پیتھوجین ٹیسٹ کا نتیجہ %s کے لیے مخصوص کیا گیا ہے۔ ٹیسٹ کی قسم\: %s۔ ٹیسٹڈ بیماری\: %s۔ -notificationLabResultSpecifiedEventParticipantNoDisease = %s تقریب کے شریک %s کے لیے ایک پیتھوجین ٹیسٹ کا نتیجہ %s کے لیے مخصوص کیا گیا ہے۔ ٹیسٹ کی قسم\: %s۔ notificationLabSampleShipped = کیس %s کے لیے ایک نیا نمونہ (نمونہ کوڈ\: %s) آپ کی لیبارٹری میں بھیج دیا جا رہا ہے۔ notificationLabSampleShippedShort = کیس %s کے لیے ایک نیا نمونہ آپ کی لیبارٹری میں بھیجا جا رہا ہے۔ notificationLabSampleShippedShortForContact = رابطہ %s کے لیے ایک نیا نمونہ آپ کی لیبارٹری میں بھیجا جا رہا ہے۔ @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = امیونائزیشن شروع ہونے کی promptImmunizationPositiveTestResultDateFrom = امیونائزیشن مثبت ٹیسٹ کے نتائج کی تاریخ سے... promptImmunizationRecoveryDateFrom = امیونائزیشن کی بازیابی کی تاریخ سے... +promptTravelEntryDateFrom = سفر کے اندراج کی رپورٹ کی تاریخ سے... +promptTravelEntryDateTo = ... سے +promptTravelEntryEpiWeekFrom = EPI ہفتہ سے سفری داخلہ... +promptTravelEntryEpiWeekTo = ... EPI ہفتہ تک + # Unsaved changes unsavedChanges.warningTitle = نیویگیشن کی تصدیق کریں unsavedChanges.warningMessage = آپ کے پاس اس فارم میں غیر محفوظ شدہ تبدیلیاں ہیں۔ diff --git a/sormas-api/src/main/resources/strings_zh-CN.properties b/sormas-api/src/main/resources/strings_zh-CN.properties index 841425d99aa..0ddded30421 100644 --- a/sormas-api/src/main/resources/strings_zh-CN.properties +++ b/sormas-api/src/main/resources/strings_zh-CN.properties @@ -138,6 +138,7 @@ confirmationDeleteContacts = 您确定要删除所有 %d 个选定联系人吗 confirmationDeleteEntity = 您确定要删除此 %s吗?此操作不能被撤销。 confirmationDeleteEventParticipants = 您确定要删除所有 %d 个选定的事件参与者吗? confirmationDeleteEvents = 您确定要删除所有选定的 %d 个事件吗? +confirmationDeleteTravelEntries = Are you sure you want to delete all %d selected travel entries? confirmationDeleteFile = 您确定要删除"%s "吗? confirmationDeletePathogenTests = 您确定要删除所有 %d 个选定病原体测试吗? confirmationDeletePrescriptions = 您确定要删除所有 %d 选中处方吗? @@ -529,6 +530,7 @@ headingNoClinicalVisitsSelected = No clinical assessments selected headingNoContactsSelected = No contacts selected headingNoEventParticipantsSelected = No event participants selected headingNoEventsSelected = No events selected +headingNoTravelEntriesSelected = No travel entries selected headingNoFile = No file headingNoPathogenTestsSelected = No pathogen tests selected headingNoPrescriptionsSelected = No prescriptions selected @@ -576,7 +578,8 @@ headingTasksDeleted = Tasks deleted headingTemplateNotAvailable = Template not available headingTests = Pathogen tests headingTransferCase = Transfer case -headingTravelEntryData= Travel entry data +headingTravelEntryData = Travel entry data +headingTravelEntriesDeleted = Travel entries deleted headingReferCaseFromPointOfEntry = Refer case from point of entry headingTreatments = Executed treatments headingTreatmentsDeleted = Treatments deleted @@ -1012,6 +1015,7 @@ messageNoDocumentTemplateUploadFile = You have not selected a file to upload. Pl messageNoDocumentUploadFile = You have not selected a file to upload. Please select a file you want to import from your computer. messageNoEventParticipantsSelected = You have not selected any event participants messageNoEventsSelected = You have not selected any events +messageNoTravelEntriesSelected = You have not selected any travel entries messageNoPathogenTestsSelected = You have not selected any pathogen tests messageNoPrescriptionsSelected = You have not selected any prescriptions messageNoSamplesSelected = You have not selected any samples @@ -1050,6 +1054,7 @@ messageTravelEntrySaved = Travel entry data saved messageTravelEntryArchived = Travel entry has been archived messageTravelEntryDearchived = Travel entry has been de-archived messageTravelEntryPOEFilledBySystem = [System] Automatically filled point of entry +messageTravelEntriesDeleted = All selected travel entries have been deleted messageTreatmentCreated = Treatment created messageTreatmentSaved = Treatment saved messageTreatmentsDeleted = All selected treatments have been deleted @@ -1189,10 +1194,6 @@ notificationLabResultArrived = %s pathogen test result has arrived for %s case % notificationLabResultArrivedContact = %s pathogen test result has arrived for %s contact %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipant = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. Tested disease\: %s. notificationLabResultArrivedEventParticipantNoDisease = %s pathogen test result has arrived for %s event participant %s. Test type\: %s. -notificationLabResultSpecified = A pathogen test result for %s case %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedContact = A pathogen test result for %s contact %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipant = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. Tested disease\: %s. -notificationLabResultSpecifiedEventParticipantNoDisease = A pathogen test result for %s event participant %s has been specified to %s. Test type\: %s. notificationLabSampleShipped = A new sample (sample code\: %s) for case %s is being shipped to your laboratory. notificationLabSampleShippedShort = A new sample for case %s is being shipped to your laboratory. notificationLabSampleShippedShortForContact = A new sample for contact %s is being shipped to your laboratory. @@ -1349,6 +1350,11 @@ promptImmunizationStartDateFrom = Immunization start date from... promptImmunizationPositiveTestResultDateFrom = Immunization positive test result date from... promptImmunizationRecoveryDateFrom = Immunization recovery date from... +promptTravelEntryDateFrom = Travel entry report date from... +promptTravelEntryDateTo = ... to +promptTravelEntryEpiWeekFrom = Travel entry from epi week... +promptTravelEntryEpiWeekTo = ... to epi week + # Unsaved changes unsavedChanges.warningTitle = Confirm navigation unsavedChanges.warningMessage = You have unsaved changes on this form. diff --git a/sormas-api/src/main/resources/validations_cs-CZ.properties b/sormas-api/src/main/resources/validations_cs-CZ.properties index 1f7b067a109..75a47d55a0f 100644 --- a/sormas-api/src/main/resources/validations_cs-CZ.properties +++ b/sormas-api/src/main/resources/validations_cs-CZ.properties @@ -231,7 +231,7 @@ personMultiplePrimaryPhoneNumbers = Osoba má více primárních telefonních č personMultiplePrimaryEmailAddresses = Osoba má více primárních e-mailových adres. Povolena je pouze jedna primární e-mailová adresa. birthDateInFuture = Datum narození nesmí být v budoucnu birthDateInvalid = Zadané datum narození není platné -nameOrAnyOtherFieldShouldBeFilled=At least one name field or an other field should be filled +nameOrAnyOtherFieldShouldBeFilled=Mělo by být vyplněno alespoň jeno pole jména nebo jiné pole notAccomodationFacilityType = Typ zařízení %s nelze použít pro místo pobytu fileTooBig = Soubor je příliš velký. Maximální povolená velikost souboru je %dMB infrastructureDataLocked = Údaje o infrastruktuře jsou uzamčeny a nelze je aktualizovat From 929aebbe16550d368684033ff96f4a31edb274b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9=20Strysewske?= Date: Wed, 23 Feb 2022 11:14:40 +0100 Subject: [PATCH 150/253] #7812 - Added pre-commit listener to hospitalization form --- .../symeda/sormas/ui/caze/CaseController.java | 80 ++++++++++++++----- .../utils/CommitDiscardWrapperComponent.java | 29 ++++++- .../symeda/sormas/ui/utils/VaadinUiUtil.java | 10 ++- 3 files changed, 92 insertions(+), 27 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java index 240ad1a0981..0986695d6c9 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java @@ -17,7 +17,6 @@ *******************************************************************************/ package de.symeda.sormas.ui.caze; -import de.symeda.sormas.ui.utils.CssStyles; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -84,8 +83,10 @@ import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Strings; +import de.symeda.sormas.api.infrastructure.community.CommunityReferenceDto; import de.symeda.sormas.api.infrastructure.district.DistrictReferenceDto; import de.symeda.sormas.api.infrastructure.facility.FacilityDto; +import de.symeda.sormas.api.infrastructure.facility.FacilityReferenceDto; import de.symeda.sormas.api.infrastructure.facility.FacilityType; import de.symeda.sormas.api.infrastructure.pointofentry.PointOfEntryDto; import de.symeda.sormas.api.infrastructure.pointofentry.PointOfEntryReferenceDto; @@ -130,6 +131,7 @@ import de.symeda.sormas.ui.utils.AbstractView; import de.symeda.sormas.ui.utils.ButtonHelper; import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent; +import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.DateHelper8; import de.symeda.sormas.ui.utils.DetailSubComponentWrapper; import de.symeda.sormas.ui.utils.NullableOptionGroup; @@ -1151,35 +1153,60 @@ public CommitDiscardWrapperComponent getHospitalizationComp UserProvider.getCurrent().hasUserRight(UserRight.CASE_EDIT), hospitalizationForm.getFieldGroup()); - editView.addCommitListener(() -> { + final JurisdictionValues jurisdictionValues = new JurisdictionValues(); + + editView.setPreCommitListener(successCallback -> { final CaseDataDto cazeDto = FacadeProvider.getCaseFacade().getCaseDataByUuid(caseUuid); final YesNoUnknown initialAdmittedToHealthFacility = cazeDto.getHospitalization().getAdmittedToHealthFacility(); - cazeDto.setHospitalization(hospitalizationForm.getValue()); - final CaseDataDto caseDataDto = saveCase(cazeDto); - final YesNoUnknown admittedToHealthFacility = caseDataDto.getHospitalization().getAdmittedToHealthFacility(); + final YesNoUnknown admittedToHealthFacility = + (YesNoUnknown) ((NullableOptionGroup) hospitalizationForm.getField(HospitalizationDto.ADMITTED_TO_HEALTH_FACILITY)) + .getNullableValue(); + if (YesNoUnknown.YES == admittedToHealthFacility && initialAdmittedToHealthFacility != admittedToHealthFacility && cazeDto.getFacilityType() != FacilityType.HOSPITAL) { - PlaceOfStayEditForm placeOfStayEditForm = new PlaceOfStayEditForm(caseDataDto); - placeOfStayEditForm.setValue(caseDataDto); + + PlaceOfStayEditForm placeOfStayEditForm = new PlaceOfStayEditForm(cazeDto); + placeOfStayEditForm.setValue(cazeDto); final CommitDiscardWrapperComponent wrapperComponent = new CommitDiscardWrapperComponent<>( placeOfStayEditForm, UserProvider.getCurrent().hasUserRight(UserRight.CASE_EDIT), placeOfStayEditForm.getFieldGroup()); wrapperComponent.addCommitListener(() -> { - final CaseDataDto cazeDtoInner = FacadeProvider.getCaseFacade().getCaseDataByUuid(caseUuid); final CaseDataDto dto = placeOfStayEditForm.getValue(); - cazeDtoInner.setRegion(dto.getRegion()); - cazeDtoInner.setDistrict(dto.getDistrict()); - cazeDtoInner.setCommunity(dto.getCommunity()); - cazeDtoInner.setFacilityType(FacilityType.HOSPITAL); - cazeDtoInner.setHealthFacility(dto.getHealthFacility()); - cazeDtoInner.setHealthFacilityDetails(dto.getHealthFacilityDetails()); - FacadeProvider.getCaseFacade().save(cazeDtoInner); - ControllerProvider.getCaseController().navigateToView(HospitalizationView.VIEW_NAME, caze.getUuid(), null); + jurisdictionValues.region = dto.getRegion(); + jurisdictionValues.district = dto.getDistrict(); + jurisdictionValues.community = dto.getCommunity(); + jurisdictionValues.facilityType = FacilityType.HOSPITAL; + jurisdictionValues.facility = dto.getHealthFacility(); + jurisdictionValues.facilityDetails = dto.getHealthFacilityDetails(); + jurisdictionValues.valuesUpdated = true; }); - VaadinUiUtil.showModalPopupWindow(wrapperComponent, I18nProperties.getString(Strings.headingPlaceOfStayInHospital)); + + VaadinUiUtil + .showModalPopupWindow(wrapperComponent, I18nProperties.getString(Strings.headingPlaceOfStayInHospital), preCommitSuccessful -> { + if (preCommitSuccessful) { + successCallback.run(); + } + }); + } else { + successCallback.run(); + } + }); + + editView.addCommitListener(() -> { + final CaseDataDto cazeDto = findCase(caseUuid); + + if (jurisdictionValues.valuesUpdated) { + cazeDto.setRegion(jurisdictionValues.region); + cazeDto.setDistrict(jurisdictionValues.district); + cazeDto.setCommunity(jurisdictionValues.community); + cazeDto.setFacilityType(jurisdictionValues.facilityType); + cazeDto.setHealthFacility(jurisdictionValues.facility); + cazeDto.setHealthFacilityDetails(jurisdictionValues.facilityDetails); } + cazeDto.setHospitalization(hospitalizationForm.getValue()); + saveCase(cazeDto); }); return editView; @@ -1760,14 +1787,12 @@ public void sendCasesToExternalSurveillanceTool(Collection extends VerticalLayout implements DirtyStateComponent, Buffered { private static final long serialVersionUID = 1L; + public static interface PreCommitListener { + + void onPreCommit(Runnable successCallback); + } + public static interface CommitListener { void onCommit() throws CannotProceedException; @@ -87,6 +92,7 @@ public static interface DeleteListener { void onDelete(); } + private transient PreCommitListener preCommitListener; private transient List commitListeners = new ArrayList<>(); private transient List discardListeners = new ArrayList<>(); private transient List doneListeners = new ArrayList<>(); @@ -434,7 +440,17 @@ public boolean isCommited() { } @Override - public void commit() throws InvalidValueException, SourceException, CommitRuntimeException { + public void commit() { + + if (preCommitListener != null) { + preCommitListener.onPreCommit(this::doCommit); + } else { + doCommit(); + } + + } + + private void doCommit() throws InvalidValueException, SourceException, CommitRuntimeException { if (fieldGroups != null) { if (fieldGroups.size() > 1) { List invalidValueExceptions = @@ -620,6 +636,10 @@ public boolean isBuffered() { } } + public void setPreCommitListener(PreCommitListener listener) { + this.preCommitListener = listener; + } + public void addCommitListener(CommitListener listener) { if (!commitListeners.contains(listener)) commitListeners.add(listener); @@ -641,12 +661,13 @@ public void removeCommitListener(CommitListener listener) { private void onCommit() { - for (CommitListener listener : commitListeners) + for (CommitListener listener : commitListeners) { try { listener.onCommit(); } catch (CannotProceedException e) { break; } + } } /** diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/VaadinUiUtil.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/VaadinUiUtil.java index 32726bf8b81..116dda0bd25 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/VaadinUiUtil.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/VaadinUiUtil.java @@ -127,18 +127,26 @@ public static Window showPopupWindowWithWidth(Component content, String caption, window.setWidth(width, Unit.PERCENTAGE); } - UI.getCurrent().addWindow(window); return window; } public static Window showModalPopupWindow(CommitDiscardWrapperComponent content, String caption) { + return showModalPopupWindow(content, caption, null); + } + + public static Window showModalPopupWindow(CommitDiscardWrapperComponent content, String caption, Consumer callback) { final Window popupWindow = VaadinUiUtil.showPopupWindow(content); popupWindow.setCaption(caption); content.setMargin(true); content.addDoneListener(popupWindow::close); + if (callback != null) { + content.addCommitListener(() -> callback.accept(true)); + content.addDiscardListener(() -> callback.accept(false)); + } + return popupWindow; } From ec3bf16ef560da447ba1e385667e356f4cd0503f Mon Sep 17 00:00:00 2001 From: sergiupacurariu <62688603+sergiupacurariu@users.noreply.github.com> Date: Wed, 23 Feb 2022 12:18:33 +0200 Subject: [PATCH 151/253] #7247 - CoreAdo: Introduce "end of processing date" - event participant relevance status filter --- .../de/symeda/sormas/api/ConfigFacade.java | 2 + .../api/event/EventParticipantCriteria.java | 12 +++ .../de/symeda/sormas/api/i18n/Captions.java | 3 + .../de/symeda/sormas/api/i18n/Strings.java | 1 + .../de/symeda/sormas/api/user/UserRight.java | 23 ++++++ .../src/main/resources/captions.properties | 3 + .../src/main/resources/strings.properties | 1 + .../backend/common/ConfigFacadeEjb.java | 6 ++ .../event/EventParticipantService.java | 11 ++- .../ui/events/EventParticipantsView.java | 73 ++++++++++++++++++- .../sormas/ui/utils/ArchivingController.java | 9 +-- 11 files changed, 135 insertions(+), 9 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/ConfigFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/ConfigFacade.java index c0fdb461109..79814e3c178 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/ConfigFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/ConfigFacade.java @@ -92,6 +92,8 @@ public interface ConfigFacade { int getDaysAfterEventGetsArchived(); + int getDaysAfterEventParticipantGetsArchived(); + int getDaysAfterSystemEventGetsDeleted(); int getDaysAfterTravelEntryGetsArchived(); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventParticipantCriteria.java b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventParticipantCriteria.java index f28f0826948..a783cacf449 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/event/EventParticipantCriteria.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/event/EventParticipantCriteria.java @@ -4,6 +4,7 @@ import java.util.Date; import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.EntityRelevanceStatus; import de.symeda.sormas.api.caze.VaccinationStatus; import de.symeda.sormas.api.person.PersonReferenceDto; import de.symeda.sormas.api.sample.PathogenTestResultType; @@ -36,6 +37,7 @@ public class EventParticipantCriteria extends BaseCriteria implements Serializab private Date relevantDate; private Boolean excludePseudonymized; private Boolean noResultingCase; + private EntityRelevanceStatus relevanceStatus; @IgnoreForUrl public EventReferenceDto getEvent() { @@ -208,4 +210,14 @@ public Boolean getNoResultingCase() { public void setNoResultingCase(Boolean noResultingCase) { this.noResultingCase = noResultingCase; } + + @IgnoreForUrl + public EntityRelevanceStatus getRelevanceStatus() { + return relevanceStatus; + } + + public EventParticipantCriteria relevanceStatus(EntityRelevanceStatus relevanceStatus) { + this.relevanceStatus = relevanceStatus; + return this; + } } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java index 45dfb4fe23d..f9e3fa95c5c 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java @@ -1135,7 +1135,10 @@ public interface Captions { String EventParticipant_sex = "EventParticipant.sex"; String EventParticipant_uuid = "EventParticipant.uuid"; String EventParticipant_vaccinationStatus = "EventParticipant.vaccinationStatus"; + String eventParticipantActiveEventParticipants = "eventParticipantActiveEventParticipants"; String eventParticipantAddPerson = "eventParticipantAddPerson"; + String eventParticipantAllEventParticipants = "eventParticipantAllEventParticipants"; + String eventParticipantArchivedEventParticipants = "eventParticipantArchivedEventParticipants"; String eventParticipantContactCountOnlyWithSourceCaseInEvent = "eventParticipantContactCountOnlyWithSourceCaseInEvent"; String eventParticipantCreateNew = "eventParticipantCreateNew"; String EventParticipantExport_addressCommunity = "EventParticipantExport.addressCommunity"; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java index 2cba83d75cd..209b3215d8b 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java @@ -684,6 +684,7 @@ public interface Strings { String infoActivityAsCaseInvestigation = "infoActivityAsCaseInvestigation"; String infoAddTestsToSample = "infoAddTestsToSample"; String infoArchivedCases = "infoArchivedCases"; + String infoArchivedEventParticipants = "infoArchivedEventParticipants"; String infoArchivedEvents = "infoArchivedEvents"; String infoArchivedTravelEntries = "infoArchivedTravelEntries"; String infoAssigneeMissingEmail = "infoAssigneeMissingEmail"; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRight.java b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRight.java index 3f747bc9c2a..7f494b349fb 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRight.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRight.java @@ -851,6 +851,29 @@ public enum UserRight { IMPORT_USER, COMMUNITY_OFFICER ), + EVENTPARTICIPANT_VIEW( + ADMIN, + NATIONAL_USER, + NATIONAL_CLINICIAN, + NATIONAL_OBSERVER, + POE_NATIONAL_USER, + STATE_OBSERVER, + DISTRICT_OBSERVER, + SURVEILLANCE_SUPERVISOR, + ADMIN_SUPERVISOR, + SURVEILLANCE_OFFICER, + CASE_SUPERVISOR, + CASE_OFFICER, + CONTACT_SUPERVISOR, + CONTACT_OFFICER, + POE_SUPERVISOR, + POE_INFORMANT, + HOSPITAL_INFORMANT, + COMMUNITY_INFORMANT, + LAB_USER, + EVENT_OFFICER, + COMMUNITY_OFFICER + ), EVENTGROUP_CREATE( ADMIN, NATIONAL_USER, diff --git a/sormas-api/src/main/resources/captions.properties b/sormas-api/src/main/resources/captions.properties index 282355f7f2f..d2590120e1d 100644 --- a/sormas-api/src/main/resources/captions.properties +++ b/sormas-api/src/main/resources/captions.properties @@ -1216,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/strings.properties b/sormas-api/src/main/resources/strings.properties index 13478375620..aa0dedea171 100644 --- a/sormas-api/src/main/resources/strings.properties +++ b/sormas-api/src/main/resources/strings.properties @@ -716,6 +716,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ConfigFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ConfigFacadeEjb.java index 4da5b1ebd4d..6b51965cd18 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ConfigFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/ConfigFacadeEjb.java @@ -124,6 +124,7 @@ public class ConfigFacadeEjb implements ConfigFacade { public static final String DAYS_AFTER_CASE_GETS_ARCHIVED = "daysAfterCaseGetsArchived"; private static final String DAYS_AFTER_EVENT_GETS_ARCHIVED = "daysAfterEventGetsArchived"; + private static final String DAYS_AFTER_EVENT_PARTICIPANT_GETS_ARCHIVED = "daysAfterEventParticipantGetsArchived"; private static final String DAYS_AFTER_TRAVEL_ENTRY_GETS_ARCHIVED = "daysAfterTravelEntryGetsArchived"; private static final String DAYS_AFTER_SYSTEM_EVENT_GETS_DELETED = "daysAfterSystemEventGetsDeleted"; @@ -458,6 +459,11 @@ public int getDaysAfterEventGetsArchived() { return getInt(DAYS_AFTER_EVENT_GETS_ARCHIVED, 90); } + @Override + public int getDaysAfterEventParticipantGetsArchived() { + return getInt(DAYS_AFTER_EVENT_PARTICIPANT_GETS_ARCHIVED, 90); + } + @Override public int getDaysAfterSystemEventGetsDeleted() { return getInt(DAYS_AFTER_SYSTEM_EVENT_GETS_DELETED, 90); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java index aeaf5c165a5..1a5a0b1f8c8 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java @@ -39,10 +39,10 @@ import javax.persistence.criteria.Root; import javax.persistence.criteria.Subquery; -import de.symeda.sormas.backend.common.ChangeDateFilterBuilder; import org.apache.commons.collections.CollectionUtils; import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.EntityRelevanceStatus; import de.symeda.sormas.api.caze.VaccinationStatus; import de.symeda.sormas.api.event.EventParticipantCriteria; import de.symeda.sormas.api.utils.DataHelper; @@ -51,6 +51,7 @@ import de.symeda.sormas.backend.common.AbstractCoreAdoService; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.ChangeDateBuilder; +import de.symeda.sormas.backend.common.ChangeDateFilterBuilder; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.contact.ContactQueryContext; @@ -221,6 +222,14 @@ public Predicate buildCriteriaFilter(EventParticipantCriteria criteria, EventPar filter = CriteriaBuilderHelper.and(cb, filter, cb.isNull(from.get(EventParticipant.RESULTING_CASE))); } + if (criteria.getRelevanceStatus() != null) { + if (criteria.getRelevanceStatus() == EntityRelevanceStatus.ACTIVE) { + filter = CriteriaBuilderHelper.and(cb, filter, cb.or(cb.equal(from.get(Event.ARCHIVED), false), cb.isNull(from.get(Event.ARCHIVED)))); + } else if (criteria.getRelevanceStatus() == EntityRelevanceStatus.ARCHIVED) { + filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(Event.ARCHIVED), true)); + } + } + filter = CriteriaBuilderHelper.and(cb, filter, createDefaultFilter(cb, from)); return filter; diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsView.java index 6435addb2d3..767c2be13f4 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsView.java @@ -19,10 +19,10 @@ import static de.symeda.sormas.ui.docgeneration.DocGenerationHelper.isDocGenerationAllowed; -import de.symeda.sormas.api.event.EventParticipantReferenceDto; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -31,9 +31,11 @@ import com.vaadin.icons.VaadinIcons; import com.vaadin.server.Page; import com.vaadin.server.StreamResource; +import com.vaadin.shared.ui.ContentMode; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Label; import com.vaadin.ui.MenuBar; import com.vaadin.ui.Notification; import com.vaadin.ui.UI; @@ -41,11 +43,14 @@ import com.vaadin.ui.Window; import com.vaadin.ui.components.grid.MultiSelectionModelImpl; import com.vaadin.ui.themes.ValoTheme; +import com.vaadin.v7.ui.ComboBox; +import de.symeda.sormas.api.EntityRelevanceStatus; import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.event.EventDto; import de.symeda.sormas.api.event.EventParticipantCriteria; import de.symeda.sormas.api.event.EventParticipantIndexDto; +import de.symeda.sormas.api.event.EventParticipantReferenceDto; import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.Descriptions; import de.symeda.sormas.api.i18n.I18nProperties; @@ -59,6 +64,7 @@ import de.symeda.sormas.ui.customexport.ExportConfigurationsLayout; import de.symeda.sormas.ui.events.eventparticipantimporter.EventParticipantImportLayout; import de.symeda.sormas.ui.utils.ButtonHelper; +import de.symeda.sormas.ui.utils.ComboBoxHelper; import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.DetailSubComponentWrapper; import de.symeda.sormas.ui.utils.EventParticipantDownloadUtil; @@ -83,6 +89,9 @@ public class EventParticipantsView extends AbstractEventView { private Button activeStatusButton; private EventParticipantsFilterForm filterForm; + private Label relevanceStatusInfoLabel; + private ComboBox eventParticipantRelevanceStatusFilter; + public EventParticipantsView() { super(VIEW_NAME); @@ -90,6 +99,10 @@ public EventParticipantsView() { addStyleName("crud-view"); criteria = ViewModelProviders.of(EventParticipantsView.class).get(EventParticipantCriteria.class); + + if (criteria.getRelevanceStatus() == null) { + criteria.relevanceStatus(EntityRelevanceStatus.ACTIVE); + } } public HorizontalLayout createTopBar() { @@ -288,18 +301,68 @@ public HorizontalLayout createStatusFilterBar() { statusFilterLayout.addComponent(statusAll); activeStatusButton = statusAll; + HorizontalLayout actionButtonsLayout = new HorizontalLayout(); + actionButtonsLayout.setSpacing(true); + + // Show active/archived/all dropdown + if (Objects.nonNull(UserProvider.getCurrent()) && UserProvider.getCurrent().hasUserRight(UserRight.EVENTPARTICIPANT_VIEW)) { + int daysAfterdaysAfterEventParticipantGetsArchived = FacadeProvider.getConfigFacade().getDaysAfterEventParticipantGetsArchived(); + if (daysAfterdaysAfterEventParticipantGetsArchived > 0) { + relevanceStatusInfoLabel = new Label( + VaadinIcons.INFO_CIRCLE.getHtml() + " " + + String + .format(I18nProperties.getString(Strings.infoArchivedEventParticipants), daysAfterdaysAfterEventParticipantGetsArchived), + ContentMode.HTML); + relevanceStatusInfoLabel.setVisible(false); + relevanceStatusInfoLabel.addStyleName(CssStyles.LABEL_VERTICAL_ALIGN_SUPER); + actionButtonsLayout.addComponent(relevanceStatusInfoLabel); + actionButtonsLayout.setComponentAlignment(relevanceStatusInfoLabel, Alignment.MIDDLE_RIGHT); + } + + eventParticipantRelevanceStatusFilter = buildRelevanceStatusFilter( + Captions.eventParticipantActiveEventParticipants, + Captions.eventParticipantArchivedEventParticipants, + Captions.eventParticipantAllEventParticipants); + + eventParticipantRelevanceStatusFilter.addValueChangeListener(e -> { + relevanceStatusInfoLabel.setVisible(EntityRelevanceStatus.ARCHIVED.equals(e.getProperty().getValue())); + criteria.relevanceStatus((EntityRelevanceStatus) e.getProperty().getValue()); + navigateTo(criteria); + }); + actionButtonsLayout.addComponent(eventParticipantRelevanceStatusFilter); + } + if (UserProvider.getCurrent().hasUserRight(UserRight.EVENTPARTICIPANT_CREATE)) { addButton = ButtonHelper.createIconButton(Captions.eventParticipantAddPerson, VaadinIcons.PLUS_CIRCLE, e -> { ControllerProvider.getEventParticipantController().createEventParticipant(this.getEventRef(), r -> navigateTo(criteria)); }, ValoTheme.BUTTON_PRIMARY); - statusFilterLayout.addComponent(addButton); - statusFilterLayout.setComponentAlignment(addButton, Alignment.MIDDLE_RIGHT); + actionButtonsLayout.addComponent(addButton); } + statusFilterLayout.addComponent(actionButtonsLayout); + statusFilterLayout.setComponentAlignment(actionButtonsLayout, Alignment.MIDDLE_RIGHT); + statusFilterLayout.setExpandRatio(actionButtonsLayout, 1); + return statusFilterLayout; } + private ComboBox buildRelevanceStatusFilter( + String eventParticipantActiveCaption, + String eventParticipantArchivedCaption, + String eventParticipantAllCaption) { + + ComboBox relevanceStatusFilter = ComboBoxHelper.createComboBoxV7(); + relevanceStatusFilter.setId("relevanceStatusFilter"); + relevanceStatusFilter.setWidth(200, Unit.PIXELS); + relevanceStatusFilter.setNullSelectionAllowed(false); + relevanceStatusFilter.addItems((Object[]) EntityRelevanceStatus.values()); + relevanceStatusFilter.setItemCaption(EntityRelevanceStatus.ACTIVE, I18nProperties.getCaption(eventParticipantActiveCaption)); + relevanceStatusFilter.setItemCaption(EntityRelevanceStatus.ARCHIVED, I18nProperties.getCaption(eventParticipantArchivedCaption)); + relevanceStatusFilter.setItemCaption(EntityRelevanceStatus.ALL, I18nProperties.getCaption(eventParticipantAllCaption)); + return relevanceStatusFilter; + } + public void updateFilterComponents() { // TODO replace with Vaadin 8 databinding @@ -307,6 +370,10 @@ public void updateFilterComponents() { updateStatusButtons(); + if (eventParticipantRelevanceStatusFilter != null) { + eventParticipantRelevanceStatusFilter.setValue(criteria.getRelevanceStatus()); + } + filterForm.setValue(criteria); applyingCriteria = false; diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchivingController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchivingController.java index 9552230fae3..484aa972be2 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchivingController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchivingController.java @@ -30,11 +30,7 @@ public void archiveEntity( Runnable callback) { VerticalLayout verticalLayout = new VerticalLayout(); - Label contentLabel = new Label( - String.format( - I18nProperties.getString(archiveConfirmationMessage), - I18nProperties.getString(entity).toLowerCase(), - I18nProperties.getString(entity).toLowerCase())); + Label contentLabel = new Label(I18nProperties.getString(archiveConfirmationMessage)); contentLabel.setWidth(100, Sizeable.Unit.PERCENTAGE); verticalLayout.addComponent(contentLabel); @@ -42,6 +38,7 @@ public void archiveEntity( endOfProcessingDate.setValue(DateHelper8.toLocalDate(entityFacade.calculateEndOfProcessingDate(coreEntityDto.getUuid()))); endOfProcessingDate.setCaption(I18nProperties.getCaption(Captions.endOfProcessingDate)); verticalLayout.addComponent(endOfProcessingDate); + verticalLayout.setMargin(false); VaadinUiUtil.showConfirmationPopup( I18nProperties.getString(popupHeading), @@ -78,6 +75,7 @@ public void dearchiveEntity( I18nProperties.getString(entity).toLowerCase())); contentLabel.setWidth(100, Sizeable.Unit.PERCENTAGE); verticalLayout.addComponent(contentLabel); + verticalLayout.setMargin(false); TextArea dearchiveReason = new TextArea(); dearchiveReason.setCaption(I18nProperties.getCaption(Captions.dearchiveReason)); @@ -180,6 +178,7 @@ public void dearchiveSelectedItems( dearchiveReason.setRows(2); dearchiveReason.setRequiredIndicatorVisible(true); verticalLayout.addComponent(dearchiveReason); + verticalLayout.setMargin(false); VaadinUiUtil.showConfirmationPopup( I18nProperties.getString(headingConfirmationDeachiving), From 967f2d3feda21298b466bcc6fbe2d186b0e37122 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Wed, 23 Feb 2022 14:44:50 +0200 Subject: [PATCH 152/253] #7451 - show more filters as default on travel entry filter form (#8103) --- .../ui/travelentry/TravelEntryFilterForm.java | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryFilterForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryFilterForm.java index 45b6281cba7..1a7555bc848 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryFilterForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryFilterForm.java @@ -3,12 +3,16 @@ import static de.symeda.sormas.ui.utils.LayoutUtil.loc; import java.util.Date; +import java.util.stream.Stream; import com.vaadin.ui.CustomLayout; import com.vaadin.ui.HorizontalLayout; import com.vaadin.v7.ui.CheckBox; +import com.vaadin.v7.ui.Field; import com.vaadin.v7.ui.TextField; +import de.symeda.sormas.api.FacadeProvider; +import de.symeda.sormas.api.caze.NewCaseDateType; import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Strings; @@ -17,6 +21,7 @@ import de.symeda.sormas.api.utils.DateFilterOption; import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.api.utils.EpiWeek; +import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; import de.symeda.sormas.ui.utils.AbstractFilterForm; import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.EpiWeekAndDateFilterComponent; @@ -27,8 +32,13 @@ public class TravelEntryFilterForm extends AbstractFilterForm streamFieldsForEmptyCheck(CustomLayout layout) { + final HorizontalLayout dateFilterLayout = (HorizontalLayout) getMoreFiltersContainer().getComponent(WEEK_AND_DATE_FILTER); + final EpiWeekAndDateFilterComponent weekAndDateFilter; + weekAndDateFilter = (EpiWeekAndDateFilterComponent) dateFilterLayout.getComponent(0); + + return super.streamFieldsForEmptyCheck(layout).filter(f -> f != weekAndDateFilter.getDateFilterOptionFilter()); + } } From 5cdbfba9f08f91e786334df1b4fa35562e1557f2 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Wed, 23 Feb 2022 18:21:09 +0100 Subject: [PATCH 153/253] refactor --- .../pages/application/persons/EditPersonPage.java | 8 ++++---- .../steps/web/application/persons/EditPersonSteps.java | 10 +++++----- .../test/resources/features/sanity/web/Persons.feature | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java index 61c26009c5d..b22ce28e452 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java @@ -103,10 +103,10 @@ public class EditPersonPage { "//*[contains(text(),'The case person was added as an event participant to the selected event.')]"); public static final By SEE_EVENTS_FOR_PERSON = By.cssSelector("div#See\\ events\\ for\\ this\\ person"); - public static final By SEE_CASES_FOR_PERSON = By.id("See cases for this person"); - public static final By SEE_CONTACTS_FOR_PERSON = By.id("See contacts for this person"); - public static final By EDIT_CASES = By.id("edit-case-0"); - public static final By EDIT_CONTACTS = By.id("edit-contact-0"); + public static final By SEE_CASES_FOR_PERSON_BUTTON = By.id("See cases for this person"); + public static final By SEE_CONTACTS_FOR_PERSON_BUTTON = By.id("See contacts for this person"); + public static final By EDIT_CASES_BUTTON = By.id("edit-case-0"); + public static final By EDIT_CONTACTS_BUTTON = By.id("edit-contact-0"); public static By getByPersonUuid(String personUuid) { return By.cssSelector("a[title='" + personUuid + "']"); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java index c0edb27dac5..970a9a89fdd 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java @@ -125,30 +125,30 @@ public EditPersonSteps( Then( "I click on See Cases for this Person button from Edit Person page", () -> { - webDriverHelpers.clickOnWebElementBySelector(SEE_CASES_FOR_PERSON); + webDriverHelpers.clickOnWebElementBySelector(SEE_CASES_FOR_PERSON_BUTTON); webDriverHelpers.waitForPageLoadingSpinnerToDisappear(150); }); Then( "I click on See CONTACTS for this Person button from Edit Person page", () -> { - webDriverHelpers.clickOnWebElementBySelector(SEE_CONTACTS_FOR_PERSON); + webDriverHelpers.clickOnWebElementBySelector(SEE_CONTACTS_FOR_PERSON_BUTTON); webDriverHelpers.waitForPageLoadingSpinnerToDisappear(150); }); Then( "I click on Edit Case button from Cases card on Edit Person page", () -> { - webDriverHelpers.clickOnWebElementBySelector(EDIT_CASES); + webDriverHelpers.clickOnWebElementBySelector(EDIT_CASES_BUTTON); webDriverHelpers.waitForPageLoadingSpinnerToDisappear(150); }); Then( "I click on Edit Contact button from Contacts card on Edit Person page", () -> { - webDriverHelpers.clickOnWebElementBySelector(EDIT_CONTACTS); + webDriverHelpers.clickOnWebElementBySelector(EDIT_CONTACTS_BUTTON); webDriverHelpers.waitForPageLoadingSpinnerToDisappear(150); }); Then( - "I click on Edit Immunization button from Immunization card on Edit Person page", + "I click on Edit Immunization button for Immunization created through API from Immunization card on Edit Person page", () -> { webDriverHelpers.clickOnWebElementBySelector( getByImmunizationUuid(apiState.getCreatedImmunization().getUuid())); diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature index 96d4ccc5f8e..e0ad0e79a14 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature @@ -19,7 +19,7 @@ Feature: Edit Persons And I check that previous edited person is correctly displayed in Edit Person page @issue=SORDEV-8469 - Scenario: Form card navigation in Edit Person Directory + Scenario: Test for navigating through Case, Contact and Immunization cards on Edit Person Page Given API: I create a new person Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 @@ -47,6 +47,6 @@ Feature: Edit Persons Then I navigate to the last created via api Person page via URL And I click on Edit Contact button from Contacts card on Edit Person page Then I navigate to the last created via api Person page via URL - And I click on Edit Immunization button from Immunization card on Edit Person page + And I click on Edit Immunization button for Immunization created through API from Immunization card on Edit Person page Then I navigate to the last created via api Person page via URL From 9b404655c15df2e09941d15617f9b710480619a5 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Wed, 23 Feb 2022 19:00:34 +0100 Subject: [PATCH 154/253] refactor --- .../enums/EventManagementStatusValues.java | 14 ++++++++++++++ .../application/events/EventDirectoryPage.java | 4 ++-- .../e2etests/services/api/EventApiService.java | 3 ++- .../application/events/EventDirectorySteps.java | 4 ++-- .../features/sanity/web/EventFilters.feature | 2 +- 5 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/EventManagementStatusValues.java diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/EventManagementStatusValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/EventManagementStatusValues.java new file mode 100644 index 00000000000..a62d70acde4 --- /dev/null +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/EventManagementStatusValues.java @@ -0,0 +1,14 @@ +package org.sormas.e2etests.enums; + +import lombok.Getter; + +@Getter +public enum EventManagementStatusValues { + ONGOING("ONGOING"); + private final String value; + + EventManagementStatusValues(String value) { + this.value = value; + } + +} diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java index 7c760fdf16c..7593d630d91 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java @@ -61,8 +61,8 @@ public class EventDirectoryPage { public static final By EVENT_CLUSTER = By.id("status-Cluster"); public static final By EVENT_DROPPED = By.id("status-Dropped"); public static final By CREATED_PARTICIPANT = By.cssSelector("[role='gridcell'] a"); - public static final By EVENT_PARTICIPANT = By.id("freeTextEventParticipants"); - public static final By EVENT_GROUP = By.id("freeTextEventGroups"); + public static final By EVENT_PARTICIPANT_INPUT = By.id("freeTextEventParticipants"); + public static final By EVENT_GROUP_INPUT= By.id("freeTextEventGroups"); /*public static By getByEventUuid(String eventUuid) { return By.cssSelector("a[title=" + eventUuid + "]"); diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/EventApiService.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/EventApiService.java index 496fd55aa2b..9f9d434a652 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/EventApiService.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/services/api/EventApiService.java @@ -24,6 +24,7 @@ import org.sormas.e2etests.enums.CommunityValues; import org.sormas.e2etests.enums.DiseasesValues; import org.sormas.e2etests.enums.DistrictsValues; +import org.sormas.e2etests.enums.EventManagementStatusValues; import org.sormas.e2etests.enums.RegionsValues; import org.sormas.e2etests.enums.RiskLevelValues; import org.sormas.e2etests.enums.SourceTypeValues; @@ -53,7 +54,7 @@ public Event buildGeneratedEvent() { .reportDateTime(new Date()) .riskLevel(RiskLevelValues.getRandomRiskLevelName()) .typeOfPlace(TypeOfPlace.getRandomTypeOfPlace()) - .eventManagementStatus("ONGOING") + .eventManagementStatus(EventManagementStatusValues.ONGOING.getValue()) .eventLocation( EventLocation.builder() .uuid(UUID.randomUUID().toString()) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index 5020bbc9f76..46e06c490e5 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -72,7 +72,7 @@ public EventDirectorySteps( () -> { String eventGroupId = EditEventSteps.groupEvent.getUuid(); webDriverHelpers.fillInWebElement( - EVENT_GROUP, dataOperations.getPartialUuidFromAssociatedLink(eventGroupId)); + EVENT_GROUP_INPUT, dataOperations.getPartialUuidFromAssociatedLink(eventGroupId)); }); When( @@ -137,7 +137,7 @@ public EventDirectorySteps( }); And( "I filter by mocked EventGroupId on Event directory page", - () -> webDriverHelpers.fillAndSubmitInWebElement(EVENT_GROUP, "TestName TestSurname")); + () -> webDriverHelpers.fillAndSubmitInWebElement(EVENT_GROUP_INPUT, "TestName TestSurname")); When( "I select random Risk level filter among the filter options from API", () -> { diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/EventFilters.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/EventFilters.feature index 1d88e2240f4..9701d3aeba1 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/EventFilters.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/EventFilters.feature @@ -44,7 +44,7 @@ Feature: Filters in Event Directory And I click on the RESET FILTERS button from Event @issue=SORQA-77 - Scenario: Filters in Event Directory + Scenario: Filters for Region, District, Community, Reporting user and Event statuses on Event Directory Page Given API: I create a new person Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 From ce41d1fd4b7456b9370bb20b5b1b88c3dc583f25 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Wed, 23 Feb 2022 19:30:31 +0100 Subject: [PATCH 155/253] refactor --- .../events/EventDirectoryPage.java | 1 + .../events/EventDirectorySteps.java | 25 ++++++----------- .../persons/PersonDirectorySteps.java | 28 +++++++++---------- .../features/sanity/web/Event.feature | 4 +-- 4 files changed, 26 insertions(+), 32 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java index 23a0a669e3f..70ccddd0bd8 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java @@ -79,6 +79,7 @@ public class EventDirectoryPage { public static final By BULK_ACTIONS_EVENT_DIRECTORY = By.id("bulkActions-2"); public static final By GROUP_EVENTS_EVENT_DIRECTORY = By.id("bulkActions-7"); public static final By GROUP_ID_COLUMN = By.xpath("(//td//a)[2]"); + public static final By EVENT_GROUP_INPUT = By.id("freeTextEventGroups"); public static By getByEventUuid(String eventUuid) { return By.xpath(String.format("//a[@title='%s']", eventUuid)); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index 4afebde1231..3225a7174f5 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -30,6 +30,7 @@ import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.ENTER_BULK_EDIT_MODE_EVENT_DIRECTORY; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENTS_RADIO_BUTTON; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_GROUP_ID_IN_GRID; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_GROUP_INPUT; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_STATUS_FILTER_BUTTONS; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTERED_EVENT_LINK_EVENT_FORM; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_DISEASE; @@ -61,7 +62,6 @@ import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.inject.Named; -import org.openqa.selenium.By; import org.sormas.e2etests.common.DataOperations; import org.sormas.e2etests.enums.DiseasesValues; import org.sormas.e2etests.enums.RiskLevelValues; @@ -100,7 +100,7 @@ public EventDirectorySteps( }); When( - "I click checkbox to choose all Event results", + "I click checkbox to choose all Event results on Event Directory Page", () -> { webDriverHelpers.clickOnWebElementBySelector(FIRST_CHECKBOX_EVENT_DIRECTORY); webDriverHelpers.waitForPageLoaded(); @@ -121,7 +121,6 @@ public EventDirectorySteps( webDriverHelpers.accessWebSite(LAST_CREATED_EVENT_PAGE_URL); webDriverHelpers.waitForPageLoaded(); webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(UUID_INPUT, 50); - TimeUnit.SECONDS.sleep(5); }); When( @@ -131,10 +130,13 @@ public EventDirectorySteps( webDriverHelpers.waitForPageLoaded(); }); When( - "I check that data of linked group is correct", + "I check that name appearing in hover is equal to name of linked Event group", () -> { EventGroup createdGroup = EditEventSteps.groupEvent; - EventGroup collectedGroup = collectEventGroup(); + EventGroup collectedGroup = + EventGroup.builder() + .name(webDriverHelpers.getWebElement(GROUP_ID_COLUMN).getAttribute("title")) + .build(); ComparisonHelper.compareEqualFieldsOfEntities( collectedGroup, createdGroup, List.of("name")); webDriverHelpers.waitForPageLoaded(); @@ -217,8 +219,7 @@ public EventDirectorySteps( "I filter by last created group in Event Directory Page", () -> { webDriverHelpers.waitForPageLoaded(); - webDriverHelpers.fillInWebElement( - By.id("freeTextEventGroups"), EditEventSteps.groupEvent.getUuid()); + webDriverHelpers.fillInWebElement(EVENT_GROUP_INPUT, EditEventSteps.groupEvent.getUuid()); }); When( @@ -381,9 +382,7 @@ public EventDirectorySteps( When( "I click on the More button on Event directory page", - () -> - webDriverHelpers.clickOnWebElementBySelector(MORE_BUTTON_EVENT_DIRECTORY) - ); + () -> webDriverHelpers.clickOnWebElementBySelector(MORE_BUTTON_EVENT_DIRECTORY)); When( "I click Enter Bulk Edit Mode on Event directory page", () -> { @@ -427,10 +426,4 @@ public EventDirectorySteps( number.intValue(), "Number of displayed cases is not correct"))); } - - private EventGroup collectEventGroup() { - return EventGroup.builder() - .name(webDriverHelpers.getWebElement(GROUP_ID_COLUMN).getAttribute("title")) - .build(); - } } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java index 8cbef9226d0..a634b8915ac 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java @@ -246,14 +246,14 @@ public PersonDirectorySteps( webDriverHelpers.clickOnWebElementBySelector(By.cssSelector("[role='gridcell'] a")); }); - When( - "I apply on the APPLY FILTERS button", - () -> { - webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable( - APPLY_FILTERS_BUTTON, 30); - webDriverHelpers.clickOnWebElementBySelector(APPLY_FILTERS_BUTTON); - TimeUnit.SECONDS.sleep(10); - }); + When( + "I apply on the APPLY FILTERS button", + () -> { + webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable( + APPLY_FILTERS_BUTTON, 30); + webDriverHelpers.clickOnWebElementBySelector(APPLY_FILTERS_BUTTON); + TimeUnit.SECONDS.sleep(10); + }); When( "I click on the RESET FILTERS button for Person", @@ -279,12 +279,12 @@ public PersonDirectorySteps( + " " + apiState.getLastCreatedPerson().getFirstName(); break; - case "phone number": - searchText = apiState.getLastCreatedPerson().getPhone(); - break; - case "email": - searchText = apiState.getLastCreatedPerson().getEmailAddress(); - break; + case "phone number": + searchText = apiState.getLastCreatedPerson().getPhone(); + break; + case "email": + searchText = apiState.getLastCreatedPerson().getEmailAddress(); + break; } webDriverHelpers.waitUntilElementIsVisibleAndClickable(APPLY_FILTERS_BUTTON); webDriverHelpers.clickOnWebElementBySelector(ALL_BUTTON); diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature index d8506559264..ff464ab6fda 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature @@ -270,7 +270,7 @@ Feature: Create events And I hover to Event Groups column of the Event result And I click on the More button on Event directory page And I click Enter Bulk Edit Mode on Event directory page - And I click checkbox to choose all Event results + And I click checkbox to choose all Event results on Event Directory Page And I click on Bulk Actions combobox on Event Directory Page And I click on Group Events from Bulk Actions combobox on Event Directory Page And I create a new event group @@ -278,7 +278,7 @@ Feature: Create events And I filter by last created group in Event Directory Page And I apply on the APPLY FILTERS button from Event And I hover to Event Groups column of the Event result - And I check that data of linked group is correct + And I check that name appearing in hover is equal to name of linked Event group And I check the number of displayed Event results from All button is 1 From 0ff73b25e7f1acdccca9b70ad34671940696eac5 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Thu, 24 Feb 2022 10:00:34 +0200 Subject: [PATCH 156/253] #6879 - use smallint for modified and snapshot columns --- .../de/symeda/sormas/app/backend/common/DatabaseHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java index 5ea0e91946c..00e9560432c 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java @@ -2953,7 +2953,7 @@ public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int getDao(ClinicalCourse.class).executeRaw( "CREATE TABLE clinicalCourse(" + "id integer primary key autoincrement," + "uuid varchar(36) not null," + "changeDate timestamp not null," + "creationDate timestamp not null," + "lastOpenedDate timestamp," - + "localChangeDate timestamp not null," + "modified integer," + "snapshot integer," + "UNIQUE(snapshot, uuid));"); + + "localChangeDate timestamp not null," + "modified SMALLINT DEFAULT 0," + "snapshot SMALLINT DEFAULT 0," + "UNIQUE(snapshot, uuid));"); getDao(ClinicalCourse.class).executeRaw( "INSERT INTO clinicalCourse(id, uuid, changeDate, creationDate, lastOpenedDate, " + "localChangeDate, modified, snapshot) " From 84778017dd069508de8daa5869742c1aaf8d356f Mon Sep 17 00:00:00 2001 From: FredrikSchaeferVitagroup <67001822+FredrikSchaeferVitagroup@users.noreply.github.com> Date: Thu, 24 Feb 2022 11:11:11 +0100 Subject: [PATCH 157/253] #7681 set minimum width for process column (#8116) --- .../java/de/symeda/sormas/ui/labmessage/LabMessageGrid.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/labmessage/LabMessageGrid.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/labmessage/LabMessageGrid.java index 4714493d9cb..bce24eee650 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/labmessage/LabMessageGrid.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/labmessage/LabMessageGrid.java @@ -95,7 +95,7 @@ public LabMessageGrid(LabMessageCriteria criteria) { Captions.labMessageProcess, e -> ControllerProvider.getLabMessageController().processLabMessage(indexDto.getUuid()), ValoTheme.BUTTON_PRIMARY) - : null).setId(COLUMN_PROCESS); + : null).setId(COLUMN_PROCESS).setMinimumWidth(100); addComponentColumn(this::buildDownloadButton).setId(COLUMN_DOWNLOAD); From eae506b7202151fef4d8a9b2c853a39338a7819c Mon Sep 17 00:00:00 2001 From: FredrikSchaeferVitagroup <67001822+FredrikSchaeferVitagroup@users.noreply.github.com> Date: Thu, 24 Feb 2022 13:48:20 +0100 Subject: [PATCH 158/253] #7964 Don't default to backend tokens for frontend calls (#8087) --- .../backend/externaljournal/PatientDiaryClient.java | 11 ++++++----- .../main/resources/workflow-documentation.properties | 10 ++++++---- .../symeda/sormas/ui/utils/ExternalJournalUtil.java | 6 +++++- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/externaljournal/PatientDiaryClient.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/externaljournal/PatientDiaryClient.java index d99389b4907..9fa63714f19 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/externaljournal/PatientDiaryClient.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/externaljournal/PatientDiaryClient.java @@ -231,21 +231,22 @@ private Invocation.Builder getExternalDataPersonInvocationBuilder(String personU * Retrieves a token used for authenticating in the patient diary. The token will be cached. * * @param frontendRequest - * if true && a interface.patientdiary.frontendAuthurl is configured, this url is used to fetch the token. - * Otherwise, the interface.patientdiary.authurl is used. - * @return the authentication token + * @return A frontend token when frontendRequest and the interface.patientdiary.frontendAuthurl is configured in the server + * configuration (sormas.properties). + * null when frontendRequest and interface.patientdiary.frontendAuthurl is NOT configured. + * A backend token when NOT frontendRequest. */ public String getPatientDiaryAuthToken(boolean frontendRequest) { try { if (frontendRequest && StringUtils.isNotBlank(configFacade.getPatientDiaryConfig().getFrontendAuthUrl())) { return frontendAuthTokenCache.get(PATIENT_DIARY_KEY, this::getPatientDiaryFrontendAuthTokenInternal); - } else { + } else if (!frontendRequest) { return backendAuthTokenCache.get(PATIENT_DIARY_KEY, this::getPatientDiaryAuthTokenInternal); } } catch (ExecutionException e) { logger.error(e.getMessage()); - return null; } + return null; } private String getPatientDiaryFrontendAuthTokenInternal() { diff --git a/sormas-rest/src/main/resources/workflow-documentation.properties b/sormas-rest/src/main/resources/workflow-documentation.properties index 9fab79ea0b3..273eb95e983 100644 --- a/sormas-rest/src/main/resources/workflow-documentation.properties +++ b/sormas-rest/src/main/resources/workflow-documentation.properties @@ -31,7 +31,7 @@ The follow up status describes the follow up for a contact or a case. Possible v Configuration in SORMAS
    \ In the domain folder, there is a sormas.properties. it holds the following values relevant for an external journal:
    \ ``interface.patientdiary.authurl``: used to fetch an authentication token (see 1. below).
    \ -``interface.patientdiary.frontendAuthurl``: URL used to retrieve tokens for frontend requests. If not specified, the authurl is used instead.
    \ +``interface.patientdiary.frontendAuthurl``: URL used to retrieve tokens for frontend requests. If not specified, no tokens will be fetched for such.
    \ ``interface.patientdiary.tokenLifetime``: Lifetime of tokens fetched via the authurl or the frontendAuthurl. To be specified in seconds. Can be set to 0 for no token caching. Defaults to 21600 (6 hrs.).
    \ ``interface.patientdiary.probandsurl``: used to register new persons in the external journal (see 2. below).
    \ ``interface.patientdiary.url``: used to open a person in the external journal (see 6. below).
    \ @@ -57,7 +57,7 @@ In the domain folder, there is a sormas.properties. it holds the following value   "token" : [token]
    \ }
    \ The token returned will be used to authenticate in other requests. Its lifetime can be configured via the ``interface.patientdiary.tokenLifetime`` property.
    \ - One special scenario is fetching a token for frontend calls (see 6.): When the interface.patientdiary.frontendAuthurl is configured, it is used instead of the interface.patientdiary.authurl here.
    \ + One special scenario is fetching a token for frontend calls (see 6.): When the interface.patientdiary.frontendAuthurl is configured, it is used instead of the interface.patientdiary.authurl here. If it is not configured, no token will be used.
    \
    \
  • Registration of a new person in the external journal

  • \ This process involves several steps that are triggered via the REGISTER button a privileged user can see in the top right corner when having opened a case or a contact.
    \ @@ -189,9 +189,11 @@ In the domain folder, there is a sormas.properties. it holds the following value
  • Opening a person in the external journal from within SORMAS

  • \ Once the symptom journal status of a person is set to REGISTERED or ACCEPTED, the external journal button in the SORMAS-UI changes. It does not provide a registration anymore, \ but the options to open the person in the external journal and to cancel external follow up. This button can be found when having opened a contact (or a case if the case follow up feature is enabled in SORMAS) \ - in the top right corner. If the user chooses to open the person in the external journal, SORMAS fetches an authentication token as described in 1 (using the interface.patientdiary.frontendAuthurl if configured), and opens a new browser tab with the following URL:
    \ - [interface.patientdiary.url]/data?q=[personUuid]&queryKey=sicFieldIdentifier&token=[token]
    \ + in the top right corner. If the user chooses to open the person in the external journal, SORMAS opens a new browser tab with the following URL:
    \ + [interface.patientdiary.url]/data?q=[personUuid]&queryKey=sicFieldIdentifier
    \ SORMAS expects the external journal to present a view of the person there.
    \ + If the interface.patientdiary.frontendAuthurl is configured, SORMAS fetches an authentication token as described in 1, and appends it to the URL:
    \ + [interface.patientdiary.url]/data?q=[personUuid]&queryKey=sicFieldIdentifier&token=[token]
    \
    \
  • Deletion of a person from an external journal

  • \ As described above, the journal button can offer the option to cancel external follow up. If a user choses this option, SORMAS fetches an authentication token as described in 1., and uses it to request:
    \ diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ExternalJournalUtil.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ExternalJournalUtil.java index 600c73eb0ef..90216073d5b 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ExternalJournalUtil.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ExternalJournalUtil.java @@ -13,6 +13,7 @@ import com.vaadin.ui.HorizontalLayout; import de.symeda.sormas.api.person.SymptomJournalStatus; import de.symeda.sormas.api.sormastosormas.SormasToSormasShareableDto; +import org.apache.commons.lang3.StringUtils; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; @@ -239,8 +240,11 @@ private static void cancelPatientDiaryFollowUp(PersonDto personDto) { private static void openPatientDiaryPage(String personUuid) { String url = FacadeProvider.getConfigFacade().getPatientDiaryConfig().getUrl(); + url += "/data?q=" + personUuid + "&queryKey=sicFieldIdentifier"; String authToken = externalJournalFacade.getPatientDiaryAuthToken(true); - url += "/data?q=" + personUuid + "&queryKey=sicFieldIdentifier" + "&token=" + authToken; + if (StringUtils.isNotEmpty(authToken)) { + url += "&token=" + authToken; + } UI.getCurrent().getPage().open(url, "_blank"); } From e0279134e384de065f3bf83bd09277587a974035 Mon Sep 17 00:00:00 2001 From: sergiupacurariu <62688603+sergiupacurariu@users.noreply.github.com> Date: Thu, 24 Feb 2022 15:07:16 +0200 Subject: [PATCH 159/253] #7247 - CoreAdo: Introduce "end of processing date" - resolve merge conflicts --- .../main/java/de/symeda/sormas/backend/caze/CaseService.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java index 16ab768961b..b61a0310c09 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java @@ -987,8 +987,7 @@ protected > T addChangeDates(T builder, From Date: Thu, 24 Feb 2022 14:07:56 +0100 Subject: [PATCH 160/253] Bug 8020 reinfection details values missing in the data dictionary (#8070) * #8020 readable Map field type * #8020 add enums contained in maps and collections to data dictionary --- .../de/symeda/sormas/api/i18n/Strings.java | 1 + .../resources/doc/SORMAS_Data_Dictionary.xlsx | Bin 257098 -> 264179 bytes .../src/main/resources/strings.properties | 1 + .../sormas/backend/info/EntityColumn.java | 28 +++++++++++------- .../sormas/backend/info/InfoFacadeEjb.java | 23 ++++++++++++++ 5 files changed, 43 insertions(+), 10 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java index 5dcd0b27db8..2571d5a658a 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java @@ -857,6 +857,7 @@ public interface Strings { String lastWeek = "lastWeek"; String lastYear = "lastYear"; String listOf = "listOf"; + String mapOf = "mapOf"; String max = "max"; String messageActivateAccount = "messageActivateAccount"; String messageAdditionalTestDeleted = "messageAdditionalTestDeleted"; diff --git a/sormas-api/src/main/resources/doc/SORMAS_Data_Dictionary.xlsx b/sormas-api/src/main/resources/doc/SORMAS_Data_Dictionary.xlsx index ef45161daa88d2e3942854b058a02a388c6f6495..5602bc2417cfa04b9bc8faea14020888e82ad1d7 100644 GIT binary patch literal 264179 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%0Dlst#&h{y|7}5 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 ?m(dk8CL`)LYyUdLO_eA`xmn8Sm^t60^` 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

    #### Workflow Description ####

    About external follow up:
    Follow up in SORMAS is done via visits. Visits hold information about symptoms at a specific time point.
    Visits can be created for cases and contacts, either via the SORMAS-UI or the external visits journal API.

    About persons, cases and contacts:
    This is a very basic concept that one needs to understand when working with visits. In SORMAS, a person entity represents a phisically existing person. Cases and contacts represent epidemiological occurrences. When a person was in contact with an infectious environment, the person has a contact in SORMAS. When the person was in contact with such environments twice, it gets two contacts.When a person falls ill, it gets a case with the according disease. This means: In SORMAS, each contact and case relates to exactly one person. One person can have several contacts and cases, though. Follow up is done for a contact (or a case, which can be enabled in the SORMAS feature configuration). Contacts (or cases) initiate follow up. A person, though, either shows symptoms or not. It can not show symptoms for just one contact and not for the other. Thus, visits are related to all active contacts (and cases) of a person. Also the communication with external symptom journals is PERSON BASED. Only the person uuid is used, visits are uploaded to each active case and contact of a person.

    Person status variables:
    It is important to understand the meaning of two variables: the follow up status and the symptom journal status.
    The follow up status describes the follow up for a contact or a case. Possible values are defined in the FollowUpStatus enum. Follow up can be done with, or without an external journal, the follow up status makes no distinction there. Because the follow up status is contact and case specific, but the communication with external journals is person based, SORMAS determines the most important follow up status of all contacts and cases related to the person in question when communicating with external journals. Whenever there is follow up ongoing for any of the persons contacts (and cases if the case follow up feature is enabled in SORMAS), SORMAS will state the FollowUpStatus.FOLLOW_UP for that person towards external journals.
    The SymptomJournalStatus describes the state of a person related to external symptom journals. it is not contact or case specific.

    Configuration in SORMAS
    In the domain folder, there is a sormas.properties. it holds the following values relevant for an external journal:
    ``interface.patientdiary.authurl``: used to fetch an authentication token (see 1. below).
    ``interface.patientdiary.frontendAuthurl``: URL used to retrieve tokens for frontend requests. If not specified, the authurl is used instead.
    ``interface.patientdiary.tokenLifetime``: Lifetime of tokens fetched via the authurl or the frontendAuthurl. To be specified in seconds. Can be set to 0 for no token caching. Defaults to 21600 (6 hrs.).
    ``interface.patientdiary.probandsurl``: used to register new persons in the external journal (see 2. below).
    ``interface.patientdiary.url``: used to open a person in the external journal (see 6. below).
    ``interface.patientdiary.email``: used to authenticate at the external journal (see 1. below).
    ``interface.patientdiary.password``: used to authenticate at the external journal.
    ``interface.patientdiary.defaultuser.username``: This user will be created in SORMAS and can be used by the external journal to authenticate.
    ``interface.patientdiary.defaultuser.password``: The above user's password.
    ``interface.patientdiary.acceptPhoneContact``: used to configure whether the phone number is considered relevant for registering a person in the external journal. It affects the validation of persons in SORMAS (see 2. below). Defaults to true

    1. SORMAS fetching an authentication token from the external journal

    2. POST to the interface.patientdiary.authurl
      Request body:
      {
        \"email\" : [patientdiary.email],
        \"password\" : [patientdiary.password]
      }
      where [patientdiary.email] is replaced with interface.patientdiary.email and [patientdiary.password] with interface.patientdiary.password specified in the sormas.properties
      Expected response body:
      {
        \"success\" : true,
        \"userId\" : [some-user-id],
        \"token\" : [token]
      }
      The token returned will be used to authenticate in other requests. Its lifetime can be configured via the ``interface.patientdiary.tokenLifetime`` property.
      One special scenario is fetching a token for frontend calls (see 6.): When the interface.patientdiary.frontendAuthurl is configured, it is used instead of the interface.patientdiary.authurl here.

    3. Registration of a new person in the external journal

    4. This process involves several steps that are triggered via the REGISTER button a privileged user can see in the top right corner when having opened a case or a contact.
      To be able to see this button, the user must have at least one of the following user roles: national user, contact supervisor, contact officer, community officer,surveillance officer, surveillance supervisor, or admin supervisor.

      First comes a SORMAS-internal validation of contact details. The person to be registered needs to have at least an email address (or a phone number if that is accepted for registration, see ``interface.patientdiary.acceptPhoneContact``) to pass this validation.Also, when there are several email addresses or phone numbers, one of them has to be marked primary contact detail, so that it is clear which contact detail shall be used.

      Then comes an external validation of the contact details. For this, SORMAS fetches an authentication token as in 1. Then it sends a GET request to the following URL for each contact detail to be used in the external journal:
      GET [interface.patientdiary.probandsurl]/probands?q=[URL-encoded-query-parameter-and-value]', with a header like 'x-access-token: [token]'
      The [URL-encoded-query-parameter-and-value] consists of a parameter-value-pair. The parameter is either 'Email' or 'Mobile phone'. The value holds the contact detail to be validated.
      An unencoded example for this is \"Email\" = \"example@example.de\"
      The URL-encoded version is %22Email%22%20%3D%20%22example%40example.de%22
      [token] is replaced with the token fetched for authorization.
      The CURL equivalent for an exemplary call is curl --request GET 'https://probands-URL.com//probands?q=%22Email%22%20%3D%20%22example%40example.de%22' --header 'x-access-token: my-access-token'

      Expected result is a PatientDiaryQueryResponse which information about any person already registered in the external journal and using the same contact detail.
      It needs to be structured as follows:
      ``PatientDiaryQueryResponse`` {
       total   integer
       count   integer
       results   List (``PatientDiaryPersonData``)
      }
      - total should state how many persons are registered in the external journal (this information is currently never used in SORMAS).
      - count should state how many registered persons using the same contact detail were found.
      - results needs to contain a PatientDiaryPersonData for each match:
      ``PatientDiaryPersonData``{
       _id   string
       idatId   ``PatientDiaryIdatId``
      }
      - _id should be a unique identifier for the person this data is about (this information is currently never used in SORMAS)
      The PatientDiaryIdatId needs to be structured as follows:
      ``PatientDiaryIdatId``{
       idat   ``PatientDiaryPersonDto``
      }
      The PatientDiaryPersonDto holds the actual person data:
      ``PatientDiaryPersonDto``{
       personUUID   string
       firstName    string
       lastName    string
       gender     string
       birthday     string
       contactInformation   ``PatientDiaryContactInformation``
       endDate     string
      }
      - personUUID should be the UUID of the person in SORMAS. This UUID is used to sync with external journals (this information is currently never used in SORMAS).
      - firstName and lastName need to hold the first and last name of the person.
      - gender should hold the persons gender (this information is currently never used in SORMAS).
      - birthday should hold the persons birthday (this information is currently never used in SORMAS).
      - contactInformation should hold the contact information of that person, which should for logical reasons always contain (at least) the contact detail provided by SORMAS in the query.
      - endDate should hold the date after which follow up is supposed to be stopped by the external journal.
      ``PatientDiaryIdatId``{
       email   string
       phone   ``PatientDiaryPhone``
      }
      - email should hold the email address for the person
      - phone should hold the phone number of that person:
      ``PatientDiaryPhone``{
       number      string
       internationalNumber   string
       nationalNumber    string
       countryCode    string
       dialCode   string
      }
      To put this all together, here is an example PatientDiaryQueryResponse with one person using the same contact detail:
      {
        \"total\" : 100,
        \"count\" : 1,
        \"results\" : [
          {
            \"_id\" : \"60586691d4c30700119515c8\"
            \"idatId\" : {
              \"idat\" : {
                \"contactInformation\" : {
                  \"phone\" : null,
                  \"email\" : \"example@example.de\"
                },
                \"personUUID\" : \"RMTEF2-UZXCXE-7YBJK6-KUMSSEME\"
                ,\"firstName\" : \"Maria\",
                ,\"lastName\" : \"Muster\",
                \"gender\" : \"female\"
                \"birthday\" : null
              },
            }
          }
        ]
      }
      SORMAS allows to continue with the registration of a new person only when the person has a unique first name, so when all persons of the response have a different one (or if the response does not contain any matches, which needs to show in PatientDiaryQueryResponse.count == 0). This validation is necessary to avoid confusion of person related data in some external journals.

      When there are no validation errors in the process described above, SORMAS fetches an authentication token as described in 1. and then uses it to request the external journal to register the person:
      POST [interface.patientdiary.probandsurl]/external-data/[personUUID]
      The [personUUID] is replaced with the UUID of the person, which is later used to sync data between the external journal and SORMAS.
      Expected response body:
      {
       \"success\" : [boolean]
       \"message\" : [messageString]
      }
      [boolean] is expected to be true in case of successful registration. SORMAS then sets the symptom journal status to REGISTERED and displays the message to the user.
      When [boolean] is false, the message is shown as an error to the user.
      To fetch data relevent for the registration, the external journal can use the ``/visits-external/person/{personUuid}`` API endpoint described below.

    5. Synchronization of person data changed in SORMAS

    6. It may happen that person data (like a contact detail) gets changed after a person is registered in an external journal. SORMAS notifies external journals about such a change with first fetching an authentication token as descriced in 1., and the using this token for this request:
      PUT [interface.patientdiary.probandsurl]/external-data/[personUUID]
      The external journal is expected to refetch the person data via the ``/visits-external/person/{personUuid}`` API endpoint described below and save the changes.
      After refetching the person data, the symptom journal does its own internal validation and responds to SORMAS with the synchronization result, containing eventual validation errors.The expected response body:
      {
       \"success\" : [boolean]
       \"message\" : [messageString]
       \"errors\" : [
        {[errorKey]:[errorString]}
       ]
      }
      If the changes were done manually by a user from the person edit form, the synchronization result is shown to the user in a popup window, so that the user can fix eventual errors and resynchronize the person data.
    7. Upload of symptom journal data to SORMAS

    8. For this, the ``/visits-external`` API endpoint is to be used. This is described below.

    9. Upload of a symptom journal status to SORMAS

    10. For this, the ``/visits-external/person/{personUuid}/status`` API endpoint is to be used. This is described below.

    11. Opening a person in the external journal from within SORMAS

    12. Once the symptom journal status of a person is set to REGISTERED or ACCEPTED, the external journal button in the SORMAS-UI changes. It does not provide a registration anymore, but the options to open the person in the external journal and to cancel external follow up. This button can be found when having opened a contact (or a case if the case follow up feature is enabled in SORMAS) in the top right corner. If the user chooses to open the person in the external journal, SORMAS fetches an authentication token as described in 1 (using the interface.patientdiary.frontendAuthurl if configured), and opens a new browser tab with the following URL:
      [interface.patientdiary.url]/data?q=[personUuid]&queryKey=sicFieldIdentifier&token=[token]
      SORMAS expects the external journal to present a view of the person there.

    13. Deletion of a person from an external journal

    14. As described above, the journal button can offer the option to cancel external follow up. If a user choses this option, SORMAS fetches an authentication token as described in 1., and uses it to request:
      DELETE [interface.patientdiary.probandsurl]/external-data/[personUUID]
      Expected response body:
      {
       \"success\" : [boolean]
       \"message\" : [messageString]
      }
      [boolean] is expected to be true in case of successful deletion. SORMAS then sets the symptom journal status to DELETED and displays the message to the user.
      When [boolean] is false, the message is shown as an error to the user.
      Please note that this does not affect any follow up status. Cancelling follow up of a contact or case is independent from cancelling external follow up of a person.
    It follows a autogenerated description of the relevant API endpoints provided by SORMAS.", + "description" : "The purpose of this API is to enable communication between SORMAS and other symptom journals.
    Only users with the role ``REST_EXTERNAL_VISITS_USER`` are authorized to use the endpoints. Authentication is done using basic auth, with the user and password.
    For technical details please contact the dev team on gitter.

    #### Workflow Description ####

    About external follow up:
    Follow up in SORMAS is done via visits. Visits hold information about symptoms at a specific time point.
    Visits can be created for cases and contacts, either via the SORMAS-UI or the external visits journal API.

    About persons, cases and contacts:
    This is a very basic concept that one needs to understand when working with visits. In SORMAS, a person entity represents a phisically existing person. Cases and contacts represent epidemiological occurrences. When a person was in contact with an infectious environment, the person has a contact in SORMAS. When the person was in contact with such environments twice, it gets two contacts.When a person falls ill, it gets a case with the according disease. This means: In SORMAS, each contact and case relates to exactly one person. One person can have several contacts and cases, though. Follow up is done for a contact (or a case, which can be enabled in the SORMAS feature configuration). Contacts (or cases) initiate follow up. A person, though, either shows symptoms or not. It can not show symptoms for just one contact and not for the other. Thus, visits are related to all active contacts (and cases) of a person. Also the communication with external symptom journals is PERSON BASED. Only the person uuid is used, visits are uploaded to each active case and contact of a person.

    Person status variables:
    It is important to understand the meaning of two variables: the follow up status and the symptom journal status.
    The follow up status describes the follow up for a contact or a case. Possible values are defined in the FollowUpStatus enum. Follow up can be done with, or without an external journal, the follow up status makes no distinction there. Because the follow up status is contact and case specific, but the communication with external journals is person based, SORMAS determines the most important follow up status of all contacts and cases related to the person in question when communicating with external journals. Whenever there is follow up ongoing for any of the persons contacts (and cases if the case follow up feature is enabled in SORMAS), SORMAS will state the FollowUpStatus.FOLLOW_UP for that person towards external journals.
    The SymptomJournalStatus describes the state of a person related to external symptom journals. it is not contact or case specific.

    Configuration in SORMAS
    In the domain folder, there is a sormas.properties. it holds the following values relevant for an external journal:
    ``interface.patientdiary.authurl``: used to fetch an authentication token (see 1. below).
    ``interface.patientdiary.frontendAuthurl``: URL used to retrieve tokens for frontend requests. If not specified, no tokens will be fetched for such.
    ``interface.patientdiary.tokenLifetime``: Lifetime of tokens fetched via the authurl or the frontendAuthurl. To be specified in seconds. Can be set to 0 for no token caching. Defaults to 21600 (6 hrs.).
    ``interface.patientdiary.probandsurl``: used to register new persons in the external journal (see 2. below).
    ``interface.patientdiary.url``: used to open a person in the external journal (see 6. below).
    ``interface.patientdiary.email``: used to authenticate at the external journal (see 1. below).
    ``interface.patientdiary.password``: used to authenticate at the external journal.
    ``interface.patientdiary.defaultuser.username``: This user will be created in SORMAS and can be used by the external journal to authenticate.
    ``interface.patientdiary.defaultuser.password``: The above user's password.
    ``interface.patientdiary.acceptPhoneContact``: used to configure whether the phone number is considered relevant for registering a person in the external journal. It affects the validation of persons in SORMAS (see 2. below). Defaults to true

    1. SORMAS fetching an authentication token from the external journal

    2. POST to the interface.patientdiary.authurl
      Request body:
      {
        \"email\" : [patientdiary.email],
        \"password\" : [patientdiary.password]
      }
      where [patientdiary.email] is replaced with interface.patientdiary.email and [patientdiary.password] with interface.patientdiary.password specified in the sormas.properties
      Expected response body:
      {
        \"success\" : true,
        \"userId\" : [some-user-id],
        \"token\" : [token]
      }
      The token returned will be used to authenticate in other requests. Its lifetime can be configured via the ``interface.patientdiary.tokenLifetime`` property.
      One special scenario is fetching a token for frontend calls (see 6.): When the interface.patientdiary.frontendAuthurl is configured, it is used instead of the interface.patientdiary.authurl here. If it is not configured, no token will be used.

    3. Registration of a new person in the external journal

    4. This process involves several steps that are triggered via the REGISTER button a privileged user can see in the top right corner when having opened a case or a contact.
      To be able to see this button, the user must have at least one of the following user roles: national user, contact supervisor, contact officer, community officer,surveillance officer, surveillance supervisor, or admin supervisor.

      First comes a SORMAS-internal validation of contact details. The person to be registered needs to have at least an email address (or a phone number if that is accepted for registration, see ``interface.patientdiary.acceptPhoneContact``) to pass this validation.Also, when there are several email addresses or phone numbers, one of them has to be marked primary contact detail, so that it is clear which contact detail shall be used.

      Then comes an external validation of the contact details. For this, SORMAS fetches an authentication token as in 1. Then it sends a GET request to the following URL for each contact detail to be used in the external journal:
      GET [interface.patientdiary.probandsurl]/probands?q=[URL-encoded-query-parameter-and-value]', with a header like 'x-access-token: [token]'
      The [URL-encoded-query-parameter-and-value] consists of a parameter-value-pair. The parameter is either 'Email' or 'Mobile phone'. The value holds the contact detail to be validated.
      An unencoded example for this is \"Email\" = \"example@example.de\"
      The URL-encoded version is %22Email%22%20%3D%20%22example%40example.de%22
      [token] is replaced with the token fetched for authorization.
      The CURL equivalent for an exemplary call is curl --request GET 'https://probands-URL.com//probands?q=%22Email%22%20%3D%20%22example%40example.de%22' --header 'x-access-token: my-access-token'

      Expected result is a PatientDiaryQueryResponse which information about any person already registered in the external journal and using the same contact detail.
      It needs to be structured as follows:
      ``PatientDiaryQueryResponse`` {
       total   integer
       count   integer
       results   List (``PatientDiaryPersonData``)
      }
      - total should state how many persons are registered in the external journal (this information is currently never used in SORMAS).
      - count should state how many registered persons using the same contact detail were found.
      - results needs to contain a PatientDiaryPersonData for each match:
      ``PatientDiaryPersonData``{
       _id   string
       idatId   ``PatientDiaryIdatId``
      }
      - _id should be a unique identifier for the person this data is about (this information is currently never used in SORMAS)
      The PatientDiaryIdatId needs to be structured as follows:
      ``PatientDiaryIdatId``{
       idat   ``PatientDiaryPersonDto``
      }
      The PatientDiaryPersonDto holds the actual person data:
      ``PatientDiaryPersonDto``{
       personUUID   string
       firstName    string
       lastName    string
       gender     string
       birthday     string
       contactInformation   ``PatientDiaryContactInformation``
       endDate     string
      }
      - personUUID should be the UUID of the person in SORMAS. This UUID is used to sync with external journals (this information is currently never used in SORMAS).
      - firstName and lastName need to hold the first and last name of the person.
      - gender should hold the persons gender (this information is currently never used in SORMAS).
      - birthday should hold the persons birthday (this information is currently never used in SORMAS).
      - contactInformation should hold the contact information of that person, which should for logical reasons always contain (at least) the contact detail provided by SORMAS in the query.
      - endDate should hold the date after which follow up is supposed to be stopped by the external journal.
      ``PatientDiaryIdatId``{
       email   string
       phone   ``PatientDiaryPhone``
      }
      - email should hold the email address for the person
      - phone should hold the phone number of that person:
      ``PatientDiaryPhone``{
       number      string
       internationalNumber   string
       nationalNumber    string
       countryCode    string
       dialCode   string
      }
      To put this all together, here is an example PatientDiaryQueryResponse with one person using the same contact detail:
      {
        \"total\" : 100,
        \"count\" : 1,
        \"results\" : [
          {
            \"_id\" : \"60586691d4c30700119515c8\"
            \"idatId\" : {
              \"idat\" : {
                \"contactInformation\" : {
                  \"phone\" : null,
                  \"email\" : \"example@example.de\"
                },
                \"personUUID\" : \"RMTEF2-UZXCXE-7YBJK6-KUMSSEME\"
                ,\"firstName\" : \"Maria\",
                ,\"lastName\" : \"Muster\",
                \"gender\" : \"female\"
                \"birthday\" : null
              },
            }
          }
        ]
      }
      SORMAS allows to continue with the registration of a new person only when the person has a unique first name, so when all persons of the response have a different one (or if the response does not contain any matches, which needs to show in PatientDiaryQueryResponse.count == 0). This validation is necessary to avoid confusion of person related data in some external journals.

      When there are no validation errors in the process described above, SORMAS fetches an authentication token as described in 1. and then uses it to request the external journal to register the person:
      POST [interface.patientdiary.probandsurl]/external-data/[personUUID]
      The [personUUID] is replaced with the UUID of the person, which is later used to sync data between the external journal and SORMAS.
      Expected response body:
      {
       \"success\" : [boolean]
       \"message\" : [messageString]
      }
      [boolean] is expected to be true in case of successful registration. SORMAS then sets the symptom journal status to REGISTERED and displays the message to the user.
      When [boolean] is false, the message is shown as an error to the user.
      To fetch data relevent for the registration, the external journal can use the ``/visits-external/person/{personUuid}`` API endpoint described below.

    5. Synchronization of person data changed in SORMAS

    6. It may happen that person data (like a contact detail) gets changed after a person is registered in an external journal. SORMAS notifies external journals about such a change with first fetching an authentication token as descriced in 1., and the using this token for this request:
      PUT [interface.patientdiary.probandsurl]/external-data/[personUUID]
      The external journal is expected to refetch the person data via the ``/visits-external/person/{personUuid}`` API endpoint described below and save the changes.
      After refetching the person data, the symptom journal does its own internal validation and responds to SORMAS with the synchronization result, containing eventual validation errors.The expected response body:
      {
       \"success\" : [boolean]
       \"message\" : [messageString]
       \"errors\" : [
        {[errorKey]:[errorString]}
       ]
      }
      If the changes were done manually by a user from the person edit form, the synchronization result is shown to the user in a popup window, so that the user can fix eventual errors and resynchronize the person data.
    7. Upload of symptom journal data to SORMAS

    8. For this, the ``/visits-external`` API endpoint is to be used. This is described below.

    9. Upload of a symptom journal status to SORMAS

    10. For this, the ``/visits-external/person/{personUuid}/status`` API endpoint is to be used. This is described below.

    11. Opening a person in the external journal from within SORMAS

    12. Once the symptom journal status of a person is set to REGISTERED or ACCEPTED, the external journal button in the SORMAS-UI changes. It does not provide a registration anymore, but the options to open the person in the external journal and to cancel external follow up. This button can be found when having opened a contact (or a case if the case follow up feature is enabled in SORMAS) in the top right corner. If the user chooses to open the person in the external journal, SORMAS opens a new browser tab with the following URL:
      [interface.patientdiary.url]/data?q=[personUuid]&queryKey=sicFieldIdentifier
      SORMAS expects the external journal to present a view of the person there.
      If the interface.patientdiary.frontendAuthurl is configured, SORMAS fetches an authentication token as described in 1, and appends it to the URL:
      [interface.patientdiary.url]/data?q=[personUuid]&queryKey=sicFieldIdentifier&token=[token]

    13. Deletion of a person from an external journal

    14. As described above, the journal button can offer the option to cancel external follow up. If a user choses this option, SORMAS fetches an authentication token as described in 1., and uses it to request:
      DELETE [interface.patientdiary.probandsurl]/external-data/[personUUID]
      Expected response body:
      {
       \"success\" : [boolean]
       \"message\" : [messageString]
      }
      [boolean] is expected to be true in case of successful deletion. SORMAS then sets the symptom journal status to DELETED and displays the message to the user.
      When [boolean] is false, the message is shown as an error to the user.
      Please note that this does not affect any follow up status. Cancelling follow up of a contact or case is independent from cancelling external follow up of a person.
    It follows a autogenerated description of the relevant API endpoints provided by SORMAS.", "version" : "1.41.1" }, "servers" : [ { diff --git a/openapi/external_visits_API.yaml b/openapi/external_visits_API.yaml index 343ce32f0c2..9df24d40f20 100644 --- a/openapi/external_visits_API.yaml +++ b/openapi/external_visits_API.yaml @@ -42,10 +42,10 @@ info: \ in SORMAS
    In the domain folder, there is a sormas.properties. it holds\ \ the following values relevant for an external journal:
    ``interface.patientdiary.authurl``:\ \ used to fetch an authentication token (see 1. below).
    ``interface.patientdiary.frontendAuthurl``:\ - \ URL used to retrieve tokens for frontend requests. If not specified, the authurl\ - \ is used instead.
    ``interface.patientdiary.tokenLifetime``: Lifetime of tokens\ - \ fetched via the authurl or the frontendAuthurl. To be specified in seconds.\ - \ Can be set to 0 for no token caching. Defaults to 21600 (6 hrs.).
    ``interface.patientdiary.probandsurl``:\ + \ URL used to retrieve tokens for frontend requests. If not specified, no tokens\ + \ will be fetched for such.
    ``interface.patientdiary.tokenLifetime``: Lifetime\ + \ of tokens fetched via the authurl or the frontendAuthurl. To be specified in\ + \ seconds. Can be set to 0 for no token caching. Defaults to 21600 (6 hrs.).
    ``interface.patientdiary.probandsurl``:\ \ used to register new persons in the external journal (see 2. below).
    ``interface.patientdiary.url``:\ \ used to open a person in the external journal (see 6. below).
    ``interface.patientdiary.email``:\ \ used to authenticate at the external journal (see 1. below).
    ``interface.patientdiary.password``:\ @@ -66,22 +66,22 @@ info: \ requests. Its lifetime can be configured via the ``interface.patientdiary.tokenLifetime``\ \ property.
    One special scenario is fetching a token for frontend calls (see\ \ 6.): When the interface.patientdiary.frontendAuthurl is configured, it is used\ - \ instead of the interface.patientdiary.authurl here.

  • Registration\ - \ of a new person in the external journal

  • This process involves several\ - \ steps that are triggered via the REGISTER button a privileged user can see in\ - \ the top right corner when having opened a case or a contact.
    To be able to\ - \ see this button, the user must have at least one of the following user roles:\ - \ national user, contact supervisor, contact officer, community officer,surveillance\ - \ officer, surveillance supervisor, or admin supervisor.

    First comes a\ - \ SORMAS-internal validation of contact details. The person to be registered needs\ - \ to have at least an email address (or a phone number if that is accepted for\ - \ registration, see ``interface.patientdiary.acceptPhoneContact``) to pass this\ - \ validation.Also, when there are several email addresses or phone numbers, one\ - \ of them has to be marked primary contact detail, so that it is clear which contact\ - \ detail shall be used.

    Then comes an external validation of the contact\ - \ details. For this, SORMAS fetches an authentication token as in 1. Then it sends\ - \ a GET request to the following URL for each contact detail to be used in the\ - \ external journal:
    GET [interface.patientdiary.probandsurl]/probands?q=[URL-encoded-query-parameter-and-value]',\ + \ instead of the interface.patientdiary.authurl here. If it is not configured,\ + \ no token will be used.

  • Registration of a new person in the external\ + \ journal

  • This process involves several steps that are triggered via\ + \ the REGISTER button a privileged user can see in the top right corner when having\ + \ opened a case or a contact.
    To be able to see this button, the user must\ + \ have at least one of the following user roles: national user, contact supervisor,\ + \ contact officer, community officer,surveillance officer, surveillance supervisor,\ + \ or admin supervisor.

    First comes a SORMAS-internal validation of contact\ + \ details. The person to be registered needs to have at least an email address\ + \ (or a phone number if that is accepted for registration, see ``interface.patientdiary.acceptPhoneContact``)\ + \ to pass this validation.Also, when there are several email addresses or phone\ + \ numbers, one of them has to be marked primary contact detail, so that it is\ + \ clear which contact detail shall be used.

    Then comes an external validation\ + \ of the contact details. For this, SORMAS fetches an authentication token as\ + \ in 1. Then it sends a GET request to the following URL for each contact detail\ + \ to be used in the external journal:
    GET [interface.patientdiary.probandsurl]/probands?q=[URL-encoded-query-parameter-and-value]',\ \ with a header like 'x-access-token: [token]'
    The [URL-encoded-query-parameter-and-value]\ \ consists of a parameter-value-pair. The parameter is either 'Email' or 'Mobile\ \ phone'. The value holds the contact detail to be validated.
    An unencoded\ @@ -167,10 +167,11 @@ info: \ but the options to open the person in the external journal and to cancel external\ \ follow up. This button can be found when having opened a contact (or a case\ \ if the case follow up feature is enabled in SORMAS) in the top right corner.\ - \ If the user chooses to open the person in the external journal, SORMAS fetches\ - \ an authentication token as described in 1 (using the interface.patientdiary.frontendAuthurl\ - \ if configured), and opens a new browser tab with the following URL:
    [interface.patientdiary.url]/data?q=[personUuid]&queryKey=sicFieldIdentifier&token=[token]
    SORMAS\ - \ expects the external journal to present a view of the person there.

  • Deletion\ + \ If the user chooses to open the person in the external journal, SORMAS opens\ + \ a new browser tab with the following URL:
    [interface.patientdiary.url]/data?q=[personUuid]&queryKey=sicFieldIdentifier
    SORMAS\ + \ expects the external journal to present a view of the person there.
    If the\ + \ interface.patientdiary.frontendAuthurl is configured, SORMAS fetches an authentication\ + \ token as described in 1, and appends it to the URL:
    [interface.patientdiary.url]/data?q=[personUuid]&queryKey=sicFieldIdentifier&token=[token]

  • Deletion\ \ of a person from an external journal

  • As described above, the journal\ \ button can offer the option to cancel external follow up. If a user choses this\ \ option, SORMAS fetches an authentication token as described in 1., and uses\ From 4e38f22c2602f212b5732a0c9f936542e136803b Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Thu, 24 Feb 2022 16:48:47 +0200 Subject: [PATCH 162/253] #7451 - remove more dropdown for entering bulk edit on travel entries (#8121) --- .../ui/travelentry/TravelEntriesView.java | 24 ++++--------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntriesView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntriesView.java index c18dbb6db4f..11a539b13c8 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntriesView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntriesView.java @@ -37,7 +37,6 @@ import de.symeda.sormas.ui.utils.VaadinUiUtil; import de.symeda.sormas.ui.utils.ViewConfiguration; import de.symeda.sormas.ui.utils.components.expandablebutton.ExpandableButton; -import de.symeda.sormas.ui.utils.components.popupmenu.PopupMenu; public class TravelEntriesView extends AbstractView { @@ -95,27 +94,18 @@ public TravelEntriesView() { } } - final PopupMenu moreButton = new PopupMenu(I18nProperties.getCaption(Captions.moreActions)); if (UserProvider.getCurrent().hasUserRight(UserRight.TRAVEL_ENTRY_DELETE) && UserProvider.getCurrent().hasUserRight(UserRight.PERFORM_BULK_OPERATIONS)) { - Button btnEnterBulkEditMode = ButtonHelper.createIconButton(Captions.actionEnterBulkEditMode, VaadinIcons.CHECK_SQUARE_O, null); - { - btnEnterBulkEditMode.setVisible(!viewConfiguration.isInEagerMode()); - btnEnterBulkEditMode.addStyleName(ValoTheme.BUTTON_PRIMARY); - btnEnterBulkEditMode.setWidth(100, Unit.PERCENTAGE); - moreButton.addMenuEntry(btnEnterBulkEditMode); - } + Button btnEnterBulkEditMode = ButtonHelper.createIconButton(Captions.actionEnterBulkEditMode, VaadinIcons.CHECK_SQUARE_O, null); + btnEnterBulkEditMode.setVisible(!viewConfiguration.isInEagerMode()); + addHeaderComponent(btnEnterBulkEditMode); Button btnLeaveBulkEditMode = ButtonHelper.createIconButton(Captions.actionLeaveBulkEditMode, VaadinIcons.CLOSE, null, ValoTheme.BUTTON_PRIMARY); - { - btnLeaveBulkEditMode.setVisible(viewConfiguration.isInEagerMode()); - btnLeaveBulkEditMode.setWidth(100, Unit.PERCENTAGE); - - moreButton.addMenuEntry(btnLeaveBulkEditMode); - } + btnLeaveBulkEditMode.setVisible(viewConfiguration.isInEagerMode()); + addHeaderComponent(btnLeaveBulkEditMode); btnEnterBulkEditMode.addClickListener(e -> { bulkOperationsDropdown.setVisible(true); @@ -132,10 +122,6 @@ public TravelEntriesView() { navigateTo(criteria); }); } - - if (moreButton.hasMenuEntries()) { - addHeaderComponent(moreButton); - } } @Override From 289799ba312c649b1ca2733fa9e5f568dd45df4f Mon Sep 17 00:00:00 2001 From: alexcaruntu-vita <76100512+alexcaruntu-vita@users.noreply.github.com> Date: Thu, 24 Feb 2022 18:17:33 +0200 Subject: [PATCH 163/253] Bugfix 8078 error message when trying to save changes made on sample (#8112) * #8078 - Refactoring * #8078 - Removed the dependency on consumers for PathogenTestList * #8078 - Renaming * #8078 - Refactoring * #8078 - Created an event for list entry creation * #8078 - Made the create button to fire an event instead of accepting a click listener * #8078 - Refactoring * #8078 - Side component edit event * #8078 - Save sample before creating a new test result * #8978 - Code re-org * #8078 - Save sample before editing test result --- .../ui/samples/PathogenTestController.java | 3 ++ .../sormas/ui/samples/SampleDataView.java | 32 +++++++++++++---- .../pathogentestlink/PathogenTestList.java | 23 ++---------- .../PathogenTestListComponent.java | 36 ++++++++----------- .../sormas/ui/utils/PaginationList.java | 11 ++++++ .../sidecomponent/SideComponent.java | 30 ++++++++++++++++ .../EditSideComponentFieldEventListener.java | 15 -------- .../event/SideComponentCreateEvent.java | 10 ++++++ .../SideComponentCreateEventListener.java | 15 ++++++++ .../event/SideComponentEditEvent.java | 17 +++++++++ .../event/SideComponentEditEventListener.java | 14 ++++++++ ....java => SideComponentFieldEditEvent.java} | 4 +-- .../SideComponentFieldEditEventListener.java | 15 ++++++++ .../ui/vaccination/list/VaccinationList.java | 13 ++----- .../list/VaccinationListComponent.java | 4 +-- 15 files changed, 163 insertions(+), 79 deletions(-) delete mode 100644 sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/EditSideComponentFieldEventListener.java create mode 100644 sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentCreateEvent.java create mode 100644 sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentCreateEventListener.java create mode 100644 sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentEditEvent.java create mode 100644 sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentEditEventListener.java rename sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/{EditSideComponentFieldEvent.java => SideComponentFieldEditEvent.java} (51%) create mode 100644 sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentFieldEditEventListener.java diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java index de02a2af3af..778a4234629 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java @@ -53,6 +53,7 @@ import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.SormasUI; import de.symeda.sormas.ui.UserProvider; import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent; import de.symeda.sormas.ui.utils.VaadinUiUtil; @@ -96,6 +97,7 @@ public CommitDiscardWrapperComponent getPathogenTestCreateComp if (!createForm.getFieldGroup().isModified()) { savePathogenTest(createForm.getValue(), onSavedPathogenTest, false); callback.run(); + SormasUI.refreshView(); } }); return editView; @@ -140,6 +142,7 @@ public CommitDiscardWrapperComponent getPathogenTestEditCompon if (!form.getFieldGroup().isModified()) { savePathogenTest(form.getValue(), onSavedPathogenTest, false); doneCallback.run(); + SormasUI.refreshView(); } }); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleDataView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleDataView.java index 18a412ee534..d23c300e477 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleDataView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleDataView.java @@ -20,6 +20,7 @@ import com.vaadin.shared.ui.MarginInfo; import com.vaadin.ui.CustomLayout; +import com.vaadin.ui.Notification; import com.vaadin.ui.VerticalLayout; import de.symeda.sormas.api.Disease; @@ -32,8 +33,11 @@ import de.symeda.sormas.api.event.EventParticipantDto; import de.symeda.sormas.api.event.EventParticipantReferenceDto; import de.symeda.sormas.api.feature.FeatureType; +import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; import de.symeda.sormas.api.sample.PathogenTestDto; import de.symeda.sormas.api.sample.SampleDto; +import de.symeda.sormas.api.sample.SampleReferenceDto; import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.ui.ControllerProvider; @@ -47,6 +51,7 @@ import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.DetailSubComponentWrapper; import de.symeda.sormas.ui.utils.LayoutUtil; +import de.symeda.sormas.ui.utils.components.sidecomponent.SideComponentLayout; public class SampleDataView extends AbstractSampleView { @@ -155,21 +160,34 @@ protected void initView(String params) { editComponent.addStyleName(CssStyles.MAIN_COMPONENT); layout.addComponent(editComponent, EDIT_LOC); - BiConsumer onSavedPathogenTest = (pathogenTestDto, callback) -> { - callback.run(); - }; + BiConsumer onSavedPathogenTest = (pathogenTestDto, callback) -> callback.run(); // why? if(sampleDto.getSamplePurpose() !=null && sampleDto.getSamplePurpose().equals(SamplePurpose.EXTERNAL)) { Supplier createOrEditAllowedCallback = () -> editComponent.getWrappedComponent().getFieldGroup().isValid(); - PathogenTestListComponent pathogenTestList = new PathogenTestListComponent(getSampleRef(), onSavedPathogenTest, createOrEditAllowedCallback); - pathogenTestList.addStyleName(CssStyles.SIDE_COMPONENT); - layout.addComponent(pathogenTestList, PATHOGEN_TESTS_LOC); + SampleReferenceDto sampleReferenceDto = getSampleRef(); + PathogenTestListComponent pathogenTestListComponent = new PathogenTestListComponent(sampleReferenceDto); + pathogenTestListComponent.addSideComponentCreateEventListener(e -> showNavigationConfirmPopupIfDirty(() -> { + if (createOrEditAllowedCallback.get()) { + ControllerProvider.getPathogenTestController().create(sampleReferenceDto, 0, pathogenTestListComponent::reload, onSavedPathogenTest); + } else { + Notification.show(null, I18nProperties.getString(Strings.messageFormHasErrorsPathogenTest), Notification.Type.ERROR_MESSAGE); + } + })); + pathogenTestListComponent.addSideComponentEditEventListener(e -> showNavigationConfirmPopupIfDirty(() -> { + String uuid = e.getUuid(); + if (createOrEditAllowedCallback.get()) { + ControllerProvider.getPathogenTestController().edit(uuid, pathogenTestListComponent::reload, onSavedPathogenTest); + } else { + Notification.show(null, I18nProperties.getString(Strings.messageFormHasErrorsPathogenTest), Notification.Type.ERROR_MESSAGE); + } + })); + layout.addComponent(new SideComponentLayout(pathogenTestListComponent), PATHOGEN_TESTS_LOC); if (UserProvider.getCurrent() != null && UserProvider.getCurrent().hasUserRight(UserRight.ADDITIONAL_TEST_VIEW) && FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.ADDITIONAL_TESTS)) { - AdditionalTestListComponent additionalTestList = new AdditionalTestListComponent(getSampleRef().getUuid()); + AdditionalTestListComponent additionalTestList = new AdditionalTestListComponent(sampleReferenceDto.getUuid()); additionalTestList.addStyleName(CssStyles.SIDE_COMPONENT); layout.addComponent(additionalTestList, ADDITIONAL_TESTS_LOC); } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/pathogentestlink/PathogenTestList.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/pathogentestlink/PathogenTestList.java index e0c6db62f1e..4acaea92381 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/pathogentestlink/PathogenTestList.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/pathogentestlink/PathogenTestList.java @@ -18,13 +18,8 @@ package de.symeda.sormas.ui.samples.pathogentestlink; import java.util.List; -import java.util.function.BiConsumer; -import java.util.function.Supplier; -import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.Label; -import com.vaadin.ui.Notification; -import com.vaadin.ui.Notification.Type; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Strings; @@ -34,6 +29,7 @@ import de.symeda.sormas.ui.ControllerProvider; import de.symeda.sormas.ui.UserProvider; import de.symeda.sormas.ui.utils.PaginationList; +import de.symeda.sormas.ui.utils.components.sidecomponent.event.SideComponentFieldEditEvent; @SuppressWarnings("serial") public class PathogenTestList extends PaginationList { @@ -41,18 +37,11 @@ public class PathogenTestList extends PaginationList { private static final int MAX_DISPLAYED_ENTRIES = 5; private final SampleReferenceDto sampleRef; - private final BiConsumer onSavedPathogenTest; - private final Supplier createOrEditAllowedCallback; - public PathogenTestList( - SampleReferenceDto sampleRef, - BiConsumer onSavedPathogenTest, - Supplier createOrEditAllowedCallback) { + public PathogenTestList(SampleReferenceDto sampleRef) { super(MAX_DISPLAYED_ENTRIES); this.sampleRef = sampleRef; - this.onSavedPathogenTest = onSavedPathogenTest; - this.createOrEditAllowedCallback = createOrEditAllowedCallback; } @Override @@ -77,13 +66,7 @@ protected void drawDisplayedEntries() { PathogenTestListEntry listEntry = new PathogenTestListEntry(pathogenTest); if (UserProvider.getCurrent().hasUserRight(UserRight.PATHOGEN_TEST_EDIT)) { String pathogenTestUuid = pathogenTest.getUuid(); - listEntry.addEditButton("edit-test-" + pathogenTestUuid, (ClickListener) event -> { - if (createOrEditAllowedCallback.get()) { - ControllerProvider.getPathogenTestController().edit(pathogenTestUuid, PathogenTestList.this::reload, onSavedPathogenTest); - } else { - Notification.show(null, I18nProperties.getString(Strings.messageFormHasErrorsPathogenTest), Type.ERROR_MESSAGE); - } - }); + listEntry.addEditButton("edit-test-" + pathogenTestUuid, e -> fireEvent(new SideComponentFieldEditEvent(listEntry))); } listLayout.addComponent(listEntry); } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/pathogentestlink/PathogenTestListComponent.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/pathogentestlink/PathogenTestListComponent.java index 418a35ad425..c4e53a99bf1 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/pathogentestlink/PathogenTestListComponent.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/pathogentestlink/PathogenTestListComponent.java @@ -17,42 +17,34 @@ *******************************************************************************/ package de.symeda.sormas.ui.samples.pathogentestlink; -import java.util.function.BiConsumer; -import java.util.function.Supplier; - -import com.vaadin.ui.Notification; -import com.vaadin.ui.Notification.Type; - import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Strings; -import de.symeda.sormas.api.sample.PathogenTestDto; import de.symeda.sormas.api.sample.SampleReferenceDto; import de.symeda.sormas.api.user.UserRight; -import de.symeda.sormas.ui.ControllerProvider; import de.symeda.sormas.ui.utils.components.sidecomponent.SideComponent; +import de.symeda.sormas.ui.utils.components.sidecomponent.event.SideComponentEditEvent; @SuppressWarnings("serial") public class PathogenTestListComponent extends SideComponent { - private PathogenTestList list; + private final PathogenTestList pathogenTestList; - public PathogenTestListComponent( - SampleReferenceDto sampleRef, - BiConsumer onSavedPathogenTest, - Supplier createOrEditAllowedCallback) { + public PathogenTestListComponent(SampleReferenceDto sampleRef) { super(I18nProperties.getString(Strings.headingTests)); - addCreateButton(I18nProperties.getCaption(Captions.pathogenTestNewTest), UserRight.PATHOGEN_TEST_CREATE, e -> { - if (createOrEditAllowedCallback.get()) { - ControllerProvider.getPathogenTestController().create(sampleRef, 0, list::reload, onSavedPathogenTest); - } else { - Notification.show(null, I18nProperties.getString(Strings.messageFormHasErrorsPathogenTest), Type.ERROR_MESSAGE); - } + addCreateButton(I18nProperties.getCaption(Captions.pathogenTestNewTest), UserRight.PATHOGEN_TEST_CREATE); + + pathogenTestList = new PathogenTestList(sampleRef); + pathogenTestList.addSideComponentFieldEditEventListener(e -> { + PathogenTestListEntry listEntry = (PathogenTestListEntry) e.getComponent(); + fireEvent(new SideComponentEditEvent(this, listEntry.getPathogenTest().getUuid())); }); + addComponent(pathogenTestList); + pathogenTestList.reload(); + } - list = new PathogenTestList(sampleRef, onSavedPathogenTest, createOrEditAllowedCallback); - addComponent(list); - list.reload(); + public void reload() { + this.pathogenTestList.reload(); } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/PaginationList.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/PaginationList.java index a6f5072d9d0..48b8d761203 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/PaginationList.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/PaginationList.java @@ -19,6 +19,7 @@ import java.util.List; +import com.vaadin.shared.Registration; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; import com.vaadin.ui.HorizontalLayout; @@ -26,6 +27,9 @@ import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.themes.ValoTheme; +import de.symeda.sormas.ui.utils.components.sidecomponent.event.SideComponentFieldEditEvent; +import de.symeda.sormas.ui.utils.components.sidecomponent.event.SideComponentFieldEditEventListener; + public abstract class PaginationList extends VerticalLayout { private static final long serialVersionUID = -1949084832307944448L; @@ -212,4 +216,11 @@ protected List getEntries() { public boolean isEmpty() { return entries.isEmpty(); } + + public Registration addSideComponentFieldEditEventListener(SideComponentFieldEditEventListener sideComponentFieldEditEventListener) { + return addListener( + SideComponentFieldEditEvent.class, + sideComponentFieldEditEventListener, + SideComponentFieldEditEventListener.ON_SIDE_COMPONENT_FIELD_EDIT_METHOD); + } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/SideComponent.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/SideComponent.java index 52e518d658d..6f4d8831cc4 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/SideComponent.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/SideComponent.java @@ -4,6 +4,7 @@ import com.vaadin.icons.VaadinIcons; import com.vaadin.server.Sizeable; +import com.vaadin.shared.Registration; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; import com.vaadin.ui.HorizontalLayout; @@ -15,6 +16,10 @@ import de.symeda.sormas.ui.UserProvider; import de.symeda.sormas.ui.utils.ButtonHelper; import de.symeda.sormas.ui.utils.CssStyles; +import de.symeda.sormas.ui.utils.components.sidecomponent.event.SideComponentCreateEvent; +import de.symeda.sormas.ui.utils.components.sidecomponent.event.SideComponentCreateEventListener; +import de.symeda.sormas.ui.utils.components.sidecomponent.event.SideComponentEditEvent; +import de.symeda.sormas.ui.utils.components.sidecomponent.event.SideComponentEditEventListener; public class SideComponent extends VerticalLayout { @@ -51,4 +56,29 @@ protected void addCreateButton(String caption, UserRight userRight, Consumer fireEvent(new SideComponentCreateEvent(this))); + addCreateButton(createButton); + } + } + + public Registration addSideComponentCreateEventListener(SideComponentCreateEventListener sideComponentCreateEventListener) { + return addListener( + SideComponentCreateEvent.class, + sideComponentCreateEventListener, + SideComponentCreateEventListener.ON_SIDE_COMPONENT_CREATE_METHOD); + } + + public Registration addSideComponentEditEventListener(SideComponentEditEventListener sideComponentEditEventListener) { + return addListener( + SideComponentEditEvent.class, + sideComponentEditEventListener, + SideComponentEditEventListener.ON_SIDE_COMPONENT_EDIT_METHOD); + } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/EditSideComponentFieldEventListener.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/EditSideComponentFieldEventListener.java deleted file mode 100644 index f7077246ed8..00000000000 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/EditSideComponentFieldEventListener.java +++ /dev/null @@ -1,15 +0,0 @@ -package de.symeda.sormas.ui.utils.components.sidecomponent.event; - -import java.lang.reflect.Method; - -import com.vaadin.event.SerializableEventListener; -import com.vaadin.util.ReflectTools; - -@FunctionalInterface -public interface EditSideComponentFieldEventListener extends SerializableEventListener { - - Method ON_EDIT_SIDE_COMPONENT_FIELD_METHOD = - ReflectTools.findMethod(EditSideComponentFieldEventListener.class, "onEditSideComponentField", EditSideComponentFieldEvent.class); - - void onEditSideComponentField(EditSideComponentFieldEvent event); -} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentCreateEvent.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentCreateEvent.java new file mode 100644 index 00000000000..1b5e65df52c --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentCreateEvent.java @@ -0,0 +1,10 @@ +package de.symeda.sormas.ui.utils.components.sidecomponent.event; + +import com.vaadin.ui.Component; + +public class SideComponentCreateEvent extends Component.Event { + + public SideComponentCreateEvent(Component source) { + super(source); + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentCreateEventListener.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentCreateEventListener.java new file mode 100644 index 00000000000..85b816b1685 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentCreateEventListener.java @@ -0,0 +1,15 @@ +package de.symeda.sormas.ui.utils.components.sidecomponent.event; + +import java.lang.reflect.Method; + +import com.vaadin.event.SerializableEventListener; +import com.vaadin.util.ReflectTools; + +@FunctionalInterface +public interface SideComponentCreateEventListener extends SerializableEventListener { + + Method ON_SIDE_COMPONENT_CREATE_METHOD = + ReflectTools.findMethod(SideComponentCreateEventListener.class, "onCreate", SideComponentCreateEvent.class); + + void onCreate(SideComponentCreateEvent event); +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentEditEvent.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentEditEvent.java new file mode 100644 index 00000000000..1a20d445589 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentEditEvent.java @@ -0,0 +1,17 @@ +package de.symeda.sormas.ui.utils.components.sidecomponent.event; + +import com.vaadin.ui.Component; + +public class SideComponentEditEvent extends Component.Event { + + private final String uuid; + + public SideComponentEditEvent(Component source, String uuid) { + super(source); + this.uuid = uuid; + } + + public String getUuid() { + return this.uuid; + } +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentEditEventListener.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentEditEventListener.java new file mode 100644 index 00000000000..703cabc8b5a --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentEditEventListener.java @@ -0,0 +1,14 @@ +package de.symeda.sormas.ui.utils.components.sidecomponent.event; + +import java.lang.reflect.Method; + +import com.vaadin.event.SerializableEventListener; +import com.vaadin.util.ReflectTools; + +@FunctionalInterface +public interface SideComponentEditEventListener extends SerializableEventListener { + + Method ON_SIDE_COMPONENT_EDIT_METHOD = ReflectTools.findMethod(SideComponentEditEventListener.class, "onEdit", SideComponentEditEvent.class); + + void onEdit(SideComponentEditEvent event); +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/EditSideComponentFieldEvent.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentFieldEditEvent.java similarity index 51% rename from sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/EditSideComponentFieldEvent.java rename to sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentFieldEditEvent.java index 00f554b9e32..97de1e60f76 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/EditSideComponentFieldEvent.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentFieldEditEvent.java @@ -2,9 +2,9 @@ import com.vaadin.ui.Component; -public class EditSideComponentFieldEvent extends Component.Event { +public class SideComponentFieldEditEvent extends Component.Event { - public EditSideComponentFieldEvent(Component source) { + public SideComponentFieldEditEvent(Component source) { super(source); } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentFieldEditEventListener.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentFieldEditEventListener.java new file mode 100644 index 00000000000..dfcc3f62ec4 --- /dev/null +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/event/SideComponentFieldEditEventListener.java @@ -0,0 +1,15 @@ +package de.symeda.sormas.ui.utils.components.sidecomponent.event; + +import java.lang.reflect.Method; + +import com.vaadin.event.SerializableEventListener; +import com.vaadin.util.ReflectTools; + +@FunctionalInterface +public interface SideComponentFieldEditEventListener extends SerializableEventListener { + + Method ON_SIDE_COMPONENT_FIELD_EDIT_METHOD = + ReflectTools.findMethod(SideComponentFieldEditEventListener.class, "onEdit", SideComponentFieldEditEvent.class); + + void onEdit(SideComponentFieldEditEvent event); +} diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/list/VaccinationList.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/list/VaccinationList.java index aab5020a8da..293204340b6 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/list/VaccinationList.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/list/VaccinationList.java @@ -18,7 +18,6 @@ import java.util.List; import java.util.function.Function; -import com.vaadin.shared.Registration; import com.vaadin.ui.Label; import de.symeda.sormas.api.Disease; @@ -26,8 +25,7 @@ import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.vaccination.VaccinationListEntryDto; import de.symeda.sormas.ui.utils.PaginationList; -import de.symeda.sormas.ui.utils.components.sidecomponent.event.EditSideComponentFieldEvent; -import de.symeda.sormas.ui.utils.components.sidecomponent.event.EditSideComponentFieldEventListener; +import de.symeda.sormas.ui.utils.components.sidecomponent.event.SideComponentFieldEditEvent; public class VaccinationList extends PaginationList { @@ -63,15 +61,8 @@ protected void drawDisplayedEntries() { VaccinationListEntry listEntry = new VaccinationListEntry(entryDto, disease == null); listEntry.addEditButton( "edit-vaccination-" + listEntry.getVaccination().getUuid(), - e -> fireEvent(new EditSideComponentFieldEvent(listEntry))); + e -> fireEvent(new SideComponentFieldEditEvent(listEntry))); listLayout.addComponent(listEntry); } } - - public Registration addSideComponentFieldEditEventListener(EditSideComponentFieldEventListener editSideComponentFieldEventListener) { - return addListener( - EditSideComponentFieldEvent.class, - editSideComponentFieldEventListener, - EditSideComponentFieldEventListener.ON_EDIT_SIDE_COMPONENT_FIELD_METHOD); - } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/list/VaccinationListComponent.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/list/VaccinationListComponent.java index 1744d20f158..c5955cdb952 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/list/VaccinationListComponent.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/vaccination/list/VaccinationListComponent.java @@ -36,7 +36,7 @@ import de.symeda.sormas.ui.SormasUI; import de.symeda.sormas.ui.utils.AbstractDetailView; import de.symeda.sormas.ui.utils.components.sidecomponent.SideComponent; -import de.symeda.sormas.ui.utils.components.sidecomponent.event.EditSideComponentFieldEventListener; +import de.symeda.sormas.ui.utils.components.sidecomponent.event.SideComponentFieldEditEventListener; public class VaccinationListComponent extends SideComponent { @@ -139,7 +139,7 @@ private void createNewVaccinationButton( v -> refreshCallback.run()))); } - private EditSideComponentFieldEventListener editSideComponentFieldEventListener(VaccinationList vaccinationList) { + private SideComponentFieldEditEventListener editSideComponentFieldEventListener(VaccinationList vaccinationList) { return e -> view.showNavigationConfirmPopupIfDirty(() -> { VaccinationListEntry listEntry = (VaccinationListEntry) e.getComponent(); ControllerProvider.getVaccinationController() From 6d739417770fe2b12309f9a08ed9758b88beff47 Mon Sep 17 00:00:00 2001 From: Levente Gal <62599627+leventegal-she@users.noreply.github.com> Date: Fri, 25 Feb 2022 12:56:21 +0200 Subject: [PATCH 164/253] #8090 Update disease variant prompt navigates to case when only save was selected (#8130) --- .../ui/labmessage/LabMessageController.java | 2 +- .../ui/samples/PathogenTestController.java | 25 +++++++++++-------- .../sormas/ui/samples/SampleController.java | 2 +- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/labmessage/LabMessageController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/labmessage/LabMessageController.java index c79756d8072..3fddc414d66 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/labmessage/LabMessageController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/labmessage/LabMessageController.java @@ -1236,7 +1236,7 @@ private void showCreatePathogenTestWindow( }, (savedPathogenTest, callback) -> { chain.next(true); window.close(); - }); + }, true); pathogenTestCreateComponent.addDiscardListener(() -> { if (FacadeProvider.getLabMessageFacade().isProcessed(labMessage.getUuid())) { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java index 778a4234629..31d6ea2af8e 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java @@ -76,7 +76,7 @@ public void create( BiConsumer onSavedPathogenTest) { SampleDto sampleDto = FacadeProvider.getSampleFacade().getSampleByUuid(sampleRef.getUuid()); final CommitDiscardWrapperComponent editView = - getPathogenTestCreateComponent(sampleDto, caseSampleCount, callback, onSavedPathogenTest); + getPathogenTestCreateComponent(sampleDto, caseSampleCount, callback, onSavedPathogenTest, false); VaadinUiUtil.showModalPopupWindow(editView, I18nProperties.getString(Strings.headingCreatePathogenTestResult)); } @@ -85,7 +85,8 @@ public CommitDiscardWrapperComponent getPathogenTestCreateComp SampleDto sampleDto, int caseSampleCount, Runnable callback, - BiConsumer onSavedPathogenTest) { + BiConsumer onSavedPathogenTest, + boolean suppressNavigateToCase) { PathogenTestForm createForm = new PathogenTestForm(sampleDto, true, caseSampleCount, false); createForm.setValue(PathogenTestDto.build(sampleDto, UserProvider.getCurrent().getUser())); final CommitDiscardWrapperComponent editView = new CommitDiscardWrapperComponent<>( @@ -95,7 +96,7 @@ public CommitDiscardWrapperComponent getPathogenTestCreateComp editView.addCommitListener(() -> { if (!createForm.getFieldGroup().isModified()) { - savePathogenTest(createForm.getValue(), onSavedPathogenTest, false); + savePathogenTest(createForm.getValue(), onSavedPathogenTest, false, suppressNavigateToCase); callback.run(); SormasUI.refreshView(); } @@ -140,7 +141,7 @@ public CommitDiscardWrapperComponent getPathogenTestEditCompon editView.addCommitListener(() -> { if (!form.getFieldGroup().isModified()) { - savePathogenTest(form.getValue(), onSavedPathogenTest, false); + savePathogenTest(form.getValue(), onSavedPathogenTest, false, false); doneCallback.run(); SormasUI.refreshView(); } @@ -183,14 +184,15 @@ public static void showCaseUpdateWithNewDiseaseVariantDialog( public PathogenTestDto savePathogenTest( PathogenTestDto dto, BiConsumer onSavedPathogenTest, - boolean suppressSampleResultUpdatePopup) { + boolean suppressSampleResultUpdatePopup, + boolean suppressNavigateToCase) { PathogenTestDto savedDto = facade.savePathogenTest(dto); final SampleDto sample = FacadeProvider.getSampleFacade().getSampleByUuid(dto.getSample().getUuid()); final CaseReferenceDto associatedCase = sample.getAssociatedCase(); final ContactReferenceDto associatedContact = sample.getAssociatedContact(); final EventParticipantReferenceDto associatedEventParticipant = sample.getAssociatedEventParticipant(); if (associatedCase != null) { - handleAssociatedCase(dto, onSavedPathogenTest, associatedCase, suppressSampleResultUpdatePopup); + handleAssociatedCase(dto, onSavedPathogenTest, associatedCase, suppressSampleResultUpdatePopup, suppressNavigateToCase); } if (associatedContact != null) { handleAssociatedContact(dto, onSavedPathogenTest, associatedContact, suppressSampleResultUpdatePopup); @@ -206,7 +208,8 @@ private void handleAssociatedCase( PathogenTestDto dto, BiConsumer onSavedPathogenTest, CaseReferenceDto associatedCase, - boolean suppressSampleResultUpdatePopup) { + boolean suppressSampleResultUpdatePopup, + boolean suppressNavigateToCase) { // Negative test result AND test result verified // a) Tested disease == case disease AND test result != sample pathogen test result: Ask user whether to update the sample pathogen test result @@ -230,11 +233,11 @@ private void handleAssociatedCase( showChangeAssociatedSampleResultDialog(dto, null); } else if (PathogenTestResultType.POSITIVE.equals(dto.getTestResult()) && dto.getTestResultVerified()) { if (equalDisease && suppressSampleResultUpdatePopup) { - checkForDiseaseVariantUpdate(dto, caze, this::showConfirmCaseDialog); + checkForDiseaseVariantUpdate(dto, caze, suppressNavigateToCase, this::showConfirmCaseDialog); } else if (equalDisease) { showChangeAssociatedSampleResultDialog(dto, (accepted) -> { if (accepted) { - checkForDiseaseVariantUpdate(dto, caze, this::showConfirmCaseDialog); + checkForDiseaseVariantUpdate(dto, caze, suppressNavigateToCase, this::showConfirmCaseDialog); } }); } else { @@ -357,10 +360,10 @@ private void handleAssociatedEventParticipant( } } - private void checkForDiseaseVariantUpdate(PathogenTestDto test, CaseDataDto caze, Consumer callback) { + private void checkForDiseaseVariantUpdate(PathogenTestDto test, CaseDataDto caze, boolean suppressNavigateToCase, Consumer callback) { if (test.getTestedDiseaseVariant() != null && !DataHelper.equal(test.getTestedDiseaseVariant(), caze.getDiseaseVariant())) { showCaseUpdateWithNewDiseaseVariantDialog(caze, test.getTestedDiseaseVariant(), test.getTestedDiseaseVariantDetails(), yes -> { - if (yes) { + if (yes && !suppressNavigateToCase) { ControllerProvider.getCaseController().navigateToCase(caze.getUuid()); } // Retrieve the case again because it might have changed diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleController.java index 56228fba44e..be69d300ed6 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleController.java @@ -196,7 +196,7 @@ public PathogenTestForm addPathogenTestComponent( // validate pathogen test create component before saving the sample sampleComponent.addFieldGroups(pathogenTestForm.getFieldGroup()); CommitDiscardWrapperComponent.CommitListener savePathogenTest = () -> { - ControllerProvider.getPathogenTestController().savePathogenTest(pathogenTestForm.getValue(), null, true); + ControllerProvider.getPathogenTestController().savePathogenTest(pathogenTestForm.getValue(), null, true, true); if (callback != null) { callback.run(); } From 5861b772d623e5f790e48f1ffbc53fdc782c29c0 Mon Sep 17 00:00:00 2001 From: Alexandru Caruntu Date: Fri, 25 Feb 2022 13:30:17 +0200 Subject: [PATCH 165/253] #7787 - Do not trigger facility validation on discard --- .../main/java/de/symeda/sormas/ui/location/LocationEditForm.java | 1 + 1 file changed, 1 insertion(+) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/location/LocationEditForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/location/LocationEditForm.java index 415ef64c8f7..bcbefa59ef4 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/location/LocationEditForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/location/LocationEditForm.java @@ -570,6 +570,7 @@ public void discard() throws SourceException { facilityTypeGroup.setValue(null); } facility.setValue(locationDto.getFacility()); + facility.setComponentError(null); } } From 7e6183febd111db71c365caae6ff3ddb0695eefc Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Fri, 25 Feb 2022 14:32:18 +0200 Subject: [PATCH 166/253] #6879 - move health conditions above medical information in case data form --- .../src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java index 4f1a4563a5f..6f65a6f2803 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java @@ -251,6 +251,7 @@ public class CaseDataForm extends AbstractEditForm { fluidRowLocs(CaseDataDto.QUARANTINE_REASON_BEFORE_ISOLATION, CaseDataDto.QUARANTINE_REASON_BEFORE_ISOLATION_DETAILS) + fluidRowLocs(CaseDataDto.END_OF_ISOLATION_REASON, CaseDataDto.END_OF_ISOLATION_REASON_DETAILS) + fluidRowLocs(CaseDataDto.REPORT_LAT, CaseDataDto.REPORT_LON, CaseDataDto.REPORT_LAT_LON_ACCURACY) + + fluidRowLocs(CaseDataDto.HEALTH_CONDITIONS) + loc(MEDICAL_INFORMATION_LOC) + fluidRowLocs(CaseDataDto.BLOOD_ORGAN_OR_TISSUE_DONATED) + fluidRowLocs(CaseDataDto.PREGNANT, CaseDataDto.POSTPARTUM) + fluidRowLocs(CaseDataDto.TRIMESTER, "") + @@ -273,7 +274,6 @@ public class CaseDataForm extends AbstractEditForm { private static final String PAPER_FORM_DATES_AND_HEALTH_CONDITIONS_HTML_LAYOUT = fluidRowLocs(6, CaseDataDto.SURVEILLANCE_OFFICER) + - fluidRowLocs(CaseDataDto.HEALTH_CONDITIONS) + loc(PAPER_FORM_DATES_LOC) + fluidRowLocs(CaseDataDto.DISTRICT_LEVEL_DATE, CaseDataDto.REGION_LEVEL_DATE, CaseDataDto.NATIONAL_LEVEL_DATE) + loc(GENERAL_COMMENT_LOC) + fluidRowLocs(CaseDataDto.ADDITIONAL_DETAILS); From 75a8b8441c312bb372b331c7e72f6c02cf805894 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Fri, 25 Feb 2022 14:34:24 +0100 Subject: [PATCH 167/253] refactor --- .../pages/application/cases/CaseDirectoryPage.java | 3 ++- .../steps/web/application/cases/CaseDirectorySteps.java | 7 +++---- .../web/application/contacts/ContactDirectorySteps.java | 4 ++-- .../steps/web/application/events/EventDirectorySteps.java | 1 - .../web/application/persons/PersonDirectorySteps.java | 4 ++-- .../test/resources/features/sanity/web/CaseFilters.feature | 2 +- .../src/test/resources/features/sanity/web/Event.feature | 2 +- 7 files changed, 11 insertions(+), 12 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java index 4a1f8a5d19d..94583301886 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CaseDirectoryPage.java @@ -130,10 +130,11 @@ public class CaseDirectoryPage { public static final By DATE_TO_COMBOBOX = By.cssSelector("#dateTo input"); public static final By MORE_BUTTON = By.id("more"); public static final By ENTER_BULK_EDIT_MODE = By.id("actionEnterBulkEditMode"); - public static final By FIRST_CHECKBOX = + public static final By ALL_RESULTS_CHECKBOX = By.xpath("//th[@role='columnheader']//input[@type='checkbox']/../.."); public static final By NEW_EVENT_CHECKBOX = By.xpath("//*[contains(text(),'New event')]/.."); public static final By FIRST_RESULT_IN_GRID = By.xpath("//div[contains(@class, 'popupContent')]//tr[@role='row']"); + public static final By SEARCH_BUTTON = By.id("search"); // TODO refactor the other headers based on the last one added } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java index 88a1469e145..4028bed1745 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java @@ -96,7 +96,7 @@ public CaseDirectorySteps( When( "I click checkbox to choose all Case results", () -> { - webDriverHelpers.clickOnWebElementBySelector(FIRST_CHECKBOX); + webDriverHelpers.clickOnWebElementBySelector(ALL_RESULTS_CHECKBOX); webDriverHelpers.waitForPageLoaded(); }); And( @@ -115,8 +115,7 @@ public CaseDirectorySteps( () -> { String eventUuid = apiState.getCreatedEvent().getUuid(); webDriverHelpers.fillInWebElement( - By.id("search"), dataOperations.getPartialUuidFromAssociatedLink(eventUuid)); - TimeUnit.SECONDS.sleep(5); + SEARCH_BUTTON, dataOperations.getPartialUuidFromAssociatedLink(eventUuid)); }); And( "I click first result in grid on Link to Event form", @@ -312,7 +311,7 @@ public CaseDirectorySteps( () -> { webDriverHelpers.clickOnWebElementBySelector( CASE_DIRECTORY_DETAILED_PAGE_APPLY_FILTER_BUTTON); - TimeUnit.SECONDS.sleep(5); // needed for table refresh + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(20); }); Then( diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/ContactDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/ContactDirectorySteps.java index 02d73fcc950..c8a2a2ab217 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/ContactDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/contacts/ContactDirectorySteps.java @@ -137,9 +137,9 @@ public ContactDirectorySteps( webDriverHelpers.waitForPageLoaded(); }); When( - "I click checkbox to choose all Contact results", + "I click checkbox to choose all Contact results on Contact Directory Page", () -> { - webDriverHelpers.clickOnWebElementBySelector(FIRST_CHECKBOX); + webDriverHelpers.clickOnWebElementBySelector(ALL_RESULTS_CHECKBOX); webDriverHelpers.waitForPageLoaded(); }); And( diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index e90b0b054e6..0c94641480c 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -66,7 +66,6 @@ public EventDirectorySteps( webDriverHelpers.accessWebSite(LAST_CREATED_EVENT_PAGE_URL); webDriverHelpers.waitForPageLoaded(); webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(UUID_INPUT, 50); - TimeUnit.SECONDS.sleep(5); }); When( "I navigate to the last created through API Event page via URL", diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java index a634b8915ac..3a418da5c84 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java @@ -247,12 +247,12 @@ public PersonDirectorySteps( }); When( - "I apply on the APPLY FILTERS button", + "I click on the APPLY FILTERS button", () -> { webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable( APPLY_FILTERS_BUTTON, 30); webDriverHelpers.clickOnWebElementBySelector(APPLY_FILTERS_BUTTON); - TimeUnit.SECONDS.sleep(10); + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(20); }); When( diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature index f002a5a4099..d8242bc7f87 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature @@ -62,7 +62,7 @@ Feature: Case filter functionality Given API: I create a new case Then API: I check that POST call body is "OK" And API: I check that POST call status code is 200 - Given I log in as a Admin User + Given I log in with National User And I click on the Cases button from navbar And I apply Case origin "In-Country" on Case directory page And I filter by CaseID on Case directory page diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature index c413a304440..f50a8c70ad9 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature @@ -233,7 +233,7 @@ Feature: Create events And I select Screening filter from quick filter And I select Cluster filter from quick filter And I select Dropped filter from quick filter - And I click on the RESET FILTERS button + And I click on the RESET FILTERS button from Event @issue=SORDEV-5570 Scenario: Testing Event screen Impact From 7aa155d5c97d6238ffa6b2353730dd1a9525d9e9 Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Fri, 25 Feb 2022 16:09:04 +0200 Subject: [PATCH 168/253] #7773-allure-attach-logs : added first changes to check --- sormas-e2e-tests/src/main/java/recorders/StepsLogger.java | 1 + .../java/org/sormas/e2etests/helpers/AssertHelpers.java | 2 +- .../org/sormas/e2etests/helpers/WebDriverHelpers.java | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java index 4d1a8e316d5..bac16241ba4 100755 --- a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java +++ b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java @@ -65,6 +65,7 @@ public void afterStepStart(final StepResult result) { @Override public void afterStepUpdate(final StepResult result) { if (isScreenshotEnabled && driver != null) { + log.info("Attaching screenshot and console logs"); takeScreenshotAfter(); attachConsoleLog(); } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java index 73d443010f8..03969fb1dec 100755 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java @@ -51,7 +51,7 @@ public void assertWithPoll(ThrowingRunnable throwingRunnable, int seconds) { } catch (ConditionTimeoutException e) { log.error(PROCESS_ID_STRING + e.getMessage()); log.error(PROCESS_ID_STRING + Arrays.toString(e.getStackTrace())); - takeScreenshot(driver); + //takeScreenshot(driver); fail(e.getCause().getLocalizedMessage()); } } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java index 5fe3dce646b..de4b946f364 100755 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java @@ -199,7 +199,7 @@ public void fillInWebElement(By selector, String text) { } catch (ConditionTimeoutException ignored) { log.error("Unable to fill on element identified by locator: {} and text {}", selector, text); - takeScreenshot(baseSteps.getDriver()); + //takeScreenshot(baseSteps.getDriver()); throw new TimeoutException( "Unable to fill on element identified by locator: " + selector + " and text : " + text); } @@ -235,7 +235,7 @@ public void fillInAndLeaveWebElement(By selector, String text) { } catch (ConditionTimeoutException ignored) { log.error("Unable to fill on element identified by locator: {} and text {}", selector, text); - takeScreenshot(baseSteps.getDriver()); + //takeScreenshot(baseSteps.getDriver()); throw new TimeoutException( "Unable to fill on element identified by locator: " + selector + " and text : " + text); } @@ -333,7 +333,7 @@ public void clickOnWebElementBySelectorAndIndex(By selector, int index) { } catch (ConditionTimeoutException ignored) { log.error("Unable to click on element identified by locator: {}", selector); - takeScreenshot(baseSteps.getDriver()); + //takeScreenshot(baseSteps.getDriver()); throw new TimeoutException( String.format("Unable to click on element identified by locator: %s", selector)); } @@ -406,7 +406,7 @@ public void hoverToElement(By selector) { }); } catch (ConditionTimeoutException ignored) { log.error("Unable to fill on element identified by locator: {}", selector); - takeScreenshot(baseSteps.getDriver()); + //takeScreenshot(baseSteps.getDriver()); throw new TimeoutException("Unable to fill on element identified by locator: " + selector); } } From 8a163a99db5b5ee327730a2676e3dcdc4901b2bb Mon Sep 17 00:00:00 2001 From: sergiupacurariu <62688603+sergiupacurariu@users.noreply.github.com> Date: Fri, 25 Feb 2022 16:11:45 +0200 Subject: [PATCH 169/253] #7247 - CoreAdo: Introduce "end of processing date" --- .../symeda/sormas/backend/contact/ContactService.java | 11 +++++++++-- .../sormas/backend/event/EventParticipantService.java | 5 +++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java index 82474e9e77e..f7dd72e59ed 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java @@ -45,6 +45,7 @@ import javax.transaction.Transactional; import javax.validation.constraints.NotNull; +import de.symeda.sormas.backend.common.CoreAdo; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -1166,9 +1167,15 @@ public Predicate buildCriteriaFilter(ContactCriteria contactCriteria, ContactQue } if (contactCriteria.getRelevanceStatus() != null) { if (contactCriteria.getRelevanceStatus() == EntityRelevanceStatus.ACTIVE) { - filter = CriteriaBuilderHelper.and(cb, filter, cb.or(cb.equal(caze.get(Case.ARCHIVED), false), cb.isNull(caze.get(Case.ARCHIVED)))); + filter = CriteriaBuilderHelper.and( + cb, + filter, + cb.and( + cb.or(cb.equal(caze.get(Case.ARCHIVED), false), cb.isNull(caze.get(Case.ARCHIVED))), + cb.or(cb.equal(from.get(Contact.ARCHIVED), false), cb.isNull(from.get(Contact.ARCHIVED))))); } else if (contactCriteria.getRelevanceStatus() == EntityRelevanceStatus.ARCHIVED) { - filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(caze.get(Case.ARCHIVED), true)); + filter = + CriteriaBuilderHelper.and(cb, filter, cb.or(cb.equal(caze.get(Case.ARCHIVED), true), cb.equal(from.get(Contact.ARCHIVED), true))); } } if (contactCriteria.getDeleted() != null) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java index 1a5a0b1f8c8..58321ff426e 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantService.java @@ -224,9 +224,10 @@ public Predicate buildCriteriaFilter(EventParticipantCriteria criteria, EventPar if (criteria.getRelevanceStatus() != null) { if (criteria.getRelevanceStatus() == EntityRelevanceStatus.ACTIVE) { - filter = CriteriaBuilderHelper.and(cb, filter, cb.or(cb.equal(from.get(Event.ARCHIVED), false), cb.isNull(from.get(Event.ARCHIVED)))); + filter = CriteriaBuilderHelper + .and(cb, filter, cb.or(cb.equal(from.get(EventParticipant.ARCHIVED), false), cb.isNull(from.get(EventParticipant.ARCHIVED)))); } else if (criteria.getRelevanceStatus() == EntityRelevanceStatus.ARCHIVED) { - filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(Event.ARCHIVED), true)); + filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(EventParticipant.ARCHIVED), true)); } } From fb79d096767e74b4606c3dc873b36aaa6120d3dd Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Fri, 25 Feb 2022 16:36:34 +0200 Subject: [PATCH 170/253] #7773-allure-attach-logs : added changes 2 --- .../src/main/java/recorders/StepsLogger.java | 3 +++ .../java/org/sormas/e2etests/helpers/AssertHelpers.java | 3 +-- .../org/sormas/e2etests/helpers/WebDriverHelpers.java | 9 ++++----- .../src/test/resources/features/sanity/web/User.feature | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java index bac16241ba4..4c91e63f7ba 100755 --- a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java +++ b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java @@ -98,6 +98,7 @@ private void attachConsoleLog() { for (Object log : consoleLogs) { consoleLog.append(log); } + log.info("Appending logs to Allure report as attachment"); Allure.getLifecycle() .addAttachment( "Console log at :" @@ -106,6 +107,8 @@ private void attachConsoleLog() { "text", consoleLog.toString().getBytes()); } + log.info("Console logs are: " + consoleLogs.toString()); + log.info("Console logs bytes are: " + consoleLogs.toString().getBytes()); } public List consoleAllLogs(RemoteWebDriver webDriver) { diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java index 03969fb1dec..4ccc929dd01 100755 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java @@ -21,7 +21,6 @@ import static junit.framework.TestCase.fail; import static org.awaitility.Awaitility.await; import static org.awaitility.pollinterval.FibonacciPollInterval.fibonacci; -import static org.sormas.e2etests.steps.BaseSteps.driver; import static recorders.StepsLogger.PROCESS_ID_STRING; import java.io.File; @@ -51,7 +50,7 @@ public void assertWithPoll(ThrowingRunnable throwingRunnable, int seconds) { } catch (ConditionTimeoutException e) { log.error(PROCESS_ID_STRING + e.getMessage()); log.error(PROCESS_ID_STRING + Arrays.toString(e.getStackTrace())); - //takeScreenshot(driver); + // takeScreenshot(driver); fail(e.getCause().getLocalizedMessage()); } } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java index de4b946f364..d2eb1827951 100755 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java @@ -19,7 +19,6 @@ import static java.time.Duration.ofSeconds; import static org.awaitility.Awaitility.await; import static org.awaitility.Durations.ONE_HUNDRED_MILLISECONDS; -import static org.sormas.e2etests.helpers.AssertHelpers.takeScreenshot; import java.time.Instant; import java.time.temporal.ChronoUnit; @@ -199,7 +198,7 @@ public void fillInWebElement(By selector, String text) { } catch (ConditionTimeoutException ignored) { log.error("Unable to fill on element identified by locator: {} and text {}", selector, text); - //takeScreenshot(baseSteps.getDriver()); + // takeScreenshot(baseSteps.getDriver()); throw new TimeoutException( "Unable to fill on element identified by locator: " + selector + " and text : " + text); } @@ -235,7 +234,7 @@ public void fillInAndLeaveWebElement(By selector, String text) { } catch (ConditionTimeoutException ignored) { log.error("Unable to fill on element identified by locator: {} and text {}", selector, text); - //takeScreenshot(baseSteps.getDriver()); + // takeScreenshot(baseSteps.getDriver()); throw new TimeoutException( "Unable to fill on element identified by locator: " + selector + " and text : " + text); } @@ -333,7 +332,7 @@ public void clickOnWebElementBySelectorAndIndex(By selector, int index) { } catch (ConditionTimeoutException ignored) { log.error("Unable to click on element identified by locator: {}", selector); - //takeScreenshot(baseSteps.getDriver()); + // takeScreenshot(baseSteps.getDriver()); throw new TimeoutException( String.format("Unable to click on element identified by locator: %s", selector)); } @@ -406,7 +405,7 @@ public void hoverToElement(By selector) { }); } catch (ConditionTimeoutException ignored) { log.error("Unable to fill on element identified by locator: {}", selector); - //takeScreenshot(baseSteps.getDriver()); + // takeScreenshot(baseSteps.getDriver()); throw new TimeoutException("Unable to fill on element identified by locator: " + selector); } } diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/User.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/User.feature index 65bf8b2f64c..d68f0e047d2 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/User.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/User.feature @@ -36,7 +36,7 @@ Feature: Create user | National User | | POE National User | - @issue=SORDEV-9366 + @issue=SORDEV-9366 @env_main Scenario: Users with limited disease Given I log in as a Admin User And I click on the Users from navbar From a3836afa330180384197618f7f059852e1a74ac6 Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Fri, 25 Feb 2022 17:10:51 +0200 Subject: [PATCH 171/253] #7773-allure-attach-logs : added changes 3 --- .../src/main/java/recorders/StepsLogger.java | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java index 4c91e63f7ba..6f9fb9a6a67 100755 --- a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java +++ b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java @@ -65,7 +65,6 @@ public void afterStepStart(final StepResult result) { @Override public void afterStepUpdate(final StepResult result) { if (isScreenshotEnabled && driver != null) { - log.info("Attaching screenshot and console logs"); takeScreenshotAfter(); attachConsoleLog(); } @@ -89,26 +88,30 @@ public void takeScreenshotAfter() { @Attachment("Browser console log") private void attachConsoleLog() { + log.info("Attaching console logs"); List consoleLogs = consoleAllLogs(driver); StringBuilder consoleLog = new StringBuilder("CONSOLE LOG: "); if (consoleLogs.isEmpty()) { consoleLog.append(" NO CONSOLE LOGS DETECTED!"); } else { - for (Object log : consoleLogs) { - consoleLog.append(log); - } +// for (Object log : consoleLogs) { +// consoleLog.append(log); +// } log.info("Appending logs to Allure report as attachment"); - Allure.getLifecycle() - .addAttachment( - "Console log at :" - + LocalDateTime.now().format(DateTimeFormatter.ofPattern("dd-MMM-yy_hh:mm:ss")), - "text/json", - "text", - consoleLog.toString().getBytes()); + String testMessage = "Hope to work"; + Allure.getLifecycle().addAttachment("String attachment", + "text/plain", + "txt", + testMessage.getBytes()); +// Allure.getLifecycle() +// .addAttachment( +// "Console log at :" +// + LocalDateTime.now().format(DateTimeFormatter.ofPattern("dd-MMM-yy_hh:mm:ss")), +// "text/json", +// "text", +// consoleLog.toString().getBytes()); } - log.info("Console logs are: " + consoleLogs.toString()); - log.info("Console logs bytes are: " + consoleLogs.toString().getBytes()); } public List consoleAllLogs(RemoteWebDriver webDriver) { From 665e9781ef373c4675b81194a59f61fbacf9fe9e Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Fri, 25 Feb 2022 17:22:11 +0200 Subject: [PATCH 172/253] #7773-allure-attach-logs : added changes 4 --- .../src/main/java/recorders/StepsLogger.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java index 6f9fb9a6a67..c87870e881b 100755 --- a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java +++ b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java @@ -86,15 +86,15 @@ public void takeScreenshotAfter() { screenShot); } - @Attachment("Browser console log") + @Attachment(value = "Browser console log", type = "text/plain") private void attachConsoleLog() { log.info("Attaching console logs"); - List consoleLogs = consoleAllLogs(driver); - StringBuilder consoleLog = new StringBuilder("CONSOLE LOG: "); +// List consoleLogs = consoleAllLogs(driver); +// StringBuilder consoleLog = new StringBuilder("CONSOLE LOG: "); - if (consoleLogs.isEmpty()) { - consoleLog.append(" NO CONSOLE LOGS DETECTED!"); - } else { +// if (consoleLogs.isEmpty()) { +// consoleLog.append(" NO CONSOLE LOGS DETECTED!"); +// } else { // for (Object log : consoleLogs) { // consoleLog.append(log); // } @@ -111,7 +111,7 @@ private void attachConsoleLog() { // "text/json", // "text", // consoleLog.toString().getBytes()); - } + // } } public List consoleAllLogs(RemoteWebDriver webDriver) { From ba4d421df09213d58be52a7dd3a408b3f390f720 Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Fri, 25 Feb 2022 17:33:59 +0200 Subject: [PATCH 173/253] #7773-allure-attach-logs : added changes 5 --- .../src/main/java/recorders/StepsLogger.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java index c87870e881b..f6c9d18b060 100755 --- a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java +++ b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java @@ -89,21 +89,20 @@ public void takeScreenshotAfter() { @Attachment(value = "Browser console log", type = "text/plain") private void attachConsoleLog() { log.info("Attaching console logs"); -// List consoleLogs = consoleAllLogs(driver); -// StringBuilder consoleLog = new StringBuilder("CONSOLE LOG: "); + List consoleLogs = consoleAllLogs(driver); + StringBuilder consoleLog = new StringBuilder("CONSOLE LOG: "); -// if (consoleLogs.isEmpty()) { -// consoleLog.append(" NO CONSOLE LOGS DETECTED!"); -// } else { -// for (Object log : consoleLogs) { -// consoleLog.append(log); -// } + if (consoleLogs.isEmpty()) { + consoleLog.append(" NO CONSOLE LOGS DETECTED!"); + } else { + for (Object log : consoleLogs) { + consoleLog.append(log); + } log.info("Appending logs to Allure report as attachment"); - String testMessage = "Hope to work"; - Allure.getLifecycle().addAttachment("String attachment", + Allure.getLifecycle().addAttachment("Execution logs", "text/plain", "txt", - testMessage.getBytes()); + consoleLog.toString().getBytes()); // Allure.getLifecycle() // .addAttachment( // "Console log at :" @@ -111,7 +110,7 @@ private void attachConsoleLog() { // "text/json", // "text", // consoleLog.toString().getBytes()); - // } + } } public List consoleAllLogs(RemoteWebDriver webDriver) { From f0a6ca211cd01de65fe6a25ead88717e76755a74 Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Fri, 25 Feb 2022 17:43:16 +0200 Subject: [PATCH 174/253] #7773-allure-attach-logs : added changes 6 --- sormas-e2e-tests/src/main/java/recorders/StepsLogger.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java index f6c9d18b060..f3922454ae5 100755 --- a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java +++ b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java @@ -92,9 +92,12 @@ private void attachConsoleLog() { List consoleLogs = consoleAllLogs(driver); StringBuilder consoleLog = new StringBuilder("CONSOLE LOG: "); + log.info("Checking if console logs is empty"); if (consoleLogs.isEmpty()) { consoleLog.append(" NO CONSOLE LOGS DETECTED!"); - } else { + } + else { + log.info("Apending logs to object"); for (Object log : consoleLogs) { consoleLog.append(log); } @@ -128,6 +131,7 @@ public List consoleAllLogs(RemoteWebDriver webDriver) { + "\n"); allLogEntries.add(entry); }); + log.info("Found {} available console logs!", consoleLogs.size()); return consoleLogs; } } From 45ec95ce5e2f8ce57211b65d92182218916e9cc6 Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Fri, 25 Feb 2022 18:20:36 +0200 Subject: [PATCH 175/253] #7773-allure-attach-logs : added changes 7 --- .../src/main/java/recorders/StepsLogger.java | 35 ++++++++++++------- .../org/sormas/e2etests/steps/BaseSteps.java | 4 +++ 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java index f3922454ae5..622272449fb 100755 --- a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java +++ b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java @@ -23,6 +23,8 @@ import io.qameta.allure.Attachment; import io.qameta.allure.listener.StepLifecycleListener; import io.qameta.allure.model.StepResult; + +import java.io.FileInputStream; import java.lang.management.ManagementFactory; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -30,6 +32,8 @@ import java.util.Date; import java.util.List; import java.util.Objects; + +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.openqa.selenium.OutputType; import org.openqa.selenium.logging.LogEntries; @@ -86,6 +90,7 @@ public void takeScreenshotAfter() { screenShot); } + @SneakyThrows @Attachment(value = "Browser console log", type = "text/plain") private void attachConsoleLog() { log.info("Attaching console logs"); @@ -95,24 +100,28 @@ private void attachConsoleLog() { log.info("Checking if console logs is empty"); if (consoleLogs.isEmpty()) { consoleLog.append(" NO CONSOLE LOGS DETECTED!"); - } - else { - log.info("Apending logs to object"); + log.warn("There are no logs to display"); + } else { + log.info("Appending logs to object"); for (Object log : consoleLogs) { consoleLog.append(log); } log.info("Appending logs to Allure report as attachment"); - Allure.getLifecycle().addAttachment("Execution logs", - "text/plain", - "txt", - consoleLog.toString().getBytes()); + + Allure.getLifecycle() + .addAttachment("Execution logs", "text/plain", "txt", new FileInputStream("logs/file.log")); + // Allure.getLifecycle() -// .addAttachment( -// "Console log at :" -// + LocalDateTime.now().format(DateTimeFormatter.ofPattern("dd-MMM-yy_hh:mm:ss")), -// "text/json", -// "text", -// consoleLog.toString().getBytes()); +// .addAttachment("Execution logs", "text/plain", "txt", consoleLog.toString().getBytes()); + + // Allure.getLifecycle() + // .addAttachment( + // "Console log at :" + // + + // LocalDateTime.now().format(DateTimeFormatter.ofPattern("dd-MMM-yy_hh:mm:ss")), + // "text/json", + // "text", + // consoleLog.toString().getBytes()); } } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java index 8eb526e139c..0f654855dbe 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java @@ -28,7 +28,10 @@ import io.qameta.allure.listener.StepLifecycleListener; import io.restassured.RestAssured; import io.restassured.parsing.Parser; +import java.io.BufferedReader; +import java.io.InputStreamReader; import java.time.Duration; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.openqa.selenium.WebDriver; import org.openqa.selenium.remote.RemoteWebDriver; @@ -74,6 +77,7 @@ static void setup() { RestAssured.registerParser("text/html", Parser.JSON); } + @SneakyThrows @After(value = "@UI") public void afterScenario(Scenario scenario) { if (isNonApiScenario(scenario)) { From 253a966e5953cd79b84e5047b2d6b876ba270734 Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Fri, 25 Feb 2022 18:25:05 +0200 Subject: [PATCH 176/253] #7773-allure-attach-logs : added changes 8 --- .../src/main/java/recorders/StepsLogger.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java index 622272449fb..f0e30868c6c 100755 --- a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java +++ b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java @@ -97,17 +97,17 @@ private void attachConsoleLog() { List consoleLogs = consoleAllLogs(driver); StringBuilder consoleLog = new StringBuilder("CONSOLE LOG: "); - log.info("Checking if console logs is empty"); - if (consoleLogs.isEmpty()) { - consoleLog.append(" NO CONSOLE LOGS DETECTED!"); - log.warn("There are no logs to display"); - } else { - log.info("Appending logs to object"); - for (Object log : consoleLogs) { - consoleLog.append(log); - } +// log.info("Checking if console logs is empty"); +// if (consoleLogs.isEmpty()) { +// consoleLog.append(" NO CONSOLE LOGS DETECTED!"); +// log.warn("There are no logs to display"); +// } else { +// log.info("Appending logs to object"); +// for (Object log : consoleLogs) { +// consoleLog.append(log); +// } log.info("Appending logs to Allure report as attachment"); - + Allure.getLifecycle() .addAttachment("Execution logs", "text/plain", "txt", new FileInputStream("logs/file.log")); @@ -122,7 +122,7 @@ private void attachConsoleLog() { // "text/json", // "text", // consoleLog.toString().getBytes()); - } + //} } public List consoleAllLogs(RemoteWebDriver webDriver) { From 369131fe480f0e23428b91995c674469c02ab627 Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Fri, 25 Feb 2022 18:35:10 +0200 Subject: [PATCH 177/253] #7773-allure-attach-logs : added changes 9 --- .../src/main/java/recorders/StepsLogger.java | 51 ++----------------- 1 file changed, 4 insertions(+), 47 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java index f0e30868c6c..81903c61c48 100755 --- a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java +++ b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java @@ -76,6 +76,8 @@ public void afterStepUpdate(final StepResult result) { isScreenshotEnabled = true; log.info( " {} Finishing step: " + result.getName() + " and took: " + stopwatch, PROCESS_ID_STRING); + + log.info("Step status is: " + result.getStatus().value()); } @Attachment(value = "After step screenshot", type = "image/png") @@ -93,54 +95,9 @@ public void takeScreenshotAfter() { @SneakyThrows @Attachment(value = "Browser console log", type = "text/plain") private void attachConsoleLog() { - log.info("Attaching console logs"); - List consoleLogs = consoleAllLogs(driver); - StringBuilder consoleLog = new StringBuilder("CONSOLE LOG: "); - -// log.info("Checking if console logs is empty"); -// if (consoleLogs.isEmpty()) { -// consoleLog.append(" NO CONSOLE LOGS DETECTED!"); -// log.warn("There are no logs to display"); -// } else { -// log.info("Appending logs to object"); -// for (Object log : consoleLogs) { -// consoleLog.append(log); -// } - log.info("Appending logs to Allure report as attachment"); - - Allure.getLifecycle() + log.info("Appending logs to Allure report as attachment"); + Allure.getLifecycle() .addAttachment("Execution logs", "text/plain", "txt", new FileInputStream("logs/file.log")); - -// Allure.getLifecycle() -// .addAttachment("Execution logs", "text/plain", "txt", consoleLog.toString().getBytes()); - - // Allure.getLifecycle() - // .addAttachment( - // "Console log at :" - // + - // LocalDateTime.now().format(DateTimeFormatter.ofPattern("dd-MMM-yy_hh:mm:ss")), - // "text/json", - // "text", - // consoleLog.toString().getBytes()); - //} } - public List consoleAllLogs(RemoteWebDriver webDriver) { - LogEntries logEntries = Objects.requireNonNull(webDriver).manage().logs().get(LogType.BROWSER); - List consoleLogs = new ArrayList<>(); - - logEntries.forEach( - entry -> { - consoleLogs.add( - new Date(entry.getTimestamp()) - + " " - + entry.getLevel() - + " " - + entry.getMessage() - + "\n"); - allLogEntries.add(entry); - }); - log.info("Found {} available console logs!", consoleLogs.size()); - return consoleLogs; - } } From cca9b39d66d669b7ddbf68ca148f95ce7ca113cd Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Fri, 25 Feb 2022 18:39:51 +0200 Subject: [PATCH 178/253] #7773-allure-attach-logs : added changes 10 --- sormas-e2e-tests/src/main/java/recorders/StepsLogger.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java index 81903c61c48..5e6896a965e 100755 --- a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java +++ b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java @@ -70,14 +70,14 @@ public void afterStepStart(final StepResult result) { public void afterStepUpdate(final StepResult result) { if (isScreenshotEnabled && driver != null) { takeScreenshotAfter(); - attachConsoleLog(); + if(result.getStatus().value().equalsIgnoreCase("failed")){ + attachConsoleLog(); + } } stopwatch.stop(); isScreenshotEnabled = true; log.info( " {} Finishing step: " + result.getName() + " and took: " + stopwatch, PROCESS_ID_STRING); - - log.info("Step status is: " + result.getStatus().value()); } @Attachment(value = "After step screenshot", type = "image/png") From 517011040cd339b5fdfbc70509c47f7484248fa8 Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Fri, 25 Feb 2022 18:52:32 +0200 Subject: [PATCH 179/253] #7773-allure-attach-logs : added changes 11 --- sormas-e2e-tests/src/main/resources/logback.xml | 17 ++++++++++++++++- .../sormas/e2etests/helpers/AssertHelpers.java | 13 +------------ 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/sormas-e2e-tests/src/main/resources/logback.xml b/sormas-e2e-tests/src/main/resources/logback.xml index 390cb964041..94734142f88 100755 --- a/sormas-e2e-tests/src/main/resources/logback.xml +++ b/sormas-e2e-tests/src/main/resources/logback.xml @@ -78,7 +78,7 @@ 3GB - 3MB + 30MB %d{HH:mm:ss} [%thread] %-5level - %msg%n @@ -91,4 +91,19 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java index 4ccc929dd01..dc34447763c 100755 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java @@ -50,7 +50,6 @@ public void assertWithPoll(ThrowingRunnable throwingRunnable, int seconds) { } catch (ConditionTimeoutException e) { log.error(PROCESS_ID_STRING + e.getMessage()); log.error(PROCESS_ID_STRING + Arrays.toString(e.getStackTrace())); - // takeScreenshot(driver); fail(e.getCause().getLocalizedMessage()); } } @@ -58,15 +57,5 @@ public void assertWithPoll(ThrowingRunnable throwingRunnable, int seconds) { public void assertWithPoll20Second(ThrowingRunnable throwingRunnable) { assertWithPoll(throwingRunnable, 20); } - - @SneakyThrows - static void takeScreenshot(RemoteWebDriver remoteWebDriver) { - File srcFile = remoteWebDriver.getScreenshotAs(OutputType.FILE); - String projectDir = System.getProperty("user.dir"); - File destFileName = - new File( - projectDir + File.separator + "screenshots/" + System.currentTimeMillis() + ".jpg"); - log.error("{} screenshot with name: {}", PROCESS_ID_STRING, destFileName.getName()); - FileUtils.copyFile(srcFile, destFileName); - } + } From 82d5f78f544d9accefea6aa79991f70de3ab00c1 Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Fri, 25 Feb 2022 19:13:58 +0200 Subject: [PATCH 180/253] #7773-allure-attach-logs : added changes 12 --- .../src/main/java/recorders/StepsLogger.java | 11 ++--------- sormas-e2e-tests/src/main/resources/logback.xml | 5 ----- .../org/sormas/e2etests/helpers/AssertHelpers.java | 5 ----- .../org/sormas/e2etests/helpers/WebDriverHelpers.java | 9 +++++---- .../java/org/sormas/e2etests/steps/BaseSteps.java | 2 -- 5 files changed, 7 insertions(+), 25 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java index 5e6896a965e..c504bec8010 100755 --- a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java +++ b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java @@ -23,22 +23,16 @@ import io.qameta.allure.Attachment; import io.qameta.allure.listener.StepLifecycleListener; import io.qameta.allure.model.StepResult; - import java.io.FileInputStream; import java.lang.management.ManagementFactory; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; -import java.util.Date; import java.util.List; -import java.util.Objects; - import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.openqa.selenium.OutputType; -import org.openqa.selenium.logging.LogEntries; import org.openqa.selenium.logging.LogEntry; -import org.openqa.selenium.logging.LogType; import org.openqa.selenium.remote.RemoteWebDriver; @Slf4j @@ -70,7 +64,7 @@ public void afterStepStart(final StepResult result) { public void afterStepUpdate(final StepResult result) { if (isScreenshotEnabled && driver != null) { takeScreenshotAfter(); - if(result.getStatus().value().equalsIgnoreCase("failed")){ + if (result.getStatus().value().equalsIgnoreCase("failed")) { attachConsoleLog(); } } @@ -97,7 +91,6 @@ public void takeScreenshotAfter() { private void attachConsoleLog() { log.info("Appending logs to Allure report as attachment"); Allure.getLifecycle() - .addAttachment("Execution logs", "text/plain", "txt", new FileInputStream("logs/file.log")); + .addAttachment("Execution logs", "text/plain", "txt", new FileInputStream("logs/file.log")); } - } diff --git a/sormas-e2e-tests/src/main/resources/logback.xml b/sormas-e2e-tests/src/main/resources/logback.xml index 94734142f88..b6efaa0ee7e 100755 --- a/sormas-e2e-tests/src/main/resources/logback.xml +++ b/sormas-e2e-tests/src/main/resources/logback.xml @@ -101,9 +101,4 @@ - - - - - \ No newline at end of file diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java index dc34447763c..16b220d6b57 100755 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java @@ -23,17 +23,13 @@ import static org.awaitility.pollinterval.FibonacciPollInterval.fibonacci; import static recorders.StepsLogger.PROCESS_ID_STRING; -import java.io.File; import java.time.Duration; import java.util.Arrays; import java.util.concurrent.TimeUnit; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.io.FileUtils; import org.awaitility.core.ConditionTimeoutException; import org.awaitility.core.ThrowingRunnable; -import org.openqa.selenium.OutputType; -import org.openqa.selenium.remote.RemoteWebDriver; @Slf4j public class AssertHelpers { @@ -57,5 +53,4 @@ public void assertWithPoll(ThrowingRunnable throwingRunnable, int seconds) { public void assertWithPoll20Second(ThrowingRunnable throwingRunnable) { assertWithPoll(throwingRunnable, 20); } - } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java index d2eb1827951..30c6f388fda 100755 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java @@ -73,6 +73,7 @@ public WebDriverHelpers(BaseSteps baseSteps, AssertHelpers assertHelpers) { } public void waitForPageLoaded() { + log.info("Waiting for page to load"); assertHelpers.assertWithPoll20Second( () -> Assert.assertEquals( @@ -94,6 +95,7 @@ public void waitUntilIdentifiedElementIsVisibleAndClickable(final WebElement sel } public void waitUntilIdentifiedElementIsVisibleAndClickable(final Object selector, int seconds) { + log.info("Waiting for element [{}] to be visible and clickable", selector); if (selector instanceof By) { assertHelpers.assertWithPoll( () -> { @@ -127,6 +129,7 @@ public void waitUntilIdentifiedElementDisappear(final Object selector) { } public void waitUntilIdentifiedElementDisappear(final Object selector, int seconds) { + log.info("Waiting for element [{}] to disappear", selector); if (selector instanceof By) { assertHelpers.assertWithPoll( () -> { @@ -168,6 +171,7 @@ public void waitUntilAListOfWebElementsAreNotEmpty(final By selector) { } public void fillInWebElement(By selector, String text) { + log.info("Filling element [{{}] with text [{}]", selector, text); try { await() .pollInterval(ONE_HUNDRED_MILLISECONDS) @@ -198,7 +202,6 @@ public void fillInWebElement(By selector, String text) { } catch (ConditionTimeoutException ignored) { log.error("Unable to fill on element identified by locator: {} and text {}", selector, text); - // takeScreenshot(baseSteps.getDriver()); throw new TimeoutException( "Unable to fill on element identified by locator: " + selector + " and text : " + text); } @@ -234,7 +237,6 @@ public void fillInAndLeaveWebElement(By selector, String text) { } catch (ConditionTimeoutException ignored) { log.error("Unable to fill on element identified by locator: {} and text {}", selector, text); - // takeScreenshot(baseSteps.getDriver()); throw new TimeoutException( "Unable to fill on element identified by locator: " + selector + " and text : " + text); } @@ -332,7 +334,6 @@ public void clickOnWebElementBySelectorAndIndex(By selector, int index) { } catch (ConditionTimeoutException ignored) { log.error("Unable to click on element identified by locator: {}", selector); - // takeScreenshot(baseSteps.getDriver()); throw new TimeoutException( String.format("Unable to click on element identified by locator: %s", selector)); } @@ -380,6 +381,7 @@ public void clickOnWebElementWhichMayNotBePresent(final By byObject, final int i } public void scrollToElement(final Object selector) { + log.info("Scrolling to element [{}]", selector); JavascriptExecutor javascriptExecutor = baseSteps.getDriver(); try { if (selector instanceof WebElement) { @@ -405,7 +407,6 @@ public void hoverToElement(By selector) { }); } catch (ConditionTimeoutException ignored) { log.error("Unable to fill on element identified by locator: {}", selector); - // takeScreenshot(baseSteps.getDriver()); throw new TimeoutException("Unable to fill on element identified by locator: " + selector); } } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java index 0f654855dbe..2ca55c14dfc 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java @@ -28,8 +28,6 @@ import io.qameta.allure.listener.StepLifecycleListener; import io.restassured.RestAssured; import io.restassured.parsing.Parser; -import java.io.BufferedReader; -import java.io.InputStreamReader; import java.time.Duration; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; From dcf0ea682e8c9252d24936b94cb37e62d8d79e20 Mon Sep 17 00:00:00 2001 From: Alexandru Caruntu Date: Sat, 26 Feb 2022 13:57:38 +0200 Subject: [PATCH 181/253] #8054 - Do not set death place type field to other when null --- .../main/java/de/symeda/sormas/ui/person/PersonEditForm.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonEditForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonEditForm.java index 5fd63d8e33b..5a3ed14aa1e 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonEditForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonEditForm.java @@ -64,7 +64,6 @@ import de.symeda.sormas.api.person.ApproximateAgeType; import de.symeda.sormas.api.person.ApproximateAgeType.ApproximateAgeHelper; import de.symeda.sormas.api.person.CauseOfDeath; -import de.symeda.sormas.api.person.DeathPlaceType; import de.symeda.sormas.api.person.EducationType; import de.symeda.sormas.api.person.OccupationType; import de.symeda.sormas.api.person.PersonContext; @@ -845,7 +844,6 @@ private void setItemCaptionsForMonths(AbstractSelect months) { private void fillDeathAndBurialFields(AbstractSelect deathPlaceType, TextField deathPlaceDesc, TextField burialPlaceDesc) { if (deathPlaceType.isVisible() && deathPlaceType.getValue() == null) { - deathPlaceType.setValue(DeathPlaceType.OTHER); if (deathPlaceDesc.isVisible() && StringUtils.isBlank(deathPlaceDesc.getValue())) { deathPlaceDesc.setValue(getValue().getAddress().toString()); } From c606b414bc7861875b2b62426764e7fe8deeb96c Mon Sep 17 00:00:00 2001 From: Alexandru Caruntu Date: Sun, 27 Feb 2022 09:10:27 +0200 Subject: [PATCH 182/253] #7922 - Trigger case creation just once when converting a contact with a positive pathogen test --- .../sormas/ui/samples/PathogenTestController.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java index 31d6ea2af8e..aca327ee977 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java @@ -193,11 +193,9 @@ public PathogenTestDto savePathogenTest( final EventParticipantReferenceDto associatedEventParticipant = sample.getAssociatedEventParticipant(); if (associatedCase != null) { handleAssociatedCase(dto, onSavedPathogenTest, associatedCase, suppressSampleResultUpdatePopup, suppressNavigateToCase); - } - if (associatedContact != null) { + } else if (associatedContact != null) { handleAssociatedContact(dto, onSavedPathogenTest, associatedContact, suppressSampleResultUpdatePopup); - } - if (associatedEventParticipant != null) { + } else if (associatedEventParticipant != null) { handleAssociatedEventParticipant(dto, onSavedPathogenTest, associatedEventParticipant, suppressSampleResultUpdatePopup); } Notification.show(I18nProperties.getString(Strings.messagePathogenTestSavedShort), TRAY_NOTIFICATION); @@ -360,7 +358,11 @@ private void handleAssociatedEventParticipant( } } - private void checkForDiseaseVariantUpdate(PathogenTestDto test, CaseDataDto caze, boolean suppressNavigateToCase, Consumer callback) { + private void checkForDiseaseVariantUpdate( + PathogenTestDto test, + CaseDataDto caze, + boolean suppressNavigateToCase, + Consumer callback) { if (test.getTestedDiseaseVariant() != null && !DataHelper.equal(test.getTestedDiseaseVariant(), caze.getDiseaseVariant())) { showCaseUpdateWithNewDiseaseVariantDialog(caze, test.getTestedDiseaseVariant(), test.getTestedDiseaseVariantDetails(), yes -> { if (yes && !suppressNavigateToCase) { From ebede68fd2e99e04526047be361f25d368afdd0b Mon Sep 17 00:00:00 2001 From: Alexandru Caruntu Date: Sun, 27 Feb 2022 19:36:13 +0200 Subject: [PATCH 183/253] #7926 - Save parent entity after creating a new sample --- .../de/symeda/sormas/ui/caze/CaseDataView.java | 9 ++++++--- .../sormas/ui/contact/ContactDataView.java | 6 +++++- .../ui/events/EventParticipantDataView.java | 3 ++- .../sormas/ui/samples/SampleController.java | 18 +++++++++--------- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataView.java index a3d298f7185..b61954443fb 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataView.java @@ -31,6 +31,7 @@ import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.vaccination.VaccinationListCriteria; import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.SormasUI; import de.symeda.sormas.ui.UserProvider; import de.symeda.sormas.ui.caze.messaging.SmsListComponent; import de.symeda.sormas.ui.caze.surveillancereport.SurveillanceReportListComponent; @@ -140,7 +141,10 @@ protected void initView(String params) { && !caze.checkIsUnreferredPortHealthCase()) { SampleListComponent sampleList = new SampleListComponent( new SampleCriteria().caze(getCaseRef()).sampleAssociationType(SampleAssociationType.CASE), - e -> showNavigationConfirmPopupIfDirty(() -> ControllerProvider.getSampleController().create(getCaseRef(), caze.getDisease()))); + e -> showNavigationConfirmPopupIfDirty(() -> ControllerProvider.getSampleController().create(getCaseRef(), caze.getDisease(), () -> { + FacadeProvider.getCaseFacade().save(caze); + SormasUI.refreshView(); + }))); SampleListComponentLayout sampleListComponentLayout = new SampleListComponentLayout(sampleList, I18nProperties.getString(Strings.infoCreateNewSampleDiscardsChangesCase)); @@ -201,8 +205,7 @@ protected void initView(String params) { } DocumentListComponent documentList = null; if (FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.DOCUMENTS)) { - documentList = - new DocumentListComponent(DocumentRelatedEntityType.CASE, getCaseRef(), UserRight.CASE_EDIT, caze.isPseudonymized()); + documentList = new DocumentListComponent(DocumentRelatedEntityType.CASE, getCaseRef(), UserRight.CASE_EDIT, caze.isPseudonymized()); layout.addComponent(new SideComponentLayout(documentList), DOCUMENTS_LOC); } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataView.java index a0e59f28936..8a5d4fae880 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataView.java @@ -41,6 +41,7 @@ import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.vaccination.VaccinationListCriteria; import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.SormasUI; import de.symeda.sormas.ui.UserProvider; import de.symeda.sormas.ui.caze.CaseInfoLayout; import de.symeda.sormas.ui.docgeneration.QuarantineOrderDocumentsComponent; @@ -217,7 +218,10 @@ protected void initView(String params) { SampleListComponent sampleList = new SampleListComponent( new SampleCriteria().contact(getContactRef()).sampleAssociationType(SampleAssociationType.CONTACT), e -> showNavigationConfirmPopupIfDirty( - () -> ControllerProvider.getSampleController().create(getContactRef(), contactDto.getDisease()))); + () -> ControllerProvider.getSampleController().create(getContactRef(), contactDto.getDisease(), () -> { + FacadeProvider.getContactFacade().save(contactDto); + SormasUI.refreshView(); + }))); SampleListComponentLayout sampleListComponentLayout = new SampleListComponentLayout(sampleList, I18nProperties.getString(Strings.infoCreateNewSampleDiscardsChangesContact)); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantDataView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantDataView.java index 39d8accb8c1..a5447846ad4 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantDataView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantDataView.java @@ -36,6 +36,7 @@ import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.vaccination.VaccinationListCriteria; import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.SormasUI; import de.symeda.sormas.ui.SubMenu; import de.symeda.sormas.ui.UserProvider; import de.symeda.sormas.ui.contact.ContactListComponent; @@ -137,7 +138,7 @@ protected void initView(String params) { SampleListComponent sampleList = new SampleListComponent( sampleCriteria.sampleAssociationType(SampleAssociationType.EVENT_PARTICIPANT), e -> showNavigationConfirmPopupIfDirty( - () -> ControllerProvider.getSampleController().create(eventParticipantRef, event.getDisease()))); + () -> ControllerProvider.getSampleController().create(eventParticipantRef, event.getDisease(), SormasUI::refreshView))); SampleListComponentLayout sampleListComponentLayout = new SampleListComponentLayout(sampleList, I18nProperties.getString(Strings.infoCreateNewSampleDiscardsChangesEventParticipant)); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleController.java index be69d300ed6..510538d85cf 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleController.java @@ -43,8 +43,8 @@ import com.vaadin.v7.data.Validator.InvalidValueException; import com.vaadin.v7.ui.CheckBox; import com.vaadin.v7.ui.ComboBox; - import com.vaadin.v7.ui.Field; + import de.symeda.sormas.api.CountryHelper; import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.FacadeProvider; @@ -104,20 +104,20 @@ public void navigateToData(String sampleUuid) { SormasUI.get().getNavigator().navigateTo(navigationState); } - public void create(CaseReferenceDto caseRef, Disease disease) { - createSample(SampleDto.build(UserProvider.getCurrent().getUserReference(), caseRef), disease); + public void create(CaseReferenceDto caseRef, Disease disease, Runnable callback) { + createSample(SampleDto.build(UserProvider.getCurrent().getUserReference(), caseRef), disease, callback); } - public void create(ContactReferenceDto contactRef, Disease disease) { - createSample(SampleDto.build(UserProvider.getCurrent().getUserReference(), contactRef), disease); + public void create(ContactReferenceDto contactRef, Disease disease, Runnable callback) { + createSample(SampleDto.build(UserProvider.getCurrent().getUserReference(), contactRef), disease, callback); } - public void create(EventParticipantReferenceDto eventParticipantRef, Disease disease) { - createSample(SampleDto.build(UserProvider.getCurrent().getUserReference(), eventParticipantRef), disease); + public void create(EventParticipantReferenceDto eventParticipantRef, Disease disease, Runnable callback) { + createSample(SampleDto.build(UserProvider.getCurrent().getUserReference(), eventParticipantRef), disease, callback); } - private void createSample(SampleDto sampleDto, Disease disease) { - final CommitDiscardWrapperComponent editView = getSampleCreateComponent(sampleDto, disease, SormasUI::refreshView); + private void createSample(SampleDto sampleDto, Disease disease, Runnable callback) { + final CommitDiscardWrapperComponent editView = getSampleCreateComponent(sampleDto, disease, callback); // add option to create additional pathogen tests addPathogenTestButton(editView, false); VaadinUiUtil.showModalPopupWindow(editView, I18nProperties.getString(Strings.headingCreateNewSample)); From b6190035730fdd612e329b91fb9ae38954a65a58 Mon Sep 17 00:00:00 2001 From: Alexandru Caruntu Date: Sun, 27 Feb 2022 21:13:01 +0200 Subject: [PATCH 184/253] #8016 - Fix heading --- .../java/de/symeda/sormas/ui/caze/MergeCasesView.java | 7 ++----- .../de/symeda/sormas/ui/contact/MergeContactsView.java | 10 ++++------ 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/MergeCasesView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/MergeCasesView.java index ea75f99bfe6..3d09169cdc7 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/MergeCasesView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/MergeCasesView.java @@ -103,11 +103,8 @@ private void showCalculateCompletenessWindow() { e -> { if (e) { grid.calculateCompletenessValues(); - new Notification( - I18nProperties.getString(Strings.headingCasesArchived), - I18nProperties.getString(Strings.messageCompletenessValuesUpdated), - Type.HUMANIZED_MESSAGE, - false).show(Page.getCurrent()); + new Notification("", I18nProperties.getString(Strings.messageCompletenessValuesUpdated), Type.HUMANIZED_MESSAGE, false) + .show(Page.getCurrent()); } }); } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/MergeContactsView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/MergeContactsView.java index 1ac4998dc06..24023c37609 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/MergeContactsView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/MergeContactsView.java @@ -73,7 +73,8 @@ public MergeContactsView() { gridLayout.setStyleName("crud-main-layout"); addComponent(gridLayout); - Button btnOpenGuide = ButtonHelper.createIconButton(Captions.contactOpenMergeGuide, VaadinIcons.QUESTION, e -> buildAndOpenMergeInstructions()); + Button btnOpenGuide = + ButtonHelper.createIconButton(Captions.contactOpenMergeGuide, VaadinIcons.QUESTION, e -> buildAndOpenMergeInstructions()); addHeaderComponent(btnOpenGuide); Button btnCalculateCompleteness = @@ -106,11 +107,8 @@ private void showCalculateCompletenessWindow() { e -> { if (e.booleanValue() == true) { grid.calculateCompletenessValues(); - new Notification( - I18nProperties.getString(Strings.headingContactsArchived), - I18nProperties.getString(Strings.messageCompletenessValuesUpdated), - Type.HUMANIZED_MESSAGE, - false).show(Page.getCurrent()); + new Notification("", I18nProperties.getString(Strings.messageCompletenessValuesUpdated), Type.HUMANIZED_MESSAGE, false) + .show(Page.getCurrent()); } }); } From b5093262ae22343b4ed74343893a3f9451ac3da4 Mon Sep 17 00:00:00 2001 From: Alexandru Caruntu Date: Sun, 27 Feb 2022 22:13:56 +0200 Subject: [PATCH 185/253] #8105 - Set disease variant when converting travel entry to case --- .../src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java | 1 + 1 file changed, 1 insertion(+) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java index d5ea150cbb7..39c888db5e9 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java @@ -640,6 +640,7 @@ public static CaseDataDto buildFromTravelEntry(TravelEntryDto travelEntry, Perso CaseDataDto caseData = CaseDataDto.build(person.toReference(), travelEntry.getDisease()); caseData.setCaseOrigin(CaseOrigin.POINT_OF_ENTRY); + caseData.setDiseaseVariant(travelEntry.getDiseaseVariant()); caseData.setResponsibleRegion(travelEntry.getResponsibleRegion()); caseData.setResponsibleDistrict(travelEntry.getResponsibleDistrict()); caseData.setResponsibleCommunity(travelEntry.getResponsibleCommunity()); From 593cecea76402eaced2b4a72faa8aa440903227e Mon Sep 17 00:00:00 2001 From: jparzuch Date: Mon, 28 Feb 2022 06:38:41 +0100 Subject: [PATCH 186/253] Added rebased tests for directly entering home address and event report date filtering --- .../enums/EventReferenceDateOptions.java | 37 +++++ .../application/cases/CreateNewCasePage.java | 2 + .../events/EventDirectoryPage.java | 6 + .../entities/services/EventService.java | 2 + .../application/cases/CreateNewCaseSteps.java | 6 + .../web/application/cases/EditCaseSteps.java | 4 + .../events/EventDirectorySteps.java | 133 ++++++++++++++++++ .../events/EventsTableColumnsHeaders.java | 44 ++++++ .../features/sanity/web/Case.feature | 14 +- .../features/sanity/web/Event.feature | 10 ++ 10 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/EventReferenceDateOptions.java create mode 100644 sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventsTableColumnsHeaders.java diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/EventReferenceDateOptions.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/EventReferenceDateOptions.java new file mode 100644 index 00000000000..49ffdd5cf10 --- /dev/null +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/EventReferenceDateOptions.java @@ -0,0 +1,37 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.sormas.e2etests.enums; + +import lombok.Getter; + +@Getter +public enum EventReferenceDateOptions { + EVENT_DATE("Event date"), + REPORT_DATE("Report date"); + + private final String option; + + EventReferenceDateOptions(String option) { + this.option = option; + } + + @Override + public String toString() { + return this.option; + } +} diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CreateNewCasePage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CreateNewCasePage.java index bdbf9e4b7a6..bf89ba730fb 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CreateNewCasePage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/CreateNewCasePage.java @@ -57,4 +57,6 @@ public class CreateNewCasePage { public static final By PRIMARY_EMAIL_ADDRESS_INPUT = By.cssSelector(".v-window #emailAddress"); public static final By CONTACT_CASE_SAVE_BUTTON = By.xpath("//div[contains(@class, 'popupContent')]//div[@id='commit']"); + public static final By ENTER_HOME_ADDRESS_CHECKBOX = + By.cssSelector("[location='enterHomeAddressNow'] span.v-checkbox"); } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java index e44fab1042a..6e31805289b 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java @@ -53,6 +53,12 @@ public class EventDirectoryPage { public static final By EVENT_CLUSTER = By.id("status-Cluster"); public static final By EVENT_DROPPED = By.id("status-Dropped"); public static final By CREATED_PARTICIPANT = By.cssSelector("[role='gridcell'] a"); + public static final By DATE_TYPE_COMBOBOX = + By.cssSelector("[id='dateType'] [class='v-filterselect-button']"); + public static final By EVENTS_COLUMN_HEADERS = + By.cssSelector("thead" + " .v-grid-column-default-header-content"); + public static final By EVENTS_TABLE_ROW = By.cssSelector("div.v-grid-tablewrapper tbody tr"); + public static final By EVENTS_TABLE_DATA = By.tagName("td"); /*public static By getByEventUuid(String eventUuid) { return By.cssSelector("a[title=" + eventUuid + "]"); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/EventService.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/EventService.java index b1466ef27a6..a95659569fc 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/EventService.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/EventService.java @@ -68,4 +68,6 @@ public Event buildEditEvent() { .sourceType("Mathematical model") .build(); } + + public LocalDate[] timeRange; } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java index b1c9c32bd9d..6cd32d88ac1 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java @@ -161,6 +161,12 @@ public CreateNewCaseSteps(WebDriverHelpers webDriverHelpers, CaseService caseSer fillDateOfReport(caze.getDateOfReport()); fillPlaceDescription(caze.getPlaceDescription()); }); + + When( + "^I click on Enter Home Address of the Case Person Now in the Create New Case popup$", + () -> { + webDriverHelpers.clickOnWebElementBySelector(ENTER_HOME_ADDRESS_CHECKBOX); + }); } private void selectCaseOrigin(String caseOrigin) { diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java index bdf2d552189..77feae9fb50 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java @@ -103,6 +103,10 @@ public EditCaseSteps( "I navigate to Hospitalization tab in Cases", () -> webDriverHelpers.clickOnWebElementBySelector(HOSPITALIZATION_TAB)); + And( + "I navigate to case person tab", + () -> webDriverHelpers.clickOnWebElementBySelector(CASE_PERSON_TAB)); + When( "I check the created data is correctly displayed on Edit case page", () -> { diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index c8909bfe137..34bb5ef72a0 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -19,6 +19,8 @@ package org.sormas.e2etests.steps.web.application.events; import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_GRID_RESULTS_ROWS; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.DATE_FROM_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.DATE_TO_COMBOBOX; import static org.sormas.e2etests.pages.application.events.EditEventPage.*; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.*; import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.APPLY_FILTERS_BUTTON; @@ -26,10 +28,22 @@ import static org.sormas.e2etests.steps.BaseSteps.locale; import cucumber.api.java8.En; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import javax.inject.Inject; +import org.openqa.selenium.WebDriverException; +import org.openqa.selenium.WebElement; import org.sormas.e2etests.common.DataOperations; +import org.sormas.e2etests.entities.services.EventService; import org.sormas.e2etests.enums.*; +import org.sormas.e2etests.enums.EventReferenceDateOptions; import org.sormas.e2etests.enums.cases.epidemiologicalData.TypeOfPlace; import org.sormas.e2etests.envconfig.manager.EnvironmentManager; import org.sormas.e2etests.helpers.AssertHelpers; @@ -37,17 +51,26 @@ import org.sormas.e2etests.pages.application.NavBarPage; import org.sormas.e2etests.pages.application.events.EventDirectoryPage; import org.sormas.e2etests.state.ApiState; +import org.sormas.e2etests.steps.BaseSteps; import org.testng.Assert; +import org.testng.asserts.SoftAssert; public class EventDirectorySteps implements En { + private final WebDriverHelpers webDriverHelpers; + private final BaseSteps baseSteps; @Inject public EventDirectorySteps( WebDriverHelpers webDriverHelpers, + BaseSteps baseSteps, ApiState apiState, DataOperations dataOperations, AssertHelpers assertHelpers, + EventService eventService, + SoftAssert softly, EnvironmentManager environmentManager) { + this.webDriverHelpers = webDriverHelpers; + this.baseSteps = baseSteps; When( "I fill EVENT ID filter by API", @@ -179,6 +202,50 @@ public EventDirectorySteps( FILTER_BY_TYPE_OF_PLACE, TypeOfPlace.getValueFor(typeOfPlace)); }); + When( + "I select Report Date among Event Reference Date options", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.selectFromCombobox( + DATE_TYPE_COMBOBOX, EventReferenceDateOptions.REPORT_DATE.toString()); + }); + + When( + "I fill in a date range in Date of Event From Epi Week and ...To fields", + () -> { + webDriverHelpers.waitForPageLoaded(); + eventService.timeRange = buildTimeRange(); + webDriverHelpers.fillInWebElement( + DATE_FROM_COMBOBOX, + eventService + .timeRange[0] + .format(DateTimeFormatter.ofPattern("dd.MM.yyyy")) + .toString()); + webDriverHelpers.fillInWebElement( + DATE_TO_COMBOBOX, + eventService + .timeRange[1] + .format(DateTimeFormatter.ofPattern("dd.MM.yyyy")) + .toString()); + }); + + When( + "I check that the dates of displayed Event results are correct", + () -> { + webDriverHelpers.waitForPageLoaded(); + List> tableRowsData = getTableRowsData(); + for (int i = 0; i < tableRowsData.size(); i++) { + String dateCell = + tableRowsData.get(i).get(EventsTableColumnsHeaders.REPORT_DATE_HEADER.toString()); + LocalDate date = getLocalDateFromColumns(dateCell.substring(0, dateCell.indexOf(" "))); + softly.assertTrue( + date.isAfter(eventService.timeRange[0].minusDays(1)) + && date.isBefore(eventService.timeRange[1].plusDays(1)), + "The date(s) of displayed events are out of the requested range"); + } + softly.assertAll(); + }); + When( "^I check if it appears under ([^\"]*) filter in event directory", (String eventStatus) -> { @@ -289,4 +356,70 @@ public EventDirectorySteps( number.intValue(), "Number of displayed cases is not correct"))); } + + private List> getTableRowsData() { + Map headers = extractColumnHeadersHashMap(); + List tableRows = getTableRows(); + List> tableDataList = new ArrayList<>(); + tableRows.forEach( + table -> { + HashMap indexWithData = new HashMap<>(); + AtomicInteger atomicInt = new AtomicInteger(); + List tableData = table.findElements(EVENTS_TABLE_DATA); + tableData.forEach( + dataText -> { + webDriverHelpers.scrollToElementUntilIsVisible(dataText); + indexWithData.put(atomicInt.getAndIncrement(), dataText.getText()); + }); + tableDataList.add(indexWithData); + }); + List> tableObjects = new ArrayList<>(); + tableDataList.forEach( + row -> { + ConcurrentHashMap objects = new ConcurrentHashMap<>(); + headers.forEach((headerText, index) -> objects.put(headerText, row.get(index))); + tableObjects.add(objects); + }); + return tableObjects; + } + + private List getTableRows() { + webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(EVENTS_COLUMN_HEADERS); + return baseSteps.getDriver().findElements(EVENTS_TABLE_ROW); + } + + private Map extractColumnHeadersHashMap() { + AtomicInteger atomicInt = new AtomicInteger(); + HashMap headerHashmap = new HashMap<>(); + webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(EVENTS_COLUMN_HEADERS); + webDriverHelpers.waitUntilAListOfWebElementsAreNotEmpty(EVENTS_COLUMN_HEADERS); + webDriverHelpers.scrollToElementUntilIsVisible(EVENTS_COLUMN_HEADERS); + baseSteps + .getDriver() + .findElements(EVENTS_COLUMN_HEADERS) + .forEach( + webElement -> { + webDriverHelpers.scrollToElementUntilIsVisible(webElement); + headerHashmap.put(webElement.getText(), atomicInt.getAndIncrement()); + }); + return headerHashmap; + } + + private LocalDate getLocalDateFromColumns(String date) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M/d/yyyy"); + try { + return LocalDate.parse(date, formatter); + } catch (Exception e) { + throw new WebDriverException( + String.format( + "Unable to parse date: %s due to caught exception: %s", date, e.getMessage())); + } + } + + private LocalDate[] buildTimeRange() { + LocalDate[] timeRange = new LocalDate[2]; + timeRange[0] = LocalDate.now().minusMonths(1); + timeRange[1] = LocalDate.now(); + return timeRange; + } } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventsTableColumnsHeaders.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventsTableColumnsHeaders.java new file mode 100644 index 00000000000..0c6581ec4b7 --- /dev/null +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventsTableColumnsHeaders.java @@ -0,0 +1,44 @@ +package org.sormas.e2etests.steps.web.application.events; + +public enum EventsTableColumnsHeaders { + CONTACTS_HEADER("CONTACTS"), + EXTERNAL_TOKEN_HEADER("EXTERNAL TOKEN"), + INVESTIGATION_STATUS_HEADER("INVESTIGATION STATUS"), + GROUPS_HEADER("GROUPS"), + INFORMATION_SOURCE_HEADER("SOURCE OF INFORMATION"), + REPORTING_USER_HEADER("REPORTING USER"), + EXTERNAL_ID_HEADER("EXTERNAL ID"), + REPORT_DATE_HEADER("DATE OF REPORT"), + EVOLUTION_DATE_HEADER("EVOLUTION DATE"), + SOURCE_TYPE_HEADER("SOURCE TYPE"), + IDENTIFICATION_SOURCE_HEADER("EVENT IDENTIFICATION SOURCE"), + RESPONSIBLE_USER_HEADER("RESPONSIBLE USER"), + DISTRICT_HEADER("DISTRICT"), + PENDING_TASKS_HEADER("PENDING TASKS"), + COMMUNITY_HEADER("COMMUNITY"), + RISK_LEVEL_HEADER("EPIDEMIOLOGICAL RISK LEVEL"), + FATALITIES_HEADER("FATALITIES"), + DISEASE_VARIANT_HEADER("DISEASE VARIANT"), + INTERNAL_TOKEN_HEADER("INTERNAL TOKEN"), + CASES_HEADER("CASES"), + EVENT_DATE_HEADER("DATE OF EVENT"), + REGION_HEADER("REGION"), + DISEASE_HEADER("DISEASE"), + ADDRESS_HEADER("ADDRESS"), + EVENT_ID_HEADER("EVENT ID"), + TITLE_HEADER("TITLE"), + STATUS_HEADER("EVENT STATUS"), + PARTICIPANTS_HEADER("EVENT PARTICIPANTS"), + MANAGEMENT_STATUS_HEADER("EVENT MANAGEMENT STATUS"); + + private final String columnHeader; + + EventsTableColumnsHeaders(String columnHeader) { + this.columnHeader = columnHeader; + } + + @Override + public String toString() { + return this.columnHeader; + } +} diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature index 87d4babe0f1..b437cf97bdb 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature @@ -328,4 +328,16 @@ Feature: Case end to end tests And I check if Quarantine Follow up until date was extended to 1 day And I fill Quarantine change comment field Then I click on save Contact button - And I check if Quarantine change comment field was saved correctly \ No newline at end of file + And I check if Quarantine change comment field was saved correctly + + @issue=SORDEV-9033 @env_main + Scenario: Create case with directly entered home address + Given I log in with National User + And I click on the Cases button from navbar + And I click on the NEW CASE button + And I fill new case form with specific data + When I click on Enter Home Address of the Case Person Now in the Create New Case popup + And I fill specific address data in Case Person tab + Then I click on save case button + And I navigate to case person tab + And I check if saved Person data is correct \ No newline at end of file diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature index cd6547e02db..17b6e882954 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature @@ -243,6 +243,16 @@ Feature: Create events And I select Dropped filter from quick filter And I click on the RESET FILTERS button + @issue=SORDEV-9426 @env_main + Scenario: Filter for the report date of events + Given I log in with National User + And I click on the Events button from navbar + Then I click on Show more filters in Events + And I select Report Date among Event Reference Date options + And I fill in a date range in Date of Event From Epi Week and ...To fields + And I apply on the APPLY FILTERS button from Event + And I check that the dates of displayed Event results are correct + @issue=SORDEV-5570 @env_main Scenario: Testing Event screen Impact Given API: I create a new event From 0ef7e6cdf8d7e40f4c7b3fbdbe3209f7e4946948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9=20Strysewske?= Date: Mon, 28 Feb 2022 12:40:25 +0100 Subject: [PATCH 187/253] [GITFLOW]Updating development poms to hotfix version to avoid merge conflicts --- sormas-api/pom.xml | 2 +- sormas-app/pom.xml | 2 +- sormas-backend/pom.xml | 2 +- sormas-base/dependencies/serverlibs.pom | 2 +- sormas-base/pom.xml | 2 +- sormas-cargoserver/pom.xml | 2 +- sormas-ear/pom.xml | 2 +- sormas-keycloak-service-provider/pom.xml | 2 +- sormas-rest/pom.xml | 2 +- sormas-ui/pom.xml | 2 +- sormas-widgetset/pom.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sormas-api/pom.xml b/sormas-api/pom.xml index 214eb0b788e..bad03552a0d 100644 --- a/sormas-api/pom.xml +++ b/sormas-api/pom.xml @@ -2,7 +2,7 @@ de.symeda.sormas sormas-base - 1.69.0-SNAPSHOT + 1.68.1 ../sormas-base 4.0.0 diff --git a/sormas-app/pom.xml b/sormas-app/pom.xml index 3bb68392128..1617175eefb 100644 --- a/sormas-app/pom.xml +++ b/sormas-app/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.1 ../sormas-base 4.0.0 diff --git a/sormas-backend/pom.xml b/sormas-backend/pom.xml index 48b45586014..f2bfcc5af68 100644 --- a/sormas-backend/pom.xml +++ b/sormas-backend/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.1 ../sormas-base 4.0.0 diff --git a/sormas-base/dependencies/serverlibs.pom b/sormas-base/dependencies/serverlibs.pom index effd624397b..65377cf49df 100644 --- a/sormas-base/dependencies/serverlibs.pom +++ b/sormas-base/dependencies/serverlibs.pom @@ -8,7 +8,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.1 ../ diff --git a/sormas-base/pom.xml b/sormas-base/pom.xml index f5dd10b65f7..797666307c0 100644 --- a/sormas-base/pom.xml +++ b/sormas-base/pom.xml @@ -5,7 +5,7 @@ de.symeda.sormas sormas-base pom - 1.69.0-SNAPSHOT + 1.68.1 1.8 diff --git a/sormas-cargoserver/pom.xml b/sormas-cargoserver/pom.xml index 8c6009ec75f..a905e1c1ecc 100644 --- a/sormas-cargoserver/pom.xml +++ b/sormas-cargoserver/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.69.0-SNAPSHOT + 1.68.1 ../sormas-base diff --git a/sormas-ear/pom.xml b/sormas-ear/pom.xml index eb67f26b2b0..c1cd3d630e4 100644 --- a/sormas-ear/pom.xml +++ b/sormas-ear/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.69.0-SNAPSHOT + 1.68.1 ../sormas-base diff --git a/sormas-keycloak-service-provider/pom.xml b/sormas-keycloak-service-provider/pom.xml index 142c2f5858e..486cd64e275 100644 --- a/sormas-keycloak-service-provider/pom.xml +++ b/sormas-keycloak-service-provider/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.1 ../sormas-base 4.0.0 diff --git a/sormas-rest/pom.xml b/sormas-rest/pom.xml index 85e9fe6b41d..e8a9499732c 100644 --- a/sormas-rest/pom.xml +++ b/sormas-rest/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.69.0-SNAPSHOT + 1.68.1 ../sormas-base diff --git a/sormas-ui/pom.xml b/sormas-ui/pom.xml index 8b3382d103a..2b6753ad384 100644 --- a/sormas-ui/pom.xml +++ b/sormas-ui/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.1 ../sormas-base 4.0.0 diff --git a/sormas-widgetset/pom.xml b/sormas-widgetset/pom.xml index f8d6a25f29d..d5a5d7dc925 100644 --- a/sormas-widgetset/pom.xml +++ b/sormas-widgetset/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.1 ../sormas-base 4.0.0 From aff510acaa1810cccc73de24d405df948036507a Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Mon, 28 Feb 2022 14:43:55 +0200 Subject: [PATCH 188/253] #7773-allure-attach-logs : added changes 13 --- sormas-e2e-tests/scripts/runTests.sh | 2 +- .../src/main/java/recorders/StepsLogger.java | 9 ++------- sormas-e2e-tests/src/main/resources/logback.xml | 7 ++++--- .../org/sormas/e2etests/helpers/WebDriverHelpers.java | 10 +++++----- .../e2etests/steps/web/application/LoginSteps.java | 8 ++++++++ .../features/sanity/web/CaseClasification.feature | 2 +- 6 files changed, 21 insertions(+), 17 deletions(-) diff --git a/sormas-e2e-tests/scripts/runTests.sh b/sormas-e2e-tests/scripts/runTests.sh index e3e7f3b15ab..526c706daf4 100644 --- a/sormas-e2e-tests/scripts/runTests.sh +++ b/sormas-e2e-tests/scripts/runTests.sh @@ -25,7 +25,7 @@ rm -rf ./allureReports echo "Executing gradle clean..." ./gradlew clean goJF echo "Starting all BDD tests under @$1 tag..." -./gradlew startTests -Dcucumber.tags=\"@$1\" -Dheadless=true -Dcourgette.threads=9 -DenvConfig= +./gradlew startTests -Dcucumber.tags=\"@$1\" -Dheadless=true -Dcourgette.threads=9 -DenvConfig=C:/Users/Zack/Desktop/envData.json echo "Deleting test downloads folder..." rm -rf ./downloads diff --git a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java index c504bec8010..6292b986a61 100755 --- a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java +++ b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java @@ -27,12 +27,9 @@ import java.lang.management.ManagementFactory; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.List; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.openqa.selenium.OutputType; -import org.openqa.selenium.logging.LogEntry; import org.openqa.selenium.remote.RemoteWebDriver; @Slf4j @@ -41,7 +38,6 @@ public class StepsLogger implements StepLifecycleListener { private static final String PROCESS_ID = String.valueOf(ManagementFactory.getRuntimeMXBean().getPid()); public static final String PROCESS_ID_STRING = String.format("[PROCESS_ID:%s]", PROCESS_ID); - public final List allLogEntries = new ArrayList<>(); private static RemoteWebDriver driver; private static boolean isScreenshotEnabled = true; @@ -87,10 +83,9 @@ public void takeScreenshotAfter() { } @SneakyThrows - @Attachment(value = "Browser console log", type = "text/plain") + @Attachment(value = "Browser console log", type = "text/json") private void attachConsoleLog() { - log.info("Appending logs to Allure report as attachment"); Allure.getLifecycle() - .addAttachment("Execution logs", "text/plain", "txt", new FileInputStream("logs/file.log")); + .addAttachment("Execution logs", "text/json", "txt", new FileInputStream("logs/file.log")); } } diff --git a/sormas-e2e-tests/src/main/resources/logback.xml b/sormas-e2e-tests/src/main/resources/logback.xml index b6efaa0ee7e..e34984401ea 100755 --- a/sormas-e2e-tests/src/main/resources/logback.xml +++ b/sormas-e2e-tests/src/main/resources/logback.xml @@ -74,11 +74,11 @@ log-%d{yyyy-MM-dd}.log - 30 - 3GB + 0 + 30GB - 30MB + 500MB %d{HH:mm:ss} [%thread] %-5level - %msg%n @@ -101,4 +101,5 @@ + \ No newline at end of file diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java index 30c6f388fda..38f33aa7436 100755 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java @@ -73,7 +73,7 @@ public WebDriverHelpers(BaseSteps baseSteps, AssertHelpers assertHelpers) { } public void waitForPageLoaded() { - log.info("Waiting for page to load"); + log.info("Waiting for page to load"); assertHelpers.assertWithPoll20Second( () -> Assert.assertEquals( @@ -95,7 +95,7 @@ public void waitUntilIdentifiedElementIsVisibleAndClickable(final WebElement sel } public void waitUntilIdentifiedElementIsVisibleAndClickable(final Object selector, int seconds) { - log.info("Waiting for element [{}] to be visible and clickable", selector); + log.info("Waiting for element [{}] to be visible and clickable", selector); if (selector instanceof By) { assertHelpers.assertWithPoll( () -> { @@ -129,7 +129,7 @@ public void waitUntilIdentifiedElementDisappear(final Object selector) { } public void waitUntilIdentifiedElementDisappear(final Object selector, int seconds) { - log.info("Waiting for element [{}] to disappear", selector); + log.info("Waiting for element [{}] to disappear", selector); if (selector instanceof By) { assertHelpers.assertWithPoll( () -> { @@ -171,7 +171,7 @@ public void waitUntilAListOfWebElementsAreNotEmpty(final By selector) { } public void fillInWebElement(By selector, String text) { - log.info("Filling element [{{}] with text [{}]", selector, text); + log.info("Filling element [{{}] with text [{}]", selector, text); try { await() .pollInterval(ONE_HUNDRED_MILLISECONDS) @@ -381,7 +381,7 @@ public void clickOnWebElementWhichMayNotBePresent(final By byObject, final int i } public void scrollToElement(final Object selector) { - log.info("Scrolling to element [{}]", selector); + log.info("Scrolling to element [{}]", selector); JavascriptExecutor javascriptExecutor = baseSteps.getDriver(); try { if (selector instanceof WebElement) { diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/LoginSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/LoginSteps.java index bba25a27231..298691a1a08 100755 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/LoginSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/LoginSteps.java @@ -23,6 +23,7 @@ import com.google.inject.Inject; import cucumber.api.java8.En; +import lombok.extern.slf4j.Slf4j; import org.openqa.selenium.NoSuchElementException; import org.sormas.e2etests.enums.UserRoles; import org.sormas.e2etests.envconfig.dto.EnvUser; @@ -32,6 +33,7 @@ import org.sormas.e2etests.pages.application.dashboard.Surveillance.SurveillanceDashboardPage; import org.sormas.e2etests.steps.BaseSteps; +@Slf4j public class LoginSteps implements En { @Inject @@ -69,8 +71,11 @@ public LoginSteps( int attempts = 1; LOOP: while (attempts <= 3) { + log.info("Filling username"); webDriverHelpers.fillInWebElement(LoginPage.USER_NAME_INPUT, user.getUsername()); + log.info("Filling password"); webDriverHelpers.fillInWebElement(LoginPage.USER_PASSWORD_INPUT, user.getPassword()); + log.info("Click on Login button"); webDriverHelpers.clickOnWebElementBySelector(LoginPage.LOGIN_BUTTON); webDriverHelpers.waitForPageLoaded(); boolean wasUserLoggedIn; @@ -95,8 +100,11 @@ public LoginSteps( webDriverHelpers.accessWebSite(environmentManager.getEnvironmentUrlForMarket(locale)); webDriverHelpers.waitUntilIdentifiedElementIsPresent(LoginPage.USER_NAME_INPUT); EnvUser user = environmentManager.getUserByRole(locale, userRole); + log.info("Filling username"); webDriverHelpers.fillInWebElement(LoginPage.USER_NAME_INPUT, user.getUsername()); + log.info("Filling password"); webDriverHelpers.fillInWebElement(LoginPage.USER_PASSWORD_INPUT, user.getPassword()); + log.info("Clicking on login button"); webDriverHelpers.clickOnWebElementBySelector(LoginPage.LOGIN_BUTTON); webDriverHelpers.waitForPageLoaded(); webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(LOGOUT_BUTTON, 50); diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseClasification.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseClasification.feature index 5c084d8c276..6309803dbbc 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseClasification.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseClasification.feature @@ -1,7 +1,7 @@ @UI @Sanity @Case @Classification Feature: Case Classification functionality - @env_main + @env_main @mock @ignore Scenario: Case Classification change from Not Yet Classified to Suspect Case by confirming Sore Throat Given API: I create a new person Then API: I check that POST call body is "OK" From 41555ab395efec2e4081a06b9ab9b25f5bc5a36a Mon Sep 17 00:00:00 2001 From: Levente Gal <62599627+leventegal-she@users.noreply.github.com> Date: Mon, 28 Feb 2022 15:37:02 +0200 Subject: [PATCH 189/253] #5285 [DEMIS2SORMAS] Map variant specific Nucleic acid detection methods - remove unused field (#8154) --- .../de/symeda/sormas/api/labmessage/TestReportDto.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/labmessage/TestReportDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/labmessage/TestReportDto.java index c2551f067b8..530951be633 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/labmessage/TestReportDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/labmessage/TestReportDto.java @@ -39,7 +39,6 @@ public class TestReportDto extends EntityDto { private String testLabCity; private PathogenTestType testType; - private PCRTestSpecification pcrTestSpecification; private Date testDateTime; private PathogenTestResultType testResult; private Boolean testResultVerified; @@ -107,14 +106,6 @@ public void setTestType(PathogenTestType testType) { this.testType = testType; } - public PCRTestSpecification getPcrTestSpecification() { - return pcrTestSpecification; - } - - public void setPcrTestSpecification(PCRTestSpecification pcrTestSpecification) { - this.pcrTestSpecification = pcrTestSpecification; - } - public Date getTestDateTime() { return testDateTime; } From 8a4072f42a0726c8d359bec11ffa22c1492a7f41 Mon Sep 17 00:00:00 2001 From: Pawel Kujawa Date: Mon, 28 Feb 2022 15:06:01 +0100 Subject: [PATCH 190/253] fixes after rebase --- .../application/events/EditEventPage.java | 1 + .../CreateNewImmunizationPage.java | 5 ++ .../ImmunizationsDirectoryPage.java | 2 + .../samples/CreateNewSamplePage.java | 2 + .../samples/SamplesDirectoryPage.java | 5 ++ .../entities/services/CaseService.java | 11 +++ .../entities/services/SampleService.java | 16 ++++ .../e2etests/helpers/WebDriverHelpers.java | 5 ++ .../application/cases/CreateNewCaseSteps.java | 19 +++++ .../events/EventDirectorySteps.java | 6 ++ .../CreateNewImmunizationSteps.java | 31 ++++++- .../ImmunizationDirectorySteps.java | 9 ++ .../persons/PersonDirectorySteps.java | 39 +++++++-- .../samples/CreateNewSampleSteps.java | 84 ++++++++++++++++++- .../features/sanity/web/Immunization.feature | 9 ++ .../features/sanity/web/Pathogen.feature | 54 +++++++++++- 16 files changed, 290 insertions(+), 8 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EditEventPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EditEventPage.java index 926171a5b27..38c954a5dcd 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EditEventPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EditEventPage.java @@ -23,6 +23,7 @@ public class EditEventPage { public static final By EVENT_PARTICIPANTS_TAB = By.cssSelector("#tab-events-eventparticipants span"); + public static final By FIRST_EVENT_PARTICIPANT = By.xpath("//table/tbody/tr[1]/td[1]//a"); public static final By EVENT_ACTIONS_TAB = By.cssSelector("#tab-events-eventactions span"); public static final By UUID_INPUT = By.id("uuid"); public static final By TITLE_INPUT = By.cssSelector("#eventTitle"); diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/immunizations/CreateNewImmunizationPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/immunizations/CreateNewImmunizationPage.java index 2b78c03c2d0..b8552d8de0a 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/immunizations/CreateNewImmunizationPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/immunizations/CreateNewImmunizationPage.java @@ -50,4 +50,9 @@ public class CreateNewImmunizationPage { public static final By MEANS_OF_IMMUNIZATIONS_COMBOBOX = By.cssSelector(".v-window #meansOfImmunization div"); public static final By END_DATA_INPUT = By.cssSelector(".popupContent #endDate input"); + public static final By OVERWRITE_IMMUNIZATION_MANAGEMENT_STATUS_INPUT = + By.xpath("//*[@id='overwriteImmunizationManagementStatus']/label"); + public static final By DISCARD_IMMUNIZATION_BUTTON = By.cssSelector("#discard"); + public static final By MANAGEMENT_STATUS = + By.xpath("//div[@id='immunizationManagementStatus']//input"); } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/immunizations/ImmunizationsDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/immunizations/ImmunizationsDirectoryPage.java index 85b624135de..0b8073265c2 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/immunizations/ImmunizationsDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/immunizations/ImmunizationsDirectoryPage.java @@ -24,4 +24,6 @@ public class ImmunizationsDirectoryPage { public static final By ADD_NEW_IMMUNIZATION_BUTTON = By.cssSelector("#immunizationNewImmunization"); + public static final By FIRST_IMMUNIZATION_ID_BUTTON = + By.cssSelector(".v-grid-row-has-data a[title]"); } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/CreateNewSamplePage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/CreateNewSamplePage.java index 11fcd2aae58..8e187160d59 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/CreateNewSamplePage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/CreateNewSamplePage.java @@ -41,6 +41,8 @@ public class CreateNewSamplePage { By.cssSelector("[id='lab'] [class='v-filterselect-button']"); public static final By LABORATORY_INPUT = By.cssSelector("[id='lab'] input"); public static final By LABORATORY_NAME_INPUT = By.cssSelector("[id='labDetails']"); + public static final By LABORATORY_NAME_POPUP_INPUT = + By.cssSelector(".popupContent [id='labDetails']"); public static final By RECEIVED_OPTION_BUTTON = By.cssSelector("[id='received'] label"); public static final By DATE_SAMPLE_RECEIVED = By.cssSelector("[id='receivedDate'] input"); public static final By SPECIMEN_CONDITION_COMBOBOX = diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java index abb6c4fb7ca..53e1bc17a65 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/samples/SamplesDirectoryPage.java @@ -53,4 +53,9 @@ public class SamplesDirectoryPage { public static final By SAMPLE_SHIPPED = By.id("sampleShipped"); public static final By SAMPLE_RECEIVED = By.id("sampleReceived"); public static final By SAMPLE_REFFERED_TO_OTHER_LAB = By.id("sampleReferred"); + public static final By CREATE_CASE_POSITIVE_TEST_RESULT_LABEL = + By.cssSelector(".popupContent [class='v-window-header']"); + public static final By CONFIRM_BUTTON = By.id("actionConfirm"); + public static final By EDIT_PATHOGEN_TEST_BUTTON = + By.xpath("//div[@class='v-button v-widget link v-button-link compact v-button-compact']"); } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java index a79d2efb0b5..489a2cce51b 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java @@ -42,6 +42,17 @@ public CaseService(Faker faker) { this.faker = faker; } + public Case buildEditGeneratedCaseForPositivePathogenTestResult() { + return Case.builder() + .dateOfReport(LocalDate.now().minusDays(1)) + .responsibleRegion(RegionsValues.VoreingestellteBundeslander.getName()) + .responsibleDistrict(DistrictsValues.VoreingestellterLandkreis.getName()) + .responsibleCommunity(CommunityValues.VoreingestellteGemeinde.getName()) + .placeOfStay("HOME") + .placeDescription(faker.harryPotter().location()) + .build(); + } + public Case buildGeneratedCase() { firstName = faker.name().firstName(); lastName = faker.name().lastName(); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/SampleService.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/SampleService.java index cdaaa875b20..9305b750aed 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/SampleService.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/SampleService.java @@ -134,4 +134,20 @@ public Sample buildPathogenTestResultType(String testType) { .testResultsComment("Comment on Edit Pathogen requests or received " + currentTimeMillis) .build(); } + + public Sample buildPathogenTestResultTypeVerified(String testType) { + long currentTimeMillis = System.currentTimeMillis(); + return Sample.builder() + .reportDate(LocalDate.now()) + .typeOfTest(testType) + .testedDisease("COVID-19") + .dateOfResult(LocalDate.now()) + .timeOfResult(LocalTime.of(15, 15)) + .laboratory("Other facility") + .laboratoryName("Test laboratory") + .sampleTestResults("Positive") + .resultVerifiedByLabSupervisor("YES") + .testResultsComment("Comment on Edit Pathogen requests or received " + currentTimeMillis) + .build(); + } } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java index 5fe3dce646b..4000fe3ae19 100755 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java @@ -367,6 +367,11 @@ public boolean isElementVisibleWithTimeout(By selector, int seconds) { } } + public boolean isElementEnabled(By selector) { + scrollToElement(selector); + return baseSteps.getDriver().findElement(selector).isEnabled(); + } + public void clickOnWebElementWhichMayNotBePresent(final By byObject, final int index) { try { log.info("Clicking on element: {}", byObject); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java index b1c9c32bd9d..66915d8cd55 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java @@ -42,6 +42,25 @@ public class CreateNewCaseSteps implements En { public CreateNewCaseSteps(WebDriverHelpers webDriverHelpers, CaseService caseService) { this.webDriverHelpers = webDriverHelpers; + When( + "I create a new case with specific data for positive pathogen test result", + () -> { + caze = caseService.buildEditGeneratedCaseForPositivePathogenTestResult(); + fillDateOfReport(caze.getDateOfReport()); + selectResponsibleRegion(caze.getResponsibleRegion()); + selectResponsibleDistrict(caze.getResponsibleDistrict()); + selectResponsibleCommunity(caze.getResponsibleCommunity()); + selectPlaceOfStay(caze.getPlaceOfStay()); + }); + + When( + "I save a new case", + () -> { + webDriverHelpers.scrollToElement(CONTACT_CASE_SAVE_BUTTON); + webDriverHelpers.clickOnWebElementBySelector(CONTACT_CASE_SAVE_BUTTON); + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(20); + }); + When( "^I create a new case with specific data$", () -> { diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index c8909bfe137..e5021f5af7a 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -221,6 +221,12 @@ public EventDirectorySteps( webDriverHelpers.waitUntilElementIsVisibleAndClickable(getByEventUuid(personUuid)); }); + When( + "I click on the first row from event participant", + () -> { + webDriverHelpers.clickOnWebElementBySelector(FIRST_EVENT_PARTICIPANT); + }); + When( "I am accessing the event tab using the created event via api", () -> { diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/immunizations/CreateNewImmunizationSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/immunizations/CreateNewImmunizationSteps.java index 4836db3ffa3..5c5a9d57713 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/immunizations/CreateNewImmunizationSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/immunizations/CreateNewImmunizationSteps.java @@ -12,6 +12,7 @@ import org.sormas.e2etests.entities.pojo.web.Immunization; import org.sormas.e2etests.entities.services.ImmunizationService; import org.sormas.e2etests.helpers.WebDriverHelpers; +import org.testng.asserts.SoftAssert; public class CreateNewImmunizationSteps implements En { @@ -21,7 +22,9 @@ public class CreateNewImmunizationSteps implements En { @Inject public CreateNewImmunizationSteps( - WebDriverHelpers webDriverHelpers, ImmunizationService immunizationService) { + WebDriverHelpers webDriverHelpers, + ImmunizationService immunizationService, + SoftAssert softly) { this.webDriverHelpers = webDriverHelpers; When( @@ -48,6 +51,32 @@ public CreateNewImmunizationSteps( fillPrimaryEmailAddress(immunization.getPrimaryEmailAddress()); webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON); }); + + When( + "I check Overwrite immunization management status option", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.clickOnWebElementBySelector( + OVERWRITE_IMMUNIZATION_MANAGEMENT_STATUS_INPUT); + }); + + When( + "I check if Overwrite immunization management status is unchecked by Management Status", + () -> { + webDriverHelpers.waitUntilIdentifiedElementIsPresent(MANAGEMENT_STATUS); + webDriverHelpers.scrollToElement(MANAGEMENT_STATUS); + softly.assertFalse( + webDriverHelpers.isElementEnabled(MANAGEMENT_STATUS), + "Expected management status is not correct"); + softly.assertAll(); + }); + + When( + "I click on discard button from immunization tab", + () -> { + webDriverHelpers.scrollToElement(DISCARD_IMMUNIZATION_BUTTON); + webDriverHelpers.clickOnWebElementBySelector(DISCARD_IMMUNIZATION_BUTTON); + }); } private void fillDateOfReport(LocalDate date) { diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/immunizations/ImmunizationDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/immunizations/ImmunizationDirectorySteps.java index fbb3e617aef..f8f7bff19d6 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/immunizations/ImmunizationDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/immunizations/ImmunizationDirectorySteps.java @@ -1,6 +1,7 @@ package org.sormas.e2etests.steps.web.application.immunizations; import static org.sormas.e2etests.pages.application.immunizations.ImmunizationsDirectoryPage.ADD_NEW_IMMUNIZATION_BUTTON; +import static org.sormas.e2etests.pages.application.immunizations.ImmunizationsDirectoryPage.FIRST_IMMUNIZATION_ID_BUTTON; import com.google.inject.Inject; import cucumber.api.java8.En; @@ -17,5 +18,13 @@ public ImmunizationDirectorySteps(WebDriverHelpers webDriverHelpers) { webDriverHelpers.waitForPageLoadingSpinnerToDisappear(50); webDriverHelpers.clickOnWebElementBySelector(ADD_NEW_IMMUNIZATION_BUTTON); }); + + When( + "I open first immunization from grid from Immunization tab", + () -> { + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(40); + webDriverHelpers.waitUntilElementIsVisibleAndClickable(FIRST_IMMUNIZATION_ID_BUTTON); + webDriverHelpers.clickOnWebElementBySelector(FIRST_IMMUNIZATION_ID_BUTTON); + }); } } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java index db49b82cb25..b06a6df0e89 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,12 +24,14 @@ import static org.sormas.e2etests.steps.BaseSteps.locale; import com.github.javafaker.Faker; +import com.google.common.truth.Truth; import cucumber.api.java8.En; import java.util.UUID; import java.util.concurrent.TimeUnit; import javax.inject.Inject; import org.openqa.selenium.By; import org.sormas.e2etests.common.DataOperations; +import org.sormas.e2etests.entities.pojo.web.Person; import org.sormas.e2etests.enums.CommunityValues; import org.sormas.e2etests.enums.DistrictsValues; import org.sormas.e2etests.enums.PresentCondition; @@ -44,15 +46,16 @@ public class PersonDirectorySteps implements En { private final WebDriverHelpers webDriverHelpers; + protected Person createdPerson; @Inject public PersonDirectorySteps( WebDriverHelpers webDriverHelpers, ApiState apiState, - AssertHelpers assertHelpers, DataOperations dataOperations, - EnvironmentManager environmentManager, - Faker faker) { + Faker faker, + AssertHelpers assertHelpers, + EnvironmentManager environmentManager) { this.webDriverHelpers = webDriverHelpers; // TODO refactor all BDD methods naming to be more explicit regarding where data comes from @@ -76,6 +79,33 @@ public PersonDirectorySteps( webDriverHelpers.isElementVisibleWithTimeout(UUID_INPUT, 20); }); + Then( + "I check the result for UID for second person in grid PERSON ID column", + () -> { + webDriverHelpers.waitUntilAListOfElementsHasText( + CASE_GRID_RESULTS_ROWS, apiState.getLastCreatedPerson().getUuid()); + assertHelpers.assertWithPoll20Second( + () -> + Truth.assertWithMessage( + apiState.getLastCreatedPerson().getUuid() + + " value is not displayed in grid Disease column") + .that(apiState.getLastCreatedPerson().getUuid()) + .isEqualTo( + String.valueOf( + webDriverHelpers.getTextFromPresentWebElement( + CASE_PERSON_ID_COLUMN_HEADERS)))); + }); + + Then( + "I check that number of displayed Persons results is {int}", + (Integer number) -> + assertHelpers.assertWithPoll20Second( + () -> + Assert.assertEquals( + webDriverHelpers.getNumberOfElements(CASE_GRID_RESULTS_ROWS), + number.intValue(), + "Number of displayed cases is not correct"))); + Then( "I choose random value for Year of birth filter in Persons for the last created person by API", () -> { @@ -262,7 +292,6 @@ public PersonDirectorySteps( webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable( RESET_FILTERS_BUTTON, 30); webDriverHelpers.clickOnWebElementBySelector(RESET_FILTERS_BUTTON); - TimeUnit.SECONDS.sleep(10); }); Then( diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/CreateNewSampleSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/CreateNewSampleSteps.java index 96faa01cfc4..8a27f82d4fc 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/CreateNewSampleSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/CreateNewSampleSteps.java @@ -26,12 +26,14 @@ import java.time.LocalDate; import java.time.LocalTime; import java.time.format.DateTimeFormatter; +import java.util.List; import javax.inject.Inject; import org.openqa.selenium.By; import org.sormas.e2etests.entities.pojo.helpers.ComparisonHelper; import org.sormas.e2etests.entities.pojo.web.Sample; import org.sormas.e2etests.entities.services.SampleService; import org.sormas.e2etests.helpers.WebDriverHelpers; +import org.testng.asserts.SoftAssert; public class CreateNewSampleSteps implements En { public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("M/d/yyyy"); @@ -44,7 +46,10 @@ public class CreateNewSampleSteps implements En { @Inject public CreateNewSampleSteps( - WebDriverHelpers webDriverHelpers, SampleService sampleService, Faker faker) { + WebDriverHelpers webDriverHelpers, + SampleService sampleService, + Faker faker, + SoftAssert softly) { this.webDriverHelpers = webDriverHelpers; this.faker = faker; @@ -126,6 +131,35 @@ public CreateNewSampleSteps( webDriverHelpers.clickOnWebElementBySelector(SAVE_SAMPLE_BUTTON); }); + When( + "I check if Pathogen test result in Samples is displayed correctly and save", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.clickOnWebElementBySelector(EDIT_PATHOGEN_TEST_BUTTON); + final Sample actualSampleTestResult = collectPathogenTestResultsData(); + ComparisonHelper.compareEqualFieldsOfEntities( + sampleTestResult, + actualSampleTestResult, + List.of( + "laboratory", + "sampleTestResults", + "reportDate", + "typeOfTest", + "testedDisease", + "dateOfResult", + "timeOfResult", + "resultVerifiedByLabSupervisor", + "testResultsComment")); + webDriverHelpers.clickOnWebElementBySelector(SAVE_SAMPLE_BUTTON); + }); + + When( + "I complete all fields from Pathogen test result popup for IgM test type with positive verified test result$", + () -> { + simplePathogenBuilderVerifiedResult("IgG serum antibody"); + webDriverHelpers.clickOnWebElementBySelector(SAVE_SAMPLE_BUTTON); + }); + When( "^I complete all fields from Pathogen test result popup for IgG test type and save$", () -> { @@ -179,6 +213,32 @@ public CreateNewSampleSteps( final Sample actualSampleTestResult = collectPathogenTestResultsData(); ComparisonHelper.compareEqualEntities(sampleTestResult, actualSampleTestResult); }); + + When( + "I confirm the Create case from contact with positive test result", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.waitUntilElementIsVisibleAndClickable(CONFIRM_BUTTON); + String displayedText = + webDriverHelpers.getTextFromWebElement(CREATE_CASE_POSITIVE_TEST_RESULT_LABEL); + String expectedText = "Create case from contact with positive test result?"; + softly.assertEquals(displayedText, expectedText); + softly.assertAll(); + webDriverHelpers.clickOnWebElementBySelector(CONFIRM_BUTTON); + }); + + When( + "I confirm the Create case from event participant with positive test result", + () -> { + webDriverHelpers.waitForPageLoaded(); + webDriverHelpers.waitUntilElementIsVisibleAndClickable(CONFIRM_BUTTON); + String displayedText = + webDriverHelpers.getTextFromWebElement(CREATE_CASE_POSITIVE_TEST_RESULT_LABEL); + String expectedText = "Create case from event participant with positive test result?"; + softly.assertEquals(displayedText, expectedText); + softly.assertAll(); + webDriverHelpers.clickOnWebElementBySelector(CONFIRM_BUTTON); + }); } private void selectPurposeOfSample(String samplePurpose, By element) { @@ -380,6 +440,10 @@ private String getSampleTestResult() { return webDriverHelpers.getTextFromWebElement(SAMPLE_TEST_RESULT_BUTTON); } + private void selectLaboratoryNamePopup(String laboratoryName) { + webDriverHelpers.clearAndFillInWebElement(LABORATORY_NAME_POPUP_INPUT, laboratoryName); + } + private LocalDate getReportDate() { return LocalDate.parse( webDriverHelpers.getValueFromWebElement(DATE_TEST_REPORT), DATE_FORMATTER); @@ -441,4 +505,22 @@ private Sample simplePathogenBuilderResult(String testType) { fillTestResultsComment(sampleTestResult.getTestResultsComment()); return sampleTestResult; } + + private Sample simplePathogenBuilderVerifiedResult(String testType) { + SampleService sampleService = new SampleService(faker); + sampleTestResult = sampleService.buildPathogenTestResultTypeVerified(testType); + fillReportDate(sampleTestResult.getReportDate()); + selectTypeOfTest(sampleTestResult.getTypeOfTest()); + selectTestedDisease(sampleTestResult.getTestedDisease()); + selectPathogenLaboratory(sampleTestResult.getLaboratory()); + selectLaboratoryNamePopup(sampleTestResult.getLaboratoryName()); + selectTestResult(sampleTestResult.getSampleTestResults()); + fillDateOfResult(sampleTestResult.getDateOfResult()); + fillTimeOfResult(sampleTestResult.getTimeOfResult()); + selectResultVerifiedByLabSupervisor( + sampleTestResult.getResultVerifiedByLabSupervisor(), + RESULT_VERIFIED_BY_LAB_SUPERVISOR_OPTIONS); + fillTestResultsComment(sampleTestResult.getTestResultsComment()); + return sampleTestResult; + } } diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Immunization.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Immunization.feature index 616822a824c..ea9f7e94ad9 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Immunization.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Immunization.feature @@ -9,3 +9,12 @@ Feature: Immunization end to end tests When I create a new immunization with specific data Then I check the created data is correctly displayed on Edit immunization page And I check the created data is correctly displayed on Edit immunization person page + + @issue=SORDEV-9312 @env_main + Scenario: Reset the 'Overwrite immunization management status' by Discard button + Given I log in as a Surveillance Officer + And I click on the Immunizations button from navbar + And I open first immunization from grid from Immunization tab + Then I check Overwrite immunization management status option + Then I click on discard button from immunization tab + And I check if Overwrite immunization management status is unchecked by Management Status \ No newline at end of file diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Pathogen.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Pathogen.feature index 2576df39509..96e187e1269 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Pathogen.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Pathogen.feature @@ -140,4 +140,56 @@ Feature: Pathogen Functionalities And I complete all fields from Pathogen test result popup for Other test type and save Then I check that the created Pathogen is correctly displayed And I check that if Other field is correctly displayed - And I delete the Pathogen test \ No newline at end of file + And I delete the Pathogen test + + @issue=SORDEV-8058 @env_main + Scenario: Unify pathogen test saving logic between cases and contacts + When API: I create a new person + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + And API: I create a new contact + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in with National User + When I click on the Contacts button from navbar + Then I open the last created contact + And I click on New Sample + When I collect the sample UUID displayed on create new sample page + And I create a new Sample with specific data and save + And I click on edit Sample + Then I click on the new pathogen test from the Edit Sample page + And I complete all fields from Pathogen test result popup for IgM test type with positive verified test result + Then I confirm the Create case from contact with positive test result + Then I create a new case with specific data for positive pathogen test result + Then I save a new case + And I click on the Sample button from navbar + And I search for Sample using Sample UUID from the created Sample + When I open created Sample + Then I check if Pathogen test result in Samples is displayed correctly and save + + @issue=SORDEV-8058 @env_main + Scenario: Unify pathogen test saving logic between cases and event participants + When API: I create a new person + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given API: I create a new event + Then API: I check that POST call body is "OK" + And API: I check that POST call status code is 200 + Given I log in with National User + When I am accessing the event tab using the created event via api + Then I add a participant to the event + Then I check if participant appears in the event participants list + And I click on the first row from event participant + And I click on New Sample + When I collect the sample UUID displayed on create new sample page + And I create a new Sample with specific data and save + And I click on edit Sample + Then I click on the new pathogen test from the Edit Sample page + And I complete all fields from Pathogen test result popup for IgM test type with positive verified test result + Then I confirm the Create case from event participant with positive test result + Then I create a new case with specific data for positive pathogen test result + Then I save a new case + And I click on the Sample button from navbar + And I search for Sample using Sample UUID from the created Sample + When I open created Sample + Then I check if Pathogen test result in Samples is displayed correctly and save \ No newline at end of file From 9215ecf4417c9f402e0bc9bba20597d4850bb9ee Mon Sep 17 00:00:00 2001 From: Alexandru Caruntu Date: Mon, 28 Feb 2022 16:25:15 +0200 Subject: [PATCH 191/253] #8105 - Set disease variant details when converting travel entry to case --- .../src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java | 1 + 1 file changed, 1 insertion(+) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java index 39c888db5e9..91796385c77 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java @@ -641,6 +641,7 @@ public static CaseDataDto buildFromTravelEntry(TravelEntryDto travelEntry, Perso caseData.setCaseOrigin(CaseOrigin.POINT_OF_ENTRY); caseData.setDiseaseVariant(travelEntry.getDiseaseVariant()); + caseData.setDiseaseDetails(travelEntry.getDiseaseVariantDetails()); caseData.setResponsibleRegion(travelEntry.getResponsibleRegion()); caseData.setResponsibleDistrict(travelEntry.getResponsibleDistrict()); caseData.setResponsibleCommunity(travelEntry.getResponsibleCommunity()); From 303ea698169c3fb0b09e50776d94d15cdbf12d7b Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Mon, 28 Feb 2022 16:38:29 +0200 Subject: [PATCH 192/253] #7773-allure-attach-logs : added changes 13 --- .../src/test/resources/features/sanity/web/Reports.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Reports.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Reports.feature index 9de2c4309ea..73845d46a82 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Reports.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Reports.feature @@ -10,7 +10,7 @@ Feature: Reports Then I check that grid for weekly reports is shown Then I check that header names of grid for weekly reports are shown - @env_main + @env_main @ignore Scenario: Reports filter work Given I log in with National User When I click on the Reports button from navbar From aa8276f9b8787d38d4c44e9fff693f8c00768629 Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Mon, 28 Feb 2022 16:39:56 +0200 Subject: [PATCH 193/253] #8158-ignore-flaky-tests : isolated test --- .../resources/features/sanity/web/CaseClasification.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseClasification.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseClasification.feature index 5c084d8c276..1a02cd1c61e 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseClasification.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseClasification.feature @@ -21,7 +21,7 @@ Feature: Case Classification functionality And I click on save button from Edit Case page Then For the current Case the Case Classification value should be "Suspect case" - @env_main + @env_main @ignore Scenario: Case Classification change from Suspect Case to Not Yet Classified Given API: I create a new person Then API: I check that POST call body is "OK" From 53894f40c40c2f08d18305e4012fd6c2c4fabb94 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Mon, 28 Feb 2022 15:57:36 +0100 Subject: [PATCH 194/253] added decorator for test scenarios --- .../src/test/resources/features/sanity/web/Case.feature | 2 +- .../src/test/resources/features/sanity/web/Contacts.feature | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature index 5535c47f431..bf4cad188c9 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature @@ -357,7 +357,7 @@ Feature: Case end to end tests And I navigate to the last created Event page via URL And I check that number of displayed Event Participants is 1 - @issue=SORDEV-7452 + @issue=SORDEV-7452 @env_main Scenario: Bulk mode for linking/adding case to existing Event Given API: I create a new event Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature index 0d5e2db7e47..f9d216457ac 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature @@ -247,7 +247,7 @@ Feature: Contacts end to end tests And I fill the specific data of visit with Set cleared to Unknown option to all symptoms Then I save the Visit data - @issue=SORDEV-7452 + @issue=SORDEV-7452 @env_main Scenario: Bulk mode for linking/adding contacts to new Event When API: I create a new person Then API: I check that POST call body is "OK" @@ -270,7 +270,7 @@ Feature: Contacts end to end tests And I navigate to the last created Event page via URL And I check that number of displayed Event Participants is 1 - @issue=SORDEV-7452 + @issue=SORDEV-7452 @env_main Scenario: Bulk mode for linking/adding contacts to existing Event Given API: I create a new event Then API: I check that POST call body is "OK" From 97bb758930451cac2a15d647d52646238ca60c54 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Mon, 28 Feb 2022 15:59:13 +0100 Subject: [PATCH 195/253] added decorator for test scenarios --- .../src/test/resources/features/sanity/web/Contacts.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature index f9d216457ac..7ba369541c9 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature @@ -261,7 +261,7 @@ Feature: Contacts end to end tests And I click APPLY BUTTON in Contact Directory Page And I click on the More button on Contact directory page And I click Enter Bulk Edit Mode on Contact directory page - And I click checkbox to choose all Contact results + And I click checkbox to choose all Contact results on Contact Directory Page And I click on Bulk Actions combobox on Contact Directory Page And I click on Link to Event from Bulk Actions combobox on Contact Directory Page And I click on New Event option in Link to Event Form @@ -287,7 +287,7 @@ Feature: Contacts end to end tests And I click APPLY BUTTON in Contact Directory Page And I click on the More button on Contact directory page And I click Enter Bulk Edit Mode on Contact directory page - And I click checkbox to choose all Contact results + And I click checkbox to choose all Contact results on Contact Directory Page And I click on Bulk Actions combobox on Contact Directory Page And I click on Link to Event from Bulk Actions combobox on Contact Directory Page And I fill Event Id filter with last created EventId on Link to Event form From cb47f35f87b01dff818e7fac5d62ceabf1131d33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9=20Strysewske?= Date: Mon, 28 Feb 2022 16:00:58 +0100 Subject: [PATCH 196/253] [MANUAL]Update develop poms back to pre merge state --- sormas-api/pom.xml | 2 +- sormas-app/pom.xml | 2 +- sormas-backend/pom.xml | 2 +- sormas-base/dependencies/serverlibs.pom | 2 +- sormas-base/pom.xml | 2 +- sormas-cargoserver/pom.xml | 2 +- sormas-ear/pom.xml | 2 +- sormas-keycloak-service-provider/pom.xml | 2 +- sormas-rest/pom.xml | 2 +- sormas-ui/pom.xml | 2 +- sormas-widgetset/pom.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sormas-api/pom.xml b/sormas-api/pom.xml index bad03552a0d..214eb0b788e 100644 --- a/sormas-api/pom.xml +++ b/sormas-api/pom.xml @@ -2,7 +2,7 @@ de.symeda.sormas sormas-base - 1.68.1 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-app/pom.xml b/sormas-app/pom.xml index 1617175eefb..3bb68392128 100644 --- a/sormas-app/pom.xml +++ b/sormas-app/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.1 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-backend/pom.xml b/sormas-backend/pom.xml index f2bfcc5af68..48b45586014 100644 --- a/sormas-backend/pom.xml +++ b/sormas-backend/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.1 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-base/dependencies/serverlibs.pom b/sormas-base/dependencies/serverlibs.pom index 65377cf49df..effd624397b 100644 --- a/sormas-base/dependencies/serverlibs.pom +++ b/sormas-base/dependencies/serverlibs.pom @@ -8,7 +8,7 @@ sormas-base de.symeda.sormas - 1.68.1 + 1.69.0-SNAPSHOT ../ diff --git a/sormas-base/pom.xml b/sormas-base/pom.xml index 797666307c0..f5dd10b65f7 100644 --- a/sormas-base/pom.xml +++ b/sormas-base/pom.xml @@ -5,7 +5,7 @@ de.symeda.sormas sormas-base pom - 1.68.1 + 1.69.0-SNAPSHOT 1.8 diff --git a/sormas-cargoserver/pom.xml b/sormas-cargoserver/pom.xml index a905e1c1ecc..8c6009ec75f 100644 --- a/sormas-cargoserver/pom.xml +++ b/sormas-cargoserver/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.68.1 + 1.69.0-SNAPSHOT ../sormas-base diff --git a/sormas-ear/pom.xml b/sormas-ear/pom.xml index c1cd3d630e4..eb67f26b2b0 100644 --- a/sormas-ear/pom.xml +++ b/sormas-ear/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.68.1 + 1.69.0-SNAPSHOT ../sormas-base diff --git a/sormas-keycloak-service-provider/pom.xml b/sormas-keycloak-service-provider/pom.xml index 486cd64e275..142c2f5858e 100644 --- a/sormas-keycloak-service-provider/pom.xml +++ b/sormas-keycloak-service-provider/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.1 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-rest/pom.xml b/sormas-rest/pom.xml index e8a9499732c..85e9fe6b41d 100644 --- a/sormas-rest/pom.xml +++ b/sormas-rest/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.68.1 + 1.69.0-SNAPSHOT ../sormas-base diff --git a/sormas-ui/pom.xml b/sormas-ui/pom.xml index 2b6753ad384..8b3382d103a 100644 --- a/sormas-ui/pom.xml +++ b/sormas-ui/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.1 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-widgetset/pom.xml b/sormas-widgetset/pom.xml index d5a5d7dc925..f8d6a25f29d 100644 --- a/sormas-widgetset/pom.xml +++ b/sormas-widgetset/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.1 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 From 372d296c056c55f05e84e594307f4f782cf53bc2 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Mon, 28 Feb 2022 16:07:50 +0100 Subject: [PATCH 197/253] added decorators --- .../e2etests/enums/EventManagementStatusValues.java | 11 +++++------ .../entities/services/api/EventApiService.java | 9 +++------ .../features/sanity/web/EventFilters.feature | 6 +++--- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/EventManagementStatusValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/EventManagementStatusValues.java index a62d70acde4..feaf93cdbc1 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/EventManagementStatusValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/EventManagementStatusValues.java @@ -4,11 +4,10 @@ @Getter public enum EventManagementStatusValues { - ONGOING("ONGOING"); - private final String value; - - EventManagementStatusValues(String value) { - this.value = value; - } + ONGOING("ONGOING"); + private final String value; + EventManagementStatusValues(String value) { + this.value = value; + } } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/EventApiService.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/EventApiService.java index 656ee48c6c7..c1477ed61c0 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/EventApiService.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/api/EventApiService.java @@ -21,8 +21,11 @@ import com.google.inject.Inject; import java.util.Date; import java.util.UUID; +import org.sormas.e2etests.entities.pojo.api.Community; +import org.sormas.e2etests.entities.pojo.api.District; import org.sormas.e2etests.entities.pojo.api.Event; import org.sormas.e2etests.entities.pojo.api.EventLocation; +import org.sormas.e2etests.entities.pojo.api.Region; import org.sormas.e2etests.entities.pojo.api.ReportingUser; import org.sormas.e2etests.enums.CommunityValues; import org.sormas.e2etests.enums.DiseasesValues; @@ -32,12 +35,6 @@ import org.sormas.e2etests.enums.RiskLevelValues; import org.sormas.e2etests.enums.SourceTypeValues; import org.sormas.e2etests.enums.cases.epidemiologicalData.TypeOfPlace; -import org.sormas.e2etests.pojo.api.Community; -import org.sormas.e2etests.pojo.api.District; -import org.sormas.e2etests.pojo.api.Event; -import org.sormas.e2etests.pojo.api.EventLocation; -import org.sormas.e2etests.pojo.api.Region; -import org.sormas.e2etests.pojo.api.ReportingUser; public class EventApiService { diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/EventFilters.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/EventFilters.feature index 9701d3aeba1..7fae8eb5635 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/EventFilters.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/EventFilters.feature @@ -1,7 +1,7 @@ @UI @Sanity @Event @UI Feature: Filters in Event Directory - @issue=SORDEV-5915 + @issue=SORDEV-5915 @env_main Scenario: Check all filters are working properly in Event directory Given API: I create a new event Then API: I check that POST call body is "OK" @@ -43,7 +43,7 @@ Feature: Filters in Event Directory And I check the number of displayed Event results from All button is 0 And I click on the RESET FILTERS button from Event - @issue=SORQA-77 + @issue=SORQA-77 @env_main Scenario: Filters for Region, District, Community, Reporting user and Event statuses on Event Directory Page Given API: I create a new person Then API: I check that POST call body is "OK" @@ -96,7 +96,7 @@ Feature: Filters in Event Directory And I apply on the APPLY FILTERS button from Event And I check the number of displayed Event results from All button is 0 - @issue=SORQA-77 + @issue=SORQA-77 @env_main Scenario: Date filters and aggregation buttons in Event Directory Given API: I create a new event Then API: I check that POST call body is "OK" From 74f0f0bb25bfdd06d50ed875d1fe829633baca8f Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Mon, 28 Feb 2022 16:27:02 +0100 Subject: [PATCH 198/253] adjusted with EnviromentManager --- .../application/events/EventDirectorySteps.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index 7a3162ab34d..e95d4a0a1e1 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -61,20 +61,24 @@ public EventDirectorySteps( When( "I navigate to the last created Event page via URL", () -> { + String eventLinkPath = "/sormas-ui/#!events/data/"; String createdEventUUID = CreateNewEventSteps.newEvent.getUuid(); - String LAST_CREATED_EVENT_PAGE_URL = - environmentUrl + "/sormas-webdriver/#!events/data/" + createdEventUUID; - webDriverHelpers.accessWebSite(LAST_CREATED_EVENT_PAGE_URL); + webDriverHelpers.accessWebSite( + environmentManager.getEnvironmentUrlForMarket(locale) + + eventLinkPath + + createdEventUUID); webDriverHelpers.waitForPageLoaded(); webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(UUID_INPUT, 50); }); When( "I navigate to the last created through API Event page via URL", () -> { + String eventLinkPath = "/sormas-ui/#!events/data/"; String createdEventUUID = apiState.getCreatedEvent().getUuid(); - String LAST_CREATED_EVENT_PAGE_URL = - environmentUrl + "/sormas-webdriver/#!events/data/" + createdEventUUID; - webDriverHelpers.accessWebSite(LAST_CREATED_EVENT_PAGE_URL); + webDriverHelpers.accessWebSite( + environmentManager.getEnvironmentUrlForMarket(locale) + + eventLinkPath + + createdEventUUID); webDriverHelpers.waitForPageLoaded(); webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(UUID_INPUT, 50); }); From 47f0b747b3442c0256b9911d080f9ebe7132501f Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Mon, 28 Feb 2022 17:35:17 +0200 Subject: [PATCH 199/253] #8158-ignore-flaky-tests : marked tests with ignore --- .../src/test/resources/features/sanity/web/Case.feature | 6 +++--- .../features/sanity/web/CaseClasification.feature | 2 +- .../resources/features/sanity/web/CaseFilters.feature | 4 ++-- .../features/sanity/web/CaseFollowUpVisit.feature | 5 +++-- .../resources/features/sanity/web/CaseSymptoms.feature | 4 ++-- .../test/resources/features/sanity/web/CaseViews.feature | 2 +- .../test/resources/features/sanity/web/Contacts.feature | 8 ++++---- .../src/test/resources/features/sanity/web/Event.feature | 2 +- .../test/resources/features/sanity/web/Persons.feature | 4 ++-- .../test/resources/features/sanity/web/Reports.feature | 2 +- .../resources/features/sanity/web/SampleFilters.feature | 2 +- .../features/sanity/web/TaskManagementFilter.feature | 6 +++--- 12 files changed, 24 insertions(+), 23 deletions(-) diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature index 87d4babe0f1..c9945ab55b1 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Case.feature @@ -122,7 +122,7 @@ Feature: Case end to end tests And I open the Case Contacts tab of the created case via api And I verify that created contact from Case Contacts tab is correctly displayed - @env_main + @env_main @ignore Scenario: Edit all fields from Symptoms tab Given API: I create a new person Then API: I check that POST call body is "OK" @@ -137,7 +137,7 @@ Feature: Case end to end tests When I am accessing the Symptoms tab using of created case via api And I check the created data is correctly displayed on Symptoms tab page -@issue=SORDEV-5496 @env_main +@issue=SORDEV-5496 @env_main @ignore Scenario: Generate case document Given I log in with National User And I click on the Cases button from navbar @@ -209,7 +209,7 @@ Feature: Case end to end tests And I click on save button to Save Person data in Case Person Tab Then I check if saved Person data is correct - @issue=SORDEV-5529 @env_main + @issue=SORDEV-5529 @env_main @ignore Scenario: Fill the clinical course tab When API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseClasification.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseClasification.feature index 1a02cd1c61e..5c084d8c276 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseClasification.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseClasification.feature @@ -21,7 +21,7 @@ Feature: Case Classification functionality And I click on save button from Edit Case page Then For the current Case the Case Classification value should be "Suspect case" - @env_main @ignore + @env_main Scenario: Case Classification change from Suspect Case to Not Yet Classified Given API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature index 8e7454bf2a0..a211491df6c 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature @@ -1,7 +1,7 @@ @UI @Sanity @Case @Filters Feature: Case filter functionality - @env_main + @env_main @ignore Scenario: Check Cases on Sample page work as expected Given API: I create 10 new cases Then API: I check that POST call body is "OK" @@ -240,7 +240,7 @@ Feature: Case filter functionality And I check that number of displayed cases results is 0 And I fill Cases from input to 1 days before mocked Case created on Case directory page - @issue=SORQA-30 @env_main + @issue=SORQA-30 @env_main @ignore Scenario: Check complex filters regarding responsibilities, vaccination, reinfection adn quarantine Given API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFollowUpVisit.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFollowUpVisit.feature index 476886f9510..76ac179fc98 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFollowUpVisit.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFollowUpVisit.feature @@ -1,7 +1,7 @@ @UI @Sanity @Case @Visit Feature: Follow-up new visit functionality - @env_main + @env_main @ignore Scenario: Create a new visit from case follow-up Given API: I create a new person Then API: I check that POST call body is "OK" @@ -18,7 +18,8 @@ Feature: Follow-up new visit functionality And I click on edit Visit button Then I validate all fields from Visit - @issue=SORDEV-5528 @env_main + #please rename it to reflect the precise aim of the test because the same test exists in Case.feature + @issue=SORDEV-5528 @env_main @ignore Scenario: Fill the therapy tab When API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseSymptoms.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseSymptoms.feature index f91cedcea77..c97e9509404 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseSymptoms.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseSymptoms.feature @@ -1,7 +1,7 @@ @UI @Sanity @Case @Symptoms Feature: Case symptoms tab e2e test cases - @issue=SORDEV-5521 @env_main + @issue=SORDEV-5521 @env_main @ignore Scenario: Fill the symptoms tab When API: I create a new person Then API: I check that POST call body is "OK" @@ -36,7 +36,7 @@ Feature: Case symptoms tab e2e test cases And I save data in Hospitalization Then I check if error in Hospitalization data is available - @issue=SORDEV-8350 @env_main + @issue=SORDEV-8350 @env_main @ignore Scenario: Extend fever validation When API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseViews.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseViews.feature index 660dae78c9d..426e4924ef8 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseViews.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseViews.feature @@ -1,7 +1,7 @@ @UI @Sanity @CaseView Feature: Case view tests - @env_main + @env_main @ignore Scenario: Create a new Case and check details in Detailed view table Given API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature index 55bcff8e6c2..d6b745b36ee 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Contacts.feature @@ -53,7 +53,7 @@ Feature: Contacts end to end tests And I open the last created UI Contact Then I check the created data is correctly displayed on Edit Contact page - @env_main + @env_main @ignore Scenario: Source case selected for contact Given API: I create a new person Then API: I check that POST call body is "OK" @@ -77,7 +77,7 @@ Feature: Contacts end to end tests When I open the Case Contacts tab of the created case via api Then I check the linked contact information is correctly displayed - @env_main + @env_main @ignore Scenario: Change the source case contact and then delete Given API: I create a new person Then API: I check that POST call body is "OK" @@ -152,7 +152,7 @@ Feature: Contacts end to end tests And I open Follow up Visits tab from contact directory Then I am validating the From and To dates displayed - @issue=SORDEV-5490 @env_main + @issue=SORDEV-5490 @env_main @ignore Scenario: Create a contact and create a case for contact person Given I log in with National User When I click on the Contacts button from navbar @@ -220,7 +220,7 @@ Feature: Contacts end to end tests Then I am checking all Exposure data is saved and displayed in Contacts And I am checking if options in checkbox for Contact are displayed correctly - @issue=SORDEV-5670 @env_main + @issue=SORDEV-5670 @env_main @ignore Scenario: Fill the follow-up tab Given API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature index cd6547e02db..ff9c3ea1ad5 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature @@ -195,7 +195,7 @@ Feature: Create events And I fill all fields for a new case created for event participant And I click on save case button - @issue=SORDEV-5915 @env_main + @issue=SORDEV-5915 @env_main @ignore Scenario: Check all filters are work properly in Event directory Given API: I create a new event Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature index 717cdac1229..03231228a6e 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Persons.feature @@ -1,7 +1,7 @@ @UI @Sanity @Persons Feature: Edit Persons - @env_main + @env_main @ignore Scenario: Edit existent person Given I log in with National User When I click on the Contacts button from navbar @@ -86,7 +86,7 @@ Feature: Edit Persons And I apply on the APPLY FILTERS button And I click on the RESET FILTERS button for Person -@issue=SORDEV-8468 @env_main +@issue=SORDEV-8468 @env_main @ignore Scenario: Edit existent person and provoke errors in the Edit Person page Given I log in with National User When I click on the Persons button from navbar diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Reports.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Reports.feature index 73845d46a82..9de2c4309ea 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Reports.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Reports.feature @@ -10,7 +10,7 @@ Feature: Reports Then I check that grid for weekly reports is shown Then I check that header names of grid for weekly reports are shown - @env_main @ignore + @env_main Scenario: Reports filter work Given I log in with National User When I click on the Reports button from navbar diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature index a0cf92ba87b..cc6b48e3b6f 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/SampleFilters.feature @@ -15,7 +15,7 @@ Feature: Sample filter functionality When I search for samples created with the API Then I check the displayed Laboratory filter dropdown - @issue=SORDEV-5981 @env_main + @issue=SORDEV-5981 @env_main @ignore Scenario: Check all filters are work properly in Samples directory Given API: I create a new person Then API: I check that POST call body is "OK" diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/TaskManagementFilter.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/TaskManagementFilter.feature index 2f8c5a38e9b..824709feec1 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/TaskManagementFilter.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/TaskManagementFilter.feature @@ -1,7 +1,7 @@ @UI @Sanity @TaskManagementFilter -Feature: Tasks functionalities +Feature: Tasks filtering functionalities - @issue=SORDEV-5688 @env_main + @issue=SORDEV-5688 @env_main @ignore Scenario Outline: Check the filter of tasks context Given I log in with National User And I click on the Tasks button from navbar @@ -17,7 +17,7 @@ Feature: Tasks functionalities | Event | | General | - @issue=SORDEV-5688 @env_main + @issue=SORDEV-5688 @env_main @ignore Scenario Outline: Check the filter of tasks status Given I log in with National User And I click on the Tasks button from navbar From a2afdb9ce679007f9dd384b7b5c39e9323289589 Mon Sep 17 00:00:00 2001 From: Pawel Kujawa Date: Thu, 17 Feb 2022 17:51:18 +0100 Subject: [PATCH 200/253] sorqa68 --- .../sormas/e2etests/enums/GenderValuesDE.java | 23 ++++++++ .../pages/application/cases/EditCasePage.java | 1 + .../entities/services/CaseService.java | 36 +++++++++++- .../cases/CaseDetailedTableViewSteps.java | 30 +++++++++- .../application/cases/CreateNewCaseSteps.java | 47 +++++++++++++++ .../web/application/cases/EditCaseSteps.java | 58 +++++++++++++++++++ .../features/sanity/web/CaseViews.feature | 12 +++- 7 files changed, 203 insertions(+), 4 deletions(-) create mode 100644 sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValuesDE.java diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValuesDE.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValuesDE.java new file mode 100644 index 00000000000..aa259e97861 --- /dev/null +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValuesDE.java @@ -0,0 +1,23 @@ +package org.sormas.e2etests.enums; + +import java.util.Random; +import lombok.Getter; + +@Getter +public enum GenderValuesDE { + MALE("M\u00E4nnlich"), + FEMALE("Weiblich"), + OTHER("Divers"), + UNKNOWN("Unbekannt"); + + private final String gender; + + GenderValuesDE(String humanGender) { + gender = humanGender; + } + + public static String getRandomGenderDE() { + Random random = new Random(); + return String.valueOf(GenderValuesDE.values()[random.nextInt(values().length)].gender); + } +} diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EditCasePage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EditCasePage.java index 3df16ac6acd..e2c19d15c50 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EditCasePage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/cases/EditCasePage.java @@ -27,6 +27,7 @@ public class EditCasePage { public static final By SYMPTOMS_TAB = By.cssSelector("[id='tab-cases-symptoms']"); public static final By THERAPY_TAB = By.cssSelector("[id='tab-cases-therapy']"); public static final By HOSPITALIZATION_TAB = By.cssSelector("[id='tab-cases-hospitalization']"); + public static final By BACK_TO_CASES_LIST_BUTTON = By.id("tab-cases"); public static final By REGION_INPUT = By.cssSelector("#responsibleRegion input"); public static final By DISTRICT_INPUT = By.cssSelector("#responsibleDistrict input"); public static final By COMMUNITY_INPUT = By.cssSelector("#responsibleCommunity input"); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java index 489a2cce51b..c10c4edf6bf 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,12 +16,13 @@ * along with this program. If not, see . */ -package org.sormas.e2etests.entities.services; +package org.sormas.e2etests.services; import com.github.javafaker.Faker; import com.google.inject.Inject; import java.time.LocalDate; import java.util.UUID; +import org.sormas.e2etests.enums.*; import org.sormas.e2etests.entities.pojo.web.Case; import org.sormas.e2etests.enums.CommunityValues; import org.sormas.e2etests.enums.DiseasesValues; @@ -29,6 +30,7 @@ import org.sormas.e2etests.enums.GenderValues; import org.sormas.e2etests.enums.RegionsValues; import org.sormas.e2etests.helpers.strings.ASCIIHelper; +import org.sormas.e2etests.pojo.web.Case; public class CaseService { private final Faker faker; @@ -83,6 +85,36 @@ public Case buildGeneratedCase() { .build(); } + public Case buildGeneratedCaseDE() { + firstName = faker.name().firstName(); + lastName = faker.name().lastName(); + + return Case.builder() + .firstName(firstName) + .lastName(lastName) + .caseOrigin("IM LAND") + .dateOfReport(LocalDate.now().minusDays(1)) + .externalId(UUID.randomUUID().toString()) + .disease("COVID-19") + .responsibleRegion(RegionsValues.VoreingestellteBundeslander.getName()) + .responsibleDistrict(DistrictsValues.VoreingestellterLandkreis.getName()) + .responsibleCommunity(CommunityValues.VoreingestellteGemeinde.getName()) + .placeOfStay("ZUHAUSE") + .placeDescription(faker.harryPotter().location()) + .dateOfBirth( + LocalDate.of( + faker.number().numberBetween(1900, 2002), + faker.number().numberBetween(1, 12), + faker.number().numberBetween(1, 27))) + .sex(GenderValuesDE.getRandomGenderDE()) + .presentConditionOfPerson("Lebendig") + .dateOfSymptomOnset(LocalDate.now().minusDays(1)) + .primaryPhoneNumber(faker.phoneNumber().phoneNumber()) + .primaryEmailAddress( + ASCIIHelper.convertASCIIToLatin(firstName + "." + lastName + emailDomain)) + .build(); + } + public Case buildEditGeneratedCase() { return Case.builder() .dateOfReport(LocalDate.now().minusDays(3)) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java index a2a53d68c12..8c26c6fc2f9 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java @@ -1,7 +1,6 @@ package org.sormas.e2etests.steps.web.application.cases; import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.*; -import static org.sormas.e2etests.steps.BaseSteps.locale; import static recorders.StepsLogger.PROCESS_ID_STRING; import cucumber.api.java8.En; @@ -33,6 +32,7 @@ public class CaseDetailedTableViewSteps implements En { private final WebDriverHelpers webDriverHelpers; private static BaseSteps baseSteps; + static final String DATE_FORMAT_DE = "dd.MM.yyyy"; @Inject public CaseDetailedTableViewSteps( @@ -144,6 +144,34 @@ public CaseDetailedTableViewSteps( "Reporting user is not correct"); softly.assertAll(); }); + + When( + "I back to Case Directory using case list button", + () -> webDriverHelpers.clickOnWebElementBySelector(BACK_TO_CASES_LIST_BUTTON)); + + When( + "I check if Case date format is correct", + () -> { + List> tableRowsData = getTableRowsData(); + Map detailedCaseDTableRow = tableRowsData.get(0); + softly.assertTrue( + checkDateFormatDE(detailedCaseDTableRow, "NACHVERFOLGUNG BIS"), + "Date format is invalid"); + softly.assertTrue( + checkDateFormatDE(detailedCaseDTableRow, "MELDEDATUM"), "Date format is invalid"); + softly.assertAll(); + }); + } + + boolean checkDateFormatDE(Map map, String row) { + DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT_DE); + dateFormat.setLenient(false); + try { + dateFormat.parse(map.get(row)); + return true; + } catch (ParseException e) { + return false; + } } private List> getTableRowsData() { diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java index 66915d8cd55..a3f25095810 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java @@ -42,6 +42,33 @@ public class CreateNewCaseSteps implements En { public CreateNewCaseSteps(WebDriverHelpers webDriverHelpers, CaseService caseService) { this.webDriverHelpers = webDriverHelpers; + When( + "I create a new case with specific data for DE version", + () -> { + caze = caseService.buildGeneratedCaseDE(); + selectCaseOrigin(caze.getCaseOrigin()); + fillExternalId(caze.getExternalId()); + fillDisease(caze.getDisease()); + selectResponsibleRegion(caze.getResponsibleRegion()); + selectResponsibleDistrict(caze.getResponsibleDistrict()); + selectResponsibleCommunity(caze.getResponsibleCommunity()); + selectPlaceOfStay(caze.getPlaceOfStay()); + fillFirstName(caze.getFirstName()); + fillLastName(caze.getLastName()); + fillDateOfBirthDE(caze.getDateOfBirth()); + selectSex(caze.getSex()); + selectPresentConditionOfPerson(caze.getPresentConditionOfPerson()); + fillDateOfSymptomOnsetDE(caze.getDateOfSymptomOnset()); + fillPrimaryPhoneNumber(caze.getPrimaryPhoneNumber()); + fillPrimaryEmailAddress(caze.getPrimaryEmailAddress()); + fillDateOfReportDE(caze.getDateOfReport()); + fillPlaceDescription(caze.getPlaceDescription()); + webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON); + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(20); + webDriverHelpers.waitUntilElementIsVisibleAndClickable(EditCasePage.REPORT_DATE_INPUT); + webDriverHelpers.clickOnWebElementBySelector(CASE_SAVED_POPUP); + }); + When( "I create a new case with specific data for positive pathogen test result", () -> { @@ -191,6 +218,11 @@ private void fillDateOfReport(LocalDate date) { webDriverHelpers.fillInWebElement(DATE_OF_REPORT_INPUT, formatter.format(date)); } + private void fillDateOfReportDE(LocalDate date) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); + webDriverHelpers.fillInWebElement(DATE_OF_REPORT_INPUT, formatter.format(date)); + } + private void fillExternalId(String externalId) { webDriverHelpers.fillInWebElement(EXTERNAL_ID_INPUT, externalId); } @@ -237,6 +269,16 @@ private void fillDateOfBirth(LocalDate localDate) { DATE_OF_BIRTH_DAY_COMBOBOX, String.valueOf(localDate.getDayOfMonth())); } + private void fillDateOfBirthDE(LocalDate localDate) { + webDriverHelpers.selectFromCombobox( + DATE_OF_BIRTH_YEAR_COMBOBOX, String.valueOf(localDate.getYear())); + webDriverHelpers.selectFromCombobox( + DATE_OF_BIRTH_MONTH_COMBOBOX, + localDate.getMonth().getDisplayName(TextStyle.FULL, Locale.GERMAN)); + webDriverHelpers.selectFromCombobox( + DATE_OF_BIRTH_DAY_COMBOBOX, String.valueOf(localDate.getDayOfMonth())); + } + private void selectSex(String sex) { webDriverHelpers.selectFromCombobox(SEX_COMBOBOX, sex); } @@ -251,6 +293,11 @@ private void fillDateOfSymptomOnset(LocalDate date) { webDriverHelpers.fillInWebElement(DATE_OF_SYMPTOM_ONSET_INPUT, formatter.format(date)); } + private void fillDateOfSymptomOnsetDE(LocalDate date) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); + webDriverHelpers.fillInWebElement(DATE_OF_SYMPTOM_ONSET_INPUT, formatter.format(date)); + } + private void fillPrimaryPhoneNumber(String primaryPhoneNumber) { webDriverHelpers.fillInWebElement(PRIMARY_PHONE_NUMBER_INPUT, primaryPhoneNumber); } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java index bdf2d552189..bb813e1cc9d 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java @@ -58,6 +58,7 @@ public class EditCaseSteps implements En { private static Case specificCaseData; private static LocalDate dateFollowUp; public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("M/d/yyyy"); + public static final DateTimeFormatter DATE_FORMATTER_DE = DateTimeFormatter.ofPattern("d.M.yyyy"); public static final String userDirPath = System.getProperty("user.dir"); @SneakyThrows @@ -125,6 +126,28 @@ public EditCaseSteps( "dateOfBirth")); }); + When( + "I check the created data is correctly displayed on Edit case page for DE version", + () -> { + aCase = collectCasePersonDataDE(); + createdCase = CreateNewCaseSteps.caze; + ComparisonHelper.compareEqualFieldsOfEntities( + aCase, + createdCase, + List.of( + "dateOfReport", + "disease", + "externalId", + "responsibleRegion", + "responsibleDistrict", + "responsibleCommunity", + "placeOfStay", + "placeDescription", + "firstName", + "lastName", + "dateOfBirth")); + }); + When( "I select Investigation Status ([^\"]*)", (String investigationStatus) -> { @@ -668,6 +691,25 @@ private Case collectCasePersonData() { .build(); } + private Case collectCasePersonDataDE() { + Case userInfo = getUserInformationDE(); + + return Case.builder() + .dateOfReport(getDateOfReportDE()) + .firstName(userInfo.getFirstName()) + .lastName(userInfo.getLastName()) + .dateOfBirth(userInfo.getDateOfBirth()) + .externalId(webDriverHelpers.getValueFromWebElement(EXTERNAL_ID_INPUT)) + .uuid(webDriverHelpers.getValueFromWebElement(UUID_INPUT)) + .disease(webDriverHelpers.getValueFromWebElement(DISEASE_INPUT)) + .responsibleRegion(webDriverHelpers.getValueFromWebElement(REGION_INPUT)) + .responsibleDistrict(webDriverHelpers.getValueFromWebElement(DISTRICT_INPUT)) + .responsibleCommunity(webDriverHelpers.getValueFromWebElement(COMMUNITY_INPUT)) + .placeOfStay(webDriverHelpers.getTextFromWebElement(PLACE_OF_STAY_SELECTED_VALUE)) + .placeDescription(webDriverHelpers.getValueFromWebElement(PLACE_DESCRIPTION_INPUT)) + .build(); + } + private Case collectCaseData() { return Case.builder() .dateOfReport(getDateOfReport()) @@ -751,6 +793,11 @@ private LocalDate getDateOfReport() { return LocalDate.parse(dateOfReport, DATE_FORMATTER); } + private LocalDate getDateOfReportDE() { + String dateOfReport = webDriverHelpers.getValueFromWebElement(REPORT_DATE_INPUT); + return LocalDate.parse(dateOfReport, DATE_FORMATTER_DE); + } + private LocalDate getDateReceivedAtDistrictLevel() { String dateOfReport = webDriverHelpers.getValueFromWebElement(DATE_RECEIVED_AT_DISTRICT_LEVEL_INPUT); @@ -780,6 +827,17 @@ private Case getUserInformation() { .build(); } + private Case getUserInformationDE() { + String userInfo = webDriverHelpers.getTextFromWebElement(USER_INFORMATION); + String[] userInfos = userInfo.split(" "); + LocalDate localDate = LocalDate.parse(userInfos[3].replace(")", ""), DATE_FORMATTER_DE); + return Case.builder() + .firstName(userInfos[0]) + .lastName(userInfos[1]) + .dateOfBirth(localDate) + .build(); + } + private void fillDateOfReport(LocalDate date) { webDriverHelpers.fillInWebElement(REPORT_DATE_INPUT, DATE_FORMATTER.format(date)); } diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseViews.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseViews.feature index 660dae78c9d..724fef8d6a5 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseViews.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseViews.feature @@ -13,4 +13,14 @@ Feature: Case view tests Given I click on the Cases button from navbar When I click on the DETAILED button from Case directory And I filter by CaseID on Case directory page - And I am checking if all the fields are correctly displayed in the Case directory Detailed table \ No newline at end of file + And I am checking if all the fields are correctly displayed in the Case directory Detailed table + + @issue=SORQA-68 @Locale_DE + Scenario: German date format check + Given I log in with National User + And I click on the Cases button from navbar + And I click on the NEW CASE button + When I create a new case with specific data for DE version + Then I check the created data is correctly displayed on Edit case page for DE version + Then I back to Case Directory using case list button + And I check if Case date format is correct \ No newline at end of file From 242371fde32dcae041924e6ea1c873d3d5be1e85 Mon Sep 17 00:00:00 2001 From: Pawel Kujawa Date: Thu, 17 Feb 2022 18:08:08 +0100 Subject: [PATCH 201/253] wildcard fix --- .../org/sormas/e2etests/entities/services/CaseService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java index c10c4edf6bf..07303ffc9cd 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java @@ -22,12 +22,12 @@ import com.google.inject.Inject; import java.time.LocalDate; import java.util.UUID; -import org.sormas.e2etests.enums.*; -import org.sormas.e2etests.entities.pojo.web.Case; import org.sormas.e2etests.enums.CommunityValues; import org.sormas.e2etests.enums.DiseasesValues; import org.sormas.e2etests.enums.DistrictsValues; import org.sormas.e2etests.enums.GenderValues; +import org.sormas.e2etests.enums.GenderValuesDE; +import org.sormas.e2etests.entities.pojo.web.Case; import org.sormas.e2etests.enums.RegionsValues; import org.sormas.e2etests.helpers.strings.ASCIIHelper; import org.sormas.e2etests.pojo.web.Case; From 1b88fc18787479c23f2a6e1f6db8267f07ce83c2 Mon Sep 17 00:00:00 2001 From: Pawel Kujawa Date: Fri, 18 Feb 2022 16:01:22 +0100 Subject: [PATCH 202/253] sorqa68 --- .../sormas/e2etests/enums/GenderValues.java | 17 +++-- .../sormas/e2etests/enums/GenderValuesDE.java | 23 ------ .../entities/services/CaseService.java | 2 +- .../cases/CaseDetailedTableViewSteps.java | 18 +++-- .../application/cases/CreateNewCaseSteps.java | 71 +++++++------------ .../features/sanity/web/CaseViews.feature | 2 +- 6 files changed, 54 insertions(+), 79 deletions(-) delete mode 100644 sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValuesDE.java diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValues.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValues.java index 2c94ee41f3d..37eb619492e 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValues.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValues.java @@ -23,19 +23,26 @@ @Getter public enum GenderValues { - MALE("Male"), - FEMALE("Female"), - OTHER("Other"), - UNKNOWN("Unknown"); + MALE("Male", "M\u00E4nnlich"), + FEMALE("Female", "Weiblich"), + OTHER("Other", "Divers"), + UNKNOWN("Unknown", "Unbekannt"); private final String gender; + private final String genderDE; - GenderValues(String humanGender) { + GenderValues(String humanGender, String humanGenderDE) { gender = humanGender; + genderDE = humanGenderDE; } public static String getRandomGender() { Random random = new Random(); return String.valueOf(GenderValues.values()[random.nextInt(values().length)].gender); } + + public static String getRandomGenderDE() { + Random random = new Random(); + return String.valueOf(GenderValues.values()[random.nextInt(values().length)].genderDE); + } } diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValuesDE.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValuesDE.java deleted file mode 100644 index aa259e97861..00000000000 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValuesDE.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.sormas.e2etests.enums; - -import java.util.Random; -import lombok.Getter; - -@Getter -public enum GenderValuesDE { - MALE("M\u00E4nnlich"), - FEMALE("Weiblich"), - OTHER("Divers"), - UNKNOWN("Unbekannt"); - - private final String gender; - - GenderValuesDE(String humanGender) { - gender = humanGender; - } - - public static String getRandomGenderDE() { - Random random = new Random(); - return String.valueOf(GenderValuesDE.values()[random.nextInt(values().length)].gender); - } -} diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java index 07303ffc9cd..ced691c9cb2 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java @@ -106,7 +106,7 @@ public Case buildGeneratedCaseDE() { faker.number().numberBetween(1900, 2002), faker.number().numberBetween(1, 12), faker.number().numberBetween(1, 27))) - .sex(GenderValuesDE.getRandomGenderDE()) + .sex(GenderValues.getRandomGenderDE()) .presentConditionOfPerson("Lebendig") .dateOfSymptomOnset(LocalDate.now().minusDays(1)) .primaryPhoneNumber(faker.phoneNumber().phoneNumber()) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java index 8c26c6fc2f9..32c3b9245d7 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java @@ -25,6 +25,7 @@ import org.sormas.e2etests.helpers.WebDriverHelpers; import org.sormas.e2etests.state.ApiState; import org.sormas.e2etests.steps.BaseSteps; +import org.testng.Assert; import org.testng.asserts.SoftAssert; @Slf4j @@ -147,29 +148,36 @@ public CaseDetailedTableViewSteps( When( "I back to Case Directory using case list button", - () -> webDriverHelpers.clickOnWebElementBySelector(BACK_TO_CASES_LIST_BUTTON)); + () -> { + webDriverHelpers.waitUntilElementIsVisibleAndClickable(BACK_TO_CASES_LIST_BUTTON); + webDriverHelpers.clickOnWebElementBySelector(BACK_TO_CASES_LIST_BUTTON); + }); When( - "I check if Case date format is correct", + "I check if Case date format displayed in Cases tab is correct for specified fields", () -> { List> tableRowsData = getTableRowsData(); Map detailedCaseDTableRow = tableRowsData.get(0); softly.assertTrue( checkDateFormatDE(detailedCaseDTableRow, "NACHVERFOLGUNG BIS"), - "Date format is invalid"); + "Date format is invalid in NACHVERFOLGUNG BIS field"); softly.assertTrue( - checkDateFormatDE(detailedCaseDTableRow, "MELDEDATUM"), "Date format is invalid"); + checkDateFormatDE(detailedCaseDTableRow, "MELDEDATUM"), + "Date format is invalid in MELDEDATUM field"); softly.assertAll(); }); } - boolean checkDateFormatDE(Map map, String row) { + private boolean checkDateFormatDE(Map map, String row) { DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT_DE); dateFormat.setLenient(false); try { + Assert.assertFalse(map.isEmpty(), String.format("The element: %s was empty or null", map)); dateFormat.parse(map.get(row)); return true; } catch (ParseException e) { + e.printStackTrace(); + log.error(PROCESS_ID_STRING + e.getMessage()); return false; } } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java index a3f25095810..bb94bad9059 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java @@ -55,13 +55,13 @@ public CreateNewCaseSteps(WebDriverHelpers webDriverHelpers, CaseService caseSer selectPlaceOfStay(caze.getPlaceOfStay()); fillFirstName(caze.getFirstName()); fillLastName(caze.getLastName()); - fillDateOfBirthDE(caze.getDateOfBirth()); + fillDateOfBirth(caze.getDateOfBirth(), Locale.GERMAN); selectSex(caze.getSex()); selectPresentConditionOfPerson(caze.getPresentConditionOfPerson()); - fillDateOfSymptomOnsetDE(caze.getDateOfSymptomOnset()); + fillDateOfSymptomOnset(caze.getDateOfSymptomOnset(), Locale.GERMAN); fillPrimaryPhoneNumber(caze.getPrimaryPhoneNumber()); fillPrimaryEmailAddress(caze.getPrimaryEmailAddress()); - fillDateOfReportDE(caze.getDateOfReport()); + fillDateOfReport(caze.getDateOfReport(), Locale.GERMAN); fillPlaceDescription(caze.getPlaceDescription()); webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON); webDriverHelpers.waitForPageLoadingSpinnerToDisappear(20); @@ -101,13 +101,13 @@ public CreateNewCaseSteps(WebDriverHelpers webDriverHelpers, CaseService caseSer selectPlaceOfStay(caze.getPlaceOfStay()); fillFirstName(caze.getFirstName()); fillLastName(caze.getLastName()); - fillDateOfBirth(caze.getDateOfBirth()); + fillDateOfBirth(caze.getDateOfBirth(), Locale.ENGLISH); selectSex(caze.getSex()); selectPresentConditionOfPerson(caze.getPresentConditionOfPerson()); - fillDateOfSymptomOnset(caze.getDateOfSymptomOnset()); + fillDateOfSymptomOnset(caze.getDateOfSymptomOnset(), Locale.ENGLISH); fillPrimaryPhoneNumber(caze.getPrimaryPhoneNumber()); fillPrimaryEmailAddress(caze.getPrimaryEmailAddress()); - fillDateOfReport(caze.getDateOfReport()); + fillDateOfReport(caze.getDateOfReport(), Locale.ENGLISH); fillPlaceDescription(caze.getPlaceDescription()); webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON); webDriverHelpers.waitForPageLoadingSpinnerToDisappear(20); @@ -127,13 +127,13 @@ public CreateNewCaseSteps(WebDriverHelpers webDriverHelpers, CaseService caseSer selectPlaceOfStay(caze.getPlaceOfStay()); fillFirstName(caze.getFirstName()); fillLastName(caze.getLastName()); - fillDateOfBirth(caze.getDateOfBirth()); + fillDateOfBirth(caze.getDateOfBirth(), Locale.ENGLISH); selectSex(caze.getSex()); selectPresentConditionOfPerson(caze.getPresentConditionOfPerson()); - fillDateOfSymptomOnset(caze.getDateOfSymptomOnset()); + fillDateOfSymptomOnset(caze.getDateOfSymptomOnset(), Locale.ENGLISH); fillPrimaryPhoneNumber(caze.getPrimaryPhoneNumber()); fillPrimaryEmailAddress(caze.getPrimaryEmailAddress()); - fillDateOfReport(caze.getDateOfReport()); + fillDateOfReport(caze.getDateOfReport(), Locale.ENGLISH); fillPlaceDescription(caze.getPlaceDescription()); }); @@ -146,13 +146,13 @@ public CreateNewCaseSteps(WebDriverHelpers webDriverHelpers, CaseService caseSer selectPlaceOfStay(caze.getPlaceOfStay()); fillFirstName(caze.getFirstName()); fillLastName(caze.getLastName()); - fillDateOfBirth(caze.getDateOfBirth()); + fillDateOfBirth(caze.getDateOfBirth(), Locale.ENGLISH); selectSex(caze.getSex()); selectPresentConditionOfPerson(caze.getPresentConditionOfPerson()); - fillDateOfSymptomOnset(caze.getDateOfSymptomOnset()); + fillDateOfSymptomOnset(caze.getDateOfSymptomOnset(), Locale.ENGLISH); fillPrimaryPhoneNumber(caze.getPrimaryPhoneNumber()); fillPrimaryEmailAddress(caze.getPrimaryEmailAddress()); - fillDateOfReport(caze.getDateOfReport()); + fillDateOfReport(caze.getDateOfReport(), Locale.ENGLISH); fillPlaceDescription(caze.getPlaceDescription()); webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON); webDriverHelpers.waitUntilElementIsVisibleAndClickable(EditCasePage.REPORT_DATE_INPUT); @@ -162,7 +162,7 @@ public CreateNewCaseSteps(WebDriverHelpers webDriverHelpers, CaseService caseSer "^I create a new case for contact with specific data$", () -> { caze = caseService.buildGeneratedCase(); - fillDateOfReport(caze.getDateOfReport()); + fillDateOfReport(caze.getDateOfReport(), Locale.ENGLISH); selectCaseOrigin(caze.getCaseOrigin()); fillExternalId(caze.getExternalId()); selectResponsibleRegion(caze.getResponsibleRegion()); @@ -172,7 +172,7 @@ public CreateNewCaseSteps(WebDriverHelpers webDriverHelpers, CaseService caseSer selectPlaceOfStay(caze.getPlaceOfStay()); fillPlaceDescription(caze.getPlaceDescription()); selectPresentConditionOfPerson(caze.getPresentConditionOfPerson()); - fillDateOfSymptomOnset(caze.getDateOfSymptomOnset()); + fillDateOfSymptomOnset(caze.getDateOfSymptomOnset(), Locale.ENGLISH); webDriverHelpers.clickOnWebElementBySelector(CONTACT_CASE_SAVE_BUTTON); webDriverHelpers.waitForPageLoadingSpinnerToDisappear(20); @@ -199,12 +199,12 @@ public CreateNewCaseSteps(WebDriverHelpers webDriverHelpers, CaseService caseSer selectResponsibleCommunity(caze.getResponsibleCommunity()); selectPlaceOfStay(caze.getPlaceOfStay()); - fillDateOfBirth(caze.getDateOfBirth()); + fillDateOfBirth(caze.getDateOfBirth(), Locale.ENGLISH); selectPresentConditionOfPerson(caze.getPresentConditionOfPerson()); - fillDateOfSymptomOnset(caze.getDateOfSymptomOnset()); + fillDateOfSymptomOnset(caze.getDateOfSymptomOnset(), Locale.ENGLISH); fillPrimaryPhoneNumber(caze.getPrimaryPhoneNumber()); fillPrimaryEmailAddress(caze.getPrimaryEmailAddress()); - fillDateOfReport(caze.getDateOfReport()); + fillDateOfReport(caze.getDateOfReport(), Locale.ENGLISH); fillPlaceDescription(caze.getPlaceDescription()); }); } @@ -213,13 +213,10 @@ private void selectCaseOrigin(String caseOrigin) { webDriverHelpers.clickWebElementByText(CASE_ORIGIN_OPTIONS, caseOrigin); } - private void fillDateOfReport(LocalDate date) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M/d/yyyy"); - webDriverHelpers.fillInWebElement(DATE_OF_REPORT_INPUT, formatter.format(date)); - } - - private void fillDateOfReportDE(LocalDate date) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); + private void fillDateOfReport(LocalDate date, Locale locale) { + DateTimeFormatter formatter; + if (locale.equals(Locale.GERMAN)) formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); + else formatter = DateTimeFormatter.ofPattern("M/d/yyyy"); webDriverHelpers.fillInWebElement(DATE_OF_REPORT_INPUT, formatter.format(date)); } @@ -259,22 +256,11 @@ private void fillLastName(String lastName) { webDriverHelpers.fillInWebElement(LAST_NAME_INPUT, lastName); } - private void fillDateOfBirth(LocalDate localDate) { - webDriverHelpers.selectFromCombobox( - DATE_OF_BIRTH_YEAR_COMBOBOX, String.valueOf(localDate.getYear())); - webDriverHelpers.selectFromCombobox( - DATE_OF_BIRTH_MONTH_COMBOBOX, - localDate.getMonth().getDisplayName(TextStyle.FULL, Locale.ENGLISH)); - webDriverHelpers.selectFromCombobox( - DATE_OF_BIRTH_DAY_COMBOBOX, String.valueOf(localDate.getDayOfMonth())); - } - - private void fillDateOfBirthDE(LocalDate localDate) { + private void fillDateOfBirth(LocalDate localDate, Locale locale) { webDriverHelpers.selectFromCombobox( DATE_OF_BIRTH_YEAR_COMBOBOX, String.valueOf(localDate.getYear())); webDriverHelpers.selectFromCombobox( - DATE_OF_BIRTH_MONTH_COMBOBOX, - localDate.getMonth().getDisplayName(TextStyle.FULL, Locale.GERMAN)); + DATE_OF_BIRTH_MONTH_COMBOBOX, localDate.getMonth().getDisplayName(TextStyle.FULL, locale)); webDriverHelpers.selectFromCombobox( DATE_OF_BIRTH_DAY_COMBOBOX, String.valueOf(localDate.getDayOfMonth())); } @@ -288,13 +274,10 @@ private void selectPresentConditionOfPerson(String presentConditionOfPerson) { PRESENT_CONDITION_OF_PERSON_COMBOBOX, presentConditionOfPerson); } - private void fillDateOfSymptomOnset(LocalDate date) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M/d/yyyy"); - webDriverHelpers.fillInWebElement(DATE_OF_SYMPTOM_ONSET_INPUT, formatter.format(date)); - } - - private void fillDateOfSymptomOnsetDE(LocalDate date) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); + private void fillDateOfSymptomOnset(LocalDate date, Locale locale) { + DateTimeFormatter formatter; + if (locale.equals(Locale.GERMAN)) formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); + else formatter = DateTimeFormatter.ofPattern("M/d/yyyy"); webDriverHelpers.fillInWebElement(DATE_OF_SYMPTOM_ONSET_INPUT, formatter.format(date)); } diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseViews.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseViews.feature index 724fef8d6a5..73d0939a031 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseViews.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseViews.feature @@ -23,4 +23,4 @@ Feature: Case view tests When I create a new case with specific data for DE version Then I check the created data is correctly displayed on Edit case page for DE version Then I back to Case Directory using case list button - And I check if Case date format is correct \ No newline at end of file + And I check if Case date format displayed in Cases tab is correct for specified fields \ No newline at end of file From 6f5f3b6f029ef539fbeffbe378d161aaf08164db Mon Sep 17 00:00:00 2001 From: Pawel Kujawa Date: Sat, 26 Feb 2022 13:33:13 +0100 Subject: [PATCH 203/253] rebase --- .../org/sormas/e2etests/entities/services/CaseService.java | 6 ++---- .../web/application/cases/CaseDetailedTableViewSteps.java | 2 ++ .../test/resources/features/sanity/web/CaseViews.feature | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java index ced691c9cb2..81185839bc4 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java @@ -16,21 +16,19 @@ * along with this program. If not, see . */ -package org.sormas.e2etests.services; +package org.sormas.e2etests.entities.services; import com.github.javafaker.Faker; import com.google.inject.Inject; import java.time.LocalDate; import java.util.UUID; +import org.sormas.e2etests.entities.pojo.web.Case; import org.sormas.e2etests.enums.CommunityValues; import org.sormas.e2etests.enums.DiseasesValues; import org.sormas.e2etests.enums.DistrictsValues; import org.sormas.e2etests.enums.GenderValues; -import org.sormas.e2etests.enums.GenderValuesDE; -import org.sormas.e2etests.entities.pojo.web.Case; import org.sormas.e2etests.enums.RegionsValues; import org.sormas.e2etests.helpers.strings.ASCIIHelper; -import org.sormas.e2etests.pojo.web.Case; public class CaseService { private final Faker faker; diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java index 32c3b9245d7..0e09b297d5f 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java @@ -1,6 +1,8 @@ package org.sormas.e2etests.steps.web.application.cases; import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.*; +import static org.sormas.e2etests.pages.application.cases.EditCasePage.BACK_TO_CASES_LIST_BUTTON; +import static org.sormas.e2etests.steps.BaseSteps.locale; import static recorders.StepsLogger.PROCESS_ID_STRING; import cucumber.api.java8.En; diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseViews.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseViews.feature index 73d0939a031..d7288511611 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseViews.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseViews.feature @@ -15,7 +15,7 @@ Feature: Case view tests And I filter by CaseID on Case directory page And I am checking if all the fields are correctly displayed in the Case directory Detailed table - @issue=SORQA-68 @Locale_DE + @issue=SORQA-68 @env_de Scenario: German date format check Given I log in with National User And I click on the Cases button from navbar From b4371d1633b17352f75bfbd8b46a237180749cef Mon Sep 17 00:00:00 2001 From: Pawel Kujawa Date: Thu, 17 Feb 2022 17:51:18 +0100 Subject: [PATCH 204/253] sorqa68 --- .../sormas/e2etests/enums/GenderValuesDE.java | 23 +++++++++++++++++++ .../entities/services/CaseService.java | 1 + .../cases/CaseDetailedTableViewSteps.java | 5 +--- .../application/cases/CreateNewCaseSteps.java | 20 ++++++++++++++++ 4 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValuesDE.java diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValuesDE.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValuesDE.java new file mode 100644 index 00000000000..aa259e97861 --- /dev/null +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValuesDE.java @@ -0,0 +1,23 @@ +package org.sormas.e2etests.enums; + +import java.util.Random; +import lombok.Getter; + +@Getter +public enum GenderValuesDE { + MALE("M\u00E4nnlich"), + FEMALE("Weiblich"), + OTHER("Divers"), + UNKNOWN("Unbekannt"); + + private final String gender; + + GenderValuesDE(String humanGender) { + gender = humanGender; + } + + public static String getRandomGenderDE() { + Random random = new Random(); + return String.valueOf(GenderValuesDE.values()[random.nextInt(values().length)].gender); + } +} diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java index 81185839bc4..867192cb8dc 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java @@ -29,6 +29,7 @@ import org.sormas.e2etests.enums.GenderValues; import org.sormas.e2etests.enums.RegionsValues; import org.sormas.e2etests.helpers.strings.ASCIIHelper; +import org.sormas.e2etests.pojo.web.Case; public class CaseService { private final Faker faker; diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java index 0e09b297d5f..71f65d78758 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java @@ -1,8 +1,6 @@ package org.sormas.e2etests.steps.web.application.cases; import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.*; -import static org.sormas.e2etests.pages.application.cases.EditCasePage.BACK_TO_CASES_LIST_BUTTON; -import static org.sormas.e2etests.steps.BaseSteps.locale; import static recorders.StepsLogger.PROCESS_ID_STRING; import cucumber.api.java8.En; @@ -35,7 +33,6 @@ public class CaseDetailedTableViewSteps implements En { private final WebDriverHelpers webDriverHelpers; private static BaseSteps baseSteps; - static final String DATE_FORMAT_DE = "dd.MM.yyyy"; @Inject public CaseDetailedTableViewSteps( @@ -143,7 +140,7 @@ public CaseDetailedTableViewSteps( } softly.assertEquals( detailedCaseDTableRow.get(CaseDetailedTableViewHeaders.REPORTING_USER.toString()), - environmentManager.getUserByRole(locale, UserRoles.RestUser.getRole()).getUserRole(), + TestDataUser.REST_AUTOMATION.getUserRole(), "Reporting user is not correct"); softly.assertAll(); }); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java index bb94bad9059..b96a0eee08d 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java @@ -220,6 +220,11 @@ private void fillDateOfReport(LocalDate date, Locale locale) { webDriverHelpers.fillInWebElement(DATE_OF_REPORT_INPUT, formatter.format(date)); } + private void fillDateOfReportDE(LocalDate date) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); + webDriverHelpers.fillInWebElement(DATE_OF_REPORT_INPUT, formatter.format(date)); + } + private void fillExternalId(String externalId) { webDriverHelpers.fillInWebElement(EXTERNAL_ID_INPUT, externalId); } @@ -265,6 +270,16 @@ private void fillDateOfBirth(LocalDate localDate, Locale locale) { DATE_OF_BIRTH_DAY_COMBOBOX, String.valueOf(localDate.getDayOfMonth())); } + private void fillDateOfBirthDE(LocalDate localDate) { + webDriverHelpers.selectFromCombobox( + DATE_OF_BIRTH_YEAR_COMBOBOX, String.valueOf(localDate.getYear())); + webDriverHelpers.selectFromCombobox( + DATE_OF_BIRTH_MONTH_COMBOBOX, + localDate.getMonth().getDisplayName(TextStyle.FULL, Locale.GERMAN)); + webDriverHelpers.selectFromCombobox( + DATE_OF_BIRTH_DAY_COMBOBOX, String.valueOf(localDate.getDayOfMonth())); + } + private void selectSex(String sex) { webDriverHelpers.selectFromCombobox(SEX_COMBOBOX, sex); } @@ -281,6 +296,11 @@ private void fillDateOfSymptomOnset(LocalDate date, Locale locale) { webDriverHelpers.fillInWebElement(DATE_OF_SYMPTOM_ONSET_INPUT, formatter.format(date)); } + private void fillDateOfSymptomOnsetDE(LocalDate date) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); + webDriverHelpers.fillInWebElement(DATE_OF_SYMPTOM_ONSET_INPUT, formatter.format(date)); + } + private void fillPrimaryPhoneNumber(String primaryPhoneNumber) { webDriverHelpers.fillInWebElement(PRIMARY_PHONE_NUMBER_INPUT, primaryPhoneNumber); } From 455669cddd04d8ad5020d0c4bc4ea3350362dadc Mon Sep 17 00:00:00 2001 From: Pawel Kujawa Date: Fri, 18 Feb 2022 16:01:22 +0100 Subject: [PATCH 205/253] sorqa68 --- .../sormas/e2etests/enums/GenderValuesDE.java | 23 ------------- .../application/cases/CreateNewCaseSteps.java | 32 +++++++------------ 2 files changed, 11 insertions(+), 44 deletions(-) delete mode 100644 sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValuesDE.java diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValuesDE.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValuesDE.java deleted file mode 100644 index aa259e97861..00000000000 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/enums/GenderValuesDE.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.sormas.e2etests.enums; - -import java.util.Random; -import lombok.Getter; - -@Getter -public enum GenderValuesDE { - MALE("M\u00E4nnlich"), - FEMALE("Weiblich"), - OTHER("Divers"), - UNKNOWN("Unbekannt"); - - private final String gender; - - GenderValuesDE(String humanGender) { - gender = humanGender; - } - - public static String getRandomGenderDE() { - Random random = new Random(); - return String.valueOf(GenderValuesDE.values()[random.nextInt(values().length)].gender); - } -} diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java index b96a0eee08d..1dc473eeb60 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -220,11 +220,11 @@ private void fillDateOfReport(LocalDate date, Locale locale) { webDriverHelpers.fillInWebElement(DATE_OF_REPORT_INPUT, formatter.format(date)); } - private void fillDateOfReportDE(LocalDate date) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); - webDriverHelpers.fillInWebElement(DATE_OF_REPORT_INPUT, formatter.format(date)); - } - + private void fillDateOfReportDE(LocalDate date) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); + webDriverHelpers.fillInWebElement(DATE_OF_REPORT_INPUT, formatter.format(date)); + } + private void fillExternalId(String externalId) { webDriverHelpers.fillInWebElement(EXTERNAL_ID_INPUT, externalId); } @@ -270,16 +270,6 @@ private void fillDateOfBirth(LocalDate localDate, Locale locale) { DATE_OF_BIRTH_DAY_COMBOBOX, String.valueOf(localDate.getDayOfMonth())); } - private void fillDateOfBirthDE(LocalDate localDate) { - webDriverHelpers.selectFromCombobox( - DATE_OF_BIRTH_YEAR_COMBOBOX, String.valueOf(localDate.getYear())); - webDriverHelpers.selectFromCombobox( - DATE_OF_BIRTH_MONTH_COMBOBOX, - localDate.getMonth().getDisplayName(TextStyle.FULL, Locale.GERMAN)); - webDriverHelpers.selectFromCombobox( - DATE_OF_BIRTH_DAY_COMBOBOX, String.valueOf(localDate.getDayOfMonth())); - } - private void selectSex(String sex) { webDriverHelpers.selectFromCombobox(SEX_COMBOBOX, sex); } @@ -296,15 +286,15 @@ private void fillDateOfSymptomOnset(LocalDate date, Locale locale) { webDriverHelpers.fillInWebElement(DATE_OF_SYMPTOM_ONSET_INPUT, formatter.format(date)); } - private void fillDateOfSymptomOnsetDE(LocalDate date) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); - webDriverHelpers.fillInWebElement(DATE_OF_SYMPTOM_ONSET_INPUT, formatter.format(date)); - } - private void fillPrimaryPhoneNumber(String primaryPhoneNumber) { webDriverHelpers.fillInWebElement(PRIMARY_PHONE_NUMBER_INPUT, primaryPhoneNumber); } + private void fillDateOfSymptomOnsetDE(LocalDate date) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); + webDriverHelpers.fillInWebElement(DATE_OF_SYMPTOM_ONSET_INPUT, formatter.format(date)); + } + private void fillPrimaryEmailAddress(String primaryPhoneNumber) { webDriverHelpers.fillInWebElement(PRIMARY_EMAIL_ADDRESS_INPUT, primaryPhoneNumber); } From 45f7766d60d5145e57ae72ada1af7e2808bfd4d2 Mon Sep 17 00:00:00 2001 From: Pawel Kujawa Date: Sat, 26 Feb 2022 13:42:08 +0100 Subject: [PATCH 206/253] rebase --- .../steps/web/application/cases/CaseDetailedTableViewSteps.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java index 71f65d78758..a39484a6b95 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java @@ -140,7 +140,7 @@ public CaseDetailedTableViewSteps( } softly.assertEquals( detailedCaseDTableRow.get(CaseDetailedTableViewHeaders.REPORTING_USER.toString()), - TestDataUser.REST_AUTOMATION.getUserRole(), + environmentManager.getUserByRole(locale, UserRoles.RestUser.getRole()).getUserRole(), "Reporting user is not correct"); softly.assertAll(); }); From b9bd1610839ebf5f86bb811d4feca90d6821c79d Mon Sep 17 00:00:00 2001 From: Pawel Kujawa Date: Mon, 28 Feb 2022 12:15:30 +0100 Subject: [PATCH 207/253] rebase --- .../entities/services/CaseService.java | 1 - .../cases/CaseDetailedTableViewSteps.java | 3 +++ .../application/cases/CreateNewCaseSteps.java | 18 +++++++++--------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java index 867192cb8dc..81185839bc4 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java @@ -29,7 +29,6 @@ import org.sormas.e2etests.enums.GenderValues; import org.sormas.e2etests.enums.RegionsValues; import org.sormas.e2etests.helpers.strings.ASCIIHelper; -import org.sormas.e2etests.pojo.web.Case; public class CaseService { private final Faker faker; diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java index a39484a6b95..0e09b297d5f 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDetailedTableViewSteps.java @@ -1,6 +1,8 @@ package org.sormas.e2etests.steps.web.application.cases; import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.*; +import static org.sormas.e2etests.pages.application.cases.EditCasePage.BACK_TO_CASES_LIST_BUTTON; +import static org.sormas.e2etests.steps.BaseSteps.locale; import static recorders.StepsLogger.PROCESS_ID_STRING; import cucumber.api.java8.En; @@ -33,6 +35,7 @@ public class CaseDetailedTableViewSteps implements En { private final WebDriverHelpers webDriverHelpers; private static BaseSteps baseSteps; + static final String DATE_FORMAT_DE = "dd.MM.yyyy"; @Inject public CaseDetailedTableViewSteps( diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java index 1dc473eeb60..cb11f29c27b 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java @@ -220,11 +220,11 @@ private void fillDateOfReport(LocalDate date, Locale locale) { webDriverHelpers.fillInWebElement(DATE_OF_REPORT_INPUT, formatter.format(date)); } - private void fillDateOfReportDE(LocalDate date) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); - webDriverHelpers.fillInWebElement(DATE_OF_REPORT_INPUT, formatter.format(date)); - } - + private void fillDateOfReportDE(LocalDate date) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); + webDriverHelpers.fillInWebElement(DATE_OF_REPORT_INPUT, formatter.format(date)); + } + private void fillExternalId(String externalId) { webDriverHelpers.fillInWebElement(EXTERNAL_ID_INPUT, externalId); } @@ -290,10 +290,10 @@ private void fillPrimaryPhoneNumber(String primaryPhoneNumber) { webDriverHelpers.fillInWebElement(PRIMARY_PHONE_NUMBER_INPUT, primaryPhoneNumber); } - private void fillDateOfSymptomOnsetDE(LocalDate date) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); - webDriverHelpers.fillInWebElement(DATE_OF_SYMPTOM_ONSET_INPUT, formatter.format(date)); - } + private void fillDateOfSymptomOnsetDE(LocalDate date) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); + webDriverHelpers.fillInWebElement(DATE_OF_SYMPTOM_ONSET_INPUT, formatter.format(date)); + } private void fillPrimaryEmailAddress(String primaryPhoneNumber) { webDriverHelpers.fillInWebElement(PRIMARY_EMAIL_ADDRESS_INPUT, primaryPhoneNumber); From 2578c85e4845d05cf694d339dbcf5069331aab9a Mon Sep 17 00:00:00 2001 From: Pawel Kujawa Date: Mon, 28 Feb 2022 12:23:47 +0100 Subject: [PATCH 208/253] rebase --- .../java/org/sormas/e2etests/entities/services/CaseService.java | 2 +- .../steps/web/application/cases/CreateNewCaseSteps.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java index 81185839bc4..40c689ca262 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/entities/services/CaseService.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java index cb11f29c27b..19e69577aad 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java @@ -1,6 +1,6 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System - * Copyright © 2016-2021 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) + * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From 24da0ae25664e044056555fd4f7c673997462044 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Mon, 28 Feb 2022 16:47:32 +0100 Subject: [PATCH 209/253] refactored --- .../application/events/EventDirectorySteps.java | 16 +++++++++------- .../resources/features/sanity/web/Event.feature | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index 4348bd5a440..803c8db8b75 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -20,6 +20,7 @@ import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_GRID_RESULTS_ROWS; import static org.sormas.e2etests.pages.application.events.EditEventPage.EVENT_PARTICIPANTS_TAB; +import static org.sormas.e2etests.pages.application.events.EditEventPage.FIRST_EVENT_PARTICIPANT; import static org.sormas.e2etests.pages.application.events.EditEventPage.NEW_TASK_BUTTON; import static org.sormas.e2etests.pages.application.events.EditEventPage.TITLE_INPUT; import static org.sormas.e2etests.pages.application.events.EditEventPage.UUID_INPUT; @@ -62,8 +63,10 @@ import java.util.List; import java.util.concurrent.TimeUnit; import javax.inject.Inject; -import javax.inject.Named; import org.sormas.e2etests.common.DataOperations; +import org.sormas.e2etests.entities.pojo.helpers.ComparisonHelper; +import org.sormas.e2etests.entities.pojo.web.EventGroup; +import org.sormas.e2etests.entities.services.EventGroupService; import org.sormas.e2etests.enums.DiseasesValues; import org.sormas.e2etests.enums.RiskLevelValues; import org.sormas.e2etests.enums.SourceTypeValues; @@ -73,9 +76,6 @@ import org.sormas.e2etests.helpers.WebDriverHelpers; import org.sormas.e2etests.pages.application.NavBarPage; import org.sormas.e2etests.pages.application.events.EventDirectoryPage; -import org.sormas.e2etests.pojo.helpers.ComparisonHelper; -import org.sormas.e2etests.pojo.web.EventGroup; -import org.sormas.e2etests.services.EventGroupService; import org.sormas.e2etests.state.ApiState; import org.testng.Assert; @@ -114,10 +114,12 @@ public EventDirectorySteps( When( "I navigate to the last created Event page via URL", () -> { + String eventLinkPath = "/sormas-ui/#!events/data/"; String createdEventUUID = CreateNewEventSteps.newEvent.getUuid(); - String LAST_CREATED_EVENT_PAGE_URL = - environmentUrl + "/sormas-webdriver/#!events/data/" + createdEventUUID; - webDriverHelpers.accessWebSite(LAST_CREATED_EVENT_PAGE_URL); + webDriverHelpers.accessWebSite( + environmentManager.getEnvironmentUrlForMarket(locale) + + eventLinkPath + + createdEventUUID); webDriverHelpers.waitForPageLoaded(); webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(UUID_INPUT, 50); }); diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature index ef148dc47df..a06eb5c85c5 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Event.feature @@ -262,7 +262,7 @@ Feature: Create events And I click on the Navigate to event directory filtered on this event group And I check the number of displayed Event results from All button is 1 - @issue=SORDEV-5572 + @issue=SORDEV-5572 @env_main Scenario: Testing Event group adding for new event Given API: I create a new event Then API: I check that POST call body is "OK" From 6a5830f8c02c60e24e64b125d5290ae3d9f7afe8 Mon Sep 17 00:00:00 2001 From: Pawel Kujawa Date: Mon, 28 Feb 2022 16:47:53 +0100 Subject: [PATCH 210/253] fix --- .../steps/web/application/cases/CreateNewCaseSteps.java | 2 +- .../web/application/samples/SamplesDirectorySteps.java | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java index 19e69577aad..841866333d7 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java @@ -73,7 +73,7 @@ public CreateNewCaseSteps(WebDriverHelpers webDriverHelpers, CaseService caseSer "I create a new case with specific data for positive pathogen test result", () -> { caze = caseService.buildEditGeneratedCaseForPositivePathogenTestResult(); - fillDateOfReport(caze.getDateOfReport()); + fillDateOfReport(caze.getDateOfReport(), Locale.ENGLISH); selectResponsibleRegion(caze.getResponsibleRegion()); selectResponsibleDistrict(caze.getResponsibleDistrict()); selectResponsibleCommunity(caze.getResponsibleCommunity()); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java index 9ef8eb2b19c..5b86cc8f03a 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/samples/SamplesDirectorySteps.java @@ -18,8 +18,6 @@ package org.sormas.e2etests.steps.web.application.samples; -import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.*; -import static org.sormas.e2etests.steps.BaseSteps.locale; import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.APPLY_FILTER_BUTTON; import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.FINAL_LABORATORY_RESULT; import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.LABORATORY_SEARCH_COMBOBOX; @@ -37,14 +35,12 @@ import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.SEARCH_RESULT_SAMPLE; import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.SPECIMEN_CONDITION_SEARCH_COMBOBOX; import static org.sormas.e2etests.pages.application.samples.SamplesDirectoryPage.TEST_RESULTS_SEARCH_COMBOBOX; +import static org.sormas.e2etests.steps.BaseSteps.locale; import com.google.common.truth.Truth; import cucumber.api.java8.En; import java.util.Arrays; import javax.inject.Inject; -import org.sormas.e2etests.enums.*; -import org.sormas.e2etests.envconfig.manager.EnvironmentManager; -import javax.inject.Named; import org.sormas.e2etests.enums.CaseClassification; import org.sormas.e2etests.enums.DiseasesValues; import org.sormas.e2etests.enums.DistrictsValues; @@ -52,6 +48,7 @@ import org.sormas.e2etests.enums.PathogenTestResults; import org.sormas.e2etests.enums.RegionsValues; import org.sormas.e2etests.enums.SpecimenConditions; +import org.sormas.e2etests.envconfig.manager.EnvironmentManager; import org.sormas.e2etests.helpers.AssertHelpers; import org.sormas.e2etests.helpers.WebDriverHelpers; import org.sormas.e2etests.state.ApiState; From a5997114ac29b57100e32d467c0bb719aea0b384 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Mon, 28 Feb 2022 17:41:08 +0100 Subject: [PATCH 211/253] rebased --- .../steps/web/application/events/EventDirectorySteps.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index 446392fe56c..d5244453a7b 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -20,6 +20,7 @@ import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_GRID_RESULTS_ROWS; import static org.sormas.e2etests.pages.application.events.EditEventPage.EVENT_PARTICIPANTS_TAB; +import static org.sormas.e2etests.pages.application.events.EditEventPage.FIRST_EVENT_PARTICIPANT; import static org.sormas.e2etests.pages.application.events.EditEventPage.NEW_TASK_BUTTON; import static org.sormas.e2etests.pages.application.events.EditEventPage.TITLE_INPUT; import static org.sormas.e2etests.pages.application.events.EditEventPage.UUID_INPUT; @@ -327,8 +328,7 @@ public EventDirectorySteps( When( "I click on the created event participant from the list", - () -> - webDriverHelpers.clickOnWebElementBySelector(CREATED_PARTICIPANT)); + () -> webDriverHelpers.clickOnWebElementBySelector(CREATED_PARTICIPANT)); When( "I click on New Task from event tab", From 1c3d1108352b53877ac9382eb32e12f3f0b84f2b Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Mon, 28 Feb 2022 18:11:22 +0100 Subject: [PATCH 212/253] rebased --- .../application/persons/EditPersonSteps.java | 85 +++++++++++++++---- 1 file changed, 67 insertions(+), 18 deletions(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java index 91c7af83b04..9867f5b2cef 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java @@ -18,36 +18,85 @@ package org.sormas.e2etests.steps.web.application.persons; -import static org.sormas.e2etests.pages.application.contacts.CreateNewContactPage.SAVE_BUTTON; -import static org.sormas.e2etests.pages.application.contacts.EditContactPersonPage.CONTACT_PERSON_FIRST_NAME_INPUT; -import static org.sormas.e2etests.pages.application.contacts.EditContactPersonPage.CONTACT_PERSON_LAST_NAME_INPUT; -import static org.sormas.e2etests.pages.application.contacts.EditContactPersonPage.SEX_COMBOBOX; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.getByEventUuid; -import static org.sormas.e2etests.pages.application.persons.EditPersonPage.*; -import static org.sormas.e2etests.steps.BaseSteps.locale; - import cucumber.api.java8.En; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.time.format.TextStyle; -import java.util.List; -import java.util.Locale; -import java.util.concurrent.TimeUnit; -import javax.inject.Inject; import org.openqa.selenium.ElementClickInterceptedException; import org.sormas.e2etests.entities.pojo.helpers.ComparisonHelper; import org.sormas.e2etests.entities.pojo.web.Person; import org.sormas.e2etests.entities.services.PersonService; import org.sormas.e2etests.envconfig.manager.EnvironmentManager; import org.sormas.e2etests.helpers.WebDriverHelpers; -import org.sormas.e2etests.pojo.helpers.ComparisonHelper; -import org.sormas.e2etests.pojo.web.Person; -import org.sormas.e2etests.services.PersonService; import org.sormas.e2etests.state.ApiState; import org.sormas.e2etests.steps.BaseSteps; import org.sormas.e2etests.steps.web.application.contacts.EditContactPersonSteps; import org.sormas.e2etests.steps.web.application.events.EditEventSteps; +import javax.inject.Inject; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.TextStyle; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.TimeUnit; + +import static org.sormas.e2etests.pages.application.contacts.CreateNewContactPage.SAVE_BUTTON; +import static org.sormas.e2etests.pages.application.contacts.EditContactPersonPage.CONTACT_PERSON_FIRST_NAME_INPUT; +import static org.sormas.e2etests.pages.application.contacts.EditContactPersonPage.CONTACT_PERSON_LAST_NAME_INPUT; +import static org.sormas.e2etests.pages.application.contacts.EditContactPersonPage.SEX_COMBOBOX; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.getByEventUuid; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.ADDITIONAL_INFORMATION_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.AREA_TYPE_COMBOBOX; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.AREA_TYPE_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.BIRTH_NAME_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.CITY_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.COMMUNITY_COMBOBOX; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.COMMUNITY_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.DATE_OF_BIRTH_DAY_COMBOBOX; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.DATE_OF_BIRTH_MONTH_COMBOBOX; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.DATE_OF_BIRTH_YEAR_COMBOBOX; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.DISTRICT_COMBOBOX; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.DISTRICT_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.EDIT_CASES_BUTTON; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.EDIT_CONTACTS_BUTTON; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.EMAIL_FIELD; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.ERROR_INDICATOR; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.EXTERNAL_ID_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.EXTERNAL_TOKEN_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.FACILITY_CATEGORY_COMBOBOX; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.FACILITY_CATEGORY_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.FACILITY_COMBOBOX; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.FACILITY_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.FACILITY_NAME_AND_DESCRIPTION_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.FACILITY_TYPE_COMBOBOX; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.FACILITY_TYPE_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.FIRST_NAME_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.HOUSE_NUMBER_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.INVALID_DATA_ERROR; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.LAST_NAME_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.NAMES_OF_GUARDIANS_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.PERSON_CONTACT_DETAILS_CONTACT_INFORMATION_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.PERSON_CONTACT_DETAILS_TYPE_OF_DETAILS_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.PHONE_FIELD; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.POSTAL_CODE_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.PRESENT_CONDITION_COMBOBOX; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.PRESENT_CONDITION_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.REGION_COMBOBOX; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.REGION_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.SALUTATION_COMBOBOX; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.SALUTATION_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.SEE_CASES_FOR_PERSON_BUTTON; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.SEE_CONTACTS_FOR_PERSON_BUTTON; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.SEE_EVENTS_FOR_PERSON; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.SEX_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.STAFF_OF_ARMED_FORCES_COMBOBOX; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.STAFF_OF_ARMED_FORCES_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.STREET_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.TYPE_OF_OCCUPATION_COMBOBOX; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.TYPE_OF_OCCUPATION_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.USER_INFORMATION; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.UUID_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.getByImmunizationUuid; +import static org.sormas.e2etests.steps.BaseSteps.locale; + public class EditPersonSteps implements En { private final WebDriverHelpers webDriverHelpers; From 9054c4ef273a11a858901adbaee52175b54a05e1 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Mon, 28 Feb 2022 18:37:56 +0100 Subject: [PATCH 213/253] added scroll to find element on page --- .../steps/web/application/events/EventDirectorySteps.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index d5244453a7b..333c8f62344 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -126,7 +126,10 @@ public EventDirectorySteps( () -> webDriverHelpers.clickOnWebElementBySelector(LINKED_EVENT_GROUP_ID)); When( "^I click on Group Id in Events result on Event Directory Page$", - () -> webDriverHelpers.clickOnWebElementBySelector(EVENT_GROUP_ID_IN_GRID)); + () ->{ + webDriverHelpers.scrollToElement(EVENT_GROUP_ID_IN_GRID); + webDriverHelpers.clickOnWebElementBySelector(EVENT_GROUP_ID_IN_GRID); + }); When( "I click on the NEW EVENT button", From 08bdbc390413ca057997e4f9785b818b1ca425dc Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Tue, 1 Mar 2022 08:28:11 +0100 Subject: [PATCH 214/253] environment manager step refactor --- .../web/application/persons/PersonDirectorySteps.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java index b55cbdd4df1..6d2dec8972b 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java @@ -250,10 +250,10 @@ public PersonDirectorySteps( When( "I navigate to the last created via api Person page via URL", () -> { - String createdPersonUUID = apiState.getLastCreatedPerson().getUuid(); - String LAST_CREATED_PERSON_PAGE_URL = - environmentUrl + "/sormas-webdriver/#!persons/data/" + createdPersonUUID; - webDriverHelpers.accessWebSite(LAST_CREATED_PERSON_PAGE_URL); + String personLinkPath = "/sormas-ui/#!persons/data/"; + String uuid = apiState.getLastCreatedPerson().getUuid(); + webDriverHelpers.accessWebSite( + environmentManager.getEnvironmentUrlForMarket(locale) + personLinkPath + uuid); webDriverHelpers.waitForPageLoaded(); webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(UUID_INPUT, 50); }); From e20305c834948c5aadfa95da4c6b0ce3e97ac462 Mon Sep 17 00:00:00 2001 From: sergiupacurariu <62688603+sergiupacurariu@users.noreply.github.com> Date: Tue, 1 Mar 2022 09:35:39 +0200 Subject: [PATCH 215/253] #7247 - CoreAdo: Introduce "end of processing date" - update save logic when archiving entity --- .../java/de/symeda/sormas/ui/campaign/CampaignController.java | 4 +++- .../java/de/symeda/sormas/ui/contact/ContactController.java | 4 +++- .../main/java/de/symeda/sormas/ui/events/EventController.java | 4 +++- .../symeda/sormas/ui/events/EventParticipantsController.java | 4 +++- .../symeda/sormas/ui/immunization/ImmunizationController.java | 4 +++- .../symeda/sormas/ui/travelentry/TravelEntryController.java | 4 +++- 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/campaign/CampaignController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/campaign/CampaignController.java index 6a5c378b1fa..642a9a09c14 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/campaign/CampaignController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/campaign/CampaignController.java @@ -89,7 +89,9 @@ public void createOrEditCampaign(String uuid) { private void createArchiveButton(CommitDiscardWrapperComponent campaignComponent, CampaignDto campaign) { boolean archived = FacadeProvider.getCampaignFacade().isArchived(campaign.getUuid()); Button archiveCampaignButton = ButtonHelper.createButton(archived ? Captions.actionDearchive : Captions.actionArchive, e -> { - campaignComponent.commit(); + if (campaignComponent.isModified()) { + campaignComponent.commit(); + } if (archived) { ControllerProvider.getArchiveController() diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactController.java index 43ae908a9b9..6dc95d07041 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactController.java @@ -607,7 +607,9 @@ public CommitDiscardWrapperComponent getContactDataEditComponen if (UserProvider.getCurrent().hasUserRight(UserRight.CONTACT_ARCHIVE)) { boolean archived = FacadeProvider.getContactFacade().isArchived(contact.getUuid()); Button archiveButton = ButtonHelper.createButton(archived ? Captions.actionDearchive : Captions.actionArchive, e -> { - editComponent.commit(); + if (editComponent.isModified()) { + editComponent.commit(); + } if (archived) { ControllerProvider.getArchiveController() diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventController.java index c417ecbf626..6d04e8bb828 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventController.java @@ -806,7 +806,9 @@ public CommitDiscardWrapperComponent getEventDataEditComponent(fi if (UserProvider.getCurrent().hasUserRight(UserRight.EVENT_ARCHIVE)) { boolean archived = FacadeProvider.getEventFacade().isArchived(eventUuid); Button archiveEventButton = ButtonHelper.createButton(archived ? Captions.actionDearchive : Captions.actionArchive, e -> { - editView.commit(); + if (editView.isModified()) { + editView.commit(); + } if (archived) { ControllerProvider.getArchiveController() diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsController.java index c92edd1d4d5..2581d33645a 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsController.java @@ -233,7 +233,9 @@ public CommitDiscardWrapperComponent getEventParticipantDataEditComponent(Str if (UserProvider.getCurrent().hasUserRight(UserRight.EVENTPARTICIPANT_ARCHIVE)) { boolean archived = FacadeProvider.getEventParticipantFacade().isArchived(eventParticipant.getUuid()); Button archiveButton = ButtonHelper.createButton(archived ? Captions.actionDearchive : Captions.actionArchive, e -> { - editComponent.commit(); + if (editComponent.isModified()) { + editComponent.commit(); + } if (archived) { ControllerProvider.getArchiveController() diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java index 73369efb5e2..13ef62025b4 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/immunization/ImmunizationController.java @@ -190,7 +190,9 @@ public void discard() { if (UserProvider.getCurrent().hasUserRight(UserRight.IMMUNIZATION_ARCHIVE)) { boolean archived = FacadeProvider.getImmunizationFacade().isArchived(immunizationDto.getUuid()); Button archiveButton = ButtonHelper.createButton(archived ? Captions.actionDearchive : Captions.actionArchive, e -> { - editComponent.commit(); + if (editComponent.isModified()) { + editComponent.commit(); + } if (archived) { ControllerProvider.getArchiveController() diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryController.java index 623660f7227..b56fa4d37c7 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryController.java @@ -167,7 +167,9 @@ public CommitDiscardWrapperComponent getTravelEntryDataEdit if (UserProvider.getCurrent().hasUserRight(UserRight.TRAVEL_ENTRY_ARCHIVE)) { boolean archived = FacadeProvider.getTravelEntryFacade().isArchived(travelEntryUuid); Button archiveTravelEntryButton = ButtonHelper.createButton(archived ? Captions.actionDearchive : Captions.actionArchive, e -> { - editComponent.commit(); + if (editComponent.isModified()) { + editComponent.commit(); + } if (archived) { ControllerProvider.getArchiveController() From 601d8ac8ab2a44a3cbdc20acd88959101ec8f135 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Tue, 1 Mar 2022 09:25:17 +0100 Subject: [PATCH 216/253] final adjustements --- .../application/persons/EditPersonPage.java | 1 + .../application/persons/EditPersonSteps.java | 46 +++++++++++-------- .../persons/PersonDirectorySteps.java | 8 ++-- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java index 438e1f4cbd7..de73cfadf5c 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/persons/EditPersonPage.java @@ -111,6 +111,7 @@ public class EditPersonPage { public static final By SEE_CONTACTS_FOR_PERSON_BUTTON = By.id("See contacts for this person"); public static final By EDIT_CASES_BUTTON = By.id("edit-case-0"); public static final By EDIT_CONTACTS_BUTTON = By.id("edit-contact-0"); + public static final By CONFIRM_NAVIGATION_BUTTON = By.cssSelector(".popupContent #actionConfirm"); public static By getByPersonUuid(String personUuid) { return By.cssSelector("a[title='" + personUuid + "']"); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java index 9867f5b2cef..0ca8b3c82e1 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/EditPersonSteps.java @@ -18,26 +18,6 @@ package org.sormas.e2etests.steps.web.application.persons; -import cucumber.api.java8.En; -import org.openqa.selenium.ElementClickInterceptedException; -import org.sormas.e2etests.entities.pojo.helpers.ComparisonHelper; -import org.sormas.e2etests.entities.pojo.web.Person; -import org.sormas.e2etests.entities.services.PersonService; -import org.sormas.e2etests.envconfig.manager.EnvironmentManager; -import org.sormas.e2etests.helpers.WebDriverHelpers; -import org.sormas.e2etests.state.ApiState; -import org.sormas.e2etests.steps.BaseSteps; -import org.sormas.e2etests.steps.web.application.contacts.EditContactPersonSteps; -import org.sormas.e2etests.steps.web.application.events.EditEventSteps; - -import javax.inject.Inject; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.time.format.TextStyle; -import java.util.List; -import java.util.Locale; -import java.util.concurrent.TimeUnit; - import static org.sormas.e2etests.pages.application.contacts.CreateNewContactPage.SAVE_BUTTON; import static org.sormas.e2etests.pages.application.contacts.EditContactPersonPage.CONTACT_PERSON_FIRST_NAME_INPUT; import static org.sormas.e2etests.pages.application.contacts.EditContactPersonPage.CONTACT_PERSON_LAST_NAME_INPUT; @@ -50,6 +30,7 @@ import static org.sormas.e2etests.pages.application.persons.EditPersonPage.CITY_INPUT; import static org.sormas.e2etests.pages.application.persons.EditPersonPage.COMMUNITY_COMBOBOX; import static org.sormas.e2etests.pages.application.persons.EditPersonPage.COMMUNITY_INPUT; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.CONFIRM_NAVIGATION_BUTTON; import static org.sormas.e2etests.pages.application.persons.EditPersonPage.DATE_OF_BIRTH_DAY_COMBOBOX; import static org.sormas.e2etests.pages.application.persons.EditPersonPage.DATE_OF_BIRTH_MONTH_COMBOBOX; import static org.sormas.e2etests.pages.application.persons.EditPersonPage.DATE_OF_BIRTH_YEAR_COMBOBOX; @@ -97,6 +78,25 @@ import static org.sormas.e2etests.pages.application.persons.EditPersonPage.getByImmunizationUuid; import static org.sormas.e2etests.steps.BaseSteps.locale; +import cucumber.api.java8.En; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.TextStyle; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.TimeUnit; +import javax.inject.Inject; +import org.openqa.selenium.ElementClickInterceptedException; +import org.sormas.e2etests.entities.pojo.helpers.ComparisonHelper; +import org.sormas.e2etests.entities.pojo.web.Person; +import org.sormas.e2etests.entities.services.PersonService; +import org.sormas.e2etests.envconfig.manager.EnvironmentManager; +import org.sormas.e2etests.helpers.WebDriverHelpers; +import org.sormas.e2etests.state.ApiState; +import org.sormas.e2etests.steps.BaseSteps; +import org.sormas.e2etests.steps.web.application.contacts.EditContactPersonSteps; +import org.sormas.e2etests.steps.web.application.events.EditEventSteps; + public class EditPersonSteps implements En { private final WebDriverHelpers webDriverHelpers; @@ -182,13 +182,16 @@ public EditPersonSteps( Then( "I click on See Cases for this Person button from Edit Person page", () -> { + webDriverHelpers.waitForPageLoadingSpinnerToDisappear(150); webDriverHelpers.clickOnWebElementBySelector(SEE_CASES_FOR_PERSON_BUTTON); + webDriverHelpers.clickOnWebElementBySelector(CONFIRM_NAVIGATION_BUTTON); webDriverHelpers.waitForPageLoadingSpinnerToDisappear(150); }); Then( "I click on See CONTACTS for this Person button from Edit Person page", () -> { webDriverHelpers.clickOnWebElementBySelector(SEE_CONTACTS_FOR_PERSON_BUTTON); + webDriverHelpers.clickOnWebElementBySelector(CONFIRM_NAVIGATION_BUTTON); webDriverHelpers.waitForPageLoadingSpinnerToDisappear(150); }); @@ -196,12 +199,14 @@ public EditPersonSteps( "I click on Edit Case button from Cases card on Edit Person page", () -> { webDriverHelpers.clickOnWebElementBySelector(EDIT_CASES_BUTTON); + webDriverHelpers.clickOnWebElementBySelector(CONFIRM_NAVIGATION_BUTTON); webDriverHelpers.waitForPageLoadingSpinnerToDisappear(150); }); Then( "I click on Edit Contact button from Contacts card on Edit Person page", () -> { webDriverHelpers.clickOnWebElementBySelector(EDIT_CONTACTS_BUTTON); + webDriverHelpers.clickOnWebElementBySelector(CONFIRM_NAVIGATION_BUTTON); webDriverHelpers.waitForPageLoadingSpinnerToDisappear(150); }); Then( @@ -209,6 +214,7 @@ public EditPersonSteps( () -> { webDriverHelpers.clickOnWebElementBySelector( getByImmunizationUuid(apiState.getCreatedImmunization().getUuid())); + webDriverHelpers.clickOnWebElementBySelector(CONFIRM_NAVIGATION_BUTTON); webDriverHelpers.waitForPageLoadingSpinnerToDisappear(150); }); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java index 6d2dec8972b..6e0d2de81bd 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/persons/PersonDirectorySteps.java @@ -250,10 +250,10 @@ public PersonDirectorySteps( When( "I navigate to the last created via api Person page via URL", () -> { - String personLinkPath = "/sormas-ui/#!persons/data/"; - String uuid = apiState.getLastCreatedPerson().getUuid(); - webDriverHelpers.accessWebSite( - environmentManager.getEnvironmentUrlForMarket(locale) + personLinkPath + uuid); + String personLinkPath = "/sormas-ui/#!persons/data/"; + String uuid = apiState.getLastCreatedPerson().getUuid(); + webDriverHelpers.accessWebSite( + environmentManager.getEnvironmentUrlForMarket(locale) + personLinkPath + uuid); webDriverHelpers.waitForPageLoaded(); webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(UUID_INPUT, 50); }); From 0b4ed18a707edc2cd49a5399942a645d153cd632 Mon Sep 17 00:00:00 2001 From: Frank Hautpmann Date: Tue, 1 Mar 2022 11:20:01 +0100 Subject: [PATCH 217/253] New Crowdin updates (#8126) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * New translations enum.properties (French) * New translations enum.properties (Urdu (Pakistan)) * New translations enum.properties (English, Nigeria) * New translations enum.properties (English, Afghanistan) * New translations enum.properties (Spanish, Cuba) * New translations enum.properties (Pashto) * New translations enum.properties (Dari) * New translations enum.properties (Italian, Switzerland) * New translations enum.properties (French, Switzerland) * New translations enum.properties (German, Switzerland) * New translations enum.properties (Swahili) * New translations enum.properties (Fijian) * New translations enum.properties (Filipino) * New translations enum.properties (Hindi) * New translations enum.properties (Croatian) * New translations enum.properties (Spanish, Ecuador) * New translations enum.properties (Chinese Simplified) * New translations enum.properties (German) * New translations enum.properties (Ukrainian) * New translations enum.properties (Turkish) * New translations enum.properties (Swedish) * New translations enum.properties (Russian) * New translations enum.properties (Portuguese) * New translations enum.properties (Polish) * New translations enum.properties (Norwegian) * New translations enum.properties (Dutch) * New translations enum.properties (Japanese) * New translations enum.properties (Italian) * New translations enum.properties (Finnish) * New translations enum.properties (Czech) * New translations enum.properties (Spanish) * New translations enum.properties (Romanian) * New translations enum.properties (English, Ghana) * New translations strings.properties (French) * New translations strings.properties (Pashto) * New translations strings.properties (Filipino) * New translations strings.properties (Fijian) * New translations strings.properties (Swahili) * New translations strings.properties (German, Switzerland) * New translations strings.properties (French, Switzerland) * New translations strings.properties (Italian, Switzerland) * New translations strings.properties (Dari) * New translations strings.properties (Spanish, Cuba) * New translations strings.properties (Croatian) * New translations strings.properties (English, Afghanistan) * New translations strings.properties (English, Nigeria) * New translations strings.properties (English, Ghana) * New translations captions.properties (Czech) * New translations validations.properties (Czech) * New translations enum.properties (Czech) * New translations enum.properties (Urdu (Pakistan)) * New translations strings.properties (Hindi) * New translations strings.properties (Spanish, Ecuador) * New translations strings.properties (German) * New translations strings.properties (Japanese) * New translations enum.properties (French) * New translations enum.properties (German) * New translations strings.properties (Romanian) * New translations strings.properties (Spanish) * New translations strings.properties (Czech) * New translations strings.properties (Finnish) * New translations strings.properties (Italian) * New translations strings.properties (Dutch) * New translations strings.properties (Urdu (Pakistan)) * New translations strings.properties (Norwegian) * New translations strings.properties (Polish) * New translations strings.properties (Portuguese) * New translations strings.properties (Russian) * New translations strings.properties (Swedish) * New translations strings.properties (Turkish) * New translations strings.properties (Ukrainian) * New translations strings.properties (Chinese Simplified) * New translations enum.properties (German, Switzerland) * New translations strings.properties (French) * New translations enum.properties (Spanish) * New translations strings.properties (Italian, Switzerland) * New translations strings.properties (Dari) * New translations strings.properties (Pashto) * New translations strings.properties (Spanish, Cuba) * New translations strings.properties (English, Afghanistan) * New translations strings.properties (English, Nigeria) * New translations strings.properties (English, Ghana) * New translations captions.properties (German) * New translations enum.properties (Romanian) * New translations enum.properties (Czech) * New translations strings.properties (German, Switzerland) * New translations enum.properties (Finnish) * New translations enum.properties (Italian) * New translations enum.properties (Japanese) * New translations enum.properties (Dutch) * New translations enum.properties (Norwegian) * New translations enum.properties (Polish) * New translations enum.properties (Portuguese) * New translations enum.properties (Russian) * New translations enum.properties (Swedish) * New translations enum.properties (Turkish) * New translations strings.properties (French, Switzerland) * New translations strings.properties (Swahili) * New translations strings.properties (German) * New translations strings.properties (Polish) * New translations enum.properties (French) * New translations enum.properties (German) * New translations strings.properties (Romanian) * New translations strings.properties (Spanish) * New translations strings.properties (Czech) * New translations strings.properties (Finnish) * New translations strings.properties (Italian) * New translations strings.properties (Japanese) * New translations strings.properties (Dutch) * New translations strings.properties (Norwegian) * New translations strings.properties (Portuguese) * New translations strings.properties (Fijian) * New translations strings.properties (Russian) * New translations strings.properties (Swedish) * New translations strings.properties (Turkish) * New translations strings.properties (Ukrainian) * New translations strings.properties (Chinese Simplified) * New translations strings.properties (Urdu (Pakistan)) * New translations strings.properties (Spanish, Ecuador) * New translations strings.properties (Croatian) * New translations strings.properties (Hindi) * New translations strings.properties (Filipino) * New translations enum.properties (Ukrainian) * New translations enum.properties (Chinese Simplified) * New translations enum.properties (French, Switzerland) * New translations enum.properties (English, Nigeria) * New translations enum.properties (English, Afghanistan) * New translations enum.properties (Spanish, Cuba) * New translations enum.properties (Pashto) * New translations enum.properties (Dari) * New translations enum.properties (Italian, Switzerland) * New translations enum.properties (German, Switzerland) * New translations enum.properties (Urdu (Pakistan)) * New translations enum.properties (Swahili) * New translations enum.properties (Fijian) * New translations enum.properties (Filipino) * New translations enum.properties (Hindi) * New translations enum.properties (Croatian) * New translations enum.properties (Spanish, Ecuador) * New translations enum.properties (English, Ghana) * New translations captions.properties (Urdu (Pakistan)) * New translations captions.properties (Spanish) * New translations strings.properties (Dari) * New translations strings.properties (Pashto) * New translations strings.properties (Spanish, Cuba) * New translations strings.properties (English, Afghanistan) * New translations strings.properties (English, Nigeria) * New translations strings.properties (English, Ghana) * New translations captions.properties (German) * New translations captions.properties (Romanian) * New translations captions.properties (French) * New translations captions.properties (Czech) * New translations strings.properties (French, Switzerland) * New translations captions.properties (Finnish) * New translations captions.properties (Italian) * New translations captions.properties (Japanese) * New translations captions.properties (Dutch) * New translations captions.properties (Norwegian) * New translations captions.properties (Polish) * New translations captions.properties (Portuguese) * New translations captions.properties (Russian) * New translations captions.properties (Swedish) * New translations captions.properties (Turkish) * New translations strings.properties (Italian, Switzerland) * New translations strings.properties (German, Switzerland) * New translations strings.properties (French) * New translations strings.properties (Portuguese) * New translations strings.properties (German) * New translations strings.properties (Romanian) * New translations strings.properties (Spanish) * New translations strings.properties (Czech) * New translations strings.properties (Finnish) * New translations strings.properties (Italian) * New translations strings.properties (Japanese) * New translations strings.properties (Dutch) * New translations strings.properties (Norwegian) * New translations strings.properties (Polish) * New translations strings.properties (Russian) * New translations strings.properties (Swahili) * New translations strings.properties (Swedish) * New translations strings.properties (Turkish) * New translations strings.properties (Ukrainian) * New translations strings.properties (Chinese Simplified) * New translations strings.properties (Urdu (Pakistan)) * New translations strings.properties (Spanish, Ecuador) * New translations strings.properties (Croatian) * New translations strings.properties (Hindi) * New translations strings.properties (Filipino) * New translations strings.properties (Fijian) * New translations captions.properties (Ukrainian) * New translations captions.properties (Chinese Simplified) * New translations captions.properties (Italian, Switzerland) * New translations captions.properties (English, Ghana) * New translations captions.properties (English, Nigeria) * New translations captions.properties (English, Afghanistan) * New translations captions.properties (Spanish, Cuba) * New translations captions.properties (Pashto) * New translations captions.properties (Dari) * New translations captions.properties (French, Switzerland) * New translations captions.properties (Spanish, Ecuador) * New translations captions.properties (German, Switzerland) * New translations captions.properties (Swahili) * New translations captions.properties (Fijian) * New translations captions.properties (Filipino) * New translations captions.properties (Hindi) * New translations captions.properties (Croatian) * New translations enum.properties (Czech) * New translations strings.properties (German) * New translations strings.properties (Urdu (Pakistan)) * New translations strings.properties (Spanish, Cuba) * New translations captions.properties (German) * New translations captions.properties (Spanish, Cuba) * New translations strings.properties (German, Switzerland) * New translations strings.properties (French) * New translations strings.properties (Spanish, Ecuador) * New translations strings.properties (English, Ghana) * New translations strings.properties (English, Nigeria) * New translations strings.properties (English, Afghanistan) * New translations strings.properties (Spanish, Cuba) * New translations strings.properties (Pashto) * New translations strings.properties (Dari) * New translations strings.properties (Italian, Switzerland) * New translations strings.properties (French, Switzerland) * New translations strings.properties (German, Switzerland) * New translations strings.properties (Swahili) * New translations strings.properties (Fijian) * New translations strings.properties (Filipino) * New translations strings.properties (Hindi) * New translations strings.properties (Croatian) * New translations strings.properties (Urdu (Pakistan)) * New translations strings.properties (German) * New translations strings.properties (Dutch) * New translations strings.properties (Romanian) * New translations strings.properties (Spanish) * New translations strings.properties (Czech) * New translations strings.properties (Finnish) * New translations strings.properties (Italian) * New translations strings.properties (Japanese) * New translations strings.properties (Norwegian) * New translations strings.properties (Chinese Simplified) * New translations strings.properties (Polish) * New translations strings.properties (Portuguese) * New translations strings.properties (Russian) * New translations strings.properties (Swedish) * New translations strings.properties (Turkish) * New translations strings.properties (Ukrainian) * New translations captions.properties (German, Switzerland) Co-authored-by: Maté Strysewske --- .../main/resources/captions_cs-CZ.properties | 13 +++++++++---- .../main/resources/captions_de-CH.properties | 7 ++++++- .../main/resources/captions_de-DE.properties | 5 +++++ .../main/resources/captions_en-AF.properties | 5 +++++ .../main/resources/captions_en-GH.properties | 5 +++++ .../main/resources/captions_en-NG.properties | 5 +++++ .../main/resources/captions_es-CU.properties | 11 ++++++++--- .../main/resources/captions_es-EC.properties | 5 +++++ .../main/resources/captions_es-ES.properties | 5 +++++ .../main/resources/captions_fa-AF.properties | 5 +++++ .../main/resources/captions_fi-FI.properties | 5 +++++ .../main/resources/captions_fil-PH.properties | 5 +++++ .../main/resources/captions_fj-FJ.properties | 5 +++++ .../main/resources/captions_fr-CH.properties | 5 +++++ .../main/resources/captions_fr-FR.properties | 5 +++++ .../main/resources/captions_hi-IN.properties | 5 +++++ .../main/resources/captions_hr-HR.properties | 5 +++++ .../main/resources/captions_it-CH.properties | 5 +++++ .../main/resources/captions_it-IT.properties | 5 +++++ .../main/resources/captions_ja-JP.properties | 5 +++++ .../main/resources/captions_nl-NL.properties | 5 +++++ .../main/resources/captions_no-NO.properties | 5 +++++ .../main/resources/captions_pl-PL.properties | 5 +++++ .../main/resources/captions_ps-AF.properties | 5 +++++ .../main/resources/captions_pt-PT.properties | 5 +++++ .../main/resources/captions_ro-RO.properties | 5 +++++ .../main/resources/captions_ru-RU.properties | 5 +++++ .../main/resources/captions_sv-SE.properties | 5 +++++ .../main/resources/captions_sw-KE.properties | 5 +++++ .../main/resources/captions_tr-TR.properties | 5 +++++ .../main/resources/captions_uk-UA.properties | 5 +++++ .../main/resources/captions_ur-PK.properties | 15 ++++++++++----- .../main/resources/captions_zh-CN.properties | 5 +++++ .../src/main/resources/enum_cs-CZ.properties | 8 ++++---- .../main/resources/strings_cs-CZ.properties | 18 +++++++++++++++++- .../main/resources/strings_de-CH.properties | 18 +++++++++++++++++- .../main/resources/strings_de-DE.properties | 18 +++++++++++++++++- .../main/resources/strings_en-AF.properties | 18 +++++++++++++++++- .../main/resources/strings_en-GH.properties | 18 +++++++++++++++++- .../main/resources/strings_en-NG.properties | 18 +++++++++++++++++- .../main/resources/strings_es-CU.properties | 18 +++++++++++++++++- .../main/resources/strings_es-EC.properties | 18 +++++++++++++++++- .../main/resources/strings_es-ES.properties | 18 +++++++++++++++++- .../main/resources/strings_fa-AF.properties | 18 +++++++++++++++++- .../main/resources/strings_fi-FI.properties | 18 +++++++++++++++++- .../main/resources/strings_fil-PH.properties | 18 +++++++++++++++++- .../main/resources/strings_fj-FJ.properties | 18 +++++++++++++++++- .../main/resources/strings_fr-CH.properties | 18 +++++++++++++++++- .../main/resources/strings_fr-FR.properties | 18 +++++++++++++++++- .../main/resources/strings_hi-IN.properties | 18 +++++++++++++++++- .../main/resources/strings_hr-HR.properties | 18 +++++++++++++++++- .../main/resources/strings_it-CH.properties | 18 +++++++++++++++++- .../main/resources/strings_it-IT.properties | 18 +++++++++++++++++- .../main/resources/strings_ja-JP.properties | 18 +++++++++++++++++- .../main/resources/strings_nl-NL.properties | 18 +++++++++++++++++- .../main/resources/strings_no-NO.properties | 18 +++++++++++++++++- .../main/resources/strings_pl-PL.properties | 18 +++++++++++++++++- .../main/resources/strings_ps-AF.properties | 18 +++++++++++++++++- .../main/resources/strings_pt-PT.properties | 18 +++++++++++++++++- .../main/resources/strings_ro-RO.properties | 18 +++++++++++++++++- .../main/resources/strings_ru-RU.properties | 18 +++++++++++++++++- .../main/resources/strings_sv-SE.properties | 18 +++++++++++++++++- .../main/resources/strings_sw-KE.properties | 18 +++++++++++++++++- .../main/resources/strings_tr-TR.properties | 18 +++++++++++++++++- .../main/resources/strings_uk-UA.properties | 18 +++++++++++++++++- .../main/resources/strings_ur-PK.properties | 18 +++++++++++++++++- .../main/resources/strings_zh-CN.properties | 18 +++++++++++++++++- 67 files changed, 743 insertions(+), 50 deletions(-) diff --git a/sormas-api/src/main/resources/captions_cs-CZ.properties b/sormas-api/src/main/resources/captions_cs-CZ.properties index 23d095bae83..2c01d3492b1 100644 --- a/sormas-api/src/main/resources/captions_cs-CZ.properties +++ b/sormas-api/src/main/resources/captions_cs-CZ.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Podrobnosti o variantě choroby unassigned=Nepřiřazeno assign=Přiřadit assignToMe = Přiřadit mně +endOfProcessingDate=Datum ukončení zpracování +dearchiveReason=Důvod pro vyjmutí z archivu # About about=O aplikaci @@ -640,7 +642,7 @@ columnVaccineManufacturer=Výrobce očkovací látky # Community -Community=Community +Community=Komunita Community.archived=Archivováno Community.externalID=Externí ID @@ -1018,7 +1020,7 @@ districtActiveDistricts=Aktivní okresy districtArchivedDistricts=Archivované okresy districtAllDistricts=Všechny okresy -District=District +District=Okres District.archived=Archivováno District.epidCode=Epid kód District.growthRate=Míra růstu @@ -1083,7 +1085,7 @@ eventSearchEvent=Hledat událost eventSearchSpecificEvent=Hledat konkrétní událost linkEvent=Propojit případ linkEventGroup=Propojit skupinu událostí -eventSelect=Select event +eventSelect=Vyberte událost eventSelectGroup=Vyberte skupinu událostí eventDefaultView=Události eventActionsView=Akce @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Přidat účastníka eventParticipantContactCountOnlyWithSourceCaseInEvent=Počítá pouze kontakty, jejichž zdrojový případ souvisí s touto událostí eventParticipantSelect=Vyberte účastníka události eventParticipantCreateNew=Vytvořit nového účastníka události +eventParticipantActiveEventParticipants=Aktivní účastníci události +eventParticipantAllEventParticipants=Všichni účastníci události +eventParticipantArchivedEventParticipants=Účastníci archivované události EventParticipant=Účastník události EventParticipant.contactCount=Počet kontaktů @@ -1288,7 +1293,7 @@ exposureFlightNumber=Číslo letu exposureTimePeriod=Časové období exposureSourceCaseName=Název zdrojového případu -Exposure=Exposure +Exposure=Vystavení Exposure.probableInfectionEnvironment= Pravděpodobné infekční prostředí Exposure.startDate=Začátek expozice Exposure.endDate=Konec expozice diff --git a/sormas-api/src/main/resources/captions_de-CH.properties b/sormas-api/src/main/resources/captions_de-CH.properties index e0cd3b3f2ec..b6d3a68f378 100644 --- a/sormas-api/src/main/resources/captions_de-CH.properties +++ b/sormas-api/src/main/resources/captions_de-CH.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Details zur Krankheitsvariante unassigned=Nicht zugewiesen assign=Zuweisen assignToMe = Mir zuweisen +endOfProcessingDate=Verarbeitungsende-Datum +dearchiveReason=Grund der Dearchivierung # About about=Info @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Ereignisteilnehmer hinzufügen eventParticipantContactCountOnlyWithSourceCaseInEvent=Zählt nur Kontakte, deren Indexfall mit diesem Ereignis verbunden ist eventParticipantSelect=Ereignisteilnehmer auswählen eventParticipantCreateNew=Neuen Ereignisteilnehmer erstellen +eventParticipantActiveEventParticipants=Aktive Ereignisteilnehmer +eventParticipantAllEventParticipants=Alle Ereignisteilnehmer +eventParticipantArchivedEventParticipants=Archivierte Ereignisteilnehmer EventParticipant=Ereignisteilnehmer EventParticipant.contactCount=Kontaktzahl @@ -1412,7 +1417,7 @@ HealthConditions.obesity=Adipositas HealthConditions.currentSmoker=Aktuell Raucher HealthConditions.formerSmoker=Ehemaliger Raucher HealthConditions.asthma=Asthma bronchiale -HealthConditions.sickleCellDisease=Sickle cell disease +HealthConditions.sickleCellDisease=Sichelzellenanämie HealthConditions.immunodeficiencyIncludingHiv=Immunschwäche, einschließlich HIV # Import diff --git a/sormas-api/src/main/resources/captions_de-DE.properties b/sormas-api/src/main/resources/captions_de-DE.properties index e3f3fdc92c9..0dac4dedae7 100644 --- a/sormas-api/src/main/resources/captions_de-DE.properties +++ b/sormas-api/src/main/resources/captions_de-DE.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Details zur Krankheitsvariante unassigned=Nicht zugewiesen assign=Zuweisen assignToMe = Mir zuweisen +endOfProcessingDate=Verarbeitungsende-Datum +dearchiveReason=Grund der Dearchivierung # About about=Info @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Ereignisteilnehmer hinzufügen eventParticipantContactCountOnlyWithSourceCaseInEvent=Zählt nur Kontakte, deren Indexfall mit diesem Ereignis verbunden ist eventParticipantSelect=Ereignisteilnehmer auswählen eventParticipantCreateNew=Neuen Ereignisteilnehmer erstellen +eventParticipantActiveEventParticipants=Aktive Ereignisteilnehmer +eventParticipantAllEventParticipants=Alle Ereignisteilnehmer +eventParticipantArchivedEventParticipants=Archivierte Ereignisteilnehmer EventParticipant=Ereignisteilnehmer EventParticipant.contactCount=Anzahl der Kontakte diff --git a/sormas-api/src/main/resources/captions_en-AF.properties b/sormas-api/src/main/resources/captions_en-AF.properties index b61e42fd6c4..8839fb116ef 100644 --- a/sormas-api/src/main/resources/captions_en-AF.properties +++ b/sormas-api/src/main/resources/captions_en-AF.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=About @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_en-GH.properties b/sormas-api/src/main/resources/captions_en-GH.properties index 78974f4b078..6aba90760a9 100644 --- a/sormas-api/src/main/resources/captions_en-GH.properties +++ b/sormas-api/src/main/resources/captions_en-GH.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=About @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_en-NG.properties b/sormas-api/src/main/resources/captions_en-NG.properties index 10244f6a600..ff37eb6bd68 100644 --- a/sormas-api/src/main/resources/captions_en-NG.properties +++ b/sormas-api/src/main/resources/captions_en-NG.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=About @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_es-CU.properties b/sormas-api/src/main/resources/captions_es-CU.properties index b0851b435cc..0dda0628315 100644 --- a/sormas-api/src/main/resources/captions_es-CU.properties +++ b/sormas-api/src/main/resources/captions_es-CU.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Detalles de variante de enfermedad unassigned=Sin asignar assign=Asignar assignToMe = Asignar a mí +endOfProcessingDate=Fecha de fin de procesamiento +dearchiveReason=Razón de desarchivado # About about=Acerca de @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Añadir participante eventParticipantContactCountOnlyWithSourceCaseInEvent=Solo cuenta contactos cuyo caso de origen está relacionado a este evento eventParticipantSelect=Seleccionar participante de evento eventParticipantCreateNew=Crear nuevo participante de evento +eventParticipantActiveEventParticipants=Participantes de evento activos +eventParticipantAllEventParticipants=Todos los participantes de evento +eventParticipantArchivedEventParticipants=Participantes de evento archivados EventParticipant=Participante de evento EventParticipant.contactCount=Número de contactos @@ -1409,10 +1414,10 @@ HealthConditions.otherConditions=Otras condiciones preexistentes relevantes HealthConditions.immunodeficiencyOtherThanHiv=Inmunodeficiencia distinta al VIH HealthConditions.cardiovascularDiseaseIncludingHypertension=Enfermedad cardiovascular, incluída la hipertensión HealthConditions.obesity=Obesidad -HealthConditions.currentSmoker=Current smoker -HealthConditions.formerSmoker=Former smoker +HealthConditions.currentSmoker=Fumador activo +HealthConditions.formerSmoker=Ex fumador HealthConditions.asthma=Asma -HealthConditions.sickleCellDisease=Sickle cell disease +HealthConditions.sickleCellDisease=Enfermedad de células falciformes HealthConditions.immunodeficiencyIncludingHiv=Inmunodeficiencia, incluido el VIH # Import diff --git a/sormas-api/src/main/resources/captions_es-EC.properties b/sormas-api/src/main/resources/captions_es-EC.properties index 1847f098faf..77256ebe73b 100644 --- a/sormas-api/src/main/resources/captions_es-EC.properties +++ b/sormas-api/src/main/resources/captions_es-EC.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=About @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_es-ES.properties b/sormas-api/src/main/resources/captions_es-ES.properties index 4f8e2adc6c2..2c7090fc48a 100644 --- a/sormas-api/src/main/resources/captions_es-ES.properties +++ b/sormas-api/src/main/resources/captions_es-ES.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=About @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_fa-AF.properties b/sormas-api/src/main/resources/captions_fa-AF.properties index a341da180e2..e9bd0755c66 100644 --- a/sormas-api/src/main/resources/captions_fa-AF.properties +++ b/sormas-api/src/main/resources/captions_fa-AF.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=در باره @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_fi-FI.properties b/sormas-api/src/main/resources/captions_fi-FI.properties index 0a36a205e62..cfc0ba14b54 100644 --- a/sormas-api/src/main/resources/captions_fi-FI.properties +++ b/sormas-api/src/main/resources/captions_fi-FI.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=About @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_fil-PH.properties b/sormas-api/src/main/resources/captions_fil-PH.properties index 4f8e2adc6c2..2c7090fc48a 100644 --- a/sormas-api/src/main/resources/captions_fil-PH.properties +++ b/sormas-api/src/main/resources/captions_fil-PH.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=About @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_fj-FJ.properties b/sormas-api/src/main/resources/captions_fj-FJ.properties index 4f8e2adc6c2..2c7090fc48a 100644 --- a/sormas-api/src/main/resources/captions_fj-FJ.properties +++ b/sormas-api/src/main/resources/captions_fj-FJ.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=About @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_fr-CH.properties b/sormas-api/src/main/resources/captions_fr-CH.properties index 57840783920..64eecd4ef7f 100644 --- a/sormas-api/src/main/resources/captions_fr-CH.properties +++ b/sormas-api/src/main/resources/captions_fr-CH.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=À propos @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Ajouter un participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Uniquement les contacts dont le cas source est lié à l'événement spécifié eventParticipantSelect=Sélectionner un participant eventParticipantCreateNew=Créer un nouveau participant à l'événement +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Personnes impliquées EventParticipant.contactCount=Nombre de contacts diff --git a/sormas-api/src/main/resources/captions_fr-FR.properties b/sormas-api/src/main/resources/captions_fr-FR.properties index ad06918d9ca..cd2eb8594fd 100644 --- a/sormas-api/src/main/resources/captions_fr-FR.properties +++ b/sormas-api/src/main/resources/captions_fr-FR.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Non assigné assign=Affecter assignToMe = Me l'assigner +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=À propos de @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Ajouter un participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Seulement les contacts avec le cas source lié à l'événement spécifié eventParticipantSelect=Sélectionner un participant eventParticipantCreateNew=Créer un nouveau participant à l'événement +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Participant à l'événement EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_hi-IN.properties b/sormas-api/src/main/resources/captions_hi-IN.properties index 4f8e2adc6c2..2c7090fc48a 100644 --- a/sormas-api/src/main/resources/captions_hi-IN.properties +++ b/sormas-api/src/main/resources/captions_hi-IN.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=About @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_hr-HR.properties b/sormas-api/src/main/resources/captions_hr-HR.properties index 4f8e2adc6c2..2c7090fc48a 100644 --- a/sormas-api/src/main/resources/captions_hr-HR.properties +++ b/sormas-api/src/main/resources/captions_hr-HR.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=About @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_it-CH.properties b/sormas-api/src/main/resources/captions_it-CH.properties index 275d322ef35..a59ec69d6f2 100644 --- a/sormas-api/src/main/resources/captions_it-CH.properties +++ b/sormas-api/src/main/resources/captions_it-CH.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=About @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Partecipante all'evento EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_it-IT.properties b/sormas-api/src/main/resources/captions_it-IT.properties index 59baf5d68f9..f2b8963602c 100644 --- a/sormas-api/src/main/resources/captions_it-IT.properties +++ b/sormas-api/src/main/resources/captions_it-IT.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=About @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Partecipante all'evento EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_ja-JP.properties b/sormas-api/src/main/resources/captions_ja-JP.properties index 4f8e2adc6c2..2c7090fc48a 100644 --- a/sormas-api/src/main/resources/captions_ja-JP.properties +++ b/sormas-api/src/main/resources/captions_ja-JP.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=About @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_nl-NL.properties b/sormas-api/src/main/resources/captions_nl-NL.properties index 2434db79b3a..e8f2b523a0f 100644 --- a/sormas-api/src/main/resources/captions_nl-NL.properties +++ b/sormas-api/src/main/resources/captions_nl-NL.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=About @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_no-NO.properties b/sormas-api/src/main/resources/captions_no-NO.properties index 4f8e2adc6c2..2c7090fc48a 100644 --- a/sormas-api/src/main/resources/captions_no-NO.properties +++ b/sormas-api/src/main/resources/captions_no-NO.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=About @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_pl-PL.properties b/sormas-api/src/main/resources/captions_pl-PL.properties index 4f8e2adc6c2..2c7090fc48a 100644 --- a/sormas-api/src/main/resources/captions_pl-PL.properties +++ b/sormas-api/src/main/resources/captions_pl-PL.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=About @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_ps-AF.properties b/sormas-api/src/main/resources/captions_ps-AF.properties index ce5cdfbfb6c..cc669bfa437 100644 --- a/sormas-api/src/main/resources/captions_ps-AF.properties +++ b/sormas-api/src/main/resources/captions_ps-AF.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=په هکله @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_pt-PT.properties b/sormas-api/src/main/resources/captions_pt-PT.properties index ae9ce71d717..5699b55df2e 100644 --- a/sormas-api/src/main/resources/captions_pt-PT.properties +++ b/sormas-api/src/main/resources/captions_pt-PT.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=About @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_ro-RO.properties b/sormas-api/src/main/resources/captions_ro-RO.properties index 4f8e2adc6c2..2c7090fc48a 100644 --- a/sormas-api/src/main/resources/captions_ro-RO.properties +++ b/sormas-api/src/main/resources/captions_ro-RO.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=About @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_ru-RU.properties b/sormas-api/src/main/resources/captions_ru-RU.properties index c1f69a1abfe..13b39973a22 100644 --- a/sormas-api/src/main/resources/captions_ru-RU.properties +++ b/sormas-api/src/main/resources/captions_ru-RU.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Детали варианта заболевания unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=О программе @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_sv-SE.properties b/sormas-api/src/main/resources/captions_sv-SE.properties index 4f8e2adc6c2..2c7090fc48a 100644 --- a/sormas-api/src/main/resources/captions_sv-SE.properties +++ b/sormas-api/src/main/resources/captions_sv-SE.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=About @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_sw-KE.properties b/sormas-api/src/main/resources/captions_sw-KE.properties index 4f8e2adc6c2..2c7090fc48a 100644 --- a/sormas-api/src/main/resources/captions_sw-KE.properties +++ b/sormas-api/src/main/resources/captions_sw-KE.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=About @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_tr-TR.properties b/sormas-api/src/main/resources/captions_tr-TR.properties index 4f8e2adc6c2..2c7090fc48a 100644 --- a/sormas-api/src/main/resources/captions_tr-TR.properties +++ b/sormas-api/src/main/resources/captions_tr-TR.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=About @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_uk-UA.properties b/sormas-api/src/main/resources/captions_uk-UA.properties index 4f8e2adc6c2..2c7090fc48a 100644 --- a/sormas-api/src/main/resources/captions_uk-UA.properties +++ b/sormas-api/src/main/resources/captions_uk-UA.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=Disease variant details unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=About @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/captions_ur-PK.properties b/sormas-api/src/main/resources/captions_ur-PK.properties index 910e472ff8f..fab30921f90 100644 --- a/sormas-api/src/main/resources/captions_ur-PK.properties +++ b/sormas-api/src/main/resources/captions_ur-PK.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=بیماری کے مختلف قسم کی تفصیلات unassigned=غیر مختص assign=مختص assignToMe = مجھے سونپا ہوا +endOfProcessingDate=پروسیسنگ کی تاریخ کا اختتام +dearchiveReason=ڈی آرکائیو کی وجہ # About about=متعلق @@ -315,7 +317,7 @@ CampaignFormData.edit=ترمیم کریں # CaseData caseCasesList=کیسز کی فہرست caseInfrastructureDataChanged=انفراسٹرکچر کا ڈیٹا بدل گیا ہے -caseCloneCaseWithNewDisease=Generate new case for +caseCloneCaseWithNewDisease=کے لیے نیا کیس بنائیں caseContacts=روابط caseDocuments=کیس کے دستاویزات caseEditData=ڈیٹا میں ترمیم کریں @@ -601,7 +603,7 @@ caseImportMergeCase=موجودہ کیس کو، امپورٹ شدہ کیس کی # CasePreviousHospitalization CasePreviousHospitalization=گزشتہ ہسپتال میں داخلہ CasePreviousHospitalization.admissionAndDischargeDate=داخلہ اور چھٹی کی تاریخ -CasePreviousHospitalization.admittedToHealthFacility =Was patient admitted at the facility as an inpatient? +CasePreviousHospitalization.admittedToHealthFacility =کیا مریض کو، داخلی مریض کے طور پر سہولت گاہ میں داخل کیا گیا تھا؟ CasePreviousHospitalization.admissionDate=داخلے کی تاریخ CasePreviousHospitalization.description=تفصیل CasePreviousHospitalization.dischargeDate=چھٹی یا منتقلی کی تاریخ @@ -1083,7 +1085,7 @@ eventSearchEvent=تقریب تلاش کریں eventSearchSpecificEvent=مخصوص تقریب تلاش کریں linkEvent=تقریب سے مںسلک کریں linkEventGroup=تقریب کے گروپ کو لنک کریں -eventSelect=Select event +eventSelect=تقریب کا انتخاب کریں eventSelectGroup=تقریب کے گروپ انتخاب کریں eventDefaultView=تقریبات eventActionsView=اعمال @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=شریک شامل کریں eventParticipantContactCountOnlyWithSourceCaseInEvent=صرف ان رابطوں کو شمار کرتا ہے جن کا سورس کیس اس تقریب سے متعلق ہے eventParticipantSelect=تقریب کے شریک کو منتخب کریں eventParticipantCreateNew=تقریب کا نیا شریک بنائیں +eventParticipantActiveEventParticipants=فعال تقریب کے شرکاء +eventParticipantAllEventParticipants=تمام تقریب کے شرکاء +eventParticipantArchivedEventParticipants=آرکائیو شدہ تقریب کے شرکاء EventParticipant=تقریب حصہ لینے والا EventParticipant.contactCount=رابطے کی تعداد @@ -1412,7 +1417,7 @@ HealthConditions.obesity=موٹاپا HealthConditions.currentSmoker=موجودہ سگریٹ نوش HealthConditions.formerSmoker=سابقہ سگریٹ نوش HealthConditions.asthma=دمہ -HealthConditions.sickleCellDisease=Sickle cell disease +HealthConditions.sickleCellDisease=سکل سیل کی بیماری HealthConditions.immunodeficiencyIncludingHiv=ایچ آئی وی سمیت امیونو کی کمی # Import @@ -2314,7 +2319,7 @@ travelEntryOnlyRecoveredEntries=صرف بازیافت شدہ اندراجات travelEntryOnlyVaccinatedEntries=صرف ویکسین شدہ اندراجات travelEntryOnlyEntriesTestedNegative=صرف وہ اندراجات, جن کا ٹیسٹ منفی آیا travelEntryOnlyEntriesConvertedToCase=صر فوہ اندراجات، جن کو کیس میں تبدیل کیا گیا -travelEntryOpenResultingCase=Open case of this travel entry +travelEntryOpenResultingCase=اس ٹریول انٹری کے لۓ کیس اوپن کیس travelEntryActiveTravelEntries=فعال سفری اندراجات travelEntryArchivedTravelEntries=آرکائیوڈ سفری اندراجات travelEntryAllTravelEntries=تمام سفری اندراجات diff --git a/sormas-api/src/main/resources/captions_zh-CN.properties b/sormas-api/src/main/resources/captions_zh-CN.properties index 3e7729c6763..0347ef2f1b1 100644 --- a/sormas-api/src/main/resources/captions_zh-CN.properties +++ b/sormas-api/src/main/resources/captions_zh-CN.properties @@ -60,6 +60,8 @@ diseaseVariantDetails=疾病变化详情 unassigned=Unassigned assign=Assign assignToMe = Assign to me +endOfProcessingDate=End of processing date +dearchiveReason=De-archive reason # About about=关于 @@ -1214,6 +1216,9 @@ eventParticipantAddPerson=Add participant eventParticipantContactCountOnlyWithSourceCaseInEvent=Only counts contacts whose source case is related to this event eventParticipantSelect=Select event participant eventParticipantCreateNew=Create new event participant +eventParticipantActiveEventParticipants=Active event participants +eventParticipantAllEventParticipants=All event participants +eventParticipantArchivedEventParticipants=Archived event participants EventParticipant=Event participant EventParticipant.contactCount=Contact count diff --git a/sormas-api/src/main/resources/enum_cs-CZ.properties b/sormas-api/src/main/resources/enum_cs-CZ.properties index 8069dabff37..592028621d7 100644 --- a/sormas-api/src/main/resources/enum_cs-CZ.properties +++ b/sormas-api/src/main/resources/enum_cs-CZ.properties @@ -297,7 +297,7 @@ DatabaseTable.EVENTS = Události DatabaseTable.EVENTGROUPS = Skupiny událostí DatabaseTable.EVENTPARTICIPANTS = Dotčené osoby DatabaseTable.EXPOSURES = Vystavení -DatabaseTable.ACTIVITIES_AS_CASE = Activities as case +DatabaseTable.ACTIVITIES_AS_CASE = Aktivity podle případu DatabaseTable.FACILITIES = Zařízení DatabaseTable.POINTS_OF_ENTRY = Místa vstupu DatabaseTable.HEALTH_CONDITIONS = Zdravotní podmínky @@ -718,7 +718,7 @@ HabitationType.MEDICAL=Zůstat v lékařské instituci HabitationType.OTHER=Ostatní HospitalizationReasonType.REPORTED_DISEASE=Ohlášená choroba -HospitalizationReasonType.ISOLATION=Isolation +HospitalizationReasonType.ISOLATION=Izolace HospitalizationReasonType.OTHER=Jiný důvod HospitalizationReasonType.UNKNOWN=Neznámý @@ -1283,7 +1283,7 @@ UserRight.CONTACT_EXPORT = Exportovat kontakty ze SORMAS UserRight.CONTACT_SEE_ARCHIVED = Zobrazit archivované kontakty UserRight.CONTACT_VIEW = Zobrazit existující kontakty UserRight.DASHBOARD_CONTACT_VIEW = Přístup k ovládacínu panelu kontaktního orgánu -UserRight.DASHBOARD_SURVEILLANCE_VIEW = Access the surveillance supervisor dashboard +UserRight.DASHBOARD_SURVEILLANCE_VIEW = Přístup do ovládacího panelu dozorčího orgánu UserRight.DATABASE_EXPORT_ACCESS = Exportovat celou databázi UserRight.EVENT_ARCHIVE = Archivovat události UserRight.EVENT_CREATE = Vytvořit nové události @@ -1353,7 +1353,7 @@ UserRight.INFRASTRUCTURE_EXPORT = Exportovat data infrastruktury ze SORMAS UserRight.INFRASTRUCTURE_IMPORT = Importovat data infrastruktury UserRight.INFRASTRUCTURE_ARCHIVE = Importovat data infrastruktury UserRight.DASHBOARD_CONTACT_VIEW_TRANSMISSION_CHAINS = Zobrazit řetězce přenosu kontaktů na ovládacím panelu -UserRight.DASHBOARD_CAMPAIGNS_VIEW = Access campaigns dashboard +UserRight.DASHBOARD_CAMPAIGNS_VIEW = Ovládací panel kampaní přístupu UserRight.CASE_CLINICIAN_VIEW = Access case sections concerned with clinician UserRight.THERAPY_VIEW = Zobrazit existující terapie UserRight.PRESCRIPTION_CREATE = Vytvořit nový předpis diff --git a/sormas-api/src/main/resources/strings_cs-CZ.properties b/sormas-api/src/main/resources/strings_cs-CZ.properties index b280a8e3fd9..f6da3ca4821 100644 --- a/sormas-api/src/main/resources/strings_cs-CZ.properties +++ b/sormas-api/src/main/resources/strings_cs-CZ.properties @@ -78,6 +78,7 @@ date = Datum nameOf = Název %s uuidOf = UUID %s listOf = Seznam %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = Prodloužili jste následná opatření. Měl confirmationArchiveCampaign = Opravdu chcete archivovat tuto kampaň? Toto neodstraní ze systému ani ze statistik, ale skryje pouze z běžného adresáře kampaní. confirmationArchiveCase = Opravdu chcete tento případ archivovat? To jej neodstraní ze systému ani ze statistik, ale skryje pouze z adresáře běžných případů. confirmationArchiveCases = Opravdu chcete archivovat všech %d vybraných případů? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Opravdu chcete archivovat tuto událost? To ji neodstraní ze systému ani ze statistik, ale skryje pouze z běžného adresáře událostí. confirmationArchiveEvents = Jste si jisti, že chcete archivovat všech %d vybraných událostí? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Opravdu chcete archivovat tuto imunizaci? Toto neodstraní ze systému ani ze statistik, ale skryje pouze z normální adresáře imunizace. confirmationArchiveTask = Opravdu chcete archivovat všech %d vybraných úkolů? confirmationArchiveTasks = Opravdu chcete archivovat tento úkol? To jej neodstraní ze systému ani ze statistik, ale skryje pouze před běžným řízením úkolů. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Skutečně změnit případovou chorobu? confirmationDearchiveCampaign = Jste si jisti, že chcete vyjmout z archivu tuto kampaň? Tím se znovu zobrazí v běžném adresáři kampaní. confirmationDearchiveCase = Jste si jisti, že chcete vyjmout z archivu tento případ? Tím se znovu zobrazí v adresáři běžných případů. confirmationDearchiveCases = Jste si jisti, že chcete vyjmout z archivu všech %d vybraných případů? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Jste si jisti, že chcete vyjmout z archivu tuto událost? Tato akce se znovu zobrazí v normální adresáři událostí. confirmationDearchiveEvents = Jste si jisti, že chcete vyjmout z archivu všech %d vybraných události? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Jste si jisti, že chcete vyjmout z archivu tuto skupinu událostí? Ta se znovu zobrazí v normální složce skupiny událostí. confirmationDeleteCases = Jste si jisti, že chcete odstranit všech %d vybraných případů? confirmationDeleteContacts = Jste si jisti, že chcete odstranit všech %d vybraných kontaktů? @@ -365,7 +370,9 @@ headingAllContacts = Všechny kontakty headingAnimalContacts = Kontakty se zvířaty headingArchiveCampaign = Archivovat kampaň headingArchiveCase = Archivovat případ +headingArchiveContact = Archive contact headingArchiveEvent = Archivovat událost +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archivovat skupinu událostí headingArchiveImmunization = Archiv imuniizace headingArchiveTravelEntry = Archivovat cestovní vstup @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Vytvořit nový výsledek testu patogenu headingDatabaseExportFailed = Export databáze selhal headingDearchiveCampaign = Vyjmout z archivu kampaň headingDearchiveCase = Obnova archivace případu +headingDearchiveContact = De-Archive contact headingDearchiveEvent = Obnova archivaci události +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = Vyjmout z archivu skupinu událostí headingDearchiveImmunization = Vyjmout z archivu imunizaci headingDearchiveTravelEntry = Vyarchivovat cestovní vstup @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Prosím zdokumentujte VŠECHNY relevantní infoAddTestsToSample = Pro přidání výsledku testu k tomuto vzorku musí být nejprve označen jako přijatý. infoArchivedCases = Případy jsou automaticky archivovány po %d dnech beze změn dat. infoArchivedEvents = Události jsou automaticky archivovány po %d dnech bez změn dat. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Záznamy o cestování jsou automaticky archivovány po %d dnech beze změn dat. infoAssigneeMissingEmail = Uživatel přiřazený k této úloze nemá e-mailovou adresu, a proto nebude informován. infoObserverMissingEmail = Alespoň jeden z pozorovatelů tohoto úkolu neposkytl e-mailovou adresu, a proto nebude informován. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = Databáze již obsahuje minimálně je infoSelectOrCreatePersonForImport = Databáze již obsahuje nejméně jednu osobu, která se zdá být velmi podobná osobním údajům importovaného záznamu.

    Prosím, prohlédněte si seznam osob. Pokud jste si jisti, že některá z těchto osob odpovídá osobě importovaného záznamu, vyberte ji a klikněte na tlačítko Uložit. V opačném případě klikněte na Vytvořit novou osobu a vytvořte novou osobu.

    Jestliže si nejste jisti, můžete toto okno zahodit a odstranit tak záznam z aktuálního importu. infoSelectOrCreatePersonForEventParticipant = Databáze již obsahuje alespoň jednu osobu, která se zdá být velmi podobná osobním údajům vytvořeného účastníka události.

    Prohlédněte si prosím seznam osob. Pokud se domníváte, že jedna z těchto osob odpovídá vaší události, vyberte ji a klikněte na tlačítko Uložit. V opačném případě klikněte na Vytvořit novou osobu pro vytvoření nové osoby události.

    Pokud si nejste jisti, můžete toto okno zrušit a zrušit proces vytváření účastníků události. infoSelectOrCreatePersonForLabMessage = Databáze již obsahuje alespoň jednu osobu, která se zdá být velmi podobná osobním údajům zprávy laboratoře.

    Prohlédněte si prosím seznam osob. Pokud se domníváte, že jedna z těchto osob se shoduje s osobou ve zprávě laboratoře, vyberte ji a klikněte na tlačítko Potvrdit. V opačném případě klikněte na Vytvořit novou osobu, abyste vytvořili novou osobu pro zprávu laboratoře.

    Pokud si nejste jisti, můžete toto okno zrušit a zrušit proces. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = Databáze již obsahuje datový soubor pro formulář %s v kampani %s pro danou komunitu a datum. Podívejte se prosím na podrobnosti pro existující datový soubor a zvolte Přeskočit, pokud chcete zachovat existující data nebo Přepsat, pokud chcete nahradit existující data daty, které jste importovali. pseudonymizedCasesSelectedWarning = Pro hromadně upravované případy máte pouze omezený přístup k citlivým údajům. Pro tyto případy bude hodnota vložená do "Popis místa" ignorována. pseudonymizedEntitiesSelectedWarning = Máte pouze omezený přístup k některým vybraným entitám. Chcete-li pokračovat, zrušte výběr pseudonymizovaných entit. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = Všechny kontakty jsou již propojeny s vybra messageAllContactsLinkedToEvent = Všechny kontakty byly propojeny s vybranou událostí. messageAlreadyEventParticipant = Vybraná osoba je již definována jako účastník této události. messageAnimalContactsHint = Uveďte prosím odpověď týkající se všech zvířat (živých nebo mrtvých), jimž byla osoba přímo vystavena (např. při lovu, doteku, jídlem) během inkubační doby +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Kampaň byla archivována messageCampaignCreated = Nová kampaň byla vytvořena messageCampaignDearchived = Kampaň byla vyjmuta z archivu @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=Právě jste si uložili pozitivní laborat messageConvertEventParticipantToCaseDifferentDiseases=Právě jste si uložili pozitivní laboratorní výsledek na jiné onemocnění, než je onemocnění v případě události. Chcete vytvořit případ s touto nemocí pro osobu účastníka události? Případ nebude spojen s účastníkem události. messageConvertEventParticipantToCaseNoDisease=Právě jste si uložili pozitivní laboratorní výsledek pro událost bez onemocnění. Chcete vytvořit případ s touto nemocí pro osobu účastníka události? Konečný laboratorní výsledek vzorku bude automaticky nastaven jako pozitivní, ale případ nebude spojen s účastníkem události. messageContactCreated=Nový kontakt byl vytvořen +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Data kontaktu uložena messageContactsDeleted = Všechny vybrané kontakty byly odstraněny messageContactsEdited = Všechny kontakty byly upraveny @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = Odkaz mezi tímto případem a událostí by messageEventUnlinkedFromEventGroup = Spojení mezi touto událostí a skupinou událostí bylo úspěšně odstraněno messageEventDearchived = Událost byla vyjmuta z archivu messageEventGroupDearchived = Skupina událostí byla vyjmuta z archivu +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = Nová osoba vytvořena messageEventParticipantSaved = Údaje o osobě byly uloženy messageEventParticipantsDeleted = Všichni vybraní účastníci události byli odstraněni @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Neplatná data -reloadPageToSeeChanges = Prosím obnovte stránku pro zobrazení nejnovějších změn \ No newline at end of file +reloadPageToSeeChanges = Prosím obnovte stránku pro zobrazení nejnovějších změn diff --git a/sormas-api/src/main/resources/strings_de-CH.properties b/sormas-api/src/main/resources/strings_de-CH.properties index e23d430f3d8..12c5a4abda1 100644 --- a/sormas-api/src/main/resources/strings_de-CH.properties +++ b/sormas-api/src/main/resources/strings_de-CH.properties @@ -78,6 +78,7 @@ date = Datum nameOf = Name von %s uuidOf = UUID von %s listOf = Liste von %s +mapOf = Karte <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = Sie haben das Follow-up verlängert. Soll das confirmationArchiveCampaign = Sind Sie sicher, dass Sie diese Kampagne archivieren wollen? Dadurch wird sie weder aus dem System noch aus den Statistiken entfernt, sondern nur aus dem normalen Kampagnen-Verzeichnis ausgeblendet. confirmationArchiveCase = Sind Sie sicher, dass Sie diesen Fall archivieren möchten? Dies entfernt ihn nicht aus dem System oder irgendwelchen Statistiken, sondern blendet ihn nur im normalen Fallverzeichnis aus. confirmationArchiveCases = Sind Sie sicher, dass Sie alle %d ausgewählten Fälle archivieren möchten? +confirmationArchiveContact = Sind Sie sicher, dass Sie diesen Kontakt archivieren möchten? Dies entfernt ihn nicht aus dem System oder irgendwelchen Statistiken, sondern versteckt sie nur im normalen Kontaktverzeichnis. confirmationArchiveEvent = Sind Sie sicher, dass Sie dieses Ereignis archivieren möchten? Dies entfernt es nicht aus dem System oder irgendwelchen Statistiken, sondern blendet es nur im normalen Ereignisverzeichnis aus. confirmationArchiveEvents = Sind Sie sicher, dass Sie alle %d ausgewählten Ereignisse archivieren möchten? +confirmationArchiveEventParticipant = Sind Sie sicher, dass Sie diesen Ereignisteilnehmer archivieren möchten? Dies wird ihn nicht aus dem System oder irgendeiner Statistik entfernen, sondern nur aus der Liste der Ereignisteilnehmer ausblenden. confirmationArchiveImmunization = Sind Sie sicher, dass Sie diese Immunisierung archivieren möchten? Dies entfernt sie nicht aus dem System oder irgendeiner Statistik, sondern versteckt sie nur im normalen Immunisierungsverzeichnis. confirmationArchiveTask = Sind Sie sicher, dass Sie alle %d ausgewählten Aufgaben archivieren möchten? confirmationArchiveTasks = Sind Sie sicher, dass Sie diese Aufgabe archivieren möchten? Dies entfernt sie nicht aus dem System oder irgendwelchen Statistiken, sondern versteckt sie nur in der normalen Aufgabenverwaltung. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Fallerkrankung wirklich ändern? confirmationDearchiveCampaign = Sind Sie sicher, dass Sie diese Kampagne de-archivieren wollen? Dadurch wird sie wieder im normalen Kampagnen-Verzeichnis erscheinen. confirmationDearchiveCase = Sind Sie sicher, dass Sie diesen Fall de-archivieren möchten? Er wird dann im normalen Verzeichnis wieder angezeigt. confirmationDearchiveCases = Sind Sie sicher, dass Sie alle %d ausgewählten Fälle de-archivieren möchten? +confirmationDearchiveContact = Sind Sie sicher, dass Sie diesen Fall de-archivieren möchten? Er wird dann im normalen Fallverzeichnis wieder angezeigt. confirmationDearchiveEvent = Sind Sie sicher, dass Sie dieses Ereignis de-archivieren möchten? Er wird dann im normalen Ereignisverzeichnis wieder angezeigt. confirmationDearchiveEvents = Sind Sie sicher, dass Sie alle %d ausgewählten Ereignisse de-archivieren möchten? +confirmationDearchiveEventParticipant = Sind Sie sicher, dass Sie diesen Ereignisteilnehmer dearchivieren möchten? Dies wird ihn in der normalen Ereignisteilnehmerliste wieder erscheinen lassen. confirmationDearchiveEventGroup = Sind Sie sicher, dass Sie diese Ereignisgruppe dearchivieren möchten? Dadurch wird sie im normalen Ereignisgruppenverzeichnis wieder angezeigt. confirmationDeleteCases = Sind Sie sicher, dass Sie alle %d ausgewählten Fälle löschen möchten? confirmationDeleteContacts = Sind Sie sicher, dass Sie alle %d ausgewählten Kontakte löschen möchten? @@ -365,7 +370,9 @@ headingAllContacts = Alle Kontakte headingAnimalContacts = Tierkontakte headingArchiveCampaign = Archiviere Kampagnen headingArchiveCase = Fall archivieren +headingArchiveContact = Kontakt archivieren headingArchiveEvent = Ereignis archivieren +headingArchiveEventParticipant = Ereignisteilnehmer archivieren headingArchiveEventGroup = Ereignisgruppe archivieren headingArchiveImmunization = Immunisierung archivieren headingArchiveTravelEntry = Einreise archivieren @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Neues Erregertestergebnis erstellen headingDatabaseExportFailed = Datenbank-Export fehlgeschlagen headingDearchiveCampaign = Kampagne de-archivieren headingDearchiveCase = Fall de-archivieren +headingDearchiveContact = Kontakt de-archivieren headingDearchiveEvent = Ereignis de-archivieren +headingDearchiveEventParticipant = Ereignisteilnehmer de-archivieren headingDearchiveEventGroup = Ereignisgruppe de-archivieren headingDearchiveImmunization = Immunisierung de-archivieren headingDearchiveTravelEntry = Einreise de-archivieren @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Bitte dokumentieren Sie ALLE relevanten Akt infoAddTestsToSample = Um ein Testergebnis zu dieser Probe hinzuzufügen, muss es zuerst als empfangen markiert werden. infoArchivedCases = Fälle werden automatisch nach %d Tagen ohne Änderungen der Daten archiviert. infoArchivedEvents = Ereignisse werden automatisch nach %d Tagen ohne Änderungen der Daten archiviert. +infoArchivedEventParticipants = Ereignisteilnehmer werden nach %d Tagen automatisch ohne Änderungen der Daten archiviert. infoArchivedTravelEntries = Einreisen werden nach %d Tagen automatisch ohne Änderungen der Daten archiviert. infoAssigneeMissingEmail = Der dieser Aufgabe zugewiesene Benutzer hat keine E-Mail-Adresse angegeben und wird daher nicht benachrichtigt. infoObserverMissingEmail = Mindestens einer der Beobachter dieser Aufgabe hat keine E-Mail-Adresse angegeben und wird daher nicht benachrichtigt. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = Die Datenbank enthält bereits mindest infoSelectOrCreatePersonForImport = Die Datenbank enthält bereits mindestens eine Person, die den persönlichen Angaben des importierten Eintrags sehr ähnlich zu sein scheint.

    Bitte schauen Sie sich die Liste der Personen an. Wenn Sie sicher sind, dass eine dieser Personen mit der Person des importierten Eintrags übereinstimmt, wählen Sie es aus und klicken Sie auf Speichern. Ansonsten klicken Sie auf Neue Person anlegen, um eine neue Person zu erstellen.

    Wenn Sie sich nicht sicher sind, können Sie dieses Fenster verwerfen, um den Eintrag vom aktuellen Import zu entfernen. infoSelectOrCreatePersonForEventParticipant = Die Datenbank enthält bereits mindestens eine Person, die dem Ereignis-Kontakt sehr ähnlich zu sein scheint.

    Bitte schauen Sie sich die Liste der Personen an. Wenn Sie sicher sind, dass eine dieser Personen mit Ihrer Kontaktperson übereinstimmt, wählen Sie sie aus und klicken Sie auf Speichern. Ansonsten klicken Sie auf Neue Person anlegen, um eine neue Person für Ihren Kontakt zu erstellen.

    Wenn Sie sich unsicher sind, können Sie dieses Fenster schließen und die Ereignis-Kontakterstellung abbrechen. infoSelectOrCreatePersonForLabMessage = Die Datenbank enthält bereits mindestens eine Person, die den persönlichen Angaben in der Labormeldung sehr ähnlich zu sein scheint.

    Bitte schauen Sie sich die Liste der Personen an. Wenn Sie sicher sind, dass eine dieser Personen mit der Person in der Labormeldung übereinstimmt, wählen Sie sie aus und klicken Sie auf Speichern. Ansonsten klicken Sie auf Neue Person erstellen, um eine neue Person zu der Labormeldung zu erstellen.

    Wenn Sie sich nicht sicher sind, können Sie dieses Fenster verwerfen und den Prozess abbrechen. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = Die Datenbank enthält bereits einen Datensatz für das Formular %s in der Kampagne %s für die angegebene Gemeinde und das angegebene Datum. Bitte schauen Sie sich die Details für den vorhandenen Datensatz an und wählen Sie Überspringen, wenn Sie die vorhandenen Daten behalten möchten oder Überschreiben, wenn Sie die vorhandenen Daten durch die Daten ersetzen wollen, die Sie importiert haben. pseudonymizedCasesSelectedWarning = Für massenbearbeitete Fälle haben Sie nur begrenzten Zugriff auf sensible Daten. Bei diesen Fällen wird der Wert, den Sie in "Ortsbeschreibung" eingetragen haben, ignoriert. pseudonymizedEntitiesSelectedWarning = Sie haben nur begrenzten Zugriff auf einige der ausgewählten Entitäten. Bitte demarkieren Sie pseudonymisierte Entitäten, um fortzufahren. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = Alle Kontakte sind bereits mit dem ausgewähl messageAllContactsLinkedToEvent = Alle Kontakte wurden mit dem ausgewählten Ereignis verknüpft. messageAlreadyEventParticipant = Die Person, die Sie ausgewählt haben, ist bereits als Ereignisteilnehmer dieser Veranstaltung definiert. messageAnimalContactsHint = Bitte geben Sie eine Antwort in Bezug auf ALLE Tiere (lebendig oder tot) an, denen die Person während der Inkubationszeit direkt ausgesetzt war (z.B. Jagd, Berühren, Essen). +messageArchiveUndoneReasonMandatory = Bitte geben Sie einen Grund für die Dearchivierung an messageCampaignArchived = Kampagne wurde archiviert messageCampaignCreated = Neue Kampagne erstellt messageCampaignDearchived = Kampagne wurde de-archiviert @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=Sie haben gerade ein positives Laborergebni messageConvertEventParticipantToCaseDifferentDiseases=Sie haben gerade ein positives Laborergebnis für eine andere Krankheit gespeichert als die Ereigniskrankheit. Möchten Sie einen Fall mit dieser Krankheit für die Ereignisteilnehmer Person erstellen? Der Fall wird nicht mit dem Ereignisteilnehmer verknüpft. messageConvertEventParticipantToCaseNoDisease=Sie haben gerade ein positives Laborergebnis für ein Ereignis ohne Krankheit gespeichert. Möchten Sie einen Fall mit dieser Krankheit für die Ereignisteilnehmer Person erstellen? Das Endergebnis der Probe wird automatisch auf positiv gesetzt, aber der Fall wird nicht mit dem Ereignisteilnehmer verbunden. messageContactCreated=Neuer Kontakt angelegt +messageContactArchived = Kontakt wurde archiviert +messageContactDearchived = Kontakt wurde dearchiviert messageContactSaved = Kontaktdaten gespeichert messageContactsDeleted = Alle ausgewählten Kontakte wurden gelöscht messageContactsEdited = Alle Kontakte wurden bearbeitet @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = Die Verknüpfung zwischen diesem Fall und de messageEventUnlinkedFromEventGroup = Die Verknüpfung zwischen diesem Ereignis und der Ereignisgruppe wurde erfolgreich getrennt messageEventDearchived = Ereignis wurde de-archiviert messageEventGroupDearchived = Ereignisgruppe wurde de-archiviert +messageEventParticipantArchived = Ereignisteilnehmer wurde archiviert +messageEventParticipantDearchived = Ereignisteilnehmer wurde dearchiviert messageEventParticipantCreated = Neue Person erstellt messageEventParticipantSaved = Personendaten gespeichert messageEventParticipantsDeleted = Alle ausgewählten Ereignisteilnehmenden wurden gelöscht @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Teilungen werden geladen... errorConstraintViolation = Ungültige Daten -reloadPageToSeeChanges = Bitte laden Sie die Seite neu, um die neuesten Änderungen zu sehen \ No newline at end of file +reloadPageToSeeChanges = Bitte laden Sie die Seite neu, um die neuesten Änderungen zu sehen diff --git a/sormas-api/src/main/resources/strings_de-DE.properties b/sormas-api/src/main/resources/strings_de-DE.properties index 08f3c4e737d..1aa7fffe910 100644 --- a/sormas-api/src/main/resources/strings_de-DE.properties +++ b/sormas-api/src/main/resources/strings_de-DE.properties @@ -78,6 +78,7 @@ date = Datum nameOf = Name von %s uuidOf = UUID von %s listOf = Liste von %s +mapOf = Karte <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = Sie haben das Follow-up verlängert. Soll das confirmationArchiveCampaign = Sind Sie sicher, dass Sie diese Kampagne archivieren wollen? Dadurch wird sie weder aus dem System noch aus den Statistiken entfernt, sondern nur aus dem normalen Kampagnen-Verzeichnis ausgeblendet. confirmationArchiveCase = Sind Sie sicher, dass Sie diesen Fall archivieren möchten? Dies entfernt ihn nicht aus dem System oder irgendwelchen Statistiken, sondern blendet ihn nur im normalen Fallverzeichnis aus. confirmationArchiveCases = Sind Sie sicher, dass Sie alle %d ausgewählten Fälle archivieren möchten? +confirmationArchiveContact = Sind Sie sicher, dass Sie diesen Kontakt archivieren möchten? Dies entfernt ihn nicht aus dem System oder irgendwelchen Statistiken, sondern versteckt sie nur im normalen Kontaktverzeichnis. confirmationArchiveEvent = Sind Sie sicher, dass Sie dieses Ereignis archivieren möchten? Dies entfernt es nicht aus dem System oder irgendwelchen Statistiken, sondern blendet es nur im normalen Ereignisverzeichnis aus. confirmationArchiveEvents = Sind Sie sicher, dass Sie alle %d ausgewählten Ereignisse archivieren möchten? +confirmationArchiveEventParticipant = Sind Sie sicher, dass Sie diesen Ereignisteilnehmer archivieren möchten? Dies wird ihn nicht aus dem System oder irgendeiner Statistik entfernen, sondern nur aus der Liste der Ereignisteilnehmer ausblenden. confirmationArchiveImmunization = Sind Sie sicher, dass Sie diese Immunisierung archivieren möchten? Dies entfernt sie nicht aus dem System oder irgendeiner Statistik, sondern versteckt sie nur im normalen Immunisierungsverzeichnis. confirmationArchiveTask = Sind Sie sicher, dass Sie alle %d ausgewählten Aufgaben archivieren möchten? confirmationArchiveTasks = Sind Sie sicher, dass Sie diese Aufgabe archivieren möchten? Dies entfernt sie nicht aus dem System oder irgendwelchen Statistiken, sondern versteckt sie nur in der normalen Aufgabenverwaltung. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Fallerkrankung wirklich ändern? confirmationDearchiveCampaign = Sind Sie sicher, dass Sie diese Kampagne de-archivieren wollen? Dadurch wird sie wieder im normalen Kampagnen-Verzeichnis erscheinen. confirmationDearchiveCase = Sind Sie sicher, dass Sie diesen Fall de-archivieren möchten? Er wird dann im normalen Verzeichnis wieder angezeigt. confirmationDearchiveCases = Sind Sie sicher, dass Sie alle %d ausgewählten Fälle de-archivieren möchten? +confirmationDearchiveContact = Sind Sie sicher, dass Sie diesen Fall de-archivieren möchten? Er wird dann im normalen Fallverzeichnis wieder angezeigt. confirmationDearchiveEvent = Sind Sie sicher, dass Sie dieses Ereignis de-archivieren möchten? Er wird dann im normalen Ereignisverzeichnis wieder angezeigt. confirmationDearchiveEvents = Sind Sie sicher, dass Sie alle %d ausgewählten Ereignisse de-archivieren möchten? +confirmationDearchiveEventParticipant = Sind Sie sicher, dass Sie diesen Ereignisteilnehmer dearchivieren möchten? Dies wird ihn in der normalen Ereignisteilnehmerliste wieder erscheinen lassen. confirmationDearchiveEventGroup = Sind Sie sicher, dass Sie diese Ereignisgruppe dearchivieren möchten? Dadurch wird sie im normalen Ereignisgruppenverzeichnis wieder angezeigt. confirmationDeleteCases = Sind Sie sicher, dass Sie alle %d ausgewählten Fälle löschen möchten? confirmationDeleteContacts = Sind Sie sicher, dass Sie alle %d ausgewählten Kontakte löschen möchten? @@ -365,7 +370,9 @@ headingAllContacts = Alle Kontakte headingAnimalContacts = Tierkontakte headingArchiveCampaign = Archivierte Kampagnen headingArchiveCase = Fall archivieren +headingArchiveContact = Kontakt archivieren headingArchiveEvent = Ereignis archivieren +headingArchiveEventParticipant = Ereignisteilnehmer archivieren headingArchiveEventGroup = Ereignisgruppe archivieren headingArchiveImmunization = Immunisierung archivieren headingArchiveTravelEntry = Einreise archivieren @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Neues Erregertestergebnis erstellen headingDatabaseExportFailed = Datenbank-Export fehlgeschlagen headingDearchiveCampaign = Kampagne de-archivieren headingDearchiveCase = Fall de-archivieren +headingDearchiveContact = Kontakt de-archivieren headingDearchiveEvent = Ereignis de-archivieren +headingDearchiveEventParticipant = Ereignisteilnehmer de-archivieren headingDearchiveEventGroup = Ereignisgruppe de-archivieren headingDearchiveImmunization = Immunisierung de-archivieren headingDearchiveTravelEntry = Einreise de-archivieren @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Bitte dokumentieren Sie ALLE relevanten Bet infoAddTestsToSample = Um ein Testergebnis zu dieser Probe hinzuzufügen, muss es zuerst als empfangen markiert werden. infoArchivedCases = Fälle werden automatisch nach %d Tagen ohne Änderungen der Daten archiviert. infoArchivedEvents = Ereignisse werden automatisch nach %d Tagen ohne Änderungen der Daten archiviert. +infoArchivedEventParticipants = Ereignisteilnehmer werden nach %d Tagen automatisch ohne Änderungen der Daten archiviert. infoArchivedTravelEntries = Einreisen werden nach %d Tagen automatisch ohne Änderungen der Daten archiviert. infoAssigneeMissingEmail = Der dieser Aufgabe zugewiesene Benutzer hat keine E-Mail-Adresse angegeben und wird daher nicht benachrichtigt. infoObserverMissingEmail = Mindestens einer der Beobachter dieser Aufgabe hat keine E-Mail-Adresse angegeben und wird daher nicht benachrichtigt. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = Die Datenbank enthält bereits mindest infoSelectOrCreatePersonForImport = Die Datenbank enthält bereits mindestens eine Person, die den persönlichen Angaben des importierten Eintrags sehr ähnlich zu sein scheint.

    Bitte schauen Sie sich die Liste der Personen an. Wenn Sie sicher sind, dass eine dieser Personen mit der Person des importierten Eintrags übereinstimmt, wählen Sie es aus und klicken Sie auf Speichern. Ansonsten klicken Sie auf Neue Person anlegen, um eine neue Person zu erstellen.

    Wenn Sie sich nicht sicher sind, können Sie dieses Fenster verwerfen, um den Eintrag vom aktuellen Import zu entfernen. infoSelectOrCreatePersonForEventParticipant = Die Datenbank enthält bereits mindestens eine Person, die dem Ereignis-Kontakt sehr ähnlich zu sein scheint.

    Bitte schauen Sie sich die Liste der Personen an. Wenn Sie sicher sind, dass eine dieser Personen mit Ihrer Kontaktperson übereinstimmt, wählen Sie sie aus und klicken Sie auf Speichern. Ansonsten klicken Sie auf Neue Person erstellen, um eine neue Person für Ihren Kontakt zu erstellen.

    Wenn Sie sich unsicher sind, können Sie dieses Fenster schließen und die Ereignis-Kontakterstellung abbrechen. infoSelectOrCreatePersonForLabMessage = Die Datenbank enthält bereits mindestens eine Person, die den persönlichen Angaben in der Labormeldung sehr ähnlich zu sein scheint.

    Bitte schauen Sie sich die Liste der Personen an. Wenn Sie sicher sind, dass eine dieser Personen mit der Person in der Labormeldung übereinstimmt, wählen Sie sie aus und klicken Sie auf Speichern. Ansonsten klicken Sie auf Neue Person erstellen, um eine neue Person zu der Labormeldung zu erstellen.

    Wenn Sie sich nicht sicher sind, können Sie dieses Fenster verwerfen und den Prozess abbrechen. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = Die Datenbank enthält bereits einen Datensatz für das Formular %s in der Kampagne %s für die angegebene Gemeinde und das angegebene Datum. Bitte schauen Sie sich die Details für den vorhandenen Datensatz an und wählen Sie Überspringen, wenn Sie die vorhandenen Daten behalten möchten oder Überschreiben, wenn Sie die vorhandenen Daten durch die Daten ersetzen wollen, die Sie importiert haben. pseudonymizedCasesSelectedWarning = Für die massenbearbeiteten Fälle haben Sie nur begrenzt Zugriff auf die sensiblen Daten. Für diese Fälle wird der Wert, den Sie in "Ortsbeschreibung" eingetragen haben ignoriert. pseudonymizedEntitiesSelectedWarning = Sie haben nur begrenzten Zugriff auf einige der ausgewählten Entitäten. Bitte demarkieren Sie pseudonymisierte Entitäten, um fortzufahren. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = Alle Kontakte sind bereits mit dem ausgewähl messageAllContactsLinkedToEvent = Alle Kontakte wurden mit dem ausgewählten Ereignis verknüpft. messageAlreadyEventParticipant = Die Person, die Sie ausgewählt haben, ist bereits als Ereignisteilnehmer dieser Veranstaltung definiert. messageAnimalContactsHint = Bitte geben Sie eine Antwort in Bezug auf ALLE Tiere (lebendig oder tot) an, denen die Person während der Inkubationszeit direkt ausgesetzt war (z.B. Jagd, Berühren, Essen). +messageArchiveUndoneReasonMandatory = Bitte geben Sie einen Grund für die Dearchivierung an messageCampaignArchived = Kampagne wurde archiviert messageCampaignCreated = Neue Kampagne erstellt messageCampaignDearchived = Kampagne wurde de-archiviert @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=Sie haben gerade ein positives Laborergebni messageConvertEventParticipantToCaseDifferentDiseases=Sie haben gerade ein positives Laborergebnis für eine andere Krankheit gespeichert als die Ereigniskrankheit. Möchten Sie einen Fall mit dieser Krankheit für die Ereignisteilnehmer Person erstellen? Der Fall wird nicht mit dem Ereignisteilnehmer verknüpft. messageConvertEventParticipantToCaseNoDisease=Sie haben gerade ein positives Laborergebnis für ein Ereignis ohne Krankheit gespeichert. Möchten Sie einen Fall mit dieser Krankheit für die Ereignisteilnehmer Person erstellen? Das Endergebnis der Probe wird automatisch auf positiv gesetzt, aber der Fall wird nicht mit dem Ereignisteilnehmer verbunden. messageContactCreated=Neuer Kontakt angelegt +messageContactArchived = Kontakt wurde archiviert +messageContactDearchived = Kontakt wurde dearchiviert messageContactSaved = Kontaktdaten gespeichert messageContactsDeleted = Alle ausgewählten Kontakte wurden gelöscht messageContactsEdited = Alle Kontakte wurden bearbeitet @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = Die Verknüpfung zwischen diesem Fall und de messageEventUnlinkedFromEventGroup = Die Verknüpfung zwischen diesem Ereignis und der Ereignisgruppe wurde erfolgreich getrennt messageEventDearchived = Ereignis wurde de-archiviert messageEventGroupDearchived = Ereignisgruppe wurde de-archiviert +messageEventParticipantArchived = Ereignisteilnehmer wurde archiviert +messageEventParticipantDearchived = Ereignisteilnehmer wurde dearchiviert messageEventParticipantCreated = Neue Person erstellt messageEventParticipantSaved = Personendaten gespeichert messageEventParticipantsDeleted = Alle ausgewählten Ereignisteilnehmenden wurden gelöscht @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Teilungen werden geladen... errorConstraintViolation = Ungültige Daten -reloadPageToSeeChanges = Bitte laden Sie die Seite neu, um die neuesten Änderungen zu sehen \ No newline at end of file +reloadPageToSeeChanges = Bitte laden Sie die Seite neu, um die neuesten Änderungen zu sehen diff --git a/sormas-api/src/main/resources/strings_en-AF.properties b/sormas-api/src/main/resources/strings_en-AF.properties index 7a8a4530c79..ba4cd37a4b9 100644 --- a/sormas-api/src/main/resources/strings_en-AF.properties +++ b/sormas-api/src/main/resources/strings_en-AF.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = Are you sure you want to archive this case? This will not remove it from the system or any statistics, but only hide it from the normal case directory. confirmationArchiveCases = Are you sure you want to archive all %d selected cases? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Really change case disease? confirmationDearchiveCampaign = Are you sure you want to de-archive this campaign? This will make it appear in the normal campaign directory again. confirmationDearchiveCase = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveCases = Are you sure you want to de-archive all %d selected cases? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Are you sure you want to de-archive this event? This will make it appear in the normal event directory again. confirmationDearchiveEvents = Are you sure you want to de-archive all %d selected events? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Are you sure you want to delete all %d selected cases? confirmationDeleteContacts = Are you sure you want to delete all %d selected contacts? @@ -365,7 +370,9 @@ headingAllContacts = All Contacts headingAnimalContacts = Animal Contacts headingArchiveCampaign = Archive Campaign headingArchiveCase = Archive case +headingArchiveContact = Archive contact headingArchiveEvent = Archive event +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new pathogen test result headingDatabaseExportFailed = Database export failed headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = De-Archive case +headingDearchiveContact = De-Archive contact headingDearchiveEvent = De-Archive event +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_en-GH.properties b/sormas-api/src/main/resources/strings_en-GH.properties index 2a951541123..0f56a666e8e 100644 --- a/sormas-api/src/main/resources/strings_en-GH.properties +++ b/sormas-api/src/main/resources/strings_en-GH.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = Are you sure you want to archive this case? This will not remove it from the system or any statistics, but only hide it from the normal case directory. confirmationArchiveCases = Are you sure you want to archive all %d selected cases? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Really change case disease? confirmationDearchiveCampaign = Are you sure you want to de-archive this campaign? This will make it appear in the normal campaign directory again. confirmationDearchiveCase = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveCases = Are you sure you want to de-archive all %d selected cases? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Are you sure you want to de-archive this event? This will make it appear in the normal event directory again. confirmationDearchiveEvents = Are you sure you want to de-archive all %d selected events? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Are you sure you want to delete all %d selected cases? confirmationDeleteContacts = Are you sure you want to delete all %d selected contacts? @@ -365,7 +370,9 @@ headingAllContacts = All Contacts headingAnimalContacts = Animal Contacts headingArchiveCampaign = Archive Campaign headingArchiveCase = Archive case +headingArchiveContact = Archive contact headingArchiveEvent = Archive event +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new pathogen test result headingDatabaseExportFailed = Database export failed headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = De-Archive case +headingDearchiveContact = De-Archive contact headingDearchiveEvent = De-Archive event +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_en-NG.properties b/sormas-api/src/main/resources/strings_en-NG.properties index 9f04e55b369..3156b704893 100644 --- a/sormas-api/src/main/resources/strings_en-NG.properties +++ b/sormas-api/src/main/resources/strings_en-NG.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = Are you sure you want to archive this case? This will not remove it from the system or any statistics, but only hide it from the normal case directory. confirmationArchiveCases = Are you sure you want to archive all %d selected cases? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Really change case disease? confirmationDearchiveCampaign = Are you sure you want to de-archive this campaign? This will make it appear in the normal campaign directory again. confirmationDearchiveCase = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveCases = Are you sure you want to de-archive all %d selected cases? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Are you sure you want to de-archive this event? This will make it appear in the normal event directory again. confirmationDearchiveEvents = Are you sure you want to de-archive all %d selected events? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Are you sure you want to delete all %d selected cases? confirmationDeleteContacts = Are you sure you want to delete all %d selected contacts? @@ -365,7 +370,9 @@ headingAllContacts = All Contacts headingAnimalContacts = Animal Contacts headingArchiveCampaign = Archive Campaign headingArchiveCase = Archive case +headingArchiveContact = Archive contact headingArchiveEvent = Archive event +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new pathogen test result headingDatabaseExportFailed = Database export failed headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = De-Archive case +headingDearchiveContact = De-Archive contact headingDearchiveEvent = De-Archive event +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_es-CU.properties b/sormas-api/src/main/resources/strings_es-CU.properties index d8bd141e6e9..b9959dff711 100644 --- a/sormas-api/src/main/resources/strings_es-CU.properties +++ b/sormas-api/src/main/resources/strings_es-CU.properties @@ -78,6 +78,7 @@ date = Fecha nameOf = Nombre de %s uuidOf = UUID de %s listOf = Lista de %s +mapOf = Mapa de <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = Ha prolongado el seguimiento. ¿Debiera ajust confirmationArchiveCampaign = ¿Está seguro de que desea archivar esta campaña? Esto no la eliminará del sistema ni de ninguna estadística; sólo la ocultará del directorio normal de campañas. confirmationArchiveCase = ¿Está seguro de que desea archivar este caso? Esto no lo eliminará del sistema ni de ninguna estadística; sólo lo ocultará del directorio normal de casos. confirmationArchiveCases = ¿Está seguro de que desea archivar todos los %d casos seleccionados? +confirmationArchiveContact = ¿Está seguro de que desea archivar este contacto? Esto no lo eliminará del sistema ni de ninguna estadística; sólo lo ocultará del directorio normal de contactos. confirmationArchiveEvent = ¿Está seguro de que desea archivar este evento? Esto no lo eliminará del sistema ni de ninguna estadística; sólo lo ocultará del directorio normal de eventos. confirmationArchiveEvents = ¿Está seguro de que desea archivar todos los %d eventos seleccionados? +confirmationArchiveEventParticipant = ¿Está seguro de que desea archivar este participante de evento? Esto no lo eliminará del sistema ni de ninguna estadística; sólo lo ocultará de la lista de participantes de evento. confirmationArchiveImmunization = ¿Está seguro de que desea archivar esta inmunización? Esto no la eliminará del sistema ni de ninguna estadística; sólo la ocultará del directorio normal de inmunización. confirmationArchiveTask = ¿Está seguro de que desea archivar todas las %d tareas seleccionadas? confirmationArchiveTasks = ¿Está seguro de que desea archivar esta tarea? Esto no la eliminará del sistema ni de ninguna estadística; sólo la ocultará de la administración normal de tareas. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = ¿Realmente cambiar la enfermedad del caso? confirmationDearchiveCampaign = ¿Está seguro de que desea desarchivar esta campaña? Esto hará que aparezca otra vez en el directorio normal de campañas. confirmationDearchiveCase = ¿Está seguro de que desea desarchivar este caso? Esto hará que aparezca otra vez en el directorio normal de casos. confirmationDearchiveCases = ¿Está seguro de que desea desarchivar todos los %d casos seleccionados? +confirmationDearchiveContact = ¿Está seguro de que desea desarchivar este caso? Esto hará que aparezca otra vez en el directorio normal de casos. confirmationDearchiveEvent = ¿Está seguro de que desea desarchivar este evento? Esto hará que vuelva a aparecer en el directorio normal de eventos. confirmationDearchiveEvents = ¿Está seguro de que desea desarchivar todos los %d eventos seleccionados? +confirmationDearchiveEventParticipant = ¿Está seguro de que desea desarchivar este participante de evento? Esto hará que vuelva a aparecer en lista normal de participantes de evento. confirmationDearchiveEventGroup = ¿Está seguro de que desea desarchivar este grupo de eventos? Esto hará que vuelva a aparecer en el directorio normal de grupos de eventos. confirmationDeleteCases = ¿Está seguro de que desea eliminar todos los %d casos seleccionados? confirmationDeleteContacts = ¿Está seguro de que desea eliminar todos los %d contactos seleccionados? @@ -365,7 +370,9 @@ headingAllContacts = Todos los contactos headingAnimalContacts = Contactos animales headingArchiveCampaign = Archivar campaña headingArchiveCase = Archivar caso +headingArchiveContact = Archivar contacto headingArchiveEvent = Archivar evento +headingArchiveEventParticipant = Archivar participante de evento headingArchiveEventGroup = Archivar grupo de eventos headingArchiveImmunization = Archivar inmunización headingArchiveTravelEntry = Archivar entrada de viaje @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Crear un nuevo resultado de prueba de patógen headingDatabaseExportFailed = Falló la exportación de la base de datos headingDearchiveCampaign = Desarchivar campaña headingDearchiveCase = Desarchivar caso +headingDearchiveContact = Desarchivar contacto headingDearchiveEvent = Desarchivar evento +headingDearchiveEventParticipant = Desarchivar participante de evento headingDearchiveEventGroup = Desarchivar grupo de eventos headingDearchiveImmunization = Desarchivar inmunización headingDearchiveTravelEntry = Desarchivar entrada de viaje @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Por favor, documente TODAS las actividades infoAddTestsToSample = Para añadir un resultado de prueba a esta muestra, se tiene que marcar como recibida primero. infoArchivedCases = Los casos se archivan automáticamente después de %d días sin cambios en los datos. infoArchivedEvents = Los eventos se archivan automáticamente después de %d días sin cambios en los datos. +infoArchivedEventParticipants = Los participantes de evento se archivan automáticamente después de %d días sin cambios en los datos. infoArchivedTravelEntries = Las entradas de viaje se archivan automáticamente después de %d días sin cambios en los datos. infoAssigneeMissingEmail = El usuario asignado a esta tarea no tiene una dirección de correo electrónico provista, y por tanto no será notificado. infoObserverMissingEmail = Al menos uno de los observadores de esta tarea no tiene una dirección de correo electrónico especificada y, por lo tanto, no será notificado. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = La base de datos ya contiene al menos infoSelectOrCreatePersonForImport = La base de datos ya contiene al menos una persona que parece muy similar a los datos personales de la entrada importada.

    Por favor, revise la lista de personas. Si está seguro de que una de esas personas coincide con la persona de la entrada importada, selecciónela y haga clic en el botón Guardar. De lo contrario, haga clic en Crear nueva persona para crear una nueva persona.

    Si no está seguro, puede descartar esta ventana para eliminar la entrada de la importación actual. infoSelectOrCreatePersonForEventParticipant = La base de datos ya contiene al menos una persona que parece muy similar a los datos personales del participante del evento creado.

    Por favor, revise la lista de personas. Si está seguro de que una de esas personas coincide con su persona de evento, selecciónela y haga clic en el botón Guardar. De lo contrario, haga clic en Crear nueva persona para crear una nueva persona de evento para su evento.

    Si no está seguro, puede descartar esta ventana y cancelar el proceso de creación de participante del evento. infoSelectOrCreatePersonForLabMessage = La base de datos ya contiene al menos una persona que parece muy similar a los datos personales del mensaje de laboratorio.

    Por favor, revise la lista de personas. Si está seguro de que una de esas personas coincide con la persona del mensaje de laboratorio, selecciónela y haga clic en el botón Confirmar. De lo contrario, haga clic en Crear nueva persona para crear una nueva persona para el mensaje de laboratorio.

    Si no está seguro, puede descartar esta ventana y cancelar el proceso. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = La base de datos ya contiene un conjunto de datos para el formulario %s en la campaña %s para el área de salud y fecha especificadas. Por favor, vea los detalles del conjunto de datos existente y elija Omitir si desea conservar los datos existentes o Sobrescribir si desea reemplazar los datos existentes por los datos que ha importado. pseudonymizedCasesSelectedWarning = Para casos editados en masa sólo tiene acceso limitado a los datos confidenciales. Para esos casos el valor que ponga en "Descripción de lugar" será ignorado. pseudonymizedEntitiesSelectedWarning = Solo tiene acceso limitado a algunas de las entidades seleccionadas. Por favor, deseleccione entidades seudonimizadas para continuar. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = Todos los contactos ya están vinculados al e messageAllContactsLinkedToEvent = Todos los contactos fueron vinculados al evento seleccionado. messageAlreadyEventParticipant = La persona seleccionada ya está definida como participante de este evento. messageAnimalContactsHint = Por favor, indique una respuesta con respecto a TODOS los animales (vivos o muertos) a los que la persona se expuso directamente (por ejemplo, cazó, tocó, comió) durante el período de incubación. +messageArchiveUndoneReasonMandatory = Por favor, agregue una razón para desarchivar messageCampaignArchived = La campaña fue archivada messageCampaignCreated = Nueva campaña creada messageCampaignDearchived = La campaña fue desarchivada @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=Acaba de guardar un resultado de laboratori messageConvertEventParticipantToCaseDifferentDiseases=Acaba de guardar un resultado de laboratorio positivo para una enfermedad distinta de la enfermedad del evento. ¿Desea crear un caso con esta enfermedad para el participante de evento? El caso no se vinculará con el participante de evento. messageConvertEventParticipantToCaseNoDisease=Acaba de guardar un resultado de laboratorio positivo para un evento sin enfermedad. ¿Desea crear un caso con esta enfermedad para el participante de evento? El resultado final de laboratorio de la muestra se establecerá automáticamente como positivo pero el caso no se vinculará con el participante de evento. messageContactCreated=Nuevo contacto creado +messageContactArchived = El contacto fue archivado +messageContactDearchived = El contacto fue desarchivado messageContactSaved = Datos del contacto guardados messageContactsDeleted = Todos los contactos seleccionados fueron eliminados messageContactsEdited = Todos los contactos fueron editados @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = El vínculo entre este caso y el evento fue messageEventUnlinkedFromEventGroup = El vínculo entre este evento y el grupo de eventos fue eliminado exitosamente messageEventDearchived = El evento fue desarchivado messageEventGroupDearchived = El grupo de eventos fue desarchivado +messageEventParticipantArchived = El participante de evento fue archivado +messageEventParticipantDearchived = El participante de evento fue desarchivado messageEventParticipantCreated = Nueva persona creada messageEventParticipantSaved = Datos de persona guardados messageEventParticipantsDeleted = Todos los participantes del evento seleccionados fueron eliminados @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Cargando comparticiones... errorConstraintViolation = Datos no válidos -reloadPageToSeeChanges = Por favor, vuelva a cargar la página para ver los últimos cambios \ No newline at end of file +reloadPageToSeeChanges = Por favor, vuelva a cargar la página para ver los últimos cambios diff --git a/sormas-api/src/main/resources/strings_es-EC.properties b/sormas-api/src/main/resources/strings_es-EC.properties index 8d873d788b5..60f316be867 100644 --- a/sormas-api/src/main/resources/strings_es-EC.properties +++ b/sormas-api/src/main/resources/strings_es-EC.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = ¿Estás seguro de que deseas archivar este caso? Esto no lo eliminará del sistema ni de ninguna estadística, sino que solo lo ocultará del directorio de casos. confirmationArchiveCases = ¿Está seguro de que desea archivar todos los %d casos seleccionados? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = ¿Estás seguro de que deseas archivar este evento? Esto no lo eliminará del sistema ni de ninguna estadística, sino que solo lo ocultará del directorio de eventos. confirmationArchiveEvents = ¿Estás seguro de que deseas archivar todos los %d eventos seleccionados? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = ¿Cambiar realmente la enfermedad del caso? confirmationDearchiveCampaign = Are you sure you want to de-archive this campaign? This will make it appear in the normal campaign directory again. confirmationDearchiveCase = ¿Está seguro de que desea desarchivar este caso? Esto hará que vuelva a aparecer en el directorio de casos. confirmationDearchiveCases = ¿Está seguro de que desea desarchivar todos los %d casos seleccionados? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = ¿Estás seguro de que deseas eliminar el archivo de este evento? Esto hará que vuelva a aparecer en el directorio de eventos. confirmationDearchiveEvents = ¿Está seguro de que desea desarchivar todos los %d eventos seleccionados? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = ¿Está seguro de que desea eliminar los %d eventos seleccionados? confirmationDeleteContacts = ¿Está seguro de que desea eliminar los %d contactos seleccionados? @@ -365,7 +370,9 @@ headingAllContacts = Todos los contactos headingAnimalContacts = Contactos animales headingArchiveCampaign = Archive Campaign headingArchiveCase = Archivar caso +headingArchiveContact = Archive contact headingArchiveEvent = Archivar evento +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Crear nuevo resultado de prueba de patógeno headingDatabaseExportFailed = Exportación de base de datos fallida headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = Desarchivar caso +headingDearchiveContact = De-Archive contact headingDearchiveEvent = Desarchivar evento +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = Para agregar un resultado de prueba a esta muestra, se tiene que marcar como recibida primero. infoArchivedCases = Los casos son automáticamente archivados después de %d días sin cambios en los datos infoArchivedEvents = Los eventos son automáticamente archivados luego %d días sin cambiar los datos. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = La base de datos contiene al menos una persona muy similar a los datos personales del nuevo contacto creado.

    Por favor revise la lista de personas. Si usted está seguro que una de esas personas coincide con su persona de contacto, selecciónela y de click en el botón de Guardar. De lo contrario, de click en Crear Nueva Persona para crear una nueva persona para su contactot.

    Si no est{a seguro, puede descartar esta ventana y cancelar el proceso de creación del contacto. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Indique una respuesta con respecto a TODOS los animales (vivos o muertos) a los que la persona estuvo expuesta directamente (Ej\: cazar, tocar, comer) durante el período de incubación. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=Nuevo contacto creado +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Datos del contacto guardados messageContactsDeleted = Todos los contactos seleccionados han sido eliminados messageContactsEdited = Todos los contactos han sido editados @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = El evento ha sido desarchivado messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = Nueva persona creada messageEventParticipantSaved = Datos personales guardados messageEventParticipantsDeleted = Todos los participantes del evento han sido eliminados @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_es-ES.properties b/sormas-api/src/main/resources/strings_es-ES.properties index e2aba1b50c7..3cfaf789853 100644 --- a/sormas-api/src/main/resources/strings_es-ES.properties +++ b/sormas-api/src/main/resources/strings_es-ES.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = Are you sure you want to archive this case? This will not remove it from the system or any statistics, but only hide it from the normal case directory. confirmationArchiveCases = Are you sure you want to archive all %d selected cases? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Really change case disease? confirmationDearchiveCampaign = Are you sure you want to de-archive this campaign? This will make it appear in the normal campaign directory again. confirmationDearchiveCase = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveCases = Are you sure you want to de-archive all %d selected cases? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Are you sure you want to de-archive this event? This will make it appear in the normal event directory again. confirmationDearchiveEvents = Are you sure you want to de-archive all %d selected events? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Are you sure you want to delete all %d selected cases? confirmationDeleteContacts = Are you sure you want to delete all %d selected contacts? @@ -365,7 +370,9 @@ headingAllContacts = All Contacts headingAnimalContacts = Animal Contacts headingArchiveCampaign = Archive Campaign headingArchiveCase = Archive case +headingArchiveContact = Archive contact headingArchiveEvent = Archive event +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new pathogen test result headingDatabaseExportFailed = Database export failed headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = De-Archive case +headingDearchiveContact = De-Archive contact headingDearchiveEvent = De-Archive event +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_fa-AF.properties b/sormas-api/src/main/resources/strings_fa-AF.properties index e2aba1b50c7..3cfaf789853 100644 --- a/sormas-api/src/main/resources/strings_fa-AF.properties +++ b/sormas-api/src/main/resources/strings_fa-AF.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = Are you sure you want to archive this case? This will not remove it from the system or any statistics, but only hide it from the normal case directory. confirmationArchiveCases = Are you sure you want to archive all %d selected cases? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Really change case disease? confirmationDearchiveCampaign = Are you sure you want to de-archive this campaign? This will make it appear in the normal campaign directory again. confirmationDearchiveCase = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveCases = Are you sure you want to de-archive all %d selected cases? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Are you sure you want to de-archive this event? This will make it appear in the normal event directory again. confirmationDearchiveEvents = Are you sure you want to de-archive all %d selected events? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Are you sure you want to delete all %d selected cases? confirmationDeleteContacts = Are you sure you want to delete all %d selected contacts? @@ -365,7 +370,9 @@ headingAllContacts = All Contacts headingAnimalContacts = Animal Contacts headingArchiveCampaign = Archive Campaign headingArchiveCase = Archive case +headingArchiveContact = Archive contact headingArchiveEvent = Archive event +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new pathogen test result headingDatabaseExportFailed = Database export failed headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = De-Archive case +headingDearchiveContact = De-Archive contact headingDearchiveEvent = De-Archive event +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_fi-FI.properties b/sormas-api/src/main/resources/strings_fi-FI.properties index cb73c9419a3..d2c6017d492 100644 --- a/sormas-api/src/main/resources/strings_fi-FI.properties +++ b/sormas-api/src/main/resources/strings_fi-FI.properties @@ -78,6 +78,7 @@ date = Päivämäärä nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Haluatko varmasti arkistoida tämän kampanjan tiedot? Arkistointi ei poista tietoja järjestelmästä tai tilastoista, mutta piilottaa sen tavallisesta kampanjalistasta. confirmationArchiveCase = Haluatko varmasti arkistoida tämän potilaan tiedot? Arkistointi ei poista tietoja järjestelmästä tai tilastoista, mutta piilottaa sen tavallisesta potilaslistasta. confirmationArchiveCases = Oletko varma, että haluat arkistoida kaikki %d valittua potilasta? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Haluatko varmasti arkistoida tämän tapahtuman? Arkistointi ei poista tietoja järjestelmästä tai tilastoista, mutta piilottaa sen tavallisesta tapahtumalistasta. confirmationArchiveEvents = Haluatko varmasti arkistoida kaikki %d valittua tapahtumaa? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Haluatko varmasti vaihtaa potilaan sairautta? confirmationDearchiveCampaign = Haluatko varmasti palauttaa tämän kampanjan tiedot arkistosta? Palauttaminen lisää kampanjan takaisin tavalliseen kampanjalistaan. confirmationDearchiveCase = Haluatko varmasti palauttaa tämän potilaan tiedot arkistosta? Palauttaminen lisää potilaan takaisin tavalliseen potilaslistaan. confirmationDearchiveCases = Haluatko varmasti palauttaa kaikkien %d potilaan tiedot arkistosta? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Haluatko varmasti palauttaa tämän tapahtuman arkistosta? Palauttaminen lisää tapahtuman takaisin tavalliseen tapahtumalistaan. confirmationDearchiveEvents = Haluatko varmasti palauttaa kaikki %d tapahtumaa arkistosta? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Haluatko varmasti poistaa kaikki %d valittua potilasta? confirmationDeleteContacts = Haluatko varmasti poistaa kaikki %d valittua kontaktia? @@ -365,7 +370,9 @@ headingAllContacts = Kaikki kontaktit headingAnimalContacts = Eläinkontaktit headingArchiveCampaign = Arkistoi kampanja headingArchiveCase = Arkistoi potilas +headingArchiveContact = Archive contact headingArchiveEvent = Arkistoi tapahtuma +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Lisää uusi patogeenitestin tulos headingDatabaseExportFailed = Tietokannan vienti epäonnistui headingDearchiveCampaign = Palauta kampanja arkistosta headingDearchiveCase = Palauta potilas arkistosta +headingDearchiveContact = De-Archive contact headingDearchiveEvent = Palauta tapahtuma arkistosta +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = Jotta näytteeseen voidaan lisätä tuloksia, se täytyy ensin merkitä otetuksi. infoArchivedCases = Potilaat arkistoidaan automaattisesti, kun on kulunut %d päivää ilman tietojen muokkausta. infoArchivedEvents = Tapahtumat arkistoidaan automaattisesti, kun on kulunut %d päivää ilman tietojen muokkausta. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = Tietokannassa on jo vähintäänkin yksi henkilö, joka vaikuttaa hyvin samankaltaiselta kuin luomasi tapahtumaan osallistunut henkilö.

    Ole hyvä, ja katso henkilöiden lista läpi. Jos olet varma, että jokin listalla olevista henkilöistä on tarkoittamasi henkilö, valitse hänet ja paina Tallenna. Muutoin, paina Luo uusi henkilö luodaksesi uuden henkilön.

    Jos olet epävarma peruuta ja peru tapahtuman osallistujan luonti. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Merkitse vastaus koskien KAIKKIA eläimiä (eläviä tai kuolleita), joille henkilö on suoraan altistunut (esim. metsästäessä, koskettaessa, syömällä) itämisajan aikana. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Kampanja on arkistoitu messageCampaignCreated = Uusi kampanja luotu messageCampaignDearchived = Kampanja on palautettu arkistosta @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=Uusi kontakti luotu +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Kontaktitiedot tallennettu messageContactsDeleted = Kaikki valitut kontaktit on poistettu messageContactsEdited = Kaikkia kontakteja on muutettu @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Tapahtuma on palautettu arkistosta messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = Uusi henkilö luotu messageEventParticipantSaved = Henkilön tiedot tallennettu messageEventParticipantsDeleted = Kaikki valitut tapahtuman osallistujat on poistettu @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_fil-PH.properties b/sormas-api/src/main/resources/strings_fil-PH.properties index e2aba1b50c7..3cfaf789853 100644 --- a/sormas-api/src/main/resources/strings_fil-PH.properties +++ b/sormas-api/src/main/resources/strings_fil-PH.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = Are you sure you want to archive this case? This will not remove it from the system or any statistics, but only hide it from the normal case directory. confirmationArchiveCases = Are you sure you want to archive all %d selected cases? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Really change case disease? confirmationDearchiveCampaign = Are you sure you want to de-archive this campaign? This will make it appear in the normal campaign directory again. confirmationDearchiveCase = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveCases = Are you sure you want to de-archive all %d selected cases? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Are you sure you want to de-archive this event? This will make it appear in the normal event directory again. confirmationDearchiveEvents = Are you sure you want to de-archive all %d selected events? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Are you sure you want to delete all %d selected cases? confirmationDeleteContacts = Are you sure you want to delete all %d selected contacts? @@ -365,7 +370,9 @@ headingAllContacts = All Contacts headingAnimalContacts = Animal Contacts headingArchiveCampaign = Archive Campaign headingArchiveCase = Archive case +headingArchiveContact = Archive contact headingArchiveEvent = Archive event +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new pathogen test result headingDatabaseExportFailed = Database export failed headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = De-Archive case +headingDearchiveContact = De-Archive contact headingDearchiveEvent = De-Archive event +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_fj-FJ.properties b/sormas-api/src/main/resources/strings_fj-FJ.properties index e2aba1b50c7..3cfaf789853 100644 --- a/sormas-api/src/main/resources/strings_fj-FJ.properties +++ b/sormas-api/src/main/resources/strings_fj-FJ.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = Are you sure you want to archive this case? This will not remove it from the system or any statistics, but only hide it from the normal case directory. confirmationArchiveCases = Are you sure you want to archive all %d selected cases? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Really change case disease? confirmationDearchiveCampaign = Are you sure you want to de-archive this campaign? This will make it appear in the normal campaign directory again. confirmationDearchiveCase = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveCases = Are you sure you want to de-archive all %d selected cases? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Are you sure you want to de-archive this event? This will make it appear in the normal event directory again. confirmationDearchiveEvents = Are you sure you want to de-archive all %d selected events? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Are you sure you want to delete all %d selected cases? confirmationDeleteContacts = Are you sure you want to delete all %d selected contacts? @@ -365,7 +370,9 @@ headingAllContacts = All Contacts headingAnimalContacts = Animal Contacts headingArchiveCampaign = Archive Campaign headingArchiveCase = Archive case +headingArchiveContact = Archive contact headingArchiveEvent = Archive event +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new pathogen test result headingDatabaseExportFailed = Database export failed headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = De-Archive case +headingDearchiveContact = De-Archive contact headingDearchiveEvent = De-Archive event +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_fr-CH.properties b/sormas-api/src/main/resources/strings_fr-CH.properties index c24e449dc5e..0b41fe4e4ee 100644 --- a/sormas-api/src/main/resources/strings_fr-CH.properties +++ b/sormas-api/src/main/resources/strings_fr-CH.properties @@ -78,6 +78,7 @@ date = Date nameOf = Nom de %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = Vous avez prolongé le suivi, la fin de l'iso confirmationArchiveCampaign = Voulez-vous vraiment archiver cette campagne? Elle ne sera supprimée ni du système ni des statistiques mais n'apparaîtra plus dans la vue par défaut du répertoire des campagnes. confirmationArchiveCase = Êtes-vous sûr de vouloir archiver ce cas ? Cela ne le supprimera ni du système ni des statistiques, mais le cachera seulement du répertoire des cas normaux. confirmationArchiveCases = Êtes-vous sûr de vouloir archiver tous les %d cas sélectionnés ? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Êtes-vous sûr de vouloir archiver cet événement? Cela ne le supprimera ni du système ni des statistiques, mais le cachera seulement du répertoire des cas normaux. confirmationArchiveEvents = Êtes-vous sûr de vouloir archiver tous les %d événéments sélectionnés? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Vraiment changer la maladie de cas? confirmationDearchiveCampaign = Voulez-vous vraiment désarchiver cette campagne? Elle figurera de nouveau dans la vue par défaut du répertoire des campagnes. confirmationDearchiveCase = Êtes-vous sûr de vouloir désarchiver ce cas ? Cela le fera apparaître dans le répertoire de cas normal à nouveau. confirmationDearchiveCases = Êtes-vous sûr de vouloir désarchiver tous les %d cas sélectionnés ? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Êtes-vous sûr de vouloir désarchiver cet événement? Cela le fera apparaître dans le répertoire de cas normal à nouveau. confirmationDearchiveEvents = Êtes-vous sûr de vouloir désarchiver tous les %d événéments sélectionnés? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Êtes-vous sûr de vouloir supprimer tous les %d cas sélectionnés ? confirmationDeleteContacts = Êtes-vous sûr de vouloir supprimer tous les %d contacts sélectionnés? @@ -365,7 +370,9 @@ headingAllContacts = Tous les contacts headingAnimalContacts = Contacts animaux headingArchiveCampaign = Archiver cette campagne headingArchiveCase = Cas archivés +headingArchiveContact = Archive contact headingArchiveEvent = Archiver l'événement +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new sample test result headingDatabaseExportFailed = Échec de l'exportation de base de données headingDearchiveCampaign = Désarchiver cette campagne headingDearchiveCase = Cas désarchiver +headingDearchiveContact = De-Archive contact headingDearchiveEvent = Evénement désarchiver +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = Pour ajouter un résultat de test à cet échantillon, il doit d'abord être marqué comme reçu. infoArchivedCases = Les cas sont automatiquement archivés après %d jours sans modification des données. infoArchivedEvents = Les événements sont automatiquement archivés après %d jours sans modification des données. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = L'utilisateur assigné à cette tâche n'a pas renseigné un adresse e-mail et ne sera donc pas notifié. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = Pour les cas gérés en bloc, vous n'avez qu'un accès limité aux données sensibles. Pour ces cas, la valeur que vous avez mis dans "Place Description" sera ignorée. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = La personne sélectionnée est déjà un participant à cet événement. messageAnimalContactsHint = Veuillez indiquer une réponse concernant TOUS les animaux (vivants ou morts) que la personne a eu une exposition directe (par exemple chasse, toucher, manger) pendant la période d'incubation. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = La campagne a été archivée messageCampaignCreated = Nouvelle campagne créée messageCampaignDearchived = La campagne a été désarchivée @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=Nouveau contact créé +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Données de contact enregistrées messageContactsDeleted = Tous les contacts sélectionnés ont été supprimés messageContactsEdited = Tous les contacts ont été modifiés @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = L'événement a été désarchivé messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = Nouvelle personne créée messageEventParticipantSaved = Données de la personne enregistrées messageEventParticipantsDeleted = Tous les participants à l'événement sélectionnés ont été supprimés @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_fr-FR.properties b/sormas-api/src/main/resources/strings_fr-FR.properties index e90342a1e7e..76caaee78f7 100644 --- a/sormas-api/src/main/resources/strings_fr-FR.properties +++ b/sormas-api/src/main/resources/strings_fr-FR.properties @@ -78,6 +78,7 @@ date = Date nameOf = Nom de %s uuidOf = UUID de %s listOf = Liste de %s +mapOf = Carte de <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = Vous avez prolongé le suivi, la fin de la qu confirmationArchiveCampaign = Voulez-vous vraiment archiver cette campagne? Elle ne sera supprimée ni du système ni des statistiques mais n'apparaîtra plus dans la vue par défaut du répertoire des campagnes. confirmationArchiveCase = Êtes-vous sûr de vouloir archiver ce cas ? Cela ne le supprimera ni du système ni des statistiques, mais le cachera seulement du répertoire des cas normaux. confirmationArchiveCases = Êtes-vous sûr de vouloir archiver les %d cas sélectionnés ? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Êtes-vous sûr de vouloir archiver cet événement? Cela ne le supprimera ni du système ni des statistiques, mais le cachera seulement du répertoire des cas normaux. confirmationArchiveEvents = Êtes-vous sûr de vouloir archiver les %d événéments sélectionnés? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Êtes-vous sûr de vouloir archiver toutes les %d tâches sélectionnées ? confirmationArchiveTasks = Êtes-vous sûr de vouloir archiver cette tâche? Cela ne le supprimera pas du système ou des statistiques, mais le masquera de la gestion normale des tâches. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Vraiment changer la maladie du cas? confirmationDearchiveCampaign = Voulez-vous vraiment désarchiver cette campagne? Elle figurera de nouveau dans la vue par défaut du répertoire des campagnes. confirmationDearchiveCase = Êtes-vous sûr de vouloir désarchiver ce cas ? Cela le fera apparaître dans le répertoire de cas normal à nouveau. confirmationDearchiveCases = Êtes-vous sûr de vouloir désarchiver les %d cas sélectionnés ? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Êtes-vous sûr de vouloir désarchiver cet événement? Cela le fera apparaître dans le répertoire de cas normal à nouveau. confirmationDearchiveEvents = Êtes-vous sûr de vouloir désarchiver les %d événéments sélectionnés? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Êtes-vous sûr de vouloir désarchiver ce groupe d'événements? Cela le fera apparaître dans le répertoire normal des groupes d'événements. confirmationDeleteCases = Êtes-vous sûr de vouloir supprimer les %d cas sélectionnés ? confirmationDeleteContacts = Êtes-vous sûr de vouloir supprimer les %d contacts sélectionnés? @@ -365,7 +370,9 @@ headingAllContacts = Tous les contacts headingAnimalContacts = Contacts animaux headingArchiveCampaign = Archiver cette campagne headingArchiveCase = Cas archivés +headingArchiveContact = Archive contact headingArchiveEvent = Archiver l'événement +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archiver le groupe d'événements headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new sample test result headingDatabaseExportFailed = Échec de l'exportation de base de données headingDearchiveCampaign = Désarchiver cette campagne headingDearchiveCase = Cas désarchiver +headingDearchiveContact = De-Archive contact headingDearchiveEvent = Evénement désarchiver +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = Désarchiver le groupe d'événements headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Veuillez documenter toutes les activités p infoAddTestsToSample = Pour ajouter un résultat de test à cet échantillon, il doit d'abord être marqué comme reçu. infoArchivedCases = Les cas sont automatiquement archivés après %d jours sans modification des données. infoArchivedEvents = Les événements sont automatiquement archivés après %d jours sans modification des données. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = L'utilisateur assigné à cette tâche n'a pas d'adresse e-mail et ne sera donc pas notifié. infoObserverMissingEmail = Au moins un des observateurs de cette tâche n'a pas d'adresse e-mail fournie, et ne sera donc pas notifié. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = La base de données contient déjà au moins une personne qui semble être très similaire aux données personnelles du contact créé.

    Veuillez consulter la liste des personnes. Si vous avez la certitude qu'une de ces personnes correspond à votre personne de contact, sélectionnez-la et cliquez sur le bouton Enregistrer . Sinon, cliquez sur Créer une nouvelle personne pour créer une nouvelle personne pour votre contact.

    Si vous n'êtes pas sûr, vous pouvez supprimer cette fenêtre et annuler le processus de création de contact. infoSelectOrCreatePersonForLabMessage = La base de données contient déjà au moins une personne qui semble être très similaire aux données personnelles du message de laboratoire.

    Veuillez consulter la liste des personnes. Si vous avez la certitude que l'une de ces personnes correspond à la personne du message de laboratoire, sélectionnez-le et cliquez sur le bouton Confirmer . Sinon, cliquez sur Créer une nouvelle personne pour créer une nouvelle personne pour le message de laboratoire.

    Si vous n'êtes pas sûr, vous pouvez supprimer cette fenêtre et annuler le processus. +infoSelectOrCreatePersonForLabMessageWithoutMatches = Une personne qui correspond étroitement aux détails de la personne du message de laboratoire n'a pas pu être automatiquement déterminée.

    Vous pouvez rechercher manuellement des correspondances, ou vous pouvez créer une nouvelle personne. Une fois que vous avez sélectionné une option, continuez via le bouton Confirmer .

    Si vous n'êtes pas sûr, vous pouvez supprimer cette fenêtre et annuler le processus. infoSkipOrOverrideDuplicateCampaignFormDataImport = La base de données contient déjà un jeu de données pour le formulaire %s dans la campagne %s pour la communauté et la date spécifiées. Veuillez consulter les détails du jeu de données existant et choisir Ignorer si vous voulez conserver les données existantes ou Écraser si vous voulez remplacer les données existantes par les données que vous avez importées. pseudonymizedCasesSelectedWarning = Pour les cas gérés en bloc, vous n'avez qu'un accès limité aux données sensibles. Dans ces cas, la valeur que vous mettez dans "Place Description" sera ignorée. pseudonymizedEntitiesSelectedWarning = Vous n'avez qu'un accès limité à certaines des entités sélectionnées. Veuillez désélectionner les entités pseudonymées pour continuer. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = La personne que vous avez sélectionnée est déjà définie comme participant à cet événement. messageAnimalContactsHint = Veuillez indiquer une réponse concernant TOUS les animaux (vivants ou morts) que la personne a eu une exposition directe (par exemple chasse, toucher, manger) pendant la période d'incubation. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = La campagne a été archivée messageCampaignCreated = Nouvelle campagne créée messageCampaignDearchived = La campagne a été désarchivée @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=Vous venez de sauvegarder un résultat posi messageConvertEventParticipantToCaseDifferentDiseases=Vous venez de sauvegarder un résultat de laboratoire positif pour une maladie différente de la maladie de l'événement. Voulez-vous créer un cas avec cette maladie pour la personne participant à l'événement ? Le cas ne sera pas lié au participant à l'événement. messageConvertEventParticipantToCaseNoDisease=Vous venez de sauvegarder un résultat de laboratoire positif pour un événement sans maladie. Voulez-vous créer un cas avec cette maladie pour la personne participant à l'événement ? Le résultat final du laboratoire de l'échantillon sera automatiquement positionné, mais le cas ne sera pas lié au participant à l'événement. messageContactCreated=Nouveau contact créé +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Données de contact enregistrées messageContactsDeleted = Tous les contacts sélectionnés ont été supprimés messageContactsEdited = Tous les contacts ont été modifiés @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = Le lien entre ce cas et l'événement a ét messageEventUnlinkedFromEventGroup = Le lien entre cet événement et le groupe d'événements a été supprimé avec succès messageEventDearchived = L'événement a été désarchivé messageEventGroupDearchived = Le groupe d'événements a été désarchivé +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = Nouvelle personne créée messageEventParticipantSaved = Données de la personne enregistrées messageEventParticipantsDeleted = Tous les participants à l'événement sélectionnés ont été supprimés @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Chargement des partages... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Veuillez recharger la page pour voir les dernières modifications \ No newline at end of file +reloadPageToSeeChanges = Veuillez recharger la page pour voir les dernières modifications diff --git a/sormas-api/src/main/resources/strings_hi-IN.properties b/sormas-api/src/main/resources/strings_hi-IN.properties index e2aba1b50c7..3cfaf789853 100644 --- a/sormas-api/src/main/resources/strings_hi-IN.properties +++ b/sormas-api/src/main/resources/strings_hi-IN.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = Are you sure you want to archive this case? This will not remove it from the system or any statistics, but only hide it from the normal case directory. confirmationArchiveCases = Are you sure you want to archive all %d selected cases? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Really change case disease? confirmationDearchiveCampaign = Are you sure you want to de-archive this campaign? This will make it appear in the normal campaign directory again. confirmationDearchiveCase = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveCases = Are you sure you want to de-archive all %d selected cases? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Are you sure you want to de-archive this event? This will make it appear in the normal event directory again. confirmationDearchiveEvents = Are you sure you want to de-archive all %d selected events? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Are you sure you want to delete all %d selected cases? confirmationDeleteContacts = Are you sure you want to delete all %d selected contacts? @@ -365,7 +370,9 @@ headingAllContacts = All Contacts headingAnimalContacts = Animal Contacts headingArchiveCampaign = Archive Campaign headingArchiveCase = Archive case +headingArchiveContact = Archive contact headingArchiveEvent = Archive event +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new pathogen test result headingDatabaseExportFailed = Database export failed headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = De-Archive case +headingDearchiveContact = De-Archive contact headingDearchiveEvent = De-Archive event +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_hr-HR.properties b/sormas-api/src/main/resources/strings_hr-HR.properties index e2aba1b50c7..3cfaf789853 100644 --- a/sormas-api/src/main/resources/strings_hr-HR.properties +++ b/sormas-api/src/main/resources/strings_hr-HR.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = Are you sure you want to archive this case? This will not remove it from the system or any statistics, but only hide it from the normal case directory. confirmationArchiveCases = Are you sure you want to archive all %d selected cases? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Really change case disease? confirmationDearchiveCampaign = Are you sure you want to de-archive this campaign? This will make it appear in the normal campaign directory again. confirmationDearchiveCase = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveCases = Are you sure you want to de-archive all %d selected cases? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Are you sure you want to de-archive this event? This will make it appear in the normal event directory again. confirmationDearchiveEvents = Are you sure you want to de-archive all %d selected events? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Are you sure you want to delete all %d selected cases? confirmationDeleteContacts = Are you sure you want to delete all %d selected contacts? @@ -365,7 +370,9 @@ headingAllContacts = All Contacts headingAnimalContacts = Animal Contacts headingArchiveCampaign = Archive Campaign headingArchiveCase = Archive case +headingArchiveContact = Archive contact headingArchiveEvent = Archive event +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new pathogen test result headingDatabaseExportFailed = Database export failed headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = De-Archive case +headingDearchiveContact = De-Archive contact headingDearchiveEvent = De-Archive event +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_it-CH.properties b/sormas-api/src/main/resources/strings_it-CH.properties index a16750d1be7..94455e04c5c 100644 --- a/sormas-api/src/main/resources/strings_it-CH.properties +++ b/sormas-api/src/main/resources/strings_it-CH.properties @@ -78,6 +78,7 @@ date = Data nameOf = Nome di %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = Lei ha esteso il follow-up\: la fine della qu confirmationArchiveCampaign = Sei sicuro di voler archiviare questa campagna? Non sarà rimossa dal sistema o dalle statistiche, ma solo nascosta dal normale elenco delle campagne. confirmationArchiveCase = Sei sicuro di voler archiviare questo caso? Non sarà rimosso dal sistema o dalle statistiche, ma solo nascosto dal normale elenco dei casi. confirmationArchiveCases = Sei sicuro di voler archiviare tutti i %d casi selezionati? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Sei sicuro di voler archiviare questo evento? Non sarà rimosso dal sistema o dalle statistiche, ma solo nascosto dal normale elenco degli eventi. confirmationArchiveEvents = Sei sicuro di voler archiviare tutti i %d eventi selezionati? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Vuoi veramente cambiare la malattia del caso? confirmationDearchiveCampaign = Sei sicuro di voler disarchiviare questa campagna? Apparirà nuovamente nel normale elenco delle campagne. confirmationDearchiveCase = Sei sicuro di voler disarchiviare questo caso? Apparirà nuovamente nel normale elenco dei casi. confirmationDearchiveCases = Sei sicuro di voler disarchiviare tutti i %d casi selezionati? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Sei sicuro di voler disarchiviare questo evento? Apparirà nuovamente nel normale elenco degli eventi. confirmationDearchiveEvents = Sei sicuro di voler disarchiviare tutti i %d eventi selezionati? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Sei sicuro di voler eliminare tutti i %d casi selezionati? confirmationDeleteContacts = Sei sicuro di voler eliminare tutti i %d contatti selezionati? @@ -365,7 +370,9 @@ headingAllContacts = Tutti i contatti headingAnimalContacts = Contatti con animali headingArchiveCampaign = Archivia campagna headingArchiveCase = Archivia caso +headingArchiveContact = Archive contact headingArchiveEvent = Archivia evento +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Crea nuovo risultato di test patogeno headingDatabaseExportFailed = Esportazione della banca dati non riuscita headingDearchiveCampaign = Disarchivia campagna headingDearchiveCase = Disarchivia caso +headingDearchiveContact = De-Archive contact headingDearchiveEvent = Disarchivia evento +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = Per essere aggiunto a questo campione, il il risultato del test deve dapprima essere contrassegnato come ricevuto. infoArchivedCases = I casi sono archiviati automaticamente dopo %d giorni senza modifiche dei dati. infoArchivedEvents = Gli eventi sono archiviati automaticamente dopo %d giorni senza modifiche dei dati. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = La banca dati contiene già almeno una persona che sembra essere molto simile ai dettagli personali del partecipante creato.

    Consulta l'elenco delle persone. Se ti senti sicuro che una di queste persone corrisponde al tuo partecipante, selezionala e clicca sul pulsante Salva. Altrimenti, clicca su Crea nuova persona per creare un nuovo partecipante all'evento.

    Se non sei sicuro, puoi scartare questa finestra e annullare il processo di creazione del partecipante. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = La persona che hai selezionato è già definita come partecipante di questo evento. messageAnimalContactsHint = Si prega di indicare una risposta riguardante TUTTI gli animali (vivi o morti) a cui la persona è stata esposta direttamente (p. es. cacciare, toccare, mangiare) durante il periodo di incubazione. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = La campagna è stata archiviata messageCampaignCreated = Nuova campagna creata messageCampaignDearchived = La campagna è stata disarchiviata @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=Nuovo contatto creato +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Dati del contatto salvati messageContactsDeleted = Tutti i contatti selezionati sono stati eliminati messageContactsEdited = Tutti i contatti sono stati modificati @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = L'evento è stato disarchiviato messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = Nuova persona creata messageEventParticipantSaved = Dati personali salvati messageEventParticipantsDeleted = Tutti i partecipanti all'evento selezionati sono stati eliminati @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_it-IT.properties b/sormas-api/src/main/resources/strings_it-IT.properties index 7aafc6f8f32..e7efce31fbd 100644 --- a/sormas-api/src/main/resources/strings_it-IT.properties +++ b/sormas-api/src/main/resources/strings_it-IT.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Sei sicuro di voler archiviare questa campagna? Non sarà rimossa dal sistema o dalle statistiche, ma solo nascosta dal normale elenco delle campagne. confirmationArchiveCase = Sei sicuro di voler archiviare questo caso? Non sarà rimosso dal sistema o dalle statistiche, ma solo nascosto dal normale elenco dei casi. confirmationArchiveCases = Sei sicuro di voler archiviare tutti i %d casi selezionati? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Sei sicuro di voler archiviare questo evento? Non sarà rimosso dal sistema o dalle statistiche, ma solo nascosto dal normale elenco degli eventi. confirmationArchiveEvents = Sei sicuro di voler archiviare tutti i %d eventi selezionati? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Vuoi veramente cambiare la malattia del caso? confirmationDearchiveCampaign = Sei sicuro di voler disarchiviare questa campagna? Apparirà nuovamente nel normale elenco delle campagne. confirmationDearchiveCase = Sei sicuro di voler disarchiviare questo caso? Apparirà nuovamente nel normale elenco dei casi. confirmationDearchiveCases = Sei sicuro di voler disarchiviare tutti i %d casi selezionati? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Sei sicuro di voler disarchiviare questo evento? Apparirà nuovamente nel normale elenco degli eventi. confirmationDearchiveEvents = Sei sicuro di voler disarchiviare tutti i %d eventi selezionati? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Sei sicuro di voler eliminare tutti i %d casi selezionati? confirmationDeleteContacts = Sei sicuro di voler eliminare tutti i %d contatti selezionati? @@ -365,7 +370,9 @@ headingAllContacts = Tutti i contatti headingAnimalContacts = Contatti con animali headingArchiveCampaign = Archivia campagna headingArchiveCase = Archivia caso +headingArchiveContact = Archive contact headingArchiveEvent = Archivia evento +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Crea nuovo risultato di test patogeno headingDatabaseExportFailed = Esportazione della banca dati non riuscita headingDearchiveCampaign = Disarchivia campagna headingDearchiveCase = Disarchivia caso +headingDearchiveContact = De-Archive contact headingDearchiveEvent = Disarchivia evento +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = Per essere aggiunto a questo campione, il il risultato del test deve dapprima essere contrassegnato come ricevuto. infoArchivedCases = I casi sono archiviati automaticamente dopo %d giorni senza modifiche dei dati. infoArchivedEvents = Gli eventi sono archiviati automaticamente dopo %d giorni senza modifiche dei dati. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = La banca dati contiene già almeno una persona che sembra essere molto simile ai dettagli personali del partecipante creato.

    Consulta l'elenco delle persone. Se ti senti sicuro che una di queste persone corrisponde al tuo partecipante, selezionala e clicca sul pulsante Salva. Altrimenti, clicca su Crea nuova persona per creare un nuovo partecipante all'evento.

    Se non sei sicuro, puoi scartare questa finestra e annullare il processo di creazione del partecipante. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Si prega di indicare una risposta riguardante TUTTI gli animali (vivi o morti) a cui la persona è stata esposta direttamente (p. es. cacciare, toccare, mangiare) durante il periodo di incubazione. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = La campagna è stata archiviata messageCampaignCreated = Nuova campagna creata messageCampaignDearchived = La campagna è stata disarchiviata @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=Nuovo contatto creato +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Dati del contatto salvati messageContactsDeleted = Tutti i contatti selezionati sono stati eliminati messageContactsEdited = Tutti i contatti sono stati modificati @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = L'evento è stato disarchiviato messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = Nuova persona creata messageEventParticipantSaved = Dati personali salvati messageEventParticipantsDeleted = Tutti i partecipanti all'evento selezionati sono stati eliminati @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_ja-JP.properties b/sormas-api/src/main/resources/strings_ja-JP.properties index e2aba1b50c7..3cfaf789853 100644 --- a/sormas-api/src/main/resources/strings_ja-JP.properties +++ b/sormas-api/src/main/resources/strings_ja-JP.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = Are you sure you want to archive this case? This will not remove it from the system or any statistics, but only hide it from the normal case directory. confirmationArchiveCases = Are you sure you want to archive all %d selected cases? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Really change case disease? confirmationDearchiveCampaign = Are you sure you want to de-archive this campaign? This will make it appear in the normal campaign directory again. confirmationDearchiveCase = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveCases = Are you sure you want to de-archive all %d selected cases? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Are you sure you want to de-archive this event? This will make it appear in the normal event directory again. confirmationDearchiveEvents = Are you sure you want to de-archive all %d selected events? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Are you sure you want to delete all %d selected cases? confirmationDeleteContacts = Are you sure you want to delete all %d selected contacts? @@ -365,7 +370,9 @@ headingAllContacts = All Contacts headingAnimalContacts = Animal Contacts headingArchiveCampaign = Archive Campaign headingArchiveCase = Archive case +headingArchiveContact = Archive contact headingArchiveEvent = Archive event +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new pathogen test result headingDatabaseExportFailed = Database export failed headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = De-Archive case +headingDearchiveContact = De-Archive contact headingDearchiveEvent = De-Archive event +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_nl-NL.properties b/sormas-api/src/main/resources/strings_nl-NL.properties index e2aba1b50c7..3cfaf789853 100644 --- a/sormas-api/src/main/resources/strings_nl-NL.properties +++ b/sormas-api/src/main/resources/strings_nl-NL.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = Are you sure you want to archive this case? This will not remove it from the system or any statistics, but only hide it from the normal case directory. confirmationArchiveCases = Are you sure you want to archive all %d selected cases? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Really change case disease? confirmationDearchiveCampaign = Are you sure you want to de-archive this campaign? This will make it appear in the normal campaign directory again. confirmationDearchiveCase = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveCases = Are you sure you want to de-archive all %d selected cases? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Are you sure you want to de-archive this event? This will make it appear in the normal event directory again. confirmationDearchiveEvents = Are you sure you want to de-archive all %d selected events? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Are you sure you want to delete all %d selected cases? confirmationDeleteContacts = Are you sure you want to delete all %d selected contacts? @@ -365,7 +370,9 @@ headingAllContacts = All Contacts headingAnimalContacts = Animal Contacts headingArchiveCampaign = Archive Campaign headingArchiveCase = Archive case +headingArchiveContact = Archive contact headingArchiveEvent = Archive event +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new pathogen test result headingDatabaseExportFailed = Database export failed headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = De-Archive case +headingDearchiveContact = De-Archive contact headingDearchiveEvent = De-Archive event +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_no-NO.properties b/sormas-api/src/main/resources/strings_no-NO.properties index e2aba1b50c7..3cfaf789853 100644 --- a/sormas-api/src/main/resources/strings_no-NO.properties +++ b/sormas-api/src/main/resources/strings_no-NO.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = Are you sure you want to archive this case? This will not remove it from the system or any statistics, but only hide it from the normal case directory. confirmationArchiveCases = Are you sure you want to archive all %d selected cases? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Really change case disease? confirmationDearchiveCampaign = Are you sure you want to de-archive this campaign? This will make it appear in the normal campaign directory again. confirmationDearchiveCase = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveCases = Are you sure you want to de-archive all %d selected cases? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Are you sure you want to de-archive this event? This will make it appear in the normal event directory again. confirmationDearchiveEvents = Are you sure you want to de-archive all %d selected events? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Are you sure you want to delete all %d selected cases? confirmationDeleteContacts = Are you sure you want to delete all %d selected contacts? @@ -365,7 +370,9 @@ headingAllContacts = All Contacts headingAnimalContacts = Animal Contacts headingArchiveCampaign = Archive Campaign headingArchiveCase = Archive case +headingArchiveContact = Archive contact headingArchiveEvent = Archive event +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new pathogen test result headingDatabaseExportFailed = Database export failed headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = De-Archive case +headingDearchiveContact = De-Archive contact headingDearchiveEvent = De-Archive event +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_pl-PL.properties b/sormas-api/src/main/resources/strings_pl-PL.properties index e2aba1b50c7..3cfaf789853 100644 --- a/sormas-api/src/main/resources/strings_pl-PL.properties +++ b/sormas-api/src/main/resources/strings_pl-PL.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = Are you sure you want to archive this case? This will not remove it from the system or any statistics, but only hide it from the normal case directory. confirmationArchiveCases = Are you sure you want to archive all %d selected cases? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Really change case disease? confirmationDearchiveCampaign = Are you sure you want to de-archive this campaign? This will make it appear in the normal campaign directory again. confirmationDearchiveCase = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveCases = Are you sure you want to de-archive all %d selected cases? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Are you sure you want to de-archive this event? This will make it appear in the normal event directory again. confirmationDearchiveEvents = Are you sure you want to de-archive all %d selected events? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Are you sure you want to delete all %d selected cases? confirmationDeleteContacts = Are you sure you want to delete all %d selected contacts? @@ -365,7 +370,9 @@ headingAllContacts = All Contacts headingAnimalContacts = Animal Contacts headingArchiveCampaign = Archive Campaign headingArchiveCase = Archive case +headingArchiveContact = Archive contact headingArchiveEvent = Archive event +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new pathogen test result headingDatabaseExportFailed = Database export failed headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = De-Archive case +headingDearchiveContact = De-Archive contact headingDearchiveEvent = De-Archive event +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_ps-AF.properties b/sormas-api/src/main/resources/strings_ps-AF.properties index 3d6fe026b4e..f254ff42d0f 100644 --- a/sormas-api/src/main/resources/strings_ps-AF.properties +++ b/sormas-api/src/main/resources/strings_ps-AF.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = Are you sure you want to archive this case? This will not remove it from the system or any statistics, but only hide it from the normal case directory. confirmationArchiveCases = Are you sure you want to archive all %d selected cases? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Really change case disease? confirmationDearchiveCampaign = Are you sure you want to de-archive this campaign? This will make it appear in the normal campaign directory again. confirmationDearchiveCase = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveCases = Are you sure you want to de-archive all %d selected cases? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Are you sure you want to de-archive this event? This will make it appear in the normal event directory again. confirmationDearchiveEvents = Are you sure you want to de-archive all %d selected events? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Are you sure you want to delete all %d selected cases? confirmationDeleteContacts = Are you sure you want to delete all %d selected contacts? @@ -365,7 +370,9 @@ headingAllContacts = All Contacts headingAnimalContacts = Animal Contacts headingArchiveCampaign = Archive Campaign headingArchiveCase = Archive case +headingArchiveContact = Archive contact headingArchiveEvent = Archive event +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new pathogen test result headingDatabaseExportFailed = Database export failed headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = De-Archive case +headingDearchiveContact = De-Archive contact headingDearchiveEvent = De-Archive event +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_pt-PT.properties b/sormas-api/src/main/resources/strings_pt-PT.properties index e2aba1b50c7..3cfaf789853 100644 --- a/sormas-api/src/main/resources/strings_pt-PT.properties +++ b/sormas-api/src/main/resources/strings_pt-PT.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = Are you sure you want to archive this case? This will not remove it from the system or any statistics, but only hide it from the normal case directory. confirmationArchiveCases = Are you sure you want to archive all %d selected cases? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Really change case disease? confirmationDearchiveCampaign = Are you sure you want to de-archive this campaign? This will make it appear in the normal campaign directory again. confirmationDearchiveCase = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveCases = Are you sure you want to de-archive all %d selected cases? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Are you sure you want to de-archive this event? This will make it appear in the normal event directory again. confirmationDearchiveEvents = Are you sure you want to de-archive all %d selected events? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Are you sure you want to delete all %d selected cases? confirmationDeleteContacts = Are you sure you want to delete all %d selected contacts? @@ -365,7 +370,9 @@ headingAllContacts = All Contacts headingAnimalContacts = Animal Contacts headingArchiveCampaign = Archive Campaign headingArchiveCase = Archive case +headingArchiveContact = Archive contact headingArchiveEvent = Archive event +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new pathogen test result headingDatabaseExportFailed = Database export failed headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = De-Archive case +headingDearchiveContact = De-Archive contact headingDearchiveEvent = De-Archive event +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_ro-RO.properties b/sormas-api/src/main/resources/strings_ro-RO.properties index e2aba1b50c7..3cfaf789853 100644 --- a/sormas-api/src/main/resources/strings_ro-RO.properties +++ b/sormas-api/src/main/resources/strings_ro-RO.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = Are you sure you want to archive this case? This will not remove it from the system or any statistics, but only hide it from the normal case directory. confirmationArchiveCases = Are you sure you want to archive all %d selected cases? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Really change case disease? confirmationDearchiveCampaign = Are you sure you want to de-archive this campaign? This will make it appear in the normal campaign directory again. confirmationDearchiveCase = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveCases = Are you sure you want to de-archive all %d selected cases? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Are you sure you want to de-archive this event? This will make it appear in the normal event directory again. confirmationDearchiveEvents = Are you sure you want to de-archive all %d selected events? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Are you sure you want to delete all %d selected cases? confirmationDeleteContacts = Are you sure you want to delete all %d selected contacts? @@ -365,7 +370,9 @@ headingAllContacts = All Contacts headingAnimalContacts = Animal Contacts headingArchiveCampaign = Archive Campaign headingArchiveCase = Archive case +headingArchiveContact = Archive contact headingArchiveEvent = Archive event +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new pathogen test result headingDatabaseExportFailed = Database export failed headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = De-Archive case +headingDearchiveContact = De-Archive contact headingDearchiveEvent = De-Archive event +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_ru-RU.properties b/sormas-api/src/main/resources/strings_ru-RU.properties index abbd125f68f..e9cabb62f81 100644 --- a/sormas-api/src/main/resources/strings_ru-RU.properties +++ b/sormas-api/src/main/resources/strings_ru-RU.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = Are you sure you want to archive this case? This will not remove it from the system or any statistics, but only hide it from the normal case directory. confirmationArchiveCases = Are you sure you want to archive all %d selected cases? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Really change case disease? confirmationDearchiveCampaign = Are you sure you want to de-archive this campaign? This will make it appear in the normal campaign directory again. confirmationDearchiveCase = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveCases = Are you sure you want to de-archive all %d selected cases? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Are you sure you want to de-archive this event? This will make it appear in the normal event directory again. confirmationDearchiveEvents = Are you sure you want to de-archive all %d selected events? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Are you sure you want to delete all %d selected cases? confirmationDeleteContacts = Are you sure you want to delete all %d selected contacts? @@ -365,7 +370,9 @@ headingAllContacts = All Contacts headingAnimalContacts = Animal Contacts headingArchiveCampaign = Archive Campaign headingArchiveCase = Archive case +headingArchiveContact = Archive contact headingArchiveEvent = Archive event +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new pathogen test result headingDatabaseExportFailed = Database export failed headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = De-Archive case +headingDearchiveContact = De-Archive contact headingDearchiveEvent = De-Archive event +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_sv-SE.properties b/sormas-api/src/main/resources/strings_sv-SE.properties index e2aba1b50c7..3cfaf789853 100644 --- a/sormas-api/src/main/resources/strings_sv-SE.properties +++ b/sormas-api/src/main/resources/strings_sv-SE.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = Are you sure you want to archive this case? This will not remove it from the system or any statistics, but only hide it from the normal case directory. confirmationArchiveCases = Are you sure you want to archive all %d selected cases? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Really change case disease? confirmationDearchiveCampaign = Are you sure you want to de-archive this campaign? This will make it appear in the normal campaign directory again. confirmationDearchiveCase = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveCases = Are you sure you want to de-archive all %d selected cases? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Are you sure you want to de-archive this event? This will make it appear in the normal event directory again. confirmationDearchiveEvents = Are you sure you want to de-archive all %d selected events? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Are you sure you want to delete all %d selected cases? confirmationDeleteContacts = Are you sure you want to delete all %d selected contacts? @@ -365,7 +370,9 @@ headingAllContacts = All Contacts headingAnimalContacts = Animal Contacts headingArchiveCampaign = Archive Campaign headingArchiveCase = Archive case +headingArchiveContact = Archive contact headingArchiveEvent = Archive event +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new pathogen test result headingDatabaseExportFailed = Database export failed headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = De-Archive case +headingDearchiveContact = De-Archive contact headingDearchiveEvent = De-Archive event +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_sw-KE.properties b/sormas-api/src/main/resources/strings_sw-KE.properties index e2aba1b50c7..3cfaf789853 100644 --- a/sormas-api/src/main/resources/strings_sw-KE.properties +++ b/sormas-api/src/main/resources/strings_sw-KE.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = Are you sure you want to archive this case? This will not remove it from the system or any statistics, but only hide it from the normal case directory. confirmationArchiveCases = Are you sure you want to archive all %d selected cases? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Really change case disease? confirmationDearchiveCampaign = Are you sure you want to de-archive this campaign? This will make it appear in the normal campaign directory again. confirmationDearchiveCase = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveCases = Are you sure you want to de-archive all %d selected cases? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Are you sure you want to de-archive this event? This will make it appear in the normal event directory again. confirmationDearchiveEvents = Are you sure you want to de-archive all %d selected events? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Are you sure you want to delete all %d selected cases? confirmationDeleteContacts = Are you sure you want to delete all %d selected contacts? @@ -365,7 +370,9 @@ headingAllContacts = All Contacts headingAnimalContacts = Animal Contacts headingArchiveCampaign = Archive Campaign headingArchiveCase = Archive case +headingArchiveContact = Archive contact headingArchiveEvent = Archive event +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new pathogen test result headingDatabaseExportFailed = Database export failed headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = De-Archive case +headingDearchiveContact = De-Archive contact headingDearchiveEvent = De-Archive event +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_tr-TR.properties b/sormas-api/src/main/resources/strings_tr-TR.properties index e2aba1b50c7..3cfaf789853 100644 --- a/sormas-api/src/main/resources/strings_tr-TR.properties +++ b/sormas-api/src/main/resources/strings_tr-TR.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = Are you sure you want to archive this case? This will not remove it from the system or any statistics, but only hide it from the normal case directory. confirmationArchiveCases = Are you sure you want to archive all %d selected cases? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Really change case disease? confirmationDearchiveCampaign = Are you sure you want to de-archive this campaign? This will make it appear in the normal campaign directory again. confirmationDearchiveCase = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveCases = Are you sure you want to de-archive all %d selected cases? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Are you sure you want to de-archive this event? This will make it appear in the normal event directory again. confirmationDearchiveEvents = Are you sure you want to de-archive all %d selected events? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Are you sure you want to delete all %d selected cases? confirmationDeleteContacts = Are you sure you want to delete all %d selected contacts? @@ -365,7 +370,9 @@ headingAllContacts = All Contacts headingAnimalContacts = Animal Contacts headingArchiveCampaign = Archive Campaign headingArchiveCase = Archive case +headingArchiveContact = Archive contact headingArchiveEvent = Archive event +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new pathogen test result headingDatabaseExportFailed = Database export failed headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = De-Archive case +headingDearchiveContact = De-Archive contact headingDearchiveEvent = De-Archive event +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_uk-UA.properties b/sormas-api/src/main/resources/strings_uk-UA.properties index e2aba1b50c7..3cfaf789853 100644 --- a/sormas-api/src/main/resources/strings_uk-UA.properties +++ b/sormas-api/src/main/resources/strings_uk-UA.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = Are you sure you want to archive this case? This will not remove it from the system or any statistics, but only hide it from the normal case directory. confirmationArchiveCases = Are you sure you want to archive all %d selected cases? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = Really change case disease? confirmationDearchiveCampaign = Are you sure you want to de-archive this campaign? This will make it appear in the normal campaign directory again. confirmationDearchiveCase = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveCases = Are you sure you want to de-archive all %d selected cases? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = Are you sure you want to de-archive this event? This will make it appear in the normal event directory again. confirmationDearchiveEvents = Are you sure you want to de-archive all %d selected events? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = Are you sure you want to de-archive this event group? This will make it appear in the normal event group directory again. confirmationDeleteCases = Are you sure you want to delete all %d selected cases? confirmationDeleteContacts = Are you sure you want to delete all %d selected contacts? @@ -365,7 +370,9 @@ headingAllContacts = All Contacts headingAnimalContacts = Animal Contacts headingArchiveCampaign = Archive Campaign headingArchiveCase = Archive case +headingArchiveContact = Archive contact headingArchiveEvent = Archive event +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new pathogen test result headingDatabaseExportFailed = Database export failed headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = De-Archive case +headingDearchiveContact = De-Archive contact headingDearchiveEvent = De-Archive event +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes diff --git a/sormas-api/src/main/resources/strings_ur-PK.properties b/sormas-api/src/main/resources/strings_ur-PK.properties index cc57f5291bf..8de806a9985 100644 --- a/sormas-api/src/main/resources/strings_ur-PK.properties +++ b/sormas-api/src/main/resources/strings_ur-PK.properties @@ -78,6 +78,7 @@ date = تاریخ nameOf = %s کا نام uuidOf = %s کا UUID listOf = %s کی فہرست +mapOf = کا نقشہ<%s, %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = آپ نے فالو اپ بڑھا دیا ہے confirmationArchiveCampaign = کیا آپ واقعی اس مہم کو آرکائیو کرنا چاہتے ہیں؟ یہ اس کو سسٹم یا کسی بھی اعداد و شمار سے نہیں ہٹائے گا، لیکن اسے صرف عام مہم ڈائریکٹری سے چھپائے گا۔ confirmationArchiveCase = کیا آپ واقعی اس کیس کو آرکائیو کرنا چاہتے ہیں؟ یہ اس کو سسٹم یا کسی بھی اعداد و شمار سے نہیں ہٹائے گا، لیکن اسے صرف نارمل کیس ڈائرکٹری سے چھپائے گا۔ confirmationArchiveCases = کیا آپ واقعی تمام %d منتخب کیسز کو آرکائیو کرنا چاہتے ہیں؟ +confirmationArchiveContact = کیا آپ واقعی اس رابطے کو آرکائیو کرنا چاہتے ہیں؟ یہ اسے سسٹم یا کسی بھی اعداد و شمار سے نہیں ہٹائے گا، لیکن اسے صرف عام رابطہ ڈائریکٹری سے چھپائے گا۔ confirmationArchiveEvent = کیا آپ واقعی اس تقریب کو آرکائیو کرنا چاہتے ہیں؟ یہ اس کو سسٹم یا کسی بھی اعداد و شمار سے نہیں ہٹائے گا، لیکن اسے صرف نارمل تقریب کی ڈائرکٹری سے چھپائے گا۔ confirmationArchiveEvents = کیا آپ واقعی تمام %d منتخب تقریبات کو آرکائیو کرنا چاہتے ہیں؟ +confirmationArchiveEventParticipant = کیا آپ واقعی اس تقریب کے شرکت کنندہ کو آرکائیو کرنا چاہتے ہیں؟ یہ اسے سسٹم یا کسی بھی اعداد و شمار سے نہیں ہٹائے گا، بلکہ اسے صرف تقریب کے شرکاء کی فہرست سے چھپائے گا۔ confirmationArchiveImmunization = کیا آپ واقعی اس امیونائزیشن کو آرکائیو کرنا چاہتے ہیں؟ یہ اس کو سسٹم یا کسی بھی اعداد و شمار سے نہیں ہٹائے گا، لیکن اسے صرف نارمل امیونائزیشن ڈائرکٹری سے چھپائے گا۔ confirmationArchiveTask = کیا آپ واقعی تمام %d منتخب کاموں کو آرکائیو کرنا چاہتے ہیں؟ confirmationArchiveTasks = کیا آپ واقعی اس کام کو آرکائیو کرنا چاہتے ہیں؟ یہ اس کو سسٹم یا کسی بھی اعداد و شمار سے نہیں ہٹائے گا، لیکن اسے صرف نارمل کام کی ڈائرکٹری سے چھپائے گا۔ @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = واقعی کیس کی بیماری کو تبد confirmationDearchiveCampaign = کیا آپ واقعی اس مہم کو ڈی آرکائیو کرنا چاہتے ہیں؟ اس سے یہ نارمل مہم کی ڈائریکٹری میں دوبارہ ظاہر ہو جائے گی۔ confirmationDearchiveCase = کیا آپ واقعی اس کیس کو ڈی آرکائیو کرنا چاہتے ہیں؟ اس سے یہ نارمل کیس کی ڈائریکٹری میں دوبارہ ظاہر ہو جائے گا۔ confirmationDearchiveCases = کیا آپ واقعی تمام %d منتخب کیسز کو ڈی آرکائیو کرنا چاہتے ہیں؟ +confirmationDearchiveContact = کیا آپ واقعی اس کیس کو ڈی آرکائیو کرنا چاہتے ہیں؟ اس سے یہ نارمل کیس کی ڈائریکٹری میں دوبارہ ظاہر ہو جائے گا۔ confirmationDearchiveEvent = کیا آپ واقعی اس تقریب کو ڈی آرکائیو کرنا چاہتے ہیں؟ اس سے یہ نارمل تقریب کی ڈائریکٹری میں دوبارہ ظاہر ہو جائے گا۔ confirmationDearchiveEvents = کیا آپ واقعی تمام %d منتخب تقریبات کو ڈی آرکائیو کرنا چاہتے ہیں؟ +confirmationDearchiveEventParticipant = کیا آپ واقعی اس تقریب کے شریک کو ڈی آرکائیو کرنا چاہتے ہیں؟ یہ اسے عام تقریب کے شرکاء کی فہرست میں دوبارہ ظاہر کرے گا۔ confirmationDearchiveEventGroup = کیا آپ واقعی اس تقریبی گروہ کو ڈی آرکائیو کرنا چاہتے ہیں؟ اس سے یہ نارمل تقریبی گروہ کی ڈائریکٹری میں دوبارہ ظاہر ہو جائے گا۔ confirmationDeleteCases = کیا آپ واقعی تمام %d منتخب کیسز کو مٹانا چاہتے ہیں؟ confirmationDeleteContacts = کیا آپ واقعی تمام %d منتخب روابط کو مٹانا چاہتے ہیں؟ @@ -365,7 +370,9 @@ headingAllContacts = تمام روابط headingAnimalContacts = جانوروں سے رابطے headingArchiveCampaign = آرکائیو مہم headingArchiveCase = آرکائیو کیسز +headingArchiveContact = آرکائیو رابطہ headingArchiveEvent = تقریب کو آرکائیو کریں +headingArchiveEventParticipant = آرکائیو تقریب کے شریک headingArchiveEventGroup = تقریب کے گروپس کو آرکائیو کریں headingArchiveImmunization = امیونائزیشن کو آرکائیو کریں headingArchiveTravelEntry = سفری اندراجات کو آرکائیو کریں @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = نئے پیتھوجین ٹیسٹ کا نتیج headingDatabaseExportFailed = ڈیٹا بیس ایکسپورٹ ناکام ہو گیا headingDearchiveCampaign = مہمات کو ڈی آرکائیو کريں headingDearchiveCase = کیس کو ڈی آرکائیو کريں +headingDearchiveContact = ڈی آرکائیو رابطہ headingDearchiveEvent = تقریب کو ڈی آرکائیو کريں +headingDearchiveEventParticipant = ڈی آرکائیو تقریب کے شریک headingDearchiveEventGroup = تقریب کے گروپ کو ڈی آرکائیو کريں headingDearchiveImmunization = امیونائزیشن کو ڈی آرکائیو کريں headingDearchiveTravelEntry = سفری اندراجات کو ڈی آرکائیو کريں @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = براہ کرم انفیکشن کے بعد infoAddTestsToSample = اس نمونے میں ٹیسٹ کا نتیجہ شامل کرنے کے لیے، اسے پہلے موصول ہونے کے بطور نشان زد کرنا ہوگا۔ infoArchivedCases = کیسز %d دنوں کے بعد ڈیٹا میں تبدیلی کے بغیر خودکار طور پر آرکائیو ہو جاتے ہیں۔ infoArchivedEvents = تقریبات %d دنوں کے بعد ڈیٹا میں تبدیلی کے بغیر خودکار طور پر آرکائیو ہو جاتی ہیں۔ +infoArchivedEventParticipants = تقریب کے شرکاء کو ڈیٹا میں تبدیلی کے بغیر %d دنوں کے بعد خودکار طور پر محفوظ کر لیا جاتا ہے۔ infoArchivedTravelEntries = سفری اندراجات %d دنوں کے بعد ڈیٹا میں تبدیلی کے بغیر خودکار طور پر آرکائیو ہو جاتے ہیں۔ infoAssigneeMissingEmail = اس کام کو کرنے والے صارف نے ای میل پتہ فراہم نہیں کیا ہے، اس لیے اسے نوٹیفائی نہیں کیا جائے گا۔ infoObserverMissingEmail = اس کام کے مبصرین میں سے کم از کم ایک نے ای میل ایڈریس فراہم نہیں کیا گیا ہے، اور اس لیے اسے نوٹیفائی نہیں کیا جائے گا۔ @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = ڈیٹا بیس میں پہلے سے infoSelectOrCreatePersonForImport = ڈیٹا بیس میں پہلے سے ہی کم از کم ایک شخص موجود ہے جو بظاہر امپورٹ شدہ اندراج کی ذاتی تفصیلات سے بہت ملتا جلتا ہے۔

    براہ کرم افراد کی فہرست کو دیکھیں۔ اگر آپ کو یقین ہے کہ ان افراد میں سے ایک امپورٹ شدہ اندراج کے فرد سے میل کھاتا ہے، تو اسے منتخب کریں اور محفوظ کریں بٹن پر کلک کریں۔ بصورت دیگر، نیا شخص بنانے کے لیے نیا شخص بنائیں پر کلک کریں۔

    اگر آپ کو یقین نہیں ہے، تو آپ موجودہ درآمد سے اندراج کو ہٹانے کے لیے اس ونڈو کو رد کر سکتے ہیں۔ infoSelectOrCreatePersonForEventParticipant = ڈیٹا بیس میں پہلے سے ہی کم از کم ایک شخص موجود ہے جو بناۓ گۓ تقریب کے شریک کی ذاتی تفصیلات سے بہت ملتا جلتا لگتا ہے۔

    براہ کرم افراد کی فہرست کو دیکھیں۔ اگر آپ کو یقین ہے کہ ان افراد میں سے ایک آپ کے تقریب والے سے میل کھاتا ہے، تو اسے منتخب کریں اور محفوظ کریں بٹن پر کلک کریں۔ بصورت دیگر، اپنے تقریب کے لیے ایک نیا تقریب کا شخص بنانے کے لیے نیا شخص بنائیں پر کلک کریں۔

    اگر آپ کو یقین نہیں ہے، تو آپ اس ونڈو کو رد کر سکتے ہیں اور تقریب میں شرکت کرنے والے کا، بنانے کے عمل کو منسوخ کر سکتے ہیں۔ infoSelectOrCreatePersonForLabMessage = ڈیٹا بیس میں پہلے سے ہی کم از کم ایک شخص موجود ہے جو لگتا ہے کہ لیب کے پیغام کی ذاتی تفصیلات سے بہت ملتا جلتا ہے۔

    براہ کرم افراد کی فہرست کو دیکھیں۔ اگر آپ کو یقین ہے کہ ان افراد میں سے ایک لیب میسج والے سے میل کھاتا ہے، تو اسے منتخب کریں اور تصدیق کریں بٹن پر کلک کریں۔ بصورت دیگر، لیب کے پیغام کے لیے ایک نیا شخص بنانے کے لیے نیا شخص بنائیں پر کلک کریں۔

    اگر آپ کو یقین نہیں ہے، تو آپ اس ونڈو کو رد کر کے عمل کو منسوخ کر سکتے ہیں۔ +infoSelectOrCreatePersonForLabMessageWithoutMatches = لیب میسج کی شخصی تفصیلات سے قریب سے مماثل شخص کا خود بخود تعین نہیں کیا جا سکتا۔

    آپ دستی طور پر مماثلتیں تلاش کر سکتے ہیں، یا آپ ایک نیا شخص بنا سکتے ہیں۔ ایک بار جب آپ نے کوئی آپشن منتخب کرلیا تو، تصدیق کریں بٹن کے ذریعے جاری رکھیں۔

    اگر آپ کو یقین نہیں ہے، تو آپ اس ونڈو کو رد کر کے عمل کو منسوخ کر سکتے ہیں۔ infoSkipOrOverrideDuplicateCampaignFormDataImport = ڈیٹا بیس میں پہلے سے ہی مخصوص کمیونٹی اور تاریخ کے لیے مہم %s میں فارم %s کے لیے ڈیٹا سیٹ موجود ہے۔ براہ کرم موجودہ ڈیٹاسیٹ کی تفصیلات پر ایک نظر ڈالیں اور اگر آپ موجودہ ڈیٹا کو رکھنا چاہتے ہیں تو چھوڑیں کا انتخاب کریں یا اگر آپ موجودہ ڈیٹا کو اپنے امپورٹ کردہ ڈیٹا سے تبدیل کرنا چاہتے ہیں۔ تو اوور رائٹ کریں انتخاب کریں pseudonymizedCasesSelectedWarning = بڑی تعداد میں ترمیم شدہ کیسز کے لیے آپ کے پاس صرف حساس ڈیٹا تک محدود رسائی ہے۔ ان صورتوں میں آپ نے "جگہ کی تفصیل" میں جو قدر ڈالی ہے اسے نظر انداز کر دیا جائے گا۔ pseudonymizedEntitiesSelectedWarning = آپ کو صرف کچھ منتخب نظاموں تک محدود رسائی حاصل ہے۔ جاری رکھنے کے لیے براہ کرم تخلصی نظاموں کو غیر منتخب کریں۔ @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = تمام رابطے پہلے سے ہی منت messageAllContactsLinkedToEvent = تمام رابطوں کو منتخب تقریب سے منسلک کر دیا گیا ہے۔ messageAlreadyEventParticipant = آپ نے جس شخص کو منتخب کیا ہے اس کی پہلے سے ہی اس تقریب کے ایک شرکت کنندہ کے طور پر بتایا کی گئی ہے۔ messageAnimalContactsHint = براہ کرم ان تمام جانوروں (زندہ یا مردہ) کے بارے میں ایک جواب کی نشاندہی کریں جو انکیوبیشن کی مدت کے دوران اس شخص سے براہ راست متاثر ہوا تھا (مثلاً شکار، چھونا، کھانا)۔ +messageArchiveUndoneReasonMandatory = براہ کرم ڈی آرکائیو کرنے کی وجہ شامل کریں messageCampaignArchived = مہم آرکائیو کر دی گئی ہے messageCampaignCreated = نئی مہم بنائی گئی messageCampaignDearchived = مہم کو ڈی آرکائیو کر دیا گیا ہے @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=آپ نے تقریب کی بیماری کے messageConvertEventParticipantToCaseDifferentDiseases=آپ نے تقریب کی بیماری سے مختلف بیماری کے لیے لیبارٹری کا مثبت نتیجہ محفوظ کیا ہے۔ کیا آپ تقریب میں شرکت کرنے والے شخص کے لیے اس بیماری کا کیس بنانا چاہتے ہیں؟ کیس کو تقریب کے شرکاء سے منسلک نہیں کیا جائے گا۔ messageConvertEventParticipantToCaseNoDisease=آپ نے لیبارٹری کا مثبت نتیجہ محفوظ کیا ہے ایک تقریب کے لیے جس میں کوئی بیماری نہیں ہے۔ کیا آپ تقریب میں شرکت کرنے والے شخص کے لیے اس بیماری کا کیس بنانا چاہتے ہیں؟ نمونے کا حتمی لیبارٹری نتیجہ خود بخود مثبت پر سیٹ ہو جائے گا لیکن کیس کو تقریب کے شریک سے منسلک نہیں کیا جائے گا۔ messageContactCreated=نیا رابطہ بنایا گیا +messageContactArchived = رابطہ کو آرکائیو کر دیا گیا ہے +messageContactDearchived = رابطہ ڈی آرکائیو کردیا گیا ہے messageContactSaved = رابطے کا ڈیٹا محفوظ ہو گیا messageContactsDeleted = تمام منتخب روابط کو مٹا دیا گیا ہے messageContactsEdited = تمام روابط میں ترمیم کی گئی ہے @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = اس کیس اور تقریب کے درمی messageEventUnlinkedFromEventGroup = اس تقریب اور تقریب گروہ کے درمیان تعلق کو کامیابی کے ساتھ ہٹا دیا گیا تھا messageEventDearchived = تقریب کو ڈی آرکائیو کر دیا گیا ہے messageEventGroupDearchived = تقریب گروہ کو ڈی آرکائیو کر دیا گیا ہے +messageEventParticipantArchived = تقریب کے شریک کو آرکائیو کر دیا گیا ہے +messageEventParticipantDearchived = تقریب کے شریک کو ڈی آرکائیو کر دیا گیا ہے messageEventParticipantCreated = نیا شخص بنایا messageEventParticipantSaved = شخص کا ڈیٹا محفوظ ہو گیا messageEventParticipantsDeleted = تقریب کے تمام منتخب شرکاء کو مٹا دیا گیا ہے @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = شیئرز لوڈ ہو رہے ہیں... errorConstraintViolation = غلط ڈیٹا -reloadPageToSeeChanges = تازہ ترین تبدیلیاں دیکھنے کے لیے براہ کرم صفحہ کو دوبارہ لوڈ کریں۔ \ No newline at end of file +reloadPageToSeeChanges = تازہ ترین تبدیلیاں دیکھنے کے لیے براہ کرم صفحہ کو دوبارہ لوڈ کریں۔ diff --git a/sormas-api/src/main/resources/strings_zh-CN.properties b/sormas-api/src/main/resources/strings_zh-CN.properties index 0ddded30421..6198cdd84e1 100644 --- a/sormas-api/src/main/resources/strings_zh-CN.properties +++ b/sormas-api/src/main/resources/strings_zh-CN.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s \= %s; %s \= %s; %s \= %s @@ -118,8 +119,10 @@ confirmationAlsoAdjustQuarantine = You have extended the follow-up. Should the e confirmationArchiveCampaign = Are you sure you want to archive this campaign? This will not remove it from the system or any statistics, but only hide it from the normal campaign directory. confirmationArchiveCase = Are you sure you want to archive this case? This will not remove it from the system or any statistics, but only hide it from the normal case directory. confirmationArchiveCases = Are you sure you want to archive all %d selected cases? +confirmationArchiveContact = Are you sure you want to archive this contact? This will not remove it from the system or any statistics, but only hide it from the normal contact directory. confirmationArchiveEvent = Are you sure you want to archive this event? This will not remove it from the system or any statistics, but only hide it from the normal event directory. confirmationArchiveEvents = Are you sure you want to archive all %d selected events? +confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. @@ -130,8 +133,10 @@ confirmationChangeCaseDisease = 真的要改变病例疾病吗? confirmationDearchiveCampaign = 您确定要取消对此活动的归档吗?这将使它再次出现在正常的活动目录中。 confirmationDearchiveCase = 您确定要取消存档此案例吗?这将使其再次出现在正常的案例目录中。 confirmationDearchiveCases = 您确定要取消所有选定的 %d 个案件的归档吗? +confirmationDearchiveContact = Are you sure you want to de-archive this case? This will make it appear in the normal case directory again. confirmationDearchiveEvent = 您确定要取消归档此事件吗?这将使它再次出现在正常事件目录中。 confirmationDearchiveEvents = 您确定要取消所有选定的 %d 个事件的归档吗? +confirmationDearchiveEventParticipant = Are you sure you want to de-archive this event participant? This will make it appear in the normal event participant list again. confirmationDearchiveEventGroup = 您确定要取消归档此事件组吗?这将使它再次出现在正常事件组目录中。 confirmationDeleteCases = 您确定要删除所有选定的 %d 个案例吗? confirmationDeleteContacts = 您确定要删除所有 %d 个选定联系人吗? @@ -365,7 +370,9 @@ headingAllContacts = All Contacts headingAnimalContacts = Animal Contacts headingArchiveCampaign = Archive Campaign headingArchiveCase = Archive case +headingArchiveContact = Archive contact headingArchiveEvent = Archive event +headingArchiveEventParticipant = Archive event participant headingArchiveEventGroup = Archive event group headingArchiveImmunization = Archive immunization headingArchiveTravelEntry = Archive travel entry @@ -430,7 +437,9 @@ headingCreatePathogenTestResult = Create new pathogen test result headingDatabaseExportFailed = Database export failed headingDearchiveCampaign = De-Archive campaign headingDearchiveCase = De-Archive case +headingDearchiveContact = De-Archive contact headingDearchiveEvent = De-Archive event +headingDearchiveEventParticipant = De-Archive event participant headingDearchiveEventGroup = De-Archive event group headingDearchiveImmunization = De-Archive immunization headingDearchiveTravelEntry = De-Archive travel entry @@ -708,6 +717,7 @@ infoActivityAsCaseInvestigation = Please document ALL relevant activities aft infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. infoArchivedCases = Cases are automatically archived after %d days without changes to the data. infoArchivedEvents = Events are automatically archived after %d days without changes to the data. +infoArchivedEventParticipants = Event participants are automatically archived after %d days without changes to the data. infoArchivedTravelEntries = Travel entries are automatically archived after %d days without changes to the data. infoAssigneeMissingEmail = The user assigned to this task does not have an e-mail address provided, and will therefore not be notified. infoObserverMissingEmail = At least one of the observers of this task does not have an e-mail address provided, and will therefore not be notified. @@ -832,6 +842,7 @@ infoSelectOrCreatePersonForImmunization = The database already contains at least infoSelectOrCreatePersonForImport = The database already contains at least one person that seems to be very similar to the personal details of the imported entry.

    Please look through the list of persons. If you feel certain that one of those persons matches the person of the imported entry, select it and click on the Save button. Otherwise, click on Create New Person to create a new person.

    If you are unsure, you can discard this window to remove the entry from the current import. infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.

    Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the Save button. Otherwise, click on Create New Person to create a new event person for your event.

    If you are unsure, you can discard this window and cancel the event participant creation process. infoSelectOrCreatePersonForLabMessage = The database already contains at least one person that seems to be very similar to the personal details of the lab message.

    Please look through the list of persons. If you feel certain that one of those persons matches the lab message person, select it and click on the Confirm button. Otherwise, click on Create New Person to create a new person for the lab message.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose Skip if you want to keep the existing data or Overwrite if you want to replace the existing data with the data you have imported. pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored. pseudonymizedEntitiesSelectedWarning = You only have limited access to some of the selected entities. Please deselect pseudonymized entities to continue. @@ -887,6 +898,7 @@ messageAllContactsAlreadyInEvent = All contacts are already linked to the select messageAllContactsLinkedToEvent = All contacts have been linked to the selected event. messageAlreadyEventParticipant = The person you have selected is already defined as an event participant of this event. messageAnimalContactsHint = Please indicate an answer regarding ALL animals (live or dead) the person had direct exposure to (e.g. hunt, touch, eat) during the incubation period. +messageArchiveUndoneReasonMandatory = Please add a reason for de-archiving messageCampaignArchived = Campaign has been archived messageCampaignCreated = New campaign created messageCampaignDearchived = Campaign has been de-archived @@ -926,6 +938,8 @@ messageConvertEventParticipantToCase=You have just saved a positive laboratory r messageConvertEventParticipantToCaseDifferentDiseases=You have just saved a positive laboratory result for a different disease than the event disease. Do you want to create a case with this disease for the event participant person? The case will not be linked to the event participant. messageConvertEventParticipantToCaseNoDisease=You have just saved a positive laboratory result for an event with no disease. Do you want to create a case with this disease for the event participant person? The final laboratory result of the sample will automatically be set to positive but the case will not be linked to the event participant. messageContactCreated=New contact created +messageContactArchived = Contact has been archived +messageContactDearchived = Contact has been de-archived messageContactSaved = Contact data saved messageContactsDeleted = All selected contacts have been deleted messageContactsEdited = All contacts have been edited @@ -959,6 +973,8 @@ messageEventParticipationUnlinked = The link between this case and the event was messageEventUnlinkedFromEventGroup = The link between this event and the event group was successfully removed messageEventDearchived = Event has been de-archived messageEventGroupDearchived = Event group has been de-archived +messageEventParticipantArchived = Event participant has been archived +messageEventParticipantDearchived = Event participant has been de-archived messageEventParticipantCreated = New person created messageEventParticipantSaved = Person data saved messageEventParticipantsDeleted = All selected event participants have been deleted @@ -1410,4 +1426,4 @@ sormasToSormasLoadingShares = Loading shares... errorConstraintViolation = Invalid data -reloadPageToSeeChanges = Please reload the page to see the latest changes \ No newline at end of file +reloadPageToSeeChanges = Please reload the page to see the latest changes From 34b68e391d1224b0f7584074582bcaf22d919e36 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Tue, 1 Mar 2022 11:24:46 +0100 Subject: [PATCH 218/253] wildcard and conflicts resolved --- .../application/cases/CaseDirectorySteps.java | 75 ++++++++++++++++++- 1 file changed, 72 insertions(+), 3 deletions(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java index bd05b80dba2..6d77025ca62 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java @@ -18,7 +18,70 @@ package org.sormas.e2etests.steps.web.application.cases; -import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.*; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.ALLBUTTON; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.ALL_RESULTS_CHECKBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.BULK_ACTIONS; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.BULK_ACTIONS_VALUES; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASES_FROM_OTHER_INSTANCES_CHECKBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASES_FROM_OTHER_JURISDICTIONS_CHECKBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASES_HELP_NEEDED_IN_QUARANTINE_CHECKBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASES_WITHOUT_FACILITY_CHECKBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASES_WITHOUT_GEO_COORDINATES_CHECKBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASES_WITHOUT_RESPONSIBLE_OFFICER_CHECKBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASES_WITH_EVENTS_CHECKBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASES_WITH_EXTENDED_QUARANTINE_CHECKBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASES_WITH_FULFILLED_REFERENCE_DEFINITION_CHECKBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASES_WITH_REDUCED_QUARANTINE_CHECKBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASES_WITH_REINFECTION_CHECKBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_APPLY_FILTERS_BUTTON; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_CLASSIFICATION_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_COMMUNITY_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_DATA_TYPE_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_DAY_FILTER; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_DIRECTORY_DETAILED_PAGE_APPLY_FILTER_BUTTON; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_DIRECTORY_DETAILED_PAGE_FILTER_INPUT; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_DIRECTORY_DETAILED_RADIOBUTTON; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_DISEASE_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_DISPLAY_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_DISTRICT_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_FACILITY_CATEGORY_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_FACILITY_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_FACILITY_TYPE_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_FOLLOWUP_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_GRID_RESULTS_ROWS; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_MONTH_FILTER; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_ORIGIN_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_OUTCOME_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_PRESENT_CONDITION_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_QUARANTINE_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_REGION_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_REINFECTION_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_REPORTING_USER_FILTER; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_RESET_FILTERS_BUTTON; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_RESULTS_UUID_LOCATOR; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_SURVOFF_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_VACCINATION_STATUS_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_YEAR_FILTER; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.DATE_FROM_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.DATE_TO_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.ENTER_BULK_EDIT_MODE; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.FIRST_CASE_ID_BUTTON; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.FIRST_RESULT_IN_GRID; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.GRID_HEADERS; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.INVESTIGATION_DISCARDED_BUTTON; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.INVESTIGATION_DONE_BUTTON; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.INVESTIGATION_PENDING_BUTTON; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.LINE_LISTING_BUTTON; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.MORE_BUTTON; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.NAME_UUID_EPID_NUMBER_LIKE_INPUT; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.NEW_CASE_BUTTON; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.NEW_EVENT_CHECKBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.PERSON_ID_NAME_CONTACT_INFORMATION_LIKE_INPUT; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.RESULTS_GRID_HEADER; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.SAVE_BUTTON_IN_LINK_FORM; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.SEARCH_BUTTON; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.SHOW_MORE_LESS_FILTERS; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.TOTAL_CASES_COUNTER; import static org.sormas.e2etests.pages.application.cases.CreateNewCasePage.DATE_OF_REPORT_INPUT; import com.github.javafaker.Faker; @@ -30,8 +93,14 @@ import java.util.concurrent.TimeUnit; import javax.inject.Inject; import org.openqa.selenium.By; -import org.sormas.e2etests.common.*; -import org.sormas.e2etests.enums.*; +import org.sormas.e2etests.common.DataOperations; +import org.sormas.e2etests.enums.CaseOrigin; +import org.sormas.e2etests.enums.CaseOutcome; +import org.sormas.e2etests.enums.DiseasesValues; +import org.sormas.e2etests.enums.DistrictsValues; +import org.sormas.e2etests.enums.FacilityCategory; +import org.sormas.e2etests.enums.FollowUpStatus; +import org.sormas.e2etests.enums.PresentCondition; import org.sormas.e2etests.helpers.AssertHelpers; import org.sormas.e2etests.helpers.WebDriverHelpers; import org.sormas.e2etests.state.ApiState; From 7e023178e1b063d83962fdc6b18094216c5b5bc0 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Tue, 1 Mar 2022 11:43:52 +0100 Subject: [PATCH 219/253] format change --- .../pages/application/events/EventDirectoryPage.java | 2 +- .../web/application/events/EventDirectorySteps.java | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java index 1442f6ced45..52d2b94591e 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java @@ -62,7 +62,7 @@ public class EventDirectoryPage { public static final By EVENT_DROPPED = By.id("status-Dropped"); public static final By CREATED_PARTICIPANT = By.cssSelector("[role='gridcell'] a"); public static final By EVENT_PARTICIPANT_INPUT = By.id("freeTextEventParticipants"); - public static final By EVENT_GROUP_INPUT= By.id("freeTextEventGroups"); + public static final By EVENT_GROUP_INPUT = By.id("freeTextEventGroups"); /*public static By getByEventUuid(String eventUuid) { return By.cssSelector("a[title=" + eventUuid + "]"); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index 9de828e7f12..88b82ab9a9b 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -94,7 +94,7 @@ public EventDirectorySteps( And( "I fill Event to input to {int} days after mocked Event created on Event directory page", (Integer number) -> { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy"); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M/d/yyyy"); webDriverHelpers.fillInWebElement( DATE_TO_COMBOBOX, formatter.format( @@ -106,7 +106,7 @@ public EventDirectorySteps( And( "I fill Event from input to {int} days before mocked Event created on Event directory page", (Integer number) -> { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy"); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M/d/yyyy"); webDriverHelpers.fillInWebElement( DATE_FROM_COMBOBOX, formatter.format( @@ -118,7 +118,7 @@ public EventDirectorySteps( And( "I fill Event from input to {int} days after before mocked Event created on Event directory page", (Integer number) -> { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy"); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M/d/yyyy"); webDriverHelpers.fillInWebElement( DATE_FROM_COMBOBOX, formatter.format(LocalDate.now().plusDays(number))); }); @@ -138,7 +138,8 @@ public EventDirectorySteps( }); And( "I filter by mocked EventGroupId on Event directory page", - () -> webDriverHelpers.fillAndSubmitInWebElement(EVENT_GROUP_INPUT, "TestName TestSurname")); + () -> + webDriverHelpers.fillAndSubmitInWebElement(EVENT_GROUP_INPUT, "TestName TestSurname")); When( "I select random Risk level filter among the filter options from API", () -> { From 1a68a8f4b4b9f02762cc13e3d1e364c5f194c1f4 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Tue, 1 Mar 2022 11:46:56 +0100 Subject: [PATCH 220/253] conflicts resolved --- .../events/EventDirectorySteps.java | 85 ++++++++++++------- 1 file changed, 55 insertions(+), 30 deletions(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index 2ca2f75e9af..affba163875 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -18,42 +18,15 @@ package org.sormas.e2etests.steps.web.application.events; -import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_COMMUNITY_FILTER_COMBOBOX; -import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_DATA_TYPE_FILTER_COMBOBOX; -import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_DISTRICT_FILTER_COMBOBOX; -import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_GRID_RESULTS_ROWS; -import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_REGION_FILTER_COMBOBOX; -import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.DATE_FROM_COMBOBOX; -import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.DATE_TO_COMBOBOX; -import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.PERSON_ID_NAME_CONTACT_INFORMATION_LIKE_INPUT; -import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.DATE_FROM_COMBOBOX; -import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.DATE_TO_COMBOBOX; -import static org.sormas.e2etests.pages.application.events.EditEventPage.*; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.*; -import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.APPLY_FILTERS_BUTTON; -import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.RESET_FILTERS_BUTTON; -import static org.sormas.e2etests.steps.BaseSteps.locale; - import cucumber.api.java8.En; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.time.LocalDate; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import javax.inject.Inject; import org.openqa.selenium.WebDriverException; import org.openqa.selenium.WebElement; import org.sormas.e2etests.common.DataOperations; import org.sormas.e2etests.entities.services.EventService; -import org.sormas.e2etests.enums.*; +import org.sormas.e2etests.enums.DiseasesValues; import org.sormas.e2etests.enums.EventReferenceDateOptions; +import org.sormas.e2etests.enums.RiskLevelValues; +import org.sormas.e2etests.enums.SourceTypeValues; import org.sormas.e2etests.enums.cases.epidemiologicalData.TypeOfPlace; import org.sormas.e2etests.envconfig.manager.EnvironmentManager; import org.sormas.e2etests.helpers.AssertHelpers; @@ -65,6 +38,58 @@ import org.testng.Assert; import org.testng.asserts.SoftAssert; +import javax.inject.Inject; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_COMMUNITY_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_DATA_TYPE_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_DISTRICT_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_GRID_RESULTS_ROWS; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_REGION_FILTER_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.DATE_FROM_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.DATE_TO_COMBOBOX; +import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.PERSON_ID_NAME_CONTACT_INFORMATION_LIKE_INPUT; +import static org.sormas.e2etests.pages.application.events.EditEventPage.EVENT_PARTICIPANTS_TAB; +import static org.sormas.e2etests.pages.application.events.EditEventPage.FIRST_EVENT_PARTICIPANT; +import static org.sormas.e2etests.pages.application.events.EditEventPage.NEW_TASK_BUTTON; +import static org.sormas.e2etests.pages.application.events.EditEventPage.TITLE_INPUT; +import static org.sormas.e2etests.pages.application.events.EditEventPage.UUID_INPUT; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.APPLY_FILTER; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.CREATED_PARTICIPANT; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.CREATE_CASE_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.DATE_TYPE_COMBOBOX; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENTS_COLUMN_HEADERS; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENTS_TABLE_DATA; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENTS_TABLE_ROW; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_DISPLAY_COMBOBOX; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_GROUP_INPUT; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_INVESTIGATION_STATUS; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_MANAGEMENT_FILTER; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_STATUS_FILTER_BUTTONS; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_DISEASE; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_REPORTING_USER; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_RISK_LEVEL; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_SOURCE_TYPE; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_TYPE_OF_PLACE; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FIRST_EVENT_ID_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.RESET_FILTER; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.SEARCH_EVENT_BY_FREE_TEXT; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.SEARCH_EVENT_BY_FREE_TEXT_INPUT; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.TOTAL_EVENTS_COUNTER; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.getByEventUuid; +import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.APPLY_FILTERS_BUTTON; +import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.RESET_FILTERS_BUTTON; +import static org.sormas.e2etests.steps.BaseSteps.locale; + public class EventDirectorySteps implements En { private final WebDriverHelpers webDriverHelpers; private final BaseSteps baseSteps; From 053020696d2508f30832e9b62e968755467e08f6 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Tue, 1 Mar 2022 11:57:26 +0100 Subject: [PATCH 221/253] ignore decorator added --- .../src/test/resources/features/sanity/web/EventFilters.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/EventFilters.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/EventFilters.feature index 7fae8eb5635..2ae61d3cbb2 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/EventFilters.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/EventFilters.feature @@ -96,7 +96,7 @@ Feature: Filters in Event Directory And I apply on the APPLY FILTERS button from Event And I check the number of displayed Event results from All button is 0 - @issue=SORQA-77 @env_main + @issue=SORQA-77 @env_main @ignore Scenario: Date filters and aggregation buttons in Event Directory Given API: I create a new event Then API: I check that POST call body is "OK" From 2763044e5b3b467a0cf95a08eea9c625e34bce33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9=20Strysewske?= Date: Tue, 1 Mar 2022 12:19:38 +0100 Subject: [PATCH 222/253] [GITFLOW]Updating development poms to hotfix version to avoid merge conflicts --- sormas-api/pom.xml | 2 +- sormas-app/pom.xml | 2 +- sormas-backend/pom.xml | 2 +- sormas-base/dependencies/serverlibs.pom | 2 +- sormas-base/pom.xml | 2 +- sormas-cargoserver/pom.xml | 2 +- sormas-ear/pom.xml | 2 +- sormas-keycloak-service-provider/pom.xml | 2 +- sormas-rest/pom.xml | 2 +- sormas-ui/pom.xml | 2 +- sormas-widgetset/pom.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sormas-api/pom.xml b/sormas-api/pom.xml index 214eb0b788e..cc38cc351c3 100644 --- a/sormas-api/pom.xml +++ b/sormas-api/pom.xml @@ -2,7 +2,7 @@ de.symeda.sormas sormas-base - 1.69.0-SNAPSHOT + 1.68.2 ../sormas-base 4.0.0 diff --git a/sormas-app/pom.xml b/sormas-app/pom.xml index 3bb68392128..1de3dfdd079 100644 --- a/sormas-app/pom.xml +++ b/sormas-app/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.2 ../sormas-base 4.0.0 diff --git a/sormas-backend/pom.xml b/sormas-backend/pom.xml index 48b45586014..fb0d0d99d52 100644 --- a/sormas-backend/pom.xml +++ b/sormas-backend/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.2 ../sormas-base 4.0.0 diff --git a/sormas-base/dependencies/serverlibs.pom b/sormas-base/dependencies/serverlibs.pom index effd624397b..81b7e9ac67f 100644 --- a/sormas-base/dependencies/serverlibs.pom +++ b/sormas-base/dependencies/serverlibs.pom @@ -8,7 +8,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.2 ../ diff --git a/sormas-base/pom.xml b/sormas-base/pom.xml index f5dd10b65f7..48d9421ca4c 100644 --- a/sormas-base/pom.xml +++ b/sormas-base/pom.xml @@ -5,7 +5,7 @@ de.symeda.sormas sormas-base pom - 1.69.0-SNAPSHOT + 1.68.2 1.8 diff --git a/sormas-cargoserver/pom.xml b/sormas-cargoserver/pom.xml index 8c6009ec75f..3895cc8693e 100644 --- a/sormas-cargoserver/pom.xml +++ b/sormas-cargoserver/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.69.0-SNAPSHOT + 1.68.2 ../sormas-base diff --git a/sormas-ear/pom.xml b/sormas-ear/pom.xml index eb67f26b2b0..b6a74096b4f 100644 --- a/sormas-ear/pom.xml +++ b/sormas-ear/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.69.0-SNAPSHOT + 1.68.2 ../sormas-base diff --git a/sormas-keycloak-service-provider/pom.xml b/sormas-keycloak-service-provider/pom.xml index 142c2f5858e..cd99048a141 100644 --- a/sormas-keycloak-service-provider/pom.xml +++ b/sormas-keycloak-service-provider/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.2 ../sormas-base 4.0.0 diff --git a/sormas-rest/pom.xml b/sormas-rest/pom.xml index 85e9fe6b41d..b04fd0c099f 100644 --- a/sormas-rest/pom.xml +++ b/sormas-rest/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.69.0-SNAPSHOT + 1.68.2 ../sormas-base diff --git a/sormas-ui/pom.xml b/sormas-ui/pom.xml index 8b3382d103a..046fc2f59d8 100644 --- a/sormas-ui/pom.xml +++ b/sormas-ui/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.2 ../sormas-base 4.0.0 diff --git a/sormas-widgetset/pom.xml b/sormas-widgetset/pom.xml index f8d6a25f29d..2e069725235 100644 --- a/sormas-widgetset/pom.xml +++ b/sormas-widgetset/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.2 ../sormas-base 4.0.0 From a0cfb35f68f2437ad2d5cb2766ec50dcaabe02ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9=20Strysewske?= Date: Tue, 1 Mar 2022 12:22:45 +0100 Subject: [PATCH 223/253] [Gitflow]update develop poms back to pre merge state --- sormas-api/pom.xml | 2 +- sormas-app/pom.xml | 2 +- sormas-backend/pom.xml | 2 +- sormas-base/dependencies/serverlibs.pom | 2 +- sormas-base/pom.xml | 2 +- sormas-ear/pom.xml | 2 +- sormas-keycloak-service-provider/pom.xml | 2 +- sormas-rest/pom.xml | 2 +- sormas-ui/pom.xml | 2 +- sormas-widgetset/pom.xml | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sormas-api/pom.xml b/sormas-api/pom.xml index cc38cc351c3..214eb0b788e 100644 --- a/sormas-api/pom.xml +++ b/sormas-api/pom.xml @@ -2,7 +2,7 @@ de.symeda.sormas sormas-base - 1.68.2 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-app/pom.xml b/sormas-app/pom.xml index 1de3dfdd079..3bb68392128 100644 --- a/sormas-app/pom.xml +++ b/sormas-app/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.2 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-backend/pom.xml b/sormas-backend/pom.xml index fb0d0d99d52..48b45586014 100644 --- a/sormas-backend/pom.xml +++ b/sormas-backend/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.2 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-base/dependencies/serverlibs.pom b/sormas-base/dependencies/serverlibs.pom index 81b7e9ac67f..effd624397b 100644 --- a/sormas-base/dependencies/serverlibs.pom +++ b/sormas-base/dependencies/serverlibs.pom @@ -8,7 +8,7 @@ sormas-base de.symeda.sormas - 1.68.2 + 1.69.0-SNAPSHOT ../ diff --git a/sormas-base/pom.xml b/sormas-base/pom.xml index 48d9421ca4c..f5dd10b65f7 100644 --- a/sormas-base/pom.xml +++ b/sormas-base/pom.xml @@ -5,7 +5,7 @@ de.symeda.sormas sormas-base pom - 1.68.2 + 1.69.0-SNAPSHOT 1.8 diff --git a/sormas-ear/pom.xml b/sormas-ear/pom.xml index b6a74096b4f..eb67f26b2b0 100644 --- a/sormas-ear/pom.xml +++ b/sormas-ear/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.68.2 + 1.69.0-SNAPSHOT ../sormas-base diff --git a/sormas-keycloak-service-provider/pom.xml b/sormas-keycloak-service-provider/pom.xml index cd99048a141..142c2f5858e 100644 --- a/sormas-keycloak-service-provider/pom.xml +++ b/sormas-keycloak-service-provider/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.2 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-rest/pom.xml b/sormas-rest/pom.xml index b04fd0c099f..85e9fe6b41d 100644 --- a/sormas-rest/pom.xml +++ b/sormas-rest/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.68.2 + 1.69.0-SNAPSHOT ../sormas-base diff --git a/sormas-ui/pom.xml b/sormas-ui/pom.xml index 046fc2f59d8..8b3382d103a 100644 --- a/sormas-ui/pom.xml +++ b/sormas-ui/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.2 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-widgetset/pom.xml b/sormas-widgetset/pom.xml index 2e069725235..f8d6a25f29d 100644 --- a/sormas-widgetset/pom.xml +++ b/sormas-widgetset/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.2 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 From 5d2376a0f5061a78d1b8ae3aba3a442e1d7c9b2a Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Tue, 1 Mar 2022 12:23:11 +0100 Subject: [PATCH 224/253] resolved conflicts --- .../web/application/events/EventDirectorySteps.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index be661ada8a6..85b079fbb91 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -18,16 +18,6 @@ package org.sormas.e2etests.steps.web.application.events; -import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_GRID_RESULTS_ROWS; -import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.DATE_FROM_COMBOBOX; -import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.DATE_TO_COMBOBOX; -import static org.sormas.e2etests.pages.application.events.EditEventPage.*; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.*; -import static org.sormas.e2etests.pages.application.persons.EditPersonPage.UUID_INPUT; -import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.APPLY_FILTERS_BUTTON; -import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.RESET_FILTERS_BUTTON; -import static org.sormas.e2etests.steps.BaseSteps.locale; - import cucumber.api.java8.En; import org.openqa.selenium.WebDriverException; import org.openqa.selenium.WebElement; From 70b06ae63241c6ac93324428d7699472c9bd20c3 Mon Sep 17 00:00:00 2001 From: dinua Date: Tue, 1 Mar 2022 14:16:43 +0200 Subject: [PATCH 225/253] #7974 fix bug with new tests --- .../backend/person/PersonFacadeEjb.java | 19 ++++++++++++ .../sormas/backend/TestDataCreator.java | 21 ++++++++----- .../backend/person/PersonFacadeEjbTest.java | 31 +++++++++++++++++++ 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java index 3ce63debfd1..741d75eaf5a 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java @@ -51,6 +51,8 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; +import de.symeda.sormas.backend.travelentry.TravelEntry; +import de.symeda.sormas.backend.travelentry.TravelEntryJoins; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.SerializationUtils; import org.apache.commons.lang3.StringUtils; @@ -1465,6 +1467,23 @@ private Predicate createIndexListFilter(PersonCriteria criteria, PersonQueryCont filter = CriteriaBuilderHelper.and(cb, filter, criteriaFilter); } + final User currentUser = userService.getCurrentUser(); + if(criteria != null && + PersonAssociation.TRAVEL_ENTRY.equals(criteria.getPersonAssociation()) + && currentUser.getLimitedDisease() != null){ + + final Predicate travelEntryPredicate = travelEntryLimitedDiseaseFilter(personQueryContext, currentUser.getLimitedDisease()); + filter = CriteriaBuilderHelper.and(cb, filter, travelEntryPredicate); + } + + return filter; + } + + private Predicate travelEntryLimitedDiseaseFilter(PersonQueryContext personQueryContext, Disease limitedDisease){ + PersonJoins joins = (PersonJoins) personQueryContext.getJoins(); + final Join personTravelEntryJoin = joins.getTravelEntry(); + final CriteriaBuilder cb = personQueryContext.getCriteriaBuilder(); + Predicate filter = CriteriaBuilderHelper.and(cb, cb.equal(personTravelEntryJoin.get(Contact.DISEASE), limitedDisease)); return filter; } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java index 52566fc5dd1..ee9a3d1e53a 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java @@ -174,19 +174,24 @@ public UserDto createUser(String regionUuid, String districtUuid, String facilit return createUser(regionUuid, districtUuid, null, facilityUuid, firstName, lastName, roles); } - public UserDto createUser( - String regionUuid, - String districtUuid, - String communityUuid, - String facilityUuid, - String firstName, - String lastName, - UserRole... roles) { + public UserDto createUser(String regionUuid, String districtUuid, String communityUuid, String facilityUuid, String firstName, + String lastName, UserRole... roles) { + return createUser(regionUuid, districtUuid, communityUuid, facilityUuid, firstName,lastName, null, roles); + } + + public UserDto createUser(RDCF rdcf, String firstName, String lastName, Disease limitedDisease, UserRole... roles) { + return createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), null, rdcf.facility.getUuid(), firstName, lastName, limitedDisease, roles); + } + + private UserDto createUser(String regionUuid, String districtUuid, String communityUuid, String facilityUuid, String firstName, + String lastName, Disease limitedDisease, UserRole... roles) { + UserDto user1 = UserDto.build(); user1.setFirstName(firstName); user1.setLastName(lastName); user1.setUserName(firstName + lastName); user1.setUserRoles(new HashSet(Arrays.asList(roles))); + user1.setLimitedDisease(limitedDisease); UserDto user = user1; user.setRegion(beanTest.getRegionFacade().getReferenceByUuid(regionUuid)); user.setDistrict(beanTest.getDistrictFacade().getReferenceByUuid(districtUuid)); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java index 8a345677603..d81ee31891a 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/person/PersonFacadeEjbTest.java @@ -900,4 +900,35 @@ public void testGetPersonByContext() { assertThat(getPersonFacade().getByContext(PersonContext.EVENT_PARTICIPANT, eventParticipant.getUuid()), equalTo(eventParticipantPerson)); } + + @Test + public void testUserWithLimitedDiseaseSeeOnlyLimitedTravelEntry(){ + RDCF rdcf = creator.createRDCF("Region", "District", "Community", "Facility", "PointOfEntry"); + PersonCriteria criteria = new PersonCriteria(); + criteria.setPersonAssociation(PersonAssociation.TRAVEL_ENTRY); + + UserDto natUser = useNationalUserLogin(); + // CORONAVIRUS Travel Entry + PersonDto personWithCorona = creator.createPerson("Person Coronavirus","Test"); + creator.createTravelEntry(personWithCorona.toReference(), natUser.toReference(), Disease.CORONAVIRUS, rdcf.region, rdcf.district, rdcf.pointOfEntry); + + // DENGUE Travel Entry + PersonDto personWithDengue = creator.createPerson("Person Dengue","Test"); + creator.createTravelEntry(personWithDengue.toReference(), natUser.toReference(), Disease.DENGUE, rdcf.region, rdcf.district, rdcf.pointOfEntry); + + //National User with no restrictions can see all the travel entries + List personIndexDtos = getPersonFacade().getIndexList(criteria, 0, 100, null); + assertEquals(2 , personIndexDtos.size()); + List firstNames = personIndexDtos.stream().map(p -> p.getFirstName()).collect(Collectors.toList()); + assertTrue(firstNames.contains(personWithCorona.getFirstName())); + assertTrue(firstNames.contains(personWithDengue.getFirstName())); + + //login with a user wiht limieted disease restrictions + final UserDto user = creator.createUser(rdcf, "Limieted Disease", "National User", Disease.DENGUE, UserRole.NATIONAL_USER); + loginWith(user); + + personIndexDtos = getPersonFacade().getIndexList(criteria, 0, 100, null); + assertEquals(1 , personIndexDtos.size()); + assertEquals(personWithDengue.getFirstName(), personIndexDtos.get(0).getFirstName()); + } } From 327c86102f1a5c34172dd44032be90e73270868f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9=20Strysewske?= Date: Tue, 1 Mar 2022 13:22:04 +0100 Subject: [PATCH 226/253] Fixed wrong snapshot version in cargoserver pom --- sormas-cargoserver/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sormas-cargoserver/pom.xml b/sormas-cargoserver/pom.xml index 3895cc8693e..8c6009ec75f 100644 --- a/sormas-cargoserver/pom.xml +++ b/sormas-cargoserver/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.68.2 + 1.69.0-SNAPSHOT ../sormas-base From 6b211fd4dedfd0f63542d201adb6f99bd265edd7 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Tue, 1 Mar 2022 13:31:03 +0100 Subject: [PATCH 227/253] resolved conflicts --- .../application/events/EditEventSteps.java | 87 ++++++++++++++----- .../events/EventDirectorySteps.java | 67 ++++---------- 2 files changed, 85 insertions(+), 69 deletions(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java index fb3b919c6cb..ecc252f94a2 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java @@ -18,28 +18,8 @@ package org.sormas.e2etests.steps.web.application.events; -import static org.sormas.e2etests.pages.application.actions.CreateNewActionPage.NEW_ACTION_POPUP; -import static org.sormas.e2etests.pages.application.cases.EditCasePage.UUID_INPUT; -import static org.sormas.e2etests.pages.application.events.EditEventPage.*; -import static org.sormas.e2etests.pages.application.events.EditEventPage.SAVE_BUTTON; -import static org.sormas.e2etests.pages.application.events.EventActionsPage.CREATE_BUTTON; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.TOTAL_EVENTS_COUNTER; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.getByEventUuid; -import static org.sormas.e2etests.pages.application.events.EventParticipantsPage.*; -import static org.sormas.e2etests.pages.application.events.EventParticipantsPage.EVENT_PARTICIPANTS_TAB; -import static org.sormas.e2etests.pages.application.events.EventParticipantsPage.SEX_COMBOBOX; -import static org.sormas.e2etests.pages.application.persons.EditPersonPage.*; -import static org.sormas.e2etests.steps.BaseSteps.locale; - import com.github.javafaker.Faker; import cucumber.api.java8.En; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.List; -import javax.inject.Inject; import org.sormas.e2etests.entities.pojo.helpers.ComparisonHelper; import org.sormas.e2etests.entities.pojo.web.Event; import org.sormas.e2etests.entities.pojo.web.EventGroup; @@ -61,6 +41,73 @@ import org.testng.Assert; import org.testng.asserts.SoftAssert; +import javax.inject.Inject; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.List; + +import static org.sormas.e2etests.pages.application.actions.CreateNewActionPage.NEW_ACTION_POPUP; +import static org.sormas.e2etests.pages.application.cases.EditCasePage.UUID_INPUT; +import static org.sormas.e2etests.pages.application.events.EditEventPage.DISEASE_COMBOBOX; +import static org.sormas.e2etests.pages.application.events.EditEventPage.DISEASE_INPUT; +import static org.sormas.e2etests.pages.application.events.EditEventPage.EDIT_EVENT_GROUP_BUTTON; +import static org.sormas.e2etests.pages.application.events.EditEventPage.EDIT_FIRST_TASK; +import static org.sormas.e2etests.pages.application.events.EditEventPage.EVENT_ACTIONS_TAB; +import static org.sormas.e2etests.pages.application.events.EditEventPage.EVENT_DATA_SAVED_MESSAGE; +import static org.sormas.e2etests.pages.application.events.EditEventPage.EVENT_HANDOUT_COMBOBOX; +import static org.sormas.e2etests.pages.application.events.EditEventPage.EVENT_INVESTIGATION_STATUS_OPTIONS; +import static org.sormas.e2etests.pages.application.events.EditEventPage.EVENT_MANAGEMENT_STATUS_OPTIONS; +import static org.sormas.e2etests.pages.application.events.EditEventPage.EVENT_STATUS_OPTIONS; +import static org.sormas.e2etests.pages.application.events.EditEventPage.FIRST_GROUP_ID; +import static org.sormas.e2etests.pages.application.events.EditEventPage.GROUP_EVENT_NAME_POPUP_INPUT; +import static org.sormas.e2etests.pages.application.events.EditEventPage.GROUP_EVENT_UUID; +import static org.sormas.e2etests.pages.application.events.EditEventPage.LINK_EVENT_GROUP_BUTTON; +import static org.sormas.e2etests.pages.application.events.EditEventPage.NAVIGATE_TO_EVENT_DIRECTORY_EVENT_GROUP_BUTTON; +import static org.sormas.e2etests.pages.application.events.EditEventPage.NEW_ACTION_BUTTON; +import static org.sormas.e2etests.pages.application.events.EditEventPage.NEW_EVENT_GROUP_RADIOBUTTON; +import static org.sormas.e2etests.pages.application.events.EditEventPage.NEW_GROUP_EVENT_CREATED_MESSAGE; +import static org.sormas.e2etests.pages.application.events.EditEventPage.REPORT_DATE_INPUT; +import static org.sormas.e2etests.pages.application.events.EditEventPage.RISK_LEVEL_COMBOBOX; +import static org.sormas.e2etests.pages.application.events.EditEventPage.RISK_LEVEL_INPUT; +import static org.sormas.e2etests.pages.application.events.EditEventPage.SAVE_BUTTON; +import static org.sormas.e2etests.pages.application.events.EditEventPage.SAVE_BUTTON_FOR_EDIT_EVENT_GROUP; +import static org.sormas.e2etests.pages.application.events.EditEventPage.SAVE_BUTTON_FOR_POPUP_WINDOWS; +import static org.sormas.e2etests.pages.application.events.EditEventPage.SELECT_EVENT_GROUP_RADIOBUTTON; +import static org.sormas.e2etests.pages.application.events.EditEventPage.SOURCE_TYPE_COMBOBOX; +import static org.sormas.e2etests.pages.application.events.EditEventPage.SOURCE_TYPE_INPUT; +import static org.sormas.e2etests.pages.application.events.EditEventPage.START_DATA_INPUT; +import static org.sormas.e2etests.pages.application.events.EditEventPage.TITLE_INPUT; +import static org.sormas.e2etests.pages.application.events.EditEventPage.TOTAL_ACTIONS_COUNTER; +import static org.sormas.e2etests.pages.application.events.EditEventPage.TYPE_OF_PLACE_COMBOBOX; +import static org.sormas.e2etests.pages.application.events.EditEventPage.TYPE_OF_PLACE_INPUT; +import static org.sormas.e2etests.pages.application.events.EditEventPage.UNLINK_EVENT_BUTTON; +import static org.sormas.e2etests.pages.application.events.EditEventPage.getGroupEventName; +import static org.sormas.e2etests.pages.application.events.EventActionsPage.CREATE_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.TOTAL_EVENTS_COUNTER; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.getByEventUuid; +import static org.sormas.e2etests.pages.application.events.EventParticipantsPage.ADD_PARTICIPANT_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventParticipantsPage.CREATE_NEW_PERSON_RADIO_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventParticipantsPage.DISCARD_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventParticipantsPage.ERROR_MESSAGE_TEXT; +import static org.sormas.e2etests.pages.application.events.EventParticipantsPage.EVENT_PARTICIPANTS_TAB; +import static org.sormas.e2etests.pages.application.events.EventParticipantsPage.PARTICIPANT_DISTRICT_COMBOBOX; +import static org.sormas.e2etests.pages.application.events.EventParticipantsPage.PARTICIPANT_FIRST_NAME_INPUT; +import static org.sormas.e2etests.pages.application.events.EventParticipantsPage.PARTICIPANT_LAST_NAME_INPUT; +import static org.sormas.e2etests.pages.application.events.EventParticipantsPage.PARTICIPANT_REGION_COMBOBOX; +import static org.sormas.e2etests.pages.application.events.EventParticipantsPage.PICK_OR_CREATE_PERSON_POPUP; +import static org.sormas.e2etests.pages.application.events.EventParticipantsPage.PICK_OR_CREATE_POPUP_SAVE_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventParticipantsPage.SEX_COMBOBOX; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.PERSON_DATA_ADDED_AS_A_PARTICIPANT_MESSAGE; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.PERSON_DATA_SAVED; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.POPUP_PERSON_ID; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.POPUP_RESPONSIBLE_DISTRICT_COMBOBOX; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.POPUP_RESPONSIBLE_REGION_COMBOBOX; +import static org.sormas.e2etests.pages.application.persons.EditPersonPage.POPUP_SAVE; +import static org.sormas.e2etests.steps.BaseSteps.locale; + public class EditEventSteps implements En { private final WebDriverHelpers webDriverHelpers; diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index 827d31fd0d8..7c1c72d3238 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -18,63 +18,16 @@ package org.sormas.e2etests.steps.web.application.events; -import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_GRID_RESULTS_ROWS; -import static org.sormas.e2etests.pages.application.events.EditEventPage.EVENT_PARTICIPANTS_TAB; -import static org.sormas.e2etests.pages.application.events.EditEventPage.FIRST_EVENT_PARTICIPANT; -import static org.sormas.e2etests.pages.application.events.EditEventPage.NEW_TASK_BUTTON; -import static org.sormas.e2etests.pages.application.events.EditEventPage.TITLE_INPUT; -import static org.sormas.e2etests.pages.application.events.EditEventPage.UUID_INPUT; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.APPLY_FILTER; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.BULK_ACTIONS_EVENT_DIRECTORY; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.CREATED_PARTICIPANT; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.CREATE_CASE_BUTTON; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.ENTER_BULK_EDIT_MODE_EVENT_DIRECTORY; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENTS_RADIO_BUTTON; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_GROUP_ID_IN_GRID; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_GROUP_INPUT; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_STATUS_FILTER_BUTTONS; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTERED_EVENT_LINK_EVENT_FORM; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_DISEASE; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_RISK_LEVEL; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_SOURCE_TYPE; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_TYPE_OF_PLACE; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FIRST_CHECKBOX_EVENT_DIRECTORY; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FIRST_EVENT_GROUP; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FIRST_EVENT_ID_BUTTON; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.GROUP_EVENTS_EVENT_DIRECTORY; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.GROUP_ID_COLUMN; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.ID_FIELD_FILTER; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.LINKED_EVENT_GROUP_ID; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.LINK_EVENT_BUTTON; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.LINK_EVENT_BUTTON_EDIT_PAGE; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.MORE_BUTTON_EVENT_DIRECTORY; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.RESET_FILTER; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.SAVE_BUTTON_IN_LINK_FORM; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.SEARCH_EVENT_BY_FREE_TEXT; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.SEARCH_EVENT_BY_FREE_TEXT_INPUT; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.TOTAL_EVENTS_COUNTER; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.UNLINK_EVENT_BUTTON; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.getByEventUuid; -import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.APPLY_FILTERS_BUTTON; -import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.RESET_FILTERS_BUTTON; -import static org.sormas.e2etests.steps.BaseSteps.locale; - import cucumber.api.java8.En; import org.openqa.selenium.WebDriverException; import org.openqa.selenium.WebElement; -import java.util.List; -import java.util.concurrent.TimeUnit; -import javax.inject.Inject; import org.sormas.e2etests.common.DataOperations; -import org.sormas.e2etests.entities.services.EventService; -import org.sormas.e2etests.enums.DiseasesValues; -import org.sormas.e2etests.enums.EventReferenceDateOptions; -import org.sormas.e2etests.enums.RiskLevelValues; -import org.sormas.e2etests.enums.SourceTypeValues; import org.sormas.e2etests.entities.pojo.helpers.ComparisonHelper; import org.sormas.e2etests.entities.pojo.web.EventGroup; import org.sormas.e2etests.entities.services.EventGroupService; +import org.sormas.e2etests.entities.services.EventService; import org.sormas.e2etests.enums.DiseasesValues; +import org.sormas.e2etests.enums.EventReferenceDateOptions; import org.sormas.e2etests.enums.RiskLevelValues; import org.sormas.e2etests.enums.SourceTypeValues; import org.sormas.e2etests.enums.cases.epidemiologicalData.TypeOfPlace; @@ -114,27 +67,43 @@ import static org.sormas.e2etests.pages.application.events.EditEventPage.TITLE_INPUT; import static org.sormas.e2etests.pages.application.events.EditEventPage.UUID_INPUT; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.APPLY_FILTER; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.BULK_ACTIONS_EVENT_DIRECTORY; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.CREATED_PARTICIPANT; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.CREATE_CASE_BUTTON; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.DATE_TYPE_COMBOBOX; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.ENTER_BULK_EDIT_MODE_EVENT_DIRECTORY; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENTS_COLUMN_HEADERS; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENTS_RADIO_BUTTON; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENTS_TABLE_DATA; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENTS_TABLE_ROW; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_DISPLAY_COMBOBOX; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_GROUP_ID_IN_GRID; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_GROUP_INPUT; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_INVESTIGATION_STATUS; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_MANAGEMENT_FILTER; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_STATUS_FILTER_BUTTONS; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTERED_EVENT_LINK_EVENT_FORM; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_DISEASE; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_REPORTING_USER; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_RISK_LEVEL; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_SOURCE_TYPE; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_TYPE_OF_PLACE; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FIRST_CHECKBOX_EVENT_DIRECTORY; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FIRST_EVENT_GROUP; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FIRST_EVENT_ID_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.GROUP_EVENTS_EVENT_DIRECTORY; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.GROUP_ID_COLUMN; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.ID_FIELD_FILTER; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.LINKED_EVENT_GROUP_ID; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.LINK_EVENT_BUTTON; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.LINK_EVENT_BUTTON_EDIT_PAGE; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.MORE_BUTTON_EVENT_DIRECTORY; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.RESET_FILTER; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.SAVE_BUTTON_IN_LINK_FORM; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.SEARCH_EVENT_BY_FREE_TEXT; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.SEARCH_EVENT_BY_FREE_TEXT_INPUT; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.TOTAL_EVENTS_COUNTER; +import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.UNLINK_EVENT_BUTTON; import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.getByEventUuid; import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.APPLY_FILTERS_BUTTON; import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.RESET_FILTERS_BUTTON; From 273869435f1df171cae1d61a531772a3dadc1962 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Tue, 1 Mar 2022 13:40:35 +0100 Subject: [PATCH 228/253] resolved conflicts --- .../events/EventDirectorySteps.java | 37 ------------------- 1 file changed, 37 deletions(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index ffdc42d9827..34691997268 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -18,47 +18,10 @@ package org.sormas.e2etests.steps.web.application.events; -import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_GRID_RESULTS_ROWS; -import static org.sormas.e2etests.pages.application.events.EditEventPage.EVENT_PARTICIPANTS_TAB; -import static org.sormas.e2etests.pages.application.events.EditEventPage.FIRST_EVENT_PARTICIPANT; -import static org.sormas.e2etests.pages.application.events.EditEventPage.NEW_TASK_BUTTON; -import static org.sormas.e2etests.pages.application.events.EditEventPage.TITLE_INPUT; -import static org.sormas.e2etests.pages.application.events.EditEventPage.UUID_INPUT; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.APPLY_FILTER; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.CREATED_PARTICIPANT; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.CREATE_CASE_BUTTON; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENTS_RADIO_BUTTON; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_GROUP_ID_IN_GRID; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.EVENT_STATUS_FILTER_BUTTONS; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTERED_EVENT_LINK_EVENT_FORM; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_DISEASE; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_RISK_LEVEL; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_SOURCE_TYPE; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FILTER_BY_TYPE_OF_PLACE; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FIRST_EVENT_GROUP; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.FIRST_EVENT_ID_BUTTON; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.ID_FIELD_FILTER; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.LINKED_EVENT_GROUP_ID; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.LINK_EVENT_BUTTON; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.LINK_EVENT_BUTTON_EDIT_PAGE; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.RESET_FILTER; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.SAVE_BUTTON_IN_LINK_FORM; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.SEARCH_EVENT_BY_FREE_TEXT; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.SEARCH_EVENT_BY_FREE_TEXT_INPUT; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.TOTAL_EVENTS_COUNTER; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.UNLINK_EVENT_BUTTON; -import static org.sormas.e2etests.pages.application.events.EventDirectoryPage.getByEventUuid; -import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.APPLY_FILTERS_BUTTON; -import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.RESET_FILTERS_BUTTON; -import static org.sormas.e2etests.steps.BaseSteps.locale; - import cucumber.api.java8.En; import org.openqa.selenium.WebDriverException; import org.openqa.selenium.WebElement; import org.sormas.e2etests.common.DataOperations; -import org.sormas.e2etests.enums.DiseasesValues; -import org.sormas.e2etests.enums.RiskLevelValues; -import org.sormas.e2etests.enums.SourceTypeValues; import org.sormas.e2etests.entities.pojo.helpers.ComparisonHelper; import org.sormas.e2etests.entities.pojo.web.EventGroup; import org.sormas.e2etests.entities.services.EventGroupService; From 8c7de754f2cbe8ff86bf2bf6b2968593064a5891 Mon Sep 17 00:00:00 2001 From: dinua Date: Tue, 1 Mar 2022 17:07:41 +0200 Subject: [PATCH 229/253] #7974 refactor code --- .../backend/person/PersonFacadeEjb.java | 19 ------------------- .../sormas/backend/person/PersonService.java | 4 +++- .../services/BaseTravelEntryService.java | 2 +- 3 files changed, 4 insertions(+), 21 deletions(-) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java index 741d75eaf5a..3ce63debfd1 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java @@ -51,8 +51,6 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; -import de.symeda.sormas.backend.travelentry.TravelEntry; -import de.symeda.sormas.backend.travelentry.TravelEntryJoins; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.SerializationUtils; import org.apache.commons.lang3.StringUtils; @@ -1467,23 +1465,6 @@ private Predicate createIndexListFilter(PersonCriteria criteria, PersonQueryCont filter = CriteriaBuilderHelper.and(cb, filter, criteriaFilter); } - final User currentUser = userService.getCurrentUser(); - if(criteria != null && - PersonAssociation.TRAVEL_ENTRY.equals(criteria.getPersonAssociation()) - && currentUser.getLimitedDisease() != null){ - - final Predicate travelEntryPredicate = travelEntryLimitedDiseaseFilter(personQueryContext, currentUser.getLimitedDisease()); - filter = CriteriaBuilderHelper.and(cb, filter, travelEntryPredicate); - } - - return filter; - } - - private Predicate travelEntryLimitedDiseaseFilter(PersonQueryContext personQueryContext, Disease limitedDisease){ - PersonJoins joins = (PersonJoins) personQueryContext.getJoins(); - final Join personTravelEntryJoin = joins.getTravelEntry(); - final CriteriaBuilder cb = personQueryContext.getCriteriaBuilder(); - Predicate filter = CriteriaBuilderHelper.and(cb, cb.equal(personTravelEntryJoin.get(Contact.DISEASE), limitedDisease)); return filter; } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonService.java index 2980292e0ef..bb621a3145d 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonService.java @@ -54,6 +54,7 @@ import javax.transaction.Transactional; import javax.validation.constraints.NotNull; +import de.symeda.sormas.backend.travelentry.TravelEntryQueryContext; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -271,7 +272,8 @@ public Predicate createUserFilter(PersonQueryContext personQueryContext, PersonC : () -> null; final Supplier travelEntryFilter = () -> CriteriaBuilderHelper.and( cb, - travelEntryService.createUserFilter(cb, cq, joins.getTravelEntry()), + travelEntryService.createUserFilter(new TravelEntryQueryContext(cb, cq, joins.getTravelEntry())), +// travelEntryService.createUserFilter(cb, cq, joins.getTravelEntry()), travelEntryService.createDefaultFilter(cb, joins.getTravelEntry())); // 2. Define the Joins on associations where needed diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java index 6b5eb2e7a97..709b74106f9 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java @@ -51,7 +51,7 @@ public Predicate createDefaultFilter(CriteriaBuilder cb, From ro return cb.isFalse(root.get(TravelEntry.DELETED)); } - protected Predicate createUserFilter(TravelEntryQueryContext qc) { + public Predicate createUserFilter(TravelEntryQueryContext qc) { final User currentUser = userService.getCurrentUser(); final CriteriaBuilder cb = qc.getCriteriaBuilder(); Predicate filter = inJurisdictionOrOwned(qc); From 5de337047e1a8dcc8de59a8a4523bf587d6c5954 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Tue, 1 Mar 2022 17:08:15 +0200 Subject: [PATCH 230/253] Feature 8079 hide labels on person pick form (#8169) * #8079 - hide country specific labels on person pick form * #8079 - use generic variable name --- .../ui/person/PersonSelectionField.java | 143 ++++++++++-------- 1 file changed, 77 insertions(+), 66 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonSelectionField.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonSelectionField.java index cff0d3b6cf4..06ce321dcdd 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonSelectionField.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonSelectionField.java @@ -35,6 +35,7 @@ import de.symeda.sormas.api.person.PersonHelper; import de.symeda.sormas.api.person.PersonSimilarityCriteria; import de.symeda.sormas.api.person.SimilarPersonDto; +import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; import de.symeda.sormas.ui.UserProvider; import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.VaadinUiUtil; @@ -57,6 +58,7 @@ public class PersonSelectionField extends CustomField { protected PersonSelectionFilterForm filterForm; private PersonDto referencePerson; private boolean hasMatches; + private FieldVisibilityCheckers fieldVisibilityCheckers; public PersonSelectionField(PersonDto referencePerson, String infoText) { this(referencePerson, infoText, null); @@ -75,6 +77,8 @@ public PersonSelectionField(PersonDto referencePerson, String infoText) { public PersonSelectionField(PersonDto referencePerson, String infoText, String infoTextWithoutMatches) { this.referencePerson = referencePerson; + fieldVisibilityCheckers = FieldVisibilityCheckers.withCountry(FacadeProvider.getConfigFacade().getCountryLocale()); + initializeGrid(); this.hasMatches = referencePerson == null @@ -95,20 +99,9 @@ private void addPersonDetailsComponent() { HorizontalLayout personDetailsLayout1 = new HorizontalLayout(); personDetailsLayout1.setSpacing(true); - Label lblFirstName = new Label(referencePerson.getFirstName()); - lblFirstName.setCaption(I18nProperties.getPrefixCaption(PersonDto.I18N_PREFIX, PersonDto.FIRST_NAME)); - lblFirstName.setWidthUndefined(); - personDetailsLayout1.addComponent(lblFirstName); - - Label lblLastName = new Label(referencePerson.getLastName()); - lblLastName.setWidthUndefined(); - lblLastName.setCaption(I18nProperties.getPrefixCaption(PersonDto.I18N_PREFIX, PersonDto.LAST_NAME)); - personDetailsLayout1.addComponent(lblLastName); - - Label lblNickname = new Label(referencePerson.getNickname()); - lblNickname.setWidthUndefined(); - lblNickname.setCaption(I18nProperties.getPrefixCaption(PersonDto.I18N_PREFIX, PersonDto.NICKNAME)); - personDetailsLayout1.addComponent(lblNickname); + addLabelIfVisible(personDetailsLayout1, referencePerson.getFirstName(), PersonDto.I18N_PREFIX, PersonDto.FIRST_NAME, PersonDto.class); + addLabelIfVisible(personDetailsLayout1, referencePerson.getLastName(), PersonDto.I18N_PREFIX, PersonDto.LAST_NAME, PersonDto.class); + addLabelIfVisible(personDetailsLayout1, referencePerson.getNickname(), PersonDto.I18N_PREFIX, PersonDto.NICKNAME, PersonDto.class); Label lblBirthDateAndAge = new Label( PersonHelper.getAgeAndBirthdateString( @@ -121,76 +114,94 @@ private void addPersonDetailsComponent() { lblBirthDateAndAge.setCaption(I18nProperties.getCaption(Captions.personAgeAndBirthdate)); personDetailsLayout1.addComponent(lblBirthDateAndAge); - Label lblSex = new Label(referencePerson.getSex() != null ? referencePerson.getSex().toString() : ""); - lblSex.setWidthUndefined(); - lblSex.setCaption(I18nProperties.getPrefixCaption(PersonDto.I18N_PREFIX, PersonDto.SEX)); - personDetailsLayout1.addComponent(lblSex); + addLabelIfVisible( + personDetailsLayout1, + referencePerson.getSex() != null ? referencePerson.getSex().toString() : "", + PersonDto.I18N_PREFIX, + PersonDto.SEX, + PersonDto.class); - Label lblPresentCondition = new Label(referencePerson.getPresentCondition() != null ? referencePerson.getPresentCondition().toString() : ""); - lblPresentCondition.setWidthUndefined(); - lblPresentCondition.setCaption(I18nProperties.getPrefixCaption(PersonDto.I18N_PREFIX, PersonDto.PRESENT_CONDITION)); - personDetailsLayout1.addComponent(lblPresentCondition); + addLabelIfVisible( + personDetailsLayout1, + referencePerson.getPresentCondition() != null ? referencePerson.getPresentCondition().toString() : "", + PersonDto.I18N_PREFIX, + PersonDto.PRESENT_CONDITION, + PersonDto.class); - Label lblPhone = new Label(referencePerson.getPhone()); - lblPhone.setWidthUndefined(); - lblPhone.setCaption(I18nProperties.getPrefixCaption(PersonDto.I18N_PREFIX, PersonDto.PHONE)); - personDetailsLayout1.addComponent(lblPhone); + addLabelIfVisible(personDetailsLayout1, referencePerson.getPhone(), PersonDto.I18N_PREFIX, PersonDto.PHONE, PersonDto.class); mainLayout.addComponent(personDetailsLayout1); HorizontalLayout personDetailsLayout2 = new HorizontalLayout(); personDetailsLayout2.setSpacing(true); - Label lblDistrict = - new Label(referencePerson.getAddress().getDistrict() != null ? referencePerson.getAddress().getDistrict().toString() : ""); - lblDistrict.setWidthUndefined(); - lblDistrict.setCaption(I18nProperties.getPrefixCaption(LocationDto.I18N_PREFIX, LocationDto.DISTRICT)); - personDetailsLayout2.addComponent(lblDistrict); - - Label lblCommunity = - new Label(referencePerson.getAddress().getCommunity() != null ? referencePerson.getAddress().getCommunity().toString() : ""); - lblCommunity.setWidthUndefined(); - lblCommunity.setCaption(I18nProperties.getPrefixCaption(LocationDto.I18N_PREFIX, LocationDto.COMMUNITY)); - personDetailsLayout2.addComponent(lblCommunity); - - Label lblPostalCode = new Label(referencePerson.getAddress().getPostalCode()); - lblPostalCode.setWidthUndefined(); - lblPostalCode.setCaption(I18nProperties.getPrefixCaption(LocationDto.I18N_PREFIX, LocationDto.POSTAL_CODE)); - personDetailsLayout2.addComponent(lblPostalCode); - - Label lblCity = new Label(referencePerson.getAddress().getCity()); - lblCity.setWidthUndefined(); - lblCity.setCaption(I18nProperties.getPrefixCaption(LocationDto.I18N_PREFIX, LocationDto.CITY)); - personDetailsLayout2.addComponent(lblCity); - - Label lblStreet = new Label(referencePerson.getAddress().getStreet()); - lblStreet.setWidthUndefined(); - lblStreet.setCaption(I18nProperties.getPrefixCaption(LocationDto.I18N_PREFIX, LocationDto.STREET)); - personDetailsLayout2.addComponent(lblStreet); - - Label lblHouseNumber = new Label(referencePerson.getAddress().getHouseNumber()); - lblHouseNumber.setWidthUndefined(); - lblHouseNumber.setCaption(I18nProperties.getPrefixCaption(LocationDto.I18N_PREFIX, LocationDto.HOUSE_NUMBER)); - personDetailsLayout2.addComponent(lblHouseNumber); + addLabelIfVisible( + personDetailsLayout2, + referencePerson.getAddress().getDistrict() != null ? referencePerson.getAddress().getDistrict().toString() : "", + LocationDto.I18N_PREFIX, + LocationDto.DISTRICT, + LocationDto.class); + + addLabelIfVisible( + personDetailsLayout2, + referencePerson.getAddress().getCommunity() != null ? referencePerson.getAddress().getCommunity().toString() : "", + LocationDto.I18N_PREFIX, + LocationDto.COMMUNITY, + LocationDto.class); + + addLabelIfVisible( + personDetailsLayout2, + referencePerson.getAddress().getPostalCode(), + LocationDto.I18N_PREFIX, + LocationDto.POSTAL_CODE, + LocationDto.class); + + addLabelIfVisible(personDetailsLayout2, referencePerson.getAddress().getCity(), LocationDto.I18N_PREFIX, LocationDto.CITY, LocationDto.class); + + addLabelIfVisible( + personDetailsLayout2, + referencePerson.getAddress().getStreet(), + LocationDto.I18N_PREFIX, + LocationDto.STREET, + LocationDto.class); + + addLabelIfVisible( + personDetailsLayout2, + referencePerson.getAddress().getHouseNumber(), + LocationDto.I18N_PREFIX, + LocationDto.HOUSE_NUMBER, + LocationDto.class); mainLayout.addComponent(personDetailsLayout2); HorizontalLayout personDetailsLayout3 = new HorizontalLayout(); personDetailsLayout3.setSpacing(true); - Label lblNationalHealthId = new Label(referencePerson.getNationalHealthId()); - lblNationalHealthId.setWidthUndefined(); - lblNationalHealthId.setCaption(I18nProperties.getPrefixCaption(PersonDto.I18N_PREFIX, PersonDto.NATIONAL_HEALTH_ID)); - personDetailsLayout3.addComponent(lblNationalHealthId); - - Label lblPassportNumber = new Label(referencePerson.getPassportNumber()); - lblPassportNumber.setWidthUndefined(); - lblPassportNumber.setCaption(I18nProperties.getPrefixCaption(PersonDto.I18N_PREFIX, PersonDto.PASSPORT_NUMBER)); - personDetailsLayout3.addComponent(lblPassportNumber); + addLabelIfVisible( + personDetailsLayout3, + referencePerson.getNationalHealthId(), + PersonDto.I18N_PREFIX, + PersonDto.NATIONAL_HEALTH_ID, + PersonDto.class); + addLabelIfVisible( + personDetailsLayout3, + referencePerson.getPassportNumber(), + PersonDto.I18N_PREFIX, + PersonDto.PASSPORT_NUMBER, + PersonDto.class); mainLayout.addComponent(personDetailsLayout3); } + private void addLabelIfVisible(HorizontalLayout layout, String text, String i18nPrefix, String captionKey, Class clazz) { + if (fieldVisibilityCheckers.isVisible(clazz, captionKey)) { + Label label = new Label(text); + label.setCaption(I18nProperties.getPrefixCaption(i18nPrefix, captionKey)); + label.setWidthUndefined(); + layout.addComponent(label); + } + } + private void addSelectPersonRadioGroup() { List selectPersonOption = new ArrayList<>(); if (hasMatches) { From 513bc76547a1e33e6683d90ce4b1ab2c41ed9dbb Mon Sep 17 00:00:00 2001 From: dinua Date: Tue, 1 Mar 2022 17:16:12 +0200 Subject: [PATCH 231/253] #7974 refactor code --- .../main/java/de/symeda/sormas/backend/person/PersonService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonService.java index bb621a3145d..e0c4cdf6633 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonService.java @@ -273,7 +273,6 @@ public Predicate createUserFilter(PersonQueryContext personQueryContext, PersonC final Supplier travelEntryFilter = () -> CriteriaBuilderHelper.and( cb, travelEntryService.createUserFilter(new TravelEntryQueryContext(cb, cq, joins.getTravelEntry())), -// travelEntryService.createUserFilter(cb, cq, joins.getTravelEntry()), travelEntryService.createDefaultFilter(cb, joins.getTravelEntry())); // 2. Define the Joins on associations where needed From 2affc7613e494267226146c0b3ee05433c279661 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Tue, 1 Mar 2022 16:51:56 +0100 Subject: [PATCH 232/253] fix for duplicates --- .../events/EventDirectoryPage.java | 1 - .../application/cases/CaseDirectorySteps.java | 4 - .../application/events/EditEventSteps.java | 61 +++++++------- .../events/EventDirectorySteps.java | 81 ++++++++----------- 4 files changed, 64 insertions(+), 83 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java index 1b3ee688a38..24b2daa2bca 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/events/EventDirectoryPage.java @@ -96,7 +96,6 @@ public class EventDirectoryPage { public static final By BULK_ACTIONS_EVENT_DIRECTORY = By.id("bulkActions-2"); public static final By GROUP_EVENTS_EVENT_DIRECTORY = By.id("bulkActions-7"); public static final By GROUP_ID_COLUMN = By.xpath("(//td//a)[2]"); - public static final By EVENT_GROUP_INPUT = By.id("freeTextEventGroups"); public static By getByEventUuid(String eventUuid) { return By.xpath(String.format("//a[@title='%s']", eventUuid)); diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java index 6d77025ca62..ddb0c6580ee 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CaseDirectorySteps.java @@ -78,7 +78,6 @@ import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.NEW_EVENT_CHECKBOX; import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.PERSON_ID_NAME_CONTACT_INFORMATION_LIKE_INPUT; import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.RESULTS_GRID_HEADER; -import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.SAVE_BUTTON_IN_LINK_FORM; import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.SEARCH_BUTTON; import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.SHOW_MORE_LESS_FILTERS; import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.TOTAL_CASES_COUNTER; @@ -189,9 +188,6 @@ public CaseDirectorySteps( And( "I click first result in grid on Link to Event form", () -> webDriverHelpers.clickOnWebElementBySelector(FIRST_RESULT_IN_GRID)); - When( - "^I click on SAVE button in Link Event to group form$", - () -> webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON_IN_LINK_FORM)); When( "I filter by CaseID on Case directory page", diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java index ecc252f94a2..ab8ab228986 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EditEventSteps.java @@ -18,37 +18,6 @@ package org.sormas.e2etests.steps.web.application.events; -import com.github.javafaker.Faker; -import cucumber.api.java8.En; -import org.sormas.e2etests.entities.pojo.helpers.ComparisonHelper; -import org.sormas.e2etests.entities.pojo.web.Event; -import org.sormas.e2etests.entities.pojo.web.EventGroup; -import org.sormas.e2etests.entities.pojo.web.EventHandout; -import org.sormas.e2etests.entities.pojo.web.EventParticipant; -import org.sormas.e2etests.entities.pojo.web.Person; -import org.sormas.e2etests.entities.services.EventDocumentService; -import org.sormas.e2etests.entities.services.EventGroupService; -import org.sormas.e2etests.entities.services.EventParticipantService; -import org.sormas.e2etests.entities.services.EventService; -import org.sormas.e2etests.enums.DistrictsValues; -import org.sormas.e2etests.enums.GenderValues; -import org.sormas.e2etests.enums.RegionsValues; -import org.sormas.e2etests.envconfig.manager.EnvironmentManager; -import org.sormas.e2etests.helpers.AssertHelpers; -import org.sormas.e2etests.helpers.WebDriverHelpers; -import org.sormas.e2etests.pages.application.events.EditEventPage; -import org.sormas.e2etests.state.ApiState; -import org.testng.Assert; -import org.testng.asserts.SoftAssert; - -import javax.inject.Inject; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.List; - import static org.sormas.e2etests.pages.application.actions.CreateNewActionPage.NEW_ACTION_POPUP; import static org.sormas.e2etests.pages.application.cases.EditCasePage.UUID_INPUT; import static org.sormas.e2etests.pages.application.events.EditEventPage.DISEASE_COMBOBOX; @@ -108,6 +77,36 @@ import static org.sormas.e2etests.pages.application.persons.EditPersonPage.POPUP_SAVE; import static org.sormas.e2etests.steps.BaseSteps.locale; +import com.github.javafaker.Faker; +import cucumber.api.java8.En; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.List; +import javax.inject.Inject; +import org.sormas.e2etests.entities.pojo.helpers.ComparisonHelper; +import org.sormas.e2etests.entities.pojo.web.Event; +import org.sormas.e2etests.entities.pojo.web.EventGroup; +import org.sormas.e2etests.entities.pojo.web.EventHandout; +import org.sormas.e2etests.entities.pojo.web.EventParticipant; +import org.sormas.e2etests.entities.pojo.web.Person; +import org.sormas.e2etests.entities.services.EventDocumentService; +import org.sormas.e2etests.entities.services.EventGroupService; +import org.sormas.e2etests.entities.services.EventParticipantService; +import org.sormas.e2etests.entities.services.EventService; +import org.sormas.e2etests.enums.DistrictsValues; +import org.sormas.e2etests.enums.GenderValues; +import org.sormas.e2etests.enums.RegionsValues; +import org.sormas.e2etests.envconfig.manager.EnvironmentManager; +import org.sormas.e2etests.helpers.AssertHelpers; +import org.sormas.e2etests.helpers.WebDriverHelpers; +import org.sormas.e2etests.pages.application.events.EditEventPage; +import org.sormas.e2etests.state.ApiState; +import org.testng.Assert; +import org.testng.asserts.SoftAssert; + public class EditEventSteps implements En { private final WebDriverHelpers webDriverHelpers; diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index 7c1c72d3238..1e9ea4e5b2e 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -18,41 +18,6 @@ package org.sormas.e2etests.steps.web.application.events; -import cucumber.api.java8.En; -import org.openqa.selenium.WebDriverException; -import org.openqa.selenium.WebElement; -import org.sormas.e2etests.common.DataOperations; -import org.sormas.e2etests.entities.pojo.helpers.ComparisonHelper; -import org.sormas.e2etests.entities.pojo.web.EventGroup; -import org.sormas.e2etests.entities.services.EventGroupService; -import org.sormas.e2etests.entities.services.EventService; -import org.sormas.e2etests.enums.DiseasesValues; -import org.sormas.e2etests.enums.EventReferenceDateOptions; -import org.sormas.e2etests.enums.RiskLevelValues; -import org.sormas.e2etests.enums.SourceTypeValues; -import org.sormas.e2etests.enums.cases.epidemiologicalData.TypeOfPlace; -import org.sormas.e2etests.envconfig.manager.EnvironmentManager; -import org.sormas.e2etests.helpers.AssertHelpers; -import org.sormas.e2etests.helpers.WebDriverHelpers; -import org.sormas.e2etests.pages.application.NavBarPage; -import org.sormas.e2etests.pages.application.events.EventDirectoryPage; -import org.sormas.e2etests.state.ApiState; -import org.sormas.e2etests.steps.BaseSteps; -import org.testng.Assert; -import org.testng.asserts.SoftAssert; - -import javax.inject.Inject; -import java.time.LocalDate; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_COMMUNITY_FILTER_COMBOBOX; import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_DATA_TYPE_FILTER_COMBOBOX; import static org.sormas.e2etests.pages.application.cases.CaseDirectoryPage.CASE_DISTRICT_FILTER_COMBOBOX; @@ -109,6 +74,40 @@ import static org.sormas.e2etests.pages.application.persons.PersonDirectoryPage.RESET_FILTERS_BUTTON; import static org.sormas.e2etests.steps.BaseSteps.locale; +import cucumber.api.java8.En; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import javax.inject.Inject; +import org.openqa.selenium.WebDriverException; +import org.openqa.selenium.WebElement; +import org.sormas.e2etests.common.DataOperations; +import org.sormas.e2etests.entities.pojo.helpers.ComparisonHelper; +import org.sormas.e2etests.entities.pojo.web.EventGroup; +import org.sormas.e2etests.entities.services.EventGroupService; +import org.sormas.e2etests.entities.services.EventService; +import org.sormas.e2etests.enums.DiseasesValues; +import org.sormas.e2etests.enums.EventReferenceDateOptions; +import org.sormas.e2etests.enums.RiskLevelValues; +import org.sormas.e2etests.enums.SourceTypeValues; +import org.sormas.e2etests.enums.cases.epidemiologicalData.TypeOfPlace; +import org.sormas.e2etests.envconfig.manager.EnvironmentManager; +import org.sormas.e2etests.helpers.AssertHelpers; +import org.sormas.e2etests.helpers.WebDriverHelpers; +import org.sormas.e2etests.pages.application.NavBarPage; +import org.sormas.e2etests.pages.application.events.EventDirectoryPage; +import org.sormas.e2etests.state.ApiState; +import org.sormas.e2etests.steps.BaseSteps; +import org.testng.Assert; +import org.testng.asserts.SoftAssert; + public class EventDirectorySteps implements En { private final WebDriverHelpers webDriverHelpers; private final BaseSteps baseSteps; @@ -135,18 +134,6 @@ public EventDirectorySteps( SEARCH_EVENT_BY_FREE_TEXT, dataOperations.getPartialUuidFromAssociatedLink(eventUuid)); }); - When( - "I navigate to the last created Event page via URL", - () -> { - String eventLinkPath = "/sormas-ui/#!events/data/"; - String createdEventUUID = CreateNewEventSteps.newEvent.getUuid(); - webDriverHelpers.accessWebSite( - environmentManager.getEnvironmentUrlForMarket(locale) - + eventLinkPath - + createdEventUUID); - webDriverHelpers.waitForPageLoaded(); - webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(UUID_INPUT, 50); - }); When( "I navigate to the last created through API Event page via URL", () -> { From 35ca18645d0a02a9c35b030d2a2eb9edb5b92814 Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Tue, 1 Mar 2022 17:51:38 +0100 Subject: [PATCH 233/253] fix for duplicates --- .../events/EventDirectorySteps.java | 48 ++----------------- 1 file changed, 3 insertions(+), 45 deletions(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java index 6a76211479f..e0a9f65a0f4 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/events/EventDirectorySteps.java @@ -210,48 +210,6 @@ public EventDirectorySteps( When( "^I click on Unlink Event button on Event Directory Page$", () -> webDriverHelpers.clickOnWebElementBySelector(UNLINK_EVENT_BUTTON)); - - When( - "^I fill Id filter with Id of last created event in Link Event to group form$", - () -> - webDriverHelpers.fillInWebElement( - ID_FIELD_FILTER, apiState.getCreatedEvent().getUuid())); - When( - "^I click on filtered Event in Link Event to group form$", - () -> webDriverHelpers.clickOnWebElementBySelector(FILTERED_EVENT_LINK_EVENT_FORM)); - When( - "^I click on first Event Group on the list in Link Event form$", - () -> webDriverHelpers.clickOnWebElementBySelector(FIRST_EVENT_GROUP)); - - When( - "^I click on SAVE button in Link Event to group form$", - () -> webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON_IN_LINK_FORM)); - - When( - "^I click on Linked Group Id on Edit Event Page$", - () -> webDriverHelpers.clickOnWebElementBySelector(LINKED_EVENT_GROUP_ID)); - When( - "^I click on Group Id in Events result on Event Directory Page$", - () -> webDriverHelpers.clickOnWebElementBySelector(EVENT_GROUP_ID_IN_GRID)); - - When( - "^I click on ([^\"]*) Radiobutton on Event Directory Page$", - (String buttonName) -> { - webDriverHelpers.clickWebElementByText(EVENTS_RADIO_BUTTON, buttonName); - webDriverHelpers.waitForPageLoaded(); - }); - - When( - "^I click on Link Event button on Event Directory Page$", - () -> webDriverHelpers.clickOnWebElementBySelector(LINK_EVENT_BUTTON)); - When( - "^I click on Link Event button on Edit Event Page$", - () -> webDriverHelpers.clickOnWebElementBySelector(LINK_EVENT_BUTTON_EDIT_PAGE)); - - When( - "^I click on Unlink Event button on Event Directory Page$", - () -> webDriverHelpers.clickOnWebElementBySelector(UNLINK_EVENT_BUTTON)); - When( "^I fill Id filter with Id of last created event in Link Event to group form$", () -> @@ -273,9 +231,9 @@ public EventDirectorySteps( () -> webDriverHelpers.clickOnWebElementBySelector(LINKED_EVENT_GROUP_ID)); When( "^I click on Group Id in Events result on Event Directory Page$", - () ->{ - webDriverHelpers.scrollToElement(EVENT_GROUP_ID_IN_GRID); - webDriverHelpers.clickOnWebElementBySelector(EVENT_GROUP_ID_IN_GRID); + () -> { + webDriverHelpers.scrollToElement(EVENT_GROUP_ID_IN_GRID); + webDriverHelpers.clickOnWebElementBySelector(EVENT_GROUP_ID_IN_GRID); }); When( From 8f260d42a20df264f68c4a04494cd0be51d6c2bf Mon Sep 17 00:00:00 2001 From: alexcaruntu-vita <76100512+alexcaruntu-vita@users.noreply.github.com> Date: Wed, 2 Mar 2022 08:58:05 +0200 Subject: [PATCH 234/253] #8105 - Set disease variant details field on case create form (#8178) --- .../de/symeda/sormas/ui/caze/CaseCreateForm.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseCreateForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseCreateForm.java index c857cd83e04..9f5ef00bae7 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseCreateForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseCreateForm.java @@ -43,6 +43,7 @@ import com.vaadin.ui.Button; import com.vaadin.ui.Label; import com.vaadin.ui.themes.ValoTheme; +import com.vaadin.v7.data.util.converter.Converter; import com.vaadin.v7.data.validator.EmailValidator; import com.vaadin.v7.ui.AbstractSelect; import com.vaadin.v7.ui.AbstractSelect.ItemCaptionMode; @@ -110,6 +111,7 @@ public class CaseCreateForm extends PersonDependentEditForm { private static final String HOME_ADDRESS_HEADER = "addressHeader"; private static final String HOME_ADDRESS_LOC = "homeAddressLoc"; + private TextField diseaseVariantDetailsField; private ComboBox birthDateDay; private NullableOptionGroup facilityOrHome; private ComboBox facilityTypeGroup; @@ -214,7 +216,7 @@ protected void addFields() { addField(CaseDataDto.REPORT_DATE, DateField.class); ComboBox diseaseField = addDiseaseField(CaseDataDto.DISEASE, false, true); ComboBox diseaseVariantField = addField(CaseDataDto.DISEASE_VARIANT, ComboBox.class); - TextField diseaseVariantDetailsField = addField(CaseDataDto.DISEASE_VARIANT_DETAILS, TextField.class); + diseaseVariantDetailsField = addField(CaseDataDto.DISEASE_VARIANT_DETAILS, TextField.class); diseaseVariantDetailsField.setVisible(false); diseaseVariantField.setNullSelectionAllowed(true); diseaseVariantField.setVisible(false); @@ -935,4 +937,12 @@ public LocationEditForm getHomeAddressForm() { protected String createHtmlLayout() { return String.format(HTML_LAYOUT, showPersonSearchButton ? NAME_ROW_WITH_PERSON_SEARCH : NAME_ROW_WITHOUT_PERSON_SEARCH); } + + @Override + public void setValue(CaseDataDto caseDataDto) throws com.vaadin.v7.data.Property.ReadOnlyException, Converter.ConversionException { + super.setValue(caseDataDto); + if (convertedTravelEntry != null) { + diseaseVariantDetailsField.setValue(convertedTravelEntry.getDiseaseVariantDetails()); + } + } } From 294cf49af430e0cad1a23fa843b76331f5a656f5 Mon Sep 17 00:00:00 2001 From: alexcaruntu-vita <76100512+alexcaruntu-vita@users.noreply.github.com> Date: Wed, 2 Mar 2022 10:06:08 +0200 Subject: [PATCH 235/253] #8133 - Save travel entry before creating a case (#8164) --- .../de/symeda/sormas/ui/travelentry/TravelEntryDataView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryDataView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryDataView.java index 4d7e62f04b7..174c51d72ea 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryDataView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/travelentry/TravelEntryDataView.java @@ -79,7 +79,7 @@ protected void initView(String params) { if (resultingCase == null) { Button createCaseButton = ButtonHelper.createButton( Captions.travelEntryCreateCase, - e -> ControllerProvider.getCaseController().createFromTravelEntry(travelEntryDto), + e -> showNavigationConfirmPopupIfDirty(() -> ControllerProvider.getCaseController().createFromTravelEntry(travelEntryDto)), ValoTheme.BUTTON_PRIMARY, CssStyles.VSPACE_2); layout.addComponent(createCaseButton, CASE_LOC); From 4d00bb4be0b2c44209f9ae9b358ad394903d2ccc Mon Sep 17 00:00:00 2001 From: dinua Date: Wed, 2 Mar 2022 10:18:29 +0200 Subject: [PATCH 236/253] #7974 changes after review --- .../java/de/symeda/sormas/backend/person/PersonService.java | 3 +-- .../backend/travelentry/services/BaseTravelEntryService.java | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonService.java index e0c4cdf6633..2980292e0ef 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonService.java @@ -54,7 +54,6 @@ import javax.transaction.Transactional; import javax.validation.constraints.NotNull; -import de.symeda.sormas.backend.travelentry.TravelEntryQueryContext; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -272,7 +271,7 @@ public Predicate createUserFilter(PersonQueryContext personQueryContext, PersonC : () -> null; final Supplier travelEntryFilter = () -> CriteriaBuilderHelper.and( cb, - travelEntryService.createUserFilter(new TravelEntryQueryContext(cb, cq, joins.getTravelEntry())), + travelEntryService.createUserFilter(cb, cq, joins.getTravelEntry()), travelEntryService.createDefaultFilter(cb, joins.getTravelEntry())); // 2. Define the Joins on associations where needed diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java index 709b74106f9..5c4a324d71d 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/services/BaseTravelEntryService.java @@ -36,7 +36,7 @@ public BaseTravelEntryService() { @Override public Predicate createUserFilter(CriteriaBuilder cb, CriteriaQuery cq, From travelEntryPath) { - return inJurisdictionOrOwned(new TravelEntryQueryContext(cb, cq, travelEntryPath)); + return createUserFilter(new TravelEntryQueryContext(cb, cq, travelEntryPath)); } public Predicate inJurisdictionOrOwned(TravelEntryQueryContext qc, User user) { @@ -51,7 +51,7 @@ public Predicate createDefaultFilter(CriteriaBuilder cb, From ro return cb.isFalse(root.get(TravelEntry.DELETED)); } - public Predicate createUserFilter(TravelEntryQueryContext qc) { + protected Predicate createUserFilter(TravelEntryQueryContext qc) { final User currentUser = userService.getCurrentUser(); final CriteriaBuilder cb = qc.getCriteriaBuilder(); Predicate filter = inJurisdictionOrOwned(qc); From a6bc17896b71caf37fc922a16731f561060d492b Mon Sep 17 00:00:00 2001 From: Maciej Paszylka Date: Wed, 2 Mar 2022 10:11:54 +0100 Subject: [PATCH 237/253] fix for test regarding filtering --- .../test/resources/features/sanity/web/CaseFilters.feature | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature index a211491df6c..445659f256d 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseFilters.feature @@ -240,7 +240,7 @@ Feature: Case filter functionality And I check that number of displayed cases results is 0 And I fill Cases from input to 1 days before mocked Case created on Case directory page - @issue=SORQA-30 @env_main @ignore + @issue=SORQA-30 @env_main Scenario: Check complex filters regarding responsibilities, vaccination, reinfection adn quarantine Given API: I create a new person Then API: I check that POST call body is "OK" @@ -260,10 +260,6 @@ Feature: Case filter functionality And I apply Reinfection filter to "Confirmed reinfection" on Case directory page And I click APPLY BUTTON in Case Directory Page And I check that number of displayed cases results is 1 - And I apply Surveillance Officer filter "Bas BEN - Surveillance Officer, Contact Officer" on Case directory page - And I click APPLY BUTTON in Case Directory Page - And I check that number of displayed cases results is 0 - And I apply Surveillance Officer filter "Surveillance OFFICER - Surveillance Officer" on Case directory page And I apply Reporting User filter "Surveillance OFFICER" on Case directory page And I click APPLY BUTTON in Case Directory Page And I check that number of displayed cases results is 0 From 6c555999c26d7863d2f63a7d207114474aebdf91 Mon Sep 17 00:00:00 2001 From: Bartha Barna Date: Wed, 2 Mar 2022 11:26:54 +0200 Subject: [PATCH 238/253] #8168 - fix saving sample with pathogen test for case & contact --- .../src/main/java/de/symeda/sormas/ui/caze/CaseDataView.java | 3 ++- .../main/java/de/symeda/sormas/ui/contact/ContactDataView.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataView.java index b61954443fb..c90f3fa3b8c 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataView.java @@ -142,7 +142,8 @@ protected void initView(String params) { SampleListComponent sampleList = new SampleListComponent( new SampleCriteria().caze(getCaseRef()).sampleAssociationType(SampleAssociationType.CASE), e -> showNavigationConfirmPopupIfDirty(() -> ControllerProvider.getSampleController().create(getCaseRef(), caze.getDisease(), () -> { - FacadeProvider.getCaseFacade().save(caze); + final CaseDataDto caseDataByUuid = FacadeProvider.getCaseFacade().getCaseDataByUuid(getCaseRef().getUuid()); + FacadeProvider.getCaseFacade().save(caseDataByUuid); SormasUI.refreshView(); }))); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataView.java index 8a5d4fae880..f12069d8e71 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataView.java @@ -219,7 +219,8 @@ protected void initView(String params) { new SampleCriteria().contact(getContactRef()).sampleAssociationType(SampleAssociationType.CONTACT), e -> showNavigationConfirmPopupIfDirty( () -> ControllerProvider.getSampleController().create(getContactRef(), contactDto.getDisease(), () -> { - FacadeProvider.getContactFacade().save(contactDto); + final ContactDto contactByUuid = FacadeProvider.getContactFacade().getByUuid(getContactRef().getUuid()); + FacadeProvider.getContactFacade().save(contactByUuid); SormasUI.refreshView(); }))); From 86cb1f14c04063f82112039674c22688b211286a Mon Sep 17 00:00:00 2001 From: sergiupacurariu <62688603+sergiupacurariu@users.noreply.github.com> Date: Wed, 2 Mar 2022 12:55:42 +0200 Subject: [PATCH 239/253] #7247 - CoreAdo: Introduce "end of processing date" - format date according to user language --- .../java/de/symeda/sormas/ui/utils/ArchivingController.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchivingController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchivingController.java index 484aa972be2..ce451a70549 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchivingController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/ArchivingController.java @@ -37,6 +37,8 @@ public void archiveEntity( DateField endOfProcessingDate = new DateField(); endOfProcessingDate.setValue(DateHelper8.toLocalDate(entityFacade.calculateEndOfProcessingDate(coreEntityDto.getUuid()))); endOfProcessingDate.setCaption(I18nProperties.getCaption(Captions.endOfProcessingDate)); + endOfProcessingDate.setDateFormat(DateFormatHelper.getDateFormatPattern()); + verticalLayout.addComponent(endOfProcessingDate); verticalLayout.setMargin(false); From f18e401e4b97a6e906f745bdf5e3ac2bec86ab11 Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Wed, 2 Mar 2022 13:49:33 +0200 Subject: [PATCH 240/253] #7773-allure-attach-logs : added changes 14 --- sormas-e2e-tests/src/main/resources/logback.xml | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/sormas-e2e-tests/src/main/resources/logback.xml b/sormas-e2e-tests/src/main/resources/logback.xml index e34984401ea..e2bee39372b 100755 --- a/sormas-e2e-tests/src/main/resources/logback.xml +++ b/sormas-e2e-tests/src/main/resources/logback.xml @@ -74,11 +74,11 @@ log-%d{yyyy-MM-dd}.log - 0 + 60 30GB - 500MB + 100MB %d{HH:mm:ss} [%thread] %-5level - %msg%n @@ -91,15 +91,5 @@ - - - - - - - - - - \ No newline at end of file From 19c54c20ba3769be713a1c83fb892cd737a3566e Mon Sep 17 00:00:00 2001 From: Christopher Riedel Date: Wed, 2 Mar 2022 16:26:58 +0100 Subject: [PATCH 241/253] #2802: Added caption (#8180) --- sormas-api/src/main/resources/enum.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/sormas-api/src/main/resources/enum.properties b/sormas-api/src/main/resources/enum.properties index 9fd101a6a62..cabfa8f6111 100644 --- a/sormas-api/src/main/resources/enum.properties +++ b/sormas-api/src/main/resources/enum.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation From 7d9c52e315a012217541f47bde70c7c5eb845a0a Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Wed, 2 Mar 2022 19:33:05 +0200 Subject: [PATCH 242/253] #7773-allure-attach-logs : stable fix v1 --- sormas-e2e-tests/build.gradle | 8 +++-- .../src/main/resources/logback.xml | 33 ++++++------------- .../e2etests/helpers/AssertHelpers.java | 13 ++++---- .../e2etests/helpers/WebDriverHelpers.java | 8 +++-- .../org/sormas/e2etests/steps/BaseSteps.java | 10 ++++-- 5 files changed, 37 insertions(+), 35 deletions(-) diff --git a/sormas-e2e-tests/build.gradle b/sormas-e2e-tests/build.gradle index cc531d8dc07..a052b37c76d 100755 --- a/sormas-e2e-tests/build.gradle +++ b/sormas-e2e-tests/build.gradle @@ -45,8 +45,12 @@ dependencies { implementation("com.google.inject:guice:$guiceVersion") implementation("io.cucumber:cucumber-guice:$cucumberVersion") - implementation("ch.qos.logback:logback-classic:$logBackVersion") - implementation("ch.qos.logback:logback-core:$logBackVersion") +// implementation("ch.qos.logback:logback-classic:$logBackVersion") +// implementation("ch.qos.logback:logback-core:$logBackVersion") + + implementation 'ch.qos.logback:logback-core:1.2.3' + implementation 'ch.qos.logback:logback-classic:1.2.3' + implementation 'org.slf4j:slf4j-api:1.7.30' implementation("com.github.javafaker:javafaker:$javaFakerVersion") { exclude module: "org.yaml" } diff --git a/sormas-e2e-tests/src/main/resources/logback.xml b/sormas-e2e-tests/src/main/resources/logback.xml index e2bee39372b..ad1b6fc599c 100755 --- a/sormas-e2e-tests/src/main/resources/logback.xml +++ b/sormas-e2e-tests/src/main/resources/logback.xml @@ -60,36 +60,23 @@ utf-8 %boldMagenta(%d{yyyy-MM-dd' 'HH:mm:ss,SSS}) %highlight(%level)-> %msg%n + + INFO + - - logs/log.html - - - %thread%level%logger%msg - - - - - - - log-%d{yyyy-MM-dd}.log - 60 - 30GB - - - 100MB - + + logs/file.log + true + true - %d{HH:mm:ss} [%thread] %-5level - %msg%n + %d{HH:mm:ss.SSS} %-5level [%logger{36}] - %msg%n - logs/file.log - + - - + \ No newline at end of file diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java index 16b220d6b57..d509476d92b 100755 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java @@ -21,19 +21,21 @@ import static junit.framework.TestCase.fail; import static org.awaitility.Awaitility.await; import static org.awaitility.pollinterval.FibonacciPollInterval.fibonacci; -import static recorders.StepsLogger.PROCESS_ID_STRING; import java.time.Duration; -import java.util.Arrays; import java.util.concurrent.TimeUnit; import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; +// import lombok.extern.slf4j.Slf4j; import org.awaitility.core.ConditionTimeoutException; import org.awaitility.core.ThrowingRunnable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -@Slf4j +// @Slf4j public class AssertHelpers { + private static final Logger log = LoggerFactory.getLogger(AssertHelpers.class); + @SneakyThrows public void assertWithPoll(ThrowingRunnable throwingRunnable, int seconds) { try { @@ -44,8 +46,7 @@ public void assertWithPoll(ThrowingRunnable throwingRunnable, int seconds) { .timeout(Duration.ofSeconds(seconds)) .untilAsserted(throwingRunnable); } catch (ConditionTimeoutException e) { - log.error(PROCESS_ID_STRING + e.getMessage()); - log.error(PROCESS_ID_STRING + Arrays.toString(e.getStackTrace())); + log.error("Test has failed due to: {}", e.getCause()); fail(e.getCause().getLocalizedMessage()); } } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java index 38f33aa7436..1df9d576f83 100755 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java @@ -28,7 +28,7 @@ import java.util.stream.Collectors; import javax.inject.Inject; import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; +// import lombok.extern.slf4j.Slf4j; import org.awaitility.core.ConditionTimeoutException; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; @@ -40,13 +40,17 @@ import org.openqa.selenium.WebDriverException; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.sormas.e2etests.common.TimerLite; import org.sormas.e2etests.steps.BaseSteps; import org.testng.Assert; -@Slf4j +// @Slf4j public class WebDriverHelpers { + private static final Logger log = LoggerFactory.getLogger(WebDriverHelpers.class); + public static final By SELECTED_RADIO_BUTTON = By.xpath("ancestor::div[contains(@role,'group')]//input[@checked]/following-sibling::label"); public static final By SELECTED_RADIO_DISABLED_AND_CHECKED_BUTTON = diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java index 2ca55c14dfc..0bf917a7638 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java @@ -30,15 +30,19 @@ import io.restassured.parsing.Parser; import java.time.Duration; import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; +// import lombok.extern.slf4j.Slf4j; import org.openqa.selenium.WebDriver; import org.openqa.selenium.remote.RemoteWebDriver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.sormas.e2etests.webdriver.DriverManager; import recorders.StepsLogger; -@Slf4j +// @Slf4j public class BaseSteps implements StepLifecycleListener { + private static final Logger log = LoggerFactory.getLogger(BaseSteps.class); + public static RemoteWebDriver driver; public static String locale; private final DriverManager driverManager; @@ -59,6 +63,8 @@ public void setRunningLocale(Scenario scenario) { @Before(value = "@UI") public void beforeScenario(Scenario scenario) { + log.warn("Warn message check"); + log.error("Error message check"); if (isNonApiScenario(scenario)) { driver = driverManager.borrowRemoteWebDriver(scenario.getName()); StepsLogger.setRemoteWebDriver(driver); From 111ce5d290ad0be9265d870c9a930860a1133a4c Mon Sep 17 00:00:00 2001 From: jparzuch Date: Wed, 2 Mar 2022 18:58:39 +0100 Subject: [PATCH 243/253] Rebased tests for SORQA-69 --- .../sormas/e2etests/steps/web/application/LoginSteps.java | 8 ++++++++ .../src/test/resources/features/sanity/web/Login.feature | 7 ++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/LoginSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/LoginSteps.java index bba25a27231..d3ed054008a 100755 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/LoginSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/LoginSteps.java @@ -29,6 +29,7 @@ import org.sormas.e2etests.envconfig.manager.EnvironmentManager; import org.sormas.e2etests.helpers.WebDriverHelpers; import org.sormas.e2etests.pages.application.LoginPage; +import org.sormas.e2etests.pages.application.NavBarPage; import org.sormas.e2etests.pages.application.dashboard.Surveillance.SurveillanceDashboardPage; import org.sormas.e2etests.steps.BaseSteps; @@ -101,5 +102,12 @@ public LoginSteps( webDriverHelpers.waitForPageLoaded(); webDriverHelpers.waitUntilIdentifiedElementIsVisibleAndClickable(LOGOUT_BUTTON, 50); }); + + When( + "I check that German word for Configuration is present in the left main menu", + () -> { + webDriverHelpers.checkWebElementContainsText( + NavBarPage.CONFIGURATION_BUTTON, "Einstellungen"); + }); } } diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/Login.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/Login.feature index f7cfb37f59c..afc618b81ac 100755 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/Login.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/Login.feature @@ -13,4 +13,9 @@ Feature: Login with different type of users | Contact Supervisor | | Laboratory Officer | | Point of Entry Supervisor | - | Surveillance Officer | \ No newline at end of file + | Surveillance Officer | + + @issue=SORQA-69 @env_de + Scenario: Check German language setting + Given I log in with National User + Then I check that German word for Configuration is present in the left main menu \ No newline at end of file From 9549e2a0721f8dc51a77bb72fbbf3fa00f4b51d4 Mon Sep 17 00:00:00 2001 From: alexcaruntu-vita <76100512+alexcaruntu-vita@users.noreply.github.com> Date: Thu, 3 Mar 2022 11:17:57 +0200 Subject: [PATCH 244/253] Bugfix 8131 a problem has occured when trying to save an event (#8179) * #8131 - Refactoring * #8131 - Refactoring * #8131 - Refactoring * #8131 - Refactored EventGroupListComponent * #8131 - Save event before linking an event group * #8131 - Simplifications --- .../sormas/ui/events/EventDataView.java | 60 +++++++++- .../ui/events/groups/EventGroupList.java | 12 +- .../groups/EventGroupListComponent.java | 104 ++---------------- .../ui/events/groups/EventGroupListEntry.java | 17 +-- .../sidecomponent/SideComponent.java | 11 +- 5 files changed, 80 insertions(+), 124 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventDataView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventDataView.java index bcc1052dec5..c3b009550f6 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventDataView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventDataView.java @@ -14,8 +14,14 @@ */ package de.symeda.sormas.ui.events; +import java.util.Collections; +import java.util.Set; +import java.util.stream.Collectors; + +import com.vaadin.server.Page; import com.vaadin.ui.Button; import com.vaadin.ui.CustomLayout; +import com.vaadin.ui.Notification; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.themes.ValoTheme; @@ -26,11 +32,15 @@ import de.symeda.sormas.api.document.DocumentRelatedEntityType; import de.symeda.sormas.api.event.EventCriteria; import de.symeda.sormas.api.event.EventDto; +import de.symeda.sormas.api.event.EventGroupCriteria; +import de.symeda.sormas.api.event.EventGroupReferenceDto; +import de.symeda.sormas.api.event.EventReferenceDto; import de.symeda.sormas.api.event.EventStatus; import de.symeda.sormas.api.event.TypeOfPlace; import de.symeda.sormas.api.feature.FeatureType; import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; import de.symeda.sormas.api.location.LocationDto; import de.symeda.sormas.api.task.TaskContext; import de.symeda.sormas.api.user.UserRight; @@ -131,8 +141,7 @@ protected void initView(String params) { DocumentListComponent documentList = null; if (FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.DOCUMENTS)) { // TODO: user rights? - documentList = - new DocumentListComponent(DocumentRelatedEntityType.EVENT, getEventRef(), UserRight.EVENT_EDIT, event.isPseudonymized()); + documentList = new DocumentListComponent(DocumentRelatedEntityType.EVENT, getEventRef(), UserRight.EVENT_EDIT, event.isPseudonymized()); layout.addComponent(new SideComponentLayout(documentList), DOCUMENTS_LOC); } @@ -153,9 +162,50 @@ protected void initView(String params) { boolean eventGroupsFeatureEnabled = FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.EVENT_GROUPS); if (eventGroupsFeatureEnabled) { - EventGroupListComponent eventGroupsList = new EventGroupListComponent(event.toReference()); - eventGroupsList.addStyleName(CssStyles.SIDE_COMPONENT); - layout.addComponent(eventGroupsList, EVENT_GROUPS_LOC); + EventReferenceDto eventReference = event.toReference(); + EventGroupListComponent eventGroupsList = new EventGroupListComponent(eventReference); + eventGroupsList.addSideComponentCreateEventListener(e -> showNavigationConfirmPopupIfDirty(() -> { + EventDto eventByUuid = FacadeProvider.getEventFacade().getEventByUuid(eventReference.getUuid(), false); + UserProvider user = UserProvider.getCurrent(); + if (!user.hasNationalJurisdictionLevel() && !user.hasRegion(eventByUuid.getEventLocation().getRegion())) { + new Notification( + I18nProperties.getString(Strings.headingEventGroupLinkEventIssue), + I18nProperties.getString(Strings.errorEventFromAnotherJurisdiction), + Notification.Type.ERROR_MESSAGE, + false).show(Page.getCurrent()); + return; + } + + EventGroupCriteria eventGroupCriteria = new EventGroupCriteria(); + Set eventGroupUuids = FacadeProvider.getEventGroupFacade() + .getCommonEventGroupsByEvents(Collections.singletonList(eventByUuid.toReference())) + .stream() + .map(EventGroupReferenceDto::getUuid) + .collect(Collectors.toSet()); + eventGroupCriteria.setExcludedUuids(eventGroupUuids); + if (user.hasUserRight(UserRight.EVENTGROUP_CREATE) && user.hasUserRight(UserRight.EVENTGROUP_LINK)) { + long events = FacadeProvider.getEventGroupFacade().count(eventGroupCriteria); + if (events > 0) { + ControllerProvider.getEventGroupController().selectOrCreate(eventReference); + } else { + ControllerProvider.getEventGroupController().create(eventReference); + } + } else if (user.hasUserRight(UserRight.EVENTGROUP_CREATE)) { + ControllerProvider.getEventGroupController().create(eventReference); + } else { + long events = FacadeProvider.getEventGroupFacade().count(eventGroupCriteria); + if (events > 0) { + ControllerProvider.getEventGroupController().select(eventReference); + } else { + new Notification( + I18nProperties.getString(Strings.headingEventGroupLinkEventIssue), + I18nProperties.getString(Strings.errorNotRequiredRights), + Notification.Type.ERROR_MESSAGE, + false).show(Page.getCurrent()); + } + } + })); + layout.addComponent(new SideComponentLayout(eventGroupsList), EVENT_GROUPS_LOC); } boolean sormasToSormasEnabled = FacadeProvider.getSormasToSormasFacade().isSharingEventsEnabledForUser(); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/groups/EventGroupList.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/groups/EventGroupList.java index 1aa87b98963..4d94859e15d 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/groups/EventGroupList.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/groups/EventGroupList.java @@ -43,12 +43,14 @@ public class EventGroupList extends PaginationList { + private static final int MAX_DISPLAYED_ENTRIES = 5; + private final EventReferenceDto event; private final EventGroupCriteria eventGroupCriteria = new EventGroupCriteria(); private final Label noEventGroupLabel; public EventGroupList(EventReferenceDto event) { - super(5); + super(MAX_DISPLAYED_ENTRIES); this.event = event; @@ -80,10 +82,10 @@ protected void drawDisplayedEntries() { EventGroupIndexDto eventGroup = displayedEntries.get(i); EventGroupListEntry listEntry = new EventGroupListEntry(eventGroup); - UserProvider user = UserProvider.getCurrent(); - if (user.hasUserRight(UserRight.EVENTGROUP_LINK)) { + UserProvider userProvider = UserProvider.getCurrent(); + if (userProvider != null && userProvider.hasUserRight(UserRight.EVENTGROUP_LINK)) { listEntry.addUnlinkEventListener(i, (ClickListener) clickEvent -> { - if (!user.hasNationalJurisdictionLevel() && !user.hasRegion(event.getEventLocation().getRegion())) { + if (!userProvider.hasNationalJurisdictionLevel() && !userProvider.hasRegion(event.getEventLocation().getRegion())) { new Notification( I18nProperties.getString(Strings.headingEventGroupUnlinkEventIssue), I18nProperties.getString(Strings.errorEventFromAnotherJurisdiction), @@ -96,7 +98,7 @@ protected void drawDisplayedEntries() { reload(); }); } - if (user.hasUserRight(UserRight.EVENTGROUP_EDIT)) { + if (userProvider != null && userProvider.hasUserRight(UserRight.EVENTGROUP_EDIT)) { listEntry.addEditListener(i, (ClickListener) clickEvent -> { ControllerProvider.getEventGroupController().navigateToData(listEntry.getEventGroup().getUuid()); }); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/groups/EventGroupListComponent.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/groups/EventGroupListComponent.java index 266ca9d88e2..68d8e57c292 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/groups/EventGroupListComponent.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/groups/EventGroupListComponent.java @@ -20,112 +20,22 @@ package de.symeda.sormas.ui.events.groups; -import java.util.Collections; -import java.util.Set; -import java.util.stream.Collectors; - -import com.vaadin.icons.VaadinIcons; -import com.vaadin.server.Page; -import com.vaadin.ui.Alignment; -import com.vaadin.ui.Button; -import com.vaadin.ui.HorizontalLayout; -import com.vaadin.ui.Label; -import com.vaadin.ui.Notification; -import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.themes.ValoTheme; - -import de.symeda.sormas.api.FacadeProvider; -import de.symeda.sormas.api.event.EventDto; -import de.symeda.sormas.api.event.EventGroupCriteria; -import de.symeda.sormas.api.event.EventGroupReferenceDto; import de.symeda.sormas.api.event.EventReferenceDto; import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; -import de.symeda.sormas.api.i18n.Strings; import de.symeda.sormas.api.user.UserRight; -import de.symeda.sormas.ui.ControllerProvider; -import de.symeda.sormas.ui.UserProvider; -import de.symeda.sormas.ui.utils.ButtonHelper; -import de.symeda.sormas.ui.utils.CssStyles; - -public class EventGroupListComponent extends VerticalLayout { +import de.symeda.sormas.ui.utils.components.sidecomponent.SideComponent; - private EventGroupList list; - private Button createButton; +public class EventGroupListComponent extends SideComponent { public EventGroupListComponent(EventReferenceDto eventReference) { - EventGroupList eventList = new EventGroupList(eventReference); - createEventGroupListComponent(eventList, I18nProperties.getCaption(Captions.eventGroups), e -> { - EventDto event = FacadeProvider.getEventFacade().getEventByUuid(eventReference.getUuid(), false); - UserProvider user = UserProvider.getCurrent(); - if (!user.hasNationalJurisdictionLevel() && !user.hasRegion(event.getEventLocation().getRegion())) { - new Notification( - I18nProperties.getString(Strings.headingEventGroupLinkEventIssue), - I18nProperties.getString(Strings.errorEventFromAnotherJurisdiction), - Notification.Type.ERROR_MESSAGE, - false).show(Page.getCurrent()); - return; - } - - EventGroupCriteria eventGroupCriteria = new EventGroupCriteria(); - Set eventGroupUuids = FacadeProvider.getEventGroupFacade() - .getCommonEventGroupsByEvents(Collections.singletonList(event.toReference())) - .stream() - .map(EventGroupReferenceDto::getUuid) - .collect(Collectors.toSet()); - eventGroupCriteria.setExcludedUuids(eventGroupUuids); - if (user.hasUserRight(UserRight.EVENTGROUP_CREATE) && user.hasUserRight(UserRight.EVENTGROUP_LINK)) { - long events = FacadeProvider.getEventGroupFacade().count(eventGroupCriteria); - if (events > 0) { - ControllerProvider.getEventGroupController().selectOrCreate(eventReference); - } else { - ControllerProvider.getEventGroupController().create(eventReference); - } - } else if (user.hasUserRight(UserRight.EVENTGROUP_CREATE)) { - ControllerProvider.getEventGroupController().create(eventReference); - } else { - long events = FacadeProvider.getEventGroupFacade().count(eventGroupCriteria); - if (events > 0) { - ControllerProvider.getEventGroupController().select(eventReference); - } else { - new Notification( - I18nProperties.getString(Strings.headingEventGroupLinkEventIssue), - I18nProperties.getString(Strings.errorNotRequiredRights), - Notification.Type.ERROR_MESSAGE, - false).show(Page.getCurrent()); - } - } - }); - } - - private void createEventGroupListComponent(EventGroupList eventList, String heading, Button.ClickListener clickListener) { - setWidth(100, Unit.PERCENTAGE); - setMargin(false); - setSpacing(false); - - HorizontalLayout componentHeader = new HorizontalLayout(); - componentHeader.setMargin(false); - componentHeader.setSpacing(false); - componentHeader.setWidth(100, Unit.PERCENTAGE); - addComponent(componentHeader); + super(I18nProperties.getCaption(Captions.eventGroups)); - list = eventList; - addComponent(list); - list.reload(); + addCreateButton(I18nProperties.getCaption(Captions.linkEventGroup), UserRight.EVENTGROUP_CREATE, UserRight.EVENTGROUP_LINK); - Label eventLabel = new Label(heading); - eventLabel.addStyleName(CssStyles.H3); - componentHeader.addComponent(eventLabel); - - UserProvider user = UserProvider.getCurrent(); - if (user.hasUserRight(UserRight.EVENTGROUP_CREATE) || user.hasUserRight(UserRight.EVENTGROUP_LINK)) { - createButton = ButtonHelper.createButton(I18nProperties.getCaption(Captions.linkEventGroup)); - createButton.addStyleName(ValoTheme.BUTTON_PRIMARY); - createButton.setIcon(VaadinIcons.PLUS_CIRCLE); - createButton.addClickListener(clickListener); - componentHeader.addComponent(createButton); - componentHeader.setComponentAlignment(createButton, Alignment.MIDDLE_RIGHT); - } + EventGroupList eventList = new EventGroupList(eventReference); + addComponent(eventList); + eventList.reload(); } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/groups/EventGroupListEntry.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/groups/EventGroupListEntry.java index e35f14403d2..6cb130b4ffe 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/groups/EventGroupListEntry.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/groups/EventGroupListEntry.java @@ -38,8 +38,9 @@ import de.symeda.sormas.ui.utils.ButtonHelper; import de.symeda.sormas.ui.utils.ClickableLabel; import de.symeda.sormas.ui.utils.CssStyles; +import de.symeda.sormas.ui.utils.components.sidecomponent.SideComponentField; -public class EventGroupListEntry extends HorizontalLayout { +public class EventGroupListEntry extends SideComponentField { private final EventGroupIndexDto eventGroup; private Button editButton; @@ -49,23 +50,11 @@ public class EventGroupListEntry extends HorizontalLayout { public EventGroupListEntry(EventGroupIndexDto eventGroup) { this.eventGroup = eventGroup; - setMargin(false); - setSpacing(true); - setWidth(100, Unit.PERCENTAGE); - addStyleName(CssStyles.SORMAS_LIST_ENTRY); - - VerticalLayout mainLayout = new VerticalLayout(); - mainLayout.setWidth(100, Unit.PERCENTAGE); - mainLayout.setMargin(false); - mainLayout.setSpacing(false); - addComponent(mainLayout); - setExpandRatio(mainLayout, 1); - HorizontalLayout topLayout = new HorizontalLayout(); topLayout.setWidth(100, Unit.PERCENTAGE); topLayout.setMargin(false); topLayout.setSpacing(false); - mainLayout.addComponent(topLayout); + addComponentToField(topLayout); VerticalLayout topLeftLayout = new VerticalLayout(); { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/SideComponent.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/SideComponent.java index 6f4d8831cc4..255493b612c 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/SideComponent.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/sidecomponent/SideComponent.java @@ -1,5 +1,6 @@ package de.symeda.sormas.ui.utils.components.sidecomponent; +import java.util.Arrays; import java.util.function.Consumer; import com.vaadin.icons.VaadinIcons; @@ -57,9 +58,8 @@ protected void addCreateButton(String caption, UserRight userRight, Consumer Date: Thu, 3 Mar 2022 11:47:23 +0200 Subject: [PATCH 245/253] #8184 - Clear home address checkbox when selecting a person (#8195) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * #8184 - Clear home address checkbox when selecting a person * #8184 - Clear facility field component error Co-authored-by: Maté Strysewske --- .../src/main/java/de/symeda/sormas/ui/caze/CaseCreateForm.java | 2 ++ .../java/de/symeda/sormas/ui/location/LocationEditForm.java | 1 + 2 files changed, 3 insertions(+) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseCreateForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseCreateForm.java index 9f5ef00bae7..c0207989844 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseCreateForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseCreateForm.java @@ -815,6 +815,8 @@ public void setPerson(PersonDto person) { homeAddressForm.clear(); homeAddressForm.setFacilityFieldsVisible(false, true); homeAddressForm.setVisible(false); + } else { + enterHomeAddressNow.setValue(false); } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/location/LocationEditForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/location/LocationEditForm.java index bcbefa59ef4..d9cde564b38 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/location/LocationEditForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/location/LocationEditForm.java @@ -730,6 +730,7 @@ public void setFacilityFieldsVisible(boolean visible, boolean clearOnHidden) { facilityDetails.clear(); facilityType.clear(); facilityTypeGroup.clear(); + facility.setComponentError(null); } } From f6fa042dee578be35f2efbec632989ceedb12bd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9=20Strysewske?= Date: Thu, 3 Mar 2022 11:52:18 +0100 Subject: [PATCH 246/253] #8033 - Change travel entry reference when merging cases (#8187) * #8033 - Change travel entry reference when merging cases * #8033 - Extended test --- .../sormas/backend/caze/CaseFacadeEjb.java | 14 +++++++++-- .../sormas/backend/TestDataCreator.java | 23 +++++++++++++++---- .../backend/caze/CaseFacadeEjbTest.java | 16 ++++++++++++- 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java index ae71e7d53bf..0022e50b67b 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java @@ -53,7 +53,6 @@ import javax.ejb.TransactionAttributeType; import javax.enterprise.concurrent.ManagedScheduledExecutorService; import javax.inject.Inject; -import javax.persistence.Tuple; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; @@ -69,7 +68,6 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; -import de.symeda.sormas.backend.clinicalcourse.HealthConditionsMapper; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTime; @@ -212,6 +210,7 @@ import de.symeda.sormas.backend.clinicalcourse.ClinicalVisitFacadeEjb.ClinicalVisitFacadeEjbLocal; import de.symeda.sormas.backend.clinicalcourse.ClinicalVisitService; import de.symeda.sormas.backend.clinicalcourse.HealthConditions; +import de.symeda.sormas.backend.clinicalcourse.HealthConditionsMapper; import de.symeda.sormas.backend.common.AbstractCoreFacadeEjb; import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.ConfigFacadeEjb.ConfigFacadeEjbLocal; @@ -310,6 +309,8 @@ import de.symeda.sormas.backend.therapy.TreatmentFacadeEjb; import de.symeda.sormas.backend.therapy.TreatmentFacadeEjb.TreatmentFacadeEjbLocal; import de.symeda.sormas.backend.therapy.TreatmentService; +import de.symeda.sormas.backend.travelentry.TravelEntry; +import de.symeda.sormas.backend.travelentry.services.TravelEntryService; import de.symeda.sormas.backend.user.User; import de.symeda.sormas.backend.user.UserFacadeEjb; import de.symeda.sormas.backend.user.UserReference; @@ -451,6 +452,8 @@ public class CaseFacadeEjb extends AbstractCoreFacadeEjb travelEntries = travelEntryService.getAllByResultingCase(otherCase); + travelEntries.forEach(t -> { + t.setResultingCase(leadCase); + travelEntryService.ensurePersisted(t); + }); } private void copyDtoValues(CaseDataDto leadCaseData, CaseDataDto otherCaseData, boolean cloning) { diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java index ee9a3d1e53a..b562e3daa98 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java @@ -174,17 +174,30 @@ public UserDto createUser(String regionUuid, String districtUuid, String facilit return createUser(regionUuid, districtUuid, null, facilityUuid, firstName, lastName, roles); } - public UserDto createUser(String regionUuid, String districtUuid, String communityUuid, String facilityUuid, String firstName, - String lastName, UserRole... roles) { - return createUser(regionUuid, districtUuid, communityUuid, facilityUuid, firstName,lastName, null, roles); + public UserDto createUser( + String regionUuid, + String districtUuid, + String communityUuid, + String facilityUuid, + String firstName, + String lastName, + UserRole... roles) { + return createUser(regionUuid, districtUuid, communityUuid, facilityUuid, firstName, lastName, null, roles); } public UserDto createUser(RDCF rdcf, String firstName, String lastName, Disease limitedDisease, UserRole... roles) { return createUser(rdcf.region.getUuid(), rdcf.district.getUuid(), null, rdcf.facility.getUuid(), firstName, lastName, limitedDisease, roles); } - private UserDto createUser(String regionUuid, String districtUuid, String communityUuid, String facilityUuid, String firstName, - String lastName, Disease limitedDisease, UserRole... roles) { + private UserDto createUser( + String regionUuid, + String districtUuid, + String communityUuid, + String facilityUuid, + String firstName, + String lastName, + Disease limitedDisease, + UserRole... roles) { UserDto user1 = UserDto.build(); user1.setFirstName(firstName); diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java index b0155381a50..5a82dddc48a 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java @@ -136,6 +136,7 @@ import de.symeda.sormas.api.therapy.PrescriptionDto; import de.symeda.sormas.api.therapy.TherapyDto; import de.symeda.sormas.api.therapy.TreatmentDto; +import de.symeda.sormas.api.travelentry.TravelEntryDto; import de.symeda.sormas.api.user.UserDto; import de.symeda.sormas.api.user.UserReferenceDto; import de.symeda.sormas.api.user.UserRole; @@ -1304,7 +1305,7 @@ public void testMergeCase() throws IOException { otherPerson.setBirthWeight(2); getPersonFacade().savePerson(otherPerson); PersonReferenceDto otherPersonReference = new PersonReferenceDto(otherPerson.getUuid()); - RDCF otherRdcf = creator.createRDCF(); + RDCF otherRdcf = creator.createRDCF("Reg2", "Dis2", "Comm2", "Fac2", "Poe2"); CaseDataDto otherCase = creator.createCase( otherUserReference, otherPersonReference, @@ -1359,6 +1360,15 @@ public void testMergeCase() throws IOException { getEventParticipantFacade().saveEventParticipant(otherCaseEventParticipant); creator.createSurveillanceReport(otherUserReference, otherCaseReference); + TravelEntryDto travelEntry = creator.createTravelEntry( + otherPersonReference, + otherUserReference, + otherCase.getDisease(), + otherRdcf.region, + otherRdcf.district, + otherRdcf.pointOfEntry); + travelEntry.setResultingCase(otherCaseReference); + travelEntry = getTravelEntryFacade().save(travelEntry); DocumentDto document = creator.createDocument( leadUserReference, @@ -1481,6 +1491,10 @@ public void testMergeCase() throws IOException { final List activitiesAsCase = epiData.getActivitiesAsCase(); assertEquals(1, activitiesAsCase.size()); assertEquals(ActivityAsCaseType.GATHERING, activitiesAsCase.get(0).getActivityAsCaseType()); + + // Travel entry + travelEntry = getTravelEntryFacade().getByUuid(travelEntry.getUuid()); + assertEquals(mergedCase.toReference(), travelEntry.getResultingCase()); } @Test From 920de2bb78d8c11779b1e4d1878edd00b1bed2a9 Mon Sep 17 00:00:00 2001 From: rdutu-vg Date: Thu, 3 Mar 2022 13:16:30 +0200 Subject: [PATCH 247/253] #7773-allure-attach-logs : added last fixes --- sormas-e2e-tests/build.gradle | 14 ++++------- .../customReports/data/results.txt | 2 ++ .../customReports/images/logo.png | Bin 0 -> 26298 bytes sormas-e2e-tests/scripts/runTests.sh | 2 +- .../src/main/java/recorders/StepsLogger.java | 23 +++++++++--------- .../e2etests/helpers/AssertHelpers.java | 8 ++---- .../e2etests/helpers/WebDriverHelpers.java | 23 ++++++++---------- .../org/sormas/e2etests/steps/BaseSteps.java | 15 +++--------- .../web/application/cases/EditCaseSteps.java | 2 ++ .../sanity/web/CaseClasification.feature | 2 +- 10 files changed, 38 insertions(+), 53 deletions(-) create mode 100644 sormas-e2e-tests/customReports/images/logo.png diff --git a/sormas-e2e-tests/build.gradle b/sormas-e2e-tests/build.gradle index a052b37c76d..0bc607613da 100755 --- a/sormas-e2e-tests/build.gradle +++ b/sormas-e2e-tests/build.gradle @@ -45,11 +45,9 @@ dependencies { implementation("com.google.inject:guice:$guiceVersion") implementation("io.cucumber:cucumber-guice:$cucumberVersion") -// implementation("ch.qos.logback:logback-classic:$logBackVersion") -// implementation("ch.qos.logback:logback-core:$logBackVersion") + implementation("ch.qos.logback:logback-classic:$logBackVersion") + implementation("ch.qos.logback:logback-core:$logBackVersion") - implementation 'ch.qos.logback:logback-core:1.2.3' - implementation 'ch.qos.logback:logback-classic:1.2.3' implementation 'org.slf4j:slf4j-api:1.7.30' implementation("com.github.javafaker:javafaker:$javaFakerVersion") { exclude module: "org.yaml" } @@ -89,13 +87,11 @@ task createReportFolderIfNotExist() { if (!folder.exists()) { folder.mkdirs() } + println "Removing old logs file" + delete("logs/file.log") } -task startTests { - doLast { - println "Starting the test cases" - } -} +task startTests {} task copyToGeneratedReport(type: Copy) { dependsOn "createReportFolderIfNotExist" diff --git a/sormas-e2e-tests/customReports/data/results.txt b/sormas-e2e-tests/customReports/data/results.txt index e3708a5a430..a82f7af0bab 100644 --- a/sormas-e2e-tests/customReports/data/results.txt +++ b/sormas-e2e-tests/customReports/data/results.txt @@ -7,3 +7,5 @@ Tasks page=8.724/ Persons page=11.526/ Contacts Dashboard page=6.935/ Immunizations page=17.396/ +Samples page=2.355/ +Contacts page=3.61/ diff --git a/sormas-e2e-tests/customReports/images/logo.png b/sormas-e2e-tests/customReports/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ecf0c4f573b63b39e749bed63f7afbae80296064 GIT binary patch literal 26298 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 literal 0 HcmV?d00001 diff --git a/sormas-e2e-tests/scripts/runTests.sh b/sormas-e2e-tests/scripts/runTests.sh index 526c706daf4..e3e7f3b15ab 100644 --- a/sormas-e2e-tests/scripts/runTests.sh +++ b/sormas-e2e-tests/scripts/runTests.sh @@ -25,7 +25,7 @@ rm -rf ./allureReports echo "Executing gradle clean..." ./gradlew clean goJF echo "Starting all BDD tests under @$1 tag..." -./gradlew startTests -Dcucumber.tags=\"@$1\" -Dheadless=true -Dcourgette.threads=9 -DenvConfig=C:/Users/Zack/Desktop/envData.json +./gradlew startTests -Dcucumber.tags=\"@$1\" -Dheadless=true -Dcourgette.threads=9 -DenvConfig= echo "Deleting test downloads folder..." rm -rf ./downloads diff --git a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java index 6292b986a61..ec1b76ebe27 100755 --- a/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java +++ b/sormas-e2e-tests/src/main/java/recorders/StepsLogger.java @@ -18,7 +18,6 @@ package recorders; -import com.google.common.base.Stopwatch; import io.qameta.allure.Allure; import io.qameta.allure.Attachment; import io.qameta.allure.listener.StepLifecycleListener; @@ -34,10 +33,9 @@ @Slf4j public class StepsLogger implements StepLifecycleListener { - private final Stopwatch stopwatch = Stopwatch.createUnstarted(); private static final String PROCESS_ID = String.valueOf(ManagementFactory.getRuntimeMXBean().getPid()); - public static final String PROCESS_ID_STRING = String.format("[PROCESS_ID:%s]", PROCESS_ID); + public static final String PROCESS_ID_STRING = String.format("[PROCESS_ID:%s] ->", PROCESS_ID); private static RemoteWebDriver driver; private static boolean isScreenshotEnabled = true; @@ -51,23 +49,19 @@ public static void setIsScreenshotEnabled(boolean isScreenshotEnabled) { @Override public void afterStepStart(final StepResult result) { - stopwatch.reset(); - stopwatch.start(); - log.info(PROCESS_ID_STRING + " Starting step: " + result.getName()); + log.info("{} -> Starting step -> {}", PROCESS_ID_STRING, result.getName()); } @Override public void afterStepUpdate(final StepResult result) { if (isScreenshotEnabled && driver != null) { takeScreenshotAfter(); - if (result.getStatus().value().equalsIgnoreCase("failed")) { + if (!result.getStatus().value().contains("pass")) { attachConsoleLog(); } } - stopwatch.stop(); isScreenshotEnabled = true; - log.info( - " {} Finishing step: " + result.getName() + " and took: " + stopwatch, PROCESS_ID_STRING); + log.info("{} -> Finished step -> {}", PROCESS_ID_STRING, result.getName()); } @Attachment(value = "After step screenshot", type = "image/png") @@ -85,7 +79,12 @@ public void takeScreenshotAfter() { @SneakyThrows @Attachment(value = "Browser console log", type = "text/json") private void attachConsoleLog() { - Allure.getLifecycle() - .addAttachment("Execution logs", "text/json", "txt", new FileInputStream("logs/file.log")); + try { + Allure.getLifecycle() + .addAttachment( + "Execution logs", "text/json", "txt", new FileInputStream("logs/file.log")); + } catch (Exception any) { + log.error("Failed to attach logs to Allure report due to: {}", any.getCause()); + } } } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java index d509476d92b..8f968fb7f9b 100755 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/AssertHelpers.java @@ -25,17 +25,13 @@ import java.time.Duration; import java.util.concurrent.TimeUnit; import lombok.SneakyThrows; -// import lombok.extern.slf4j.Slf4j; +import lombok.extern.slf4j.Slf4j; import org.awaitility.core.ConditionTimeoutException; import org.awaitility.core.ThrowingRunnable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -// @Slf4j +@Slf4j public class AssertHelpers { - private static final Logger log = LoggerFactory.getLogger(AssertHelpers.class); - @SneakyThrows public void assertWithPoll(ThrowingRunnable throwingRunnable, int seconds) { try { diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java index 1df9d576f83..9a68ad14a0a 100755 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/helpers/WebDriverHelpers.java @@ -28,7 +28,7 @@ import java.util.stream.Collectors; import javax.inject.Inject; import lombok.SneakyThrows; -// import lombok.extern.slf4j.Slf4j; +import lombok.extern.slf4j.Slf4j; import org.awaitility.core.ConditionTimeoutException; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; @@ -40,17 +40,13 @@ import org.openqa.selenium.WebDriverException; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.sormas.e2etests.common.TimerLite; import org.sormas.e2etests.steps.BaseSteps; import org.testng.Assert; -// @Slf4j +@Slf4j public class WebDriverHelpers { - private static final Logger log = LoggerFactory.getLogger(WebDriverHelpers.class); - public static final By SELECTED_RADIO_BUTTON = By.xpath("ancestor::div[contains(@role,'group')]//input[@checked]/following-sibling::label"); public static final By SELECTED_RADIO_DISABLED_AND_CHECKED_BUTTON = @@ -377,7 +373,7 @@ public void clickOnWebElementWhichMayNotBePresent(final By byObject, final int i baseSteps.getDriver().findElements(byObject).get(index).click(); } catch (Exception exception) { log.warn( - "Unable tp click on element: {}, at index {}, due to: {}", + "Unable to click on element: {}, at index {}, due to: {}", byObject, index, exception.getMessage()); @@ -400,18 +396,17 @@ public void scrollToElement(final Object selector) { } public void hoverToElement(By selector) { - WebElement menuOption = baseSteps.getDriver().findElement(selector); + WebElement element = baseSteps.getDriver().findElement(selector); Actions actions = new Actions(baseSteps.getDriver()); try { assertHelpers.assertWithPoll20Second( () -> { scrollToElement(selector); - actions.moveToElement(menuOption).perform(); + actions.moveToElement(element).perform(); waitUntilIdentifiedElementIsVisibleAndClickable(selector); }); } catch (ConditionTimeoutException ignored) { - log.error("Unable to fill on element identified by locator: {}", selector); - throw new TimeoutException("Unable to fill on element identified by locator: " + selector); + throw new TimeoutException("Unable to hover on element identified by locator: " + selector); } } @@ -584,8 +579,10 @@ public int getNumberOfElements(By byObject) { try { return baseSteps.getDriver().findElements(byObject).size(); } catch (Exception e) { - log.warn("Exception caught while getting the number of elements for locator: {}", byObject); - log.warn("Exception: {}", e.getMessage()); + log.warn( + "Exception caught while getting the number of elements for locator: {} : {}", + byObject, + e.getMessage()); throw new WebDriverException(String.format("No elements found for element: %s", byObject)); } } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java index 0bf917a7638..93724000569 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/BaseSteps.java @@ -30,19 +30,15 @@ import io.restassured.parsing.Parser; import java.time.Duration; import lombok.SneakyThrows; -// import lombok.extern.slf4j.Slf4j; +import lombok.extern.slf4j.Slf4j; import org.openqa.selenium.WebDriver; import org.openqa.selenium.remote.RemoteWebDriver; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.sormas.e2etests.webdriver.DriverManager; import recorders.StepsLogger; -// @Slf4j +@Slf4j public class BaseSteps implements StepLifecycleListener { - private static final Logger log = LoggerFactory.getLogger(BaseSteps.class); - public static RemoteWebDriver driver; public static String locale; private final DriverManager driverManager; @@ -63,16 +59,13 @@ public void setRunningLocale(Scenario scenario) { @Before(value = "@UI") public void beforeScenario(Scenario scenario) { - log.warn("Warn message check"); - log.error("Error message check"); if (isNonApiScenario(scenario)) { driver = driverManager.borrowRemoteWebDriver(scenario.getName()); StepsLogger.setRemoteWebDriver(driver); WebDriver.Options options = driver.manage(); options.timeouts().setScriptTimeout(Duration.ofMinutes(2)); options.timeouts().pageLoadTimeout(Duration.ofMinutes(2)); - log.info("Browser's resolution: " + driver.manage().window().getSize().toString()); - log.info("Starting test: " + scenario.getName()); + log.info("Starting test: {}", scenario.getName()); } } @@ -87,7 +80,7 @@ public void afterScenario(Scenario scenario) { if (isNonApiScenario(scenario)) { driverManager.releaseRemoteWebDriver(scenario.getName()); } - log.info("Finished test: " + scenario.getName()); + log.info("Finished test: {}", scenario.getName()); } @After(value = "@PublishCustomReport") diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java index bdf2d552189..eb6ce0e3a60 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/EditCaseSteps.java @@ -35,6 +35,7 @@ import java.util.concurrent.TimeUnit; import javax.inject.Inject; import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; import org.sormas.e2etests.entities.pojo.helpers.ComparisonHelper; import org.sormas.e2etests.entities.pojo.web.Case; import org.sormas.e2etests.entities.pojo.web.QuarantineOrder; @@ -48,6 +49,7 @@ import org.sormas.e2etests.state.ApiState; import org.testng.asserts.SoftAssert; +@Slf4j public class EditCaseSteps implements En { private final WebDriverHelpers webDriverHelpers; diff --git a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseClasification.feature b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseClasification.feature index 6309803dbbc..1e73d8a7fb4 100644 --- a/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseClasification.feature +++ b/sormas-e2e-tests/src/test/resources/features/sanity/web/CaseClasification.feature @@ -1,7 +1,7 @@ @UI @Sanity @Case @Classification Feature: Case Classification functionality - @env_main @mock @ignore + @env_main @ignore Scenario: Case Classification change from Not Yet Classified to Suspect Case by confirming Sore Throat Given API: I create a new person Then API: I check that POST call body is "OK" From 399debc1a02ba64a072ef6723cc31f9bd2711f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9=20Strysewske?= Date: Thu, 3 Mar 2022 12:43:15 +0100 Subject: [PATCH 248/253] [GITFLOW]Updating development poms to hotfix version to avoid merge conflicts --- sormas-api/pom.xml | 2 +- sormas-app/pom.xml | 2 +- sormas-backend/pom.xml | 2 +- sormas-base/dependencies/serverlibs.pom | 2 +- sormas-base/pom.xml | 2 +- sormas-cargoserver/pom.xml | 2 +- sormas-ear/pom.xml | 2 +- sormas-keycloak-service-provider/pom.xml | 2 +- sormas-rest/pom.xml | 2 +- sormas-ui/pom.xml | 2 +- sormas-widgetset/pom.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sormas-api/pom.xml b/sormas-api/pom.xml index 214eb0b788e..dcb992e831d 100644 --- a/sormas-api/pom.xml +++ b/sormas-api/pom.xml @@ -2,7 +2,7 @@ de.symeda.sormas sormas-base - 1.69.0-SNAPSHOT + 1.68.3 ../sormas-base 4.0.0 diff --git a/sormas-app/pom.xml b/sormas-app/pom.xml index 3bb68392128..d16764e2bca 100644 --- a/sormas-app/pom.xml +++ b/sormas-app/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.3 ../sormas-base 4.0.0 diff --git a/sormas-backend/pom.xml b/sormas-backend/pom.xml index 48b45586014..e4836feb0a3 100644 --- a/sormas-backend/pom.xml +++ b/sormas-backend/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.3 ../sormas-base 4.0.0 diff --git a/sormas-base/dependencies/serverlibs.pom b/sormas-base/dependencies/serverlibs.pom index effd624397b..363c039774d 100644 --- a/sormas-base/dependencies/serverlibs.pom +++ b/sormas-base/dependencies/serverlibs.pom @@ -8,7 +8,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.3 ../ diff --git a/sormas-base/pom.xml b/sormas-base/pom.xml index f5dd10b65f7..7c867e673b7 100644 --- a/sormas-base/pom.xml +++ b/sormas-base/pom.xml @@ -5,7 +5,7 @@ de.symeda.sormas sormas-base pom - 1.69.0-SNAPSHOT + 1.68.3 1.8 diff --git a/sormas-cargoserver/pom.xml b/sormas-cargoserver/pom.xml index 8c6009ec75f..3d6a601411d 100644 --- a/sormas-cargoserver/pom.xml +++ b/sormas-cargoserver/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.69.0-SNAPSHOT + 1.68.3 ../sormas-base diff --git a/sormas-ear/pom.xml b/sormas-ear/pom.xml index eb67f26b2b0..5ac6bd389ac 100644 --- a/sormas-ear/pom.xml +++ b/sormas-ear/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.69.0-SNAPSHOT + 1.68.3 ../sormas-base diff --git a/sormas-keycloak-service-provider/pom.xml b/sormas-keycloak-service-provider/pom.xml index 142c2f5858e..dd3aea6ceab 100644 --- a/sormas-keycloak-service-provider/pom.xml +++ b/sormas-keycloak-service-provider/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.3 ../sormas-base 4.0.0 diff --git a/sormas-rest/pom.xml b/sormas-rest/pom.xml index 85e9fe6b41d..e4d50686bc8 100644 --- a/sormas-rest/pom.xml +++ b/sormas-rest/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.69.0-SNAPSHOT + 1.68.3 ../sormas-base diff --git a/sormas-ui/pom.xml b/sormas-ui/pom.xml index 8b3382d103a..6798410d527 100644 --- a/sormas-ui/pom.xml +++ b/sormas-ui/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.3 ../sormas-base 4.0.0 diff --git a/sormas-widgetset/pom.xml b/sormas-widgetset/pom.xml index f8d6a25f29d..23f815f55b1 100644 --- a/sormas-widgetset/pom.xml +++ b/sormas-widgetset/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.68.3 ../sormas-base 4.0.0 From a80a780d20165fd029b5089ba5d438c3256ec302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9=20Strysewske?= Date: Thu, 3 Mar 2022 12:46:13 +0100 Subject: [PATCH 249/253] [GITFLOW]update develop poms back to pre merge state --- sormas-api/pom.xml | 2 +- sormas-app/pom.xml | 2 +- sormas-backend/pom.xml | 2 +- sormas-base/dependencies/serverlibs.pom | 2 +- sormas-base/pom.xml | 2 +- sormas-cargoserver/pom.xml | 2 +- sormas-ear/pom.xml | 2 +- sormas-keycloak-service-provider/pom.xml | 2 +- sormas-rest/pom.xml | 2 +- sormas-ui/pom.xml | 2 +- sormas-widgetset/pom.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sormas-api/pom.xml b/sormas-api/pom.xml index dcb992e831d..214eb0b788e 100644 --- a/sormas-api/pom.xml +++ b/sormas-api/pom.xml @@ -2,7 +2,7 @@ de.symeda.sormas sormas-base - 1.68.3 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-app/pom.xml b/sormas-app/pom.xml index d16764e2bca..3bb68392128 100644 --- a/sormas-app/pom.xml +++ b/sormas-app/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.3 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-backend/pom.xml b/sormas-backend/pom.xml index e4836feb0a3..48b45586014 100644 --- a/sormas-backend/pom.xml +++ b/sormas-backend/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.3 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-base/dependencies/serverlibs.pom b/sormas-base/dependencies/serverlibs.pom index 363c039774d..effd624397b 100644 --- a/sormas-base/dependencies/serverlibs.pom +++ b/sormas-base/dependencies/serverlibs.pom @@ -8,7 +8,7 @@ sormas-base de.symeda.sormas - 1.68.3 + 1.69.0-SNAPSHOT ../ diff --git a/sormas-base/pom.xml b/sormas-base/pom.xml index 7c867e673b7..f5dd10b65f7 100644 --- a/sormas-base/pom.xml +++ b/sormas-base/pom.xml @@ -5,7 +5,7 @@ de.symeda.sormas sormas-base pom - 1.68.3 + 1.69.0-SNAPSHOT 1.8 diff --git a/sormas-cargoserver/pom.xml b/sormas-cargoserver/pom.xml index 3d6a601411d..8c6009ec75f 100644 --- a/sormas-cargoserver/pom.xml +++ b/sormas-cargoserver/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.68.3 + 1.69.0-SNAPSHOT ../sormas-base diff --git a/sormas-ear/pom.xml b/sormas-ear/pom.xml index 5ac6bd389ac..eb67f26b2b0 100644 --- a/sormas-ear/pom.xml +++ b/sormas-ear/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.68.3 + 1.69.0-SNAPSHOT ../sormas-base diff --git a/sormas-keycloak-service-provider/pom.xml b/sormas-keycloak-service-provider/pom.xml index dd3aea6ceab..142c2f5858e 100644 --- a/sormas-keycloak-service-provider/pom.xml +++ b/sormas-keycloak-service-provider/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.3 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-rest/pom.xml b/sormas-rest/pom.xml index e4d50686bc8..85e9fe6b41d 100644 --- a/sormas-rest/pom.xml +++ b/sormas-rest/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.68.3 + 1.69.0-SNAPSHOT ../sormas-base diff --git a/sormas-ui/pom.xml b/sormas-ui/pom.xml index 6798410d527..8b3382d103a 100644 --- a/sormas-ui/pom.xml +++ b/sormas-ui/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.3 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-widgetset/pom.xml b/sormas-widgetset/pom.xml index 23f815f55b1..f8d6a25f29d 100644 --- a/sormas-widgetset/pom.xml +++ b/sormas-widgetset/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.68.3 + 1.69.0-SNAPSHOT ../sormas-base 4.0.0 From 75eda6b87351f5d6bac776bf3e50eafdb150b8c7 Mon Sep 17 00:00:00 2001 From: Levente Gal <62599627+leventegal-she@users.noreply.github.com> Date: Thu, 3 Mar 2022 15:35:19 +0200 Subject: [PATCH 250/253] #8065 UI validation for create new sample in lab message processing does not correctly update to valid (#8166) Co-authored-by: Levente Gal --- .../sormas/ui/samples/AbstractSampleForm.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/AbstractSampleForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/AbstractSampleForm.java index ad8c632337a..adceaadc048 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/AbstractSampleForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/AbstractSampleForm.java @@ -3,7 +3,6 @@ import static de.symeda.sormas.ui.utils.CssStyles.HSPACE_RIGHT_4; import static de.symeda.sormas.ui.utils.CssStyles.VSPACE_3; import static de.symeda.sormas.ui.utils.CssStyles.VSPACE_4; -import static de.symeda.sormas.ui.utils.CssStyles.VSPACE_NONE; import static de.symeda.sormas.ui.utils.CssStyles.VSPACE_TOP_3; import static de.symeda.sormas.ui.utils.LayoutUtil.fluidRowLocs; import static de.symeda.sormas.ui.utils.LayoutUtil.loc; @@ -11,12 +10,13 @@ import java.util.Arrays; import java.util.Collections; +import java.util.Date; +import java.util.List; -import com.vaadin.ui.Button; import com.vaadin.ui.CssLayout; import com.vaadin.ui.Label; -import com.vaadin.ui.themes.ValoTheme; import com.vaadin.v7.data.Property; +import com.vaadin.v7.ui.AbstractField; import com.vaadin.v7.ui.CheckBox; import com.vaadin.v7.ui.ComboBox; import com.vaadin.v7.ui.DateField; @@ -30,7 +30,6 @@ import de.symeda.sormas.api.caze.CaseReferenceDto; import de.symeda.sormas.api.contact.ContactReferenceDto; import de.symeda.sormas.api.feature.FeatureType; -import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.Descriptions; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Strings; @@ -43,17 +42,14 @@ import de.symeda.sormas.api.sample.SampleDto; import de.symeda.sormas.api.sample.SampleMaterial; import de.symeda.sormas.api.sample.SamplePurpose; -import de.symeda.sormas.api.sample.SampleReferenceDto; import de.symeda.sormas.api.sample.SamplingReason; import de.symeda.sormas.api.sample.SpecimenCondition; import de.symeda.sormas.api.user.UserReferenceDto; import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers; import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers; -import de.symeda.sormas.ui.ControllerProvider; import de.symeda.sormas.ui.UserProvider; import de.symeda.sormas.ui.utils.AbstractEditForm; -import de.symeda.sormas.ui.utils.ButtonHelper; import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.DateComparisonValidator; import de.symeda.sormas.ui.utils.DateFormatHelper; @@ -305,6 +301,13 @@ protected void addValidators() { false, false, I18nProperties.getValidationError(Validations.afterDate, receivedDate.getCaption(), shipmentDate.getCaption()))); + + List> validatedFields = Arrays.asList(sampleDateField, shipmentDate, receivedDate); + validatedFields.forEach(field -> field.addValueChangeListener(r -> { + validatedFields.forEach(otherField -> { + otherField.setValidationVisible(!otherField.isValid()); + }); + })); } protected void setVisibilities() { From 11441f07838f9b797ad5137d083169385805035a Mon Sep 17 00:00:00 2001 From: Frank Hautpmann Date: Thu, 3 Mar 2022 19:51:53 +0100 Subject: [PATCH 251/253] New Crowdin updates (#8175) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * New translations strings.properties (Dari) * New translations strings.properties (Spanish, Cuba) * New translations strings.properties (Croatian) * New translations strings.properties (English, Afghanistan) * New translations strings.properties (English, Nigeria) * New translations strings.properties (English, Ghana) * New translations captions.properties (Czech) * New translations validations.properties (Czech) * New translations enum.properties (Czech) * New translations enum.properties (Urdu (Pakistan)) * New translations strings.properties (Hindi) * New translations strings.properties (Spanish, Ecuador) * New translations strings.properties (German) * New translations strings.properties (Japanese) * New translations enum.properties (French) * New translations enum.properties (German) * New translations strings.properties (Romanian) * New translations strings.properties (Spanish) * New translations strings.properties (Czech) * New translations strings.properties (Finnish) * New translations strings.properties (Italian) * New translations strings.properties (Dutch) * New translations strings.properties (Urdu (Pakistan)) * New translations strings.properties (Norwegian) * New translations strings.properties (Polish) * New translations strings.properties (Portuguese) * New translations strings.properties (Russian) * New translations strings.properties (Swedish) * New translations strings.properties (Turkish) * New translations strings.properties (Ukrainian) * New translations strings.properties (Chinese Simplified) * New translations enum.properties (German, Switzerland) * New translations strings.properties (French) * New translations enum.properties (Spanish) * New translations strings.properties (Italian, Switzerland) * New translations strings.properties (Dari) * New translations strings.properties (Pashto) * New translations strings.properties (Spanish, Cuba) * New translations strings.properties (English, Afghanistan) * New translations strings.properties (English, Nigeria) * New translations strings.properties (English, Ghana) * New translations captions.properties (German) * New translations enum.properties (Romanian) * New translations enum.properties (Czech) * New translations strings.properties (German, Switzerland) * New translations enum.properties (Finnish) * New translations enum.properties (Italian) * New translations enum.properties (Japanese) * New translations enum.properties (Dutch) * New translations enum.properties (Norwegian) * New translations enum.properties (Polish) * New translations enum.properties (Portuguese) * New translations enum.properties (Russian) * New translations enum.properties (Swedish) * New translations enum.properties (Turkish) * New translations strings.properties (French, Switzerland) * New translations strings.properties (Swahili) * New translations strings.properties (German) * New translations strings.properties (Polish) * New translations enum.properties (French) * New translations enum.properties (German) * New translations strings.properties (Romanian) * New translations strings.properties (Spanish) * New translations strings.properties (Czech) * New translations strings.properties (Finnish) * New translations strings.properties (Italian) * New translations strings.properties (Japanese) * New translations strings.properties (Dutch) * New translations strings.properties (Norwegian) * New translations strings.properties (Portuguese) * New translations strings.properties (Fijian) * New translations strings.properties (Russian) * New translations strings.properties (Swedish) * New translations strings.properties (Turkish) * New translations strings.properties (Ukrainian) * New translations strings.properties (Chinese Simplified) * New translations strings.properties (Urdu (Pakistan)) * New translations strings.properties (Spanish, Ecuador) * New translations strings.properties (Croatian) * New translations strings.properties (Hindi) * New translations strings.properties (Filipino) * New translations enum.properties (Ukrainian) * New translations enum.properties (Chinese Simplified) * New translations enum.properties (French, Switzerland) * New translations enum.properties (English, Nigeria) * New translations enum.properties (English, Afghanistan) * New translations enum.properties (Spanish, Cuba) * New translations enum.properties (Pashto) * New translations enum.properties (Dari) * New translations enum.properties (Italian, Switzerland) * New translations enum.properties (German, Switzerland) * New translations enum.properties (Urdu (Pakistan)) * New translations enum.properties (Swahili) * New translations enum.properties (Fijian) * New translations enum.properties (Filipino) * New translations enum.properties (Hindi) * New translations enum.properties (Croatian) * New translations enum.properties (Spanish, Ecuador) * New translations enum.properties (English, Ghana) * New translations captions.properties (Urdu (Pakistan)) * New translations captions.properties (Spanish) * New translations strings.properties (Dari) * New translations strings.properties (Pashto) * New translations strings.properties (Spanish, Cuba) * New translations strings.properties (English, Afghanistan) * New translations strings.properties (English, Nigeria) * New translations strings.properties (English, Ghana) * New translations captions.properties (German) * New translations captions.properties (Romanian) * New translations captions.properties (French) * New translations captions.properties (Czech) * New translations strings.properties (French, Switzerland) * New translations captions.properties (Finnish) * New translations captions.properties (Italian) * New translations captions.properties (Japanese) * New translations captions.properties (Dutch) * New translations captions.properties (Norwegian) * New translations captions.properties (Polish) * New translations captions.properties (Portuguese) * New translations captions.properties (Russian) * New translations captions.properties (Swedish) * New translations captions.properties (Turkish) * New translations strings.properties (Italian, Switzerland) * New translations strings.properties (German, Switzerland) * New translations strings.properties (French) * New translations strings.properties (Portuguese) * New translations strings.properties (German) * New translations strings.properties (Romanian) * New translations strings.properties (Spanish) * New translations strings.properties (Czech) * New translations strings.properties (Finnish) * New translations strings.properties (Italian) * New translations strings.properties (Japanese) * New translations strings.properties (Dutch) * New translations strings.properties (Norwegian) * New translations strings.properties (Polish) * New translations strings.properties (Russian) * New translations strings.properties (Swahili) * New translations strings.properties (Swedish) * New translations strings.properties (Turkish) * New translations strings.properties (Ukrainian) * New translations strings.properties (Chinese Simplified) * New translations strings.properties (Urdu (Pakistan)) * New translations strings.properties (Spanish, Ecuador) * New translations strings.properties (Croatian) * New translations strings.properties (Hindi) * New translations strings.properties (Filipino) * New translations strings.properties (Fijian) * New translations captions.properties (Ukrainian) * New translations captions.properties (Chinese Simplified) * New translations captions.properties (Italian, Switzerland) * New translations captions.properties (English, Ghana) * New translations captions.properties (English, Nigeria) * New translations captions.properties (English, Afghanistan) * New translations captions.properties (Spanish, Cuba) * New translations captions.properties (Pashto) * New translations captions.properties (Dari) * New translations captions.properties (French, Switzerland) * New translations captions.properties (Spanish, Ecuador) * New translations captions.properties (German, Switzerland) * New translations captions.properties (Swahili) * New translations captions.properties (Fijian) * New translations captions.properties (Filipino) * New translations captions.properties (Hindi) * New translations captions.properties (Croatian) * New translations enum.properties (Czech) * New translations strings.properties (German) * New translations strings.properties (Urdu (Pakistan)) * New translations strings.properties (Spanish, Cuba) * New translations captions.properties (German) * New translations captions.properties (Spanish, Cuba) * New translations strings.properties (German, Switzerland) * New translations strings.properties (French) * New translations strings.properties (Spanish, Ecuador) * New translations strings.properties (English, Ghana) * New translations strings.properties (English, Nigeria) * New translations strings.properties (English, Afghanistan) * New translations strings.properties (Spanish, Cuba) * New translations strings.properties (Pashto) * New translations strings.properties (Dari) * New translations strings.properties (Italian, Switzerland) * New translations strings.properties (French, Switzerland) * New translations strings.properties (German, Switzerland) * New translations strings.properties (Swahili) * New translations strings.properties (Fijian) * New translations strings.properties (Filipino) * New translations strings.properties (Hindi) * New translations strings.properties (Croatian) * New translations strings.properties (Urdu (Pakistan)) * New translations strings.properties (German) * New translations strings.properties (Dutch) * New translations strings.properties (Romanian) * New translations strings.properties (Spanish) * New translations strings.properties (Czech) * New translations strings.properties (Finnish) * New translations strings.properties (Italian) * New translations strings.properties (Japanese) * New translations strings.properties (Norwegian) * New translations strings.properties (Chinese Simplified) * New translations strings.properties (Polish) * New translations strings.properties (Portuguese) * New translations strings.properties (Russian) * New translations strings.properties (Swedish) * New translations strings.properties (Turkish) * New translations strings.properties (Ukrainian) * New translations captions.properties (German, Switzerland) * New translations strings.properties (German) * New translations strings.properties (German, Switzerland) * New translations strings.properties (Spanish, Cuba) * New translations enum.properties (French) * New translations enum.properties (Urdu (Pakistan)) * New translations enum.properties (English, Nigeria) * New translations enum.properties (English, Afghanistan) * New translations enum.properties (Spanish, Cuba) * New translations enum.properties (Pashto) * New translations enum.properties (Dari) * New translations enum.properties (Italian, Switzerland) * New translations enum.properties (French, Switzerland) * New translations enum.properties (German, Switzerland) * New translations enum.properties (Swahili) * New translations enum.properties (Fijian) * New translations enum.properties (Filipino) * New translations enum.properties (Hindi) * New translations enum.properties (Croatian) * New translations enum.properties (Spanish, Ecuador) * New translations enum.properties (Chinese Simplified) * New translations enum.properties (German) * New translations enum.properties (Ukrainian) * New translations enum.properties (Turkish) * New translations enum.properties (Swedish) * New translations enum.properties (Russian) * New translations enum.properties (Portuguese) * New translations enum.properties (Polish) * New translations enum.properties (Norwegian) * New translations enum.properties (Dutch) * New translations enum.properties (Japanese) * New translations enum.properties (Italian) * New translations enum.properties (Finnish) * New translations enum.properties (Czech) * New translations enum.properties (Spanish) * New translations enum.properties (Romanian) * New translations enum.properties (English, Ghana) * New translations enum.properties (French) * New translations enum.properties (German) * New translations strings.properties (Czech) * New translations enum.properties (German, Switzerland) * New translations enum.properties (Spanish, Cuba) Co-authored-by: Maté Strysewske --- sormas-api/src/main/resources/enum_cs-CZ.properties | 1 + sormas-api/src/main/resources/enum_de-CH.properties | 1 + sormas-api/src/main/resources/enum_de-DE.properties | 1 + sormas-api/src/main/resources/enum_en-AF.properties | 1 + sormas-api/src/main/resources/enum_en-GH.properties | 1 + sormas-api/src/main/resources/enum_en-NG.properties | 1 + sormas-api/src/main/resources/enum_es-CU.properties | 1 + sormas-api/src/main/resources/enum_es-EC.properties | 1 + sormas-api/src/main/resources/enum_es-ES.properties | 1 + sormas-api/src/main/resources/enum_fa-AF.properties | 1 + sormas-api/src/main/resources/enum_fi-FI.properties | 1 + sormas-api/src/main/resources/enum_fil-PH.properties | 1 + sormas-api/src/main/resources/enum_fj-FJ.properties | 1 + sormas-api/src/main/resources/enum_fr-CH.properties | 1 + sormas-api/src/main/resources/enum_fr-FR.properties | 1 + sormas-api/src/main/resources/enum_hi-IN.properties | 1 + sormas-api/src/main/resources/enum_hr-HR.properties | 1 + sormas-api/src/main/resources/enum_it-CH.properties | 1 + sormas-api/src/main/resources/enum_it-IT.properties | 1 + sormas-api/src/main/resources/enum_ja-JP.properties | 1 + sormas-api/src/main/resources/enum_nl-NL.properties | 1 + sormas-api/src/main/resources/enum_no-NO.properties | 1 + sormas-api/src/main/resources/enum_pl-PL.properties | 1 + sormas-api/src/main/resources/enum_ps-AF.properties | 1 + sormas-api/src/main/resources/enum_pt-PT.properties | 1 + sormas-api/src/main/resources/enum_ro-RO.properties | 1 + sormas-api/src/main/resources/enum_ru-RU.properties | 1 + sormas-api/src/main/resources/enum_sv-SE.properties | 1 + sormas-api/src/main/resources/enum_sw-KE.properties | 1 + sormas-api/src/main/resources/enum_tr-TR.properties | 1 + sormas-api/src/main/resources/enum_uk-UA.properties | 1 + sormas-api/src/main/resources/enum_ur-PK.properties | 1 + sormas-api/src/main/resources/enum_zh-CN.properties | 1 + .../src/main/resources/strings_cs-CZ.properties | 12 ++++++------ .../src/main/resources/strings_de-CH.properties | 2 +- .../src/main/resources/strings_de-DE.properties | 5 ++--- .../src/main/resources/strings_es-CU.properties | 2 +- 37 files changed, 43 insertions(+), 11 deletions(-) diff --git a/sormas-api/src/main/resources/enum_cs-CZ.properties b/sormas-api/src/main/resources/enum_cs-CZ.properties index 592028621d7..e0721701bf6 100644 --- a/sormas-api/src/main/resources/enum_cs-CZ.properties +++ b/sormas-api/src/main/resources/enum_cs-CZ.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Exportovat data o ochraně údajů UserRight.OUTBREAK_VIEW = Zobrazit ohniska +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Vyšetřování případů diff --git a/sormas-api/src/main/resources/enum_de-CH.properties b/sormas-api/src/main/resources/enum_de-CH.properties index a934850f52f..d61d953e4bb 100644 --- a/sormas-api/src/main/resources/enum_de-CH.properties +++ b/sormas-api/src/main/resources/enum_de-CH.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Einreisen aus dem System löschen UserRight.TRAVEL_ENTRY_ARCHIVE = Einreisen archivieren UserRight.EXPORT_DATA_PROTECTION_DATA = Datenschutz-Daten exportieren UserRight.OUTBREAK_VIEW = Ausbrüche anzeigen +UserRight.OUTBREAK_EDIT = Ausbrüche bearbeiten # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Falluntersuchung diff --git a/sormas-api/src/main/resources/enum_de-DE.properties b/sormas-api/src/main/resources/enum_de-DE.properties index dc0cf6df524..3b34f303a40 100644 --- a/sormas-api/src/main/resources/enum_de-DE.properties +++ b/sormas-api/src/main/resources/enum_de-DE.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Einreisen aus dem System löschen UserRight.TRAVEL_ENTRY_ARCHIVE = Einreisen archivieren UserRight.EXPORT_DATA_PROTECTION_DATA = Datenschutz-Daten exportieren UserRight.OUTBREAK_VIEW = Ausbrüche anzeigen +UserRight.OUTBREAK_EDIT = Ausbrüche bearbeiten # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Falluntersuchung diff --git a/sormas-api/src/main/resources/enum_en-AF.properties b/sormas-api/src/main/resources/enum_en-AF.properties index 465fb992a04..3cf3369198b 100644 --- a/sormas-api/src/main/resources/enum_en-AF.properties +++ b/sormas-api/src/main/resources/enum_en-AF.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_en-GH.properties b/sormas-api/src/main/resources/enum_en-GH.properties index 0352fead6fc..e9dbe4aa797 100644 --- a/sormas-api/src/main/resources/enum_en-GH.properties +++ b/sormas-api/src/main/resources/enum_en-GH.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_en-NG.properties b/sormas-api/src/main/resources/enum_en-NG.properties index 96b852ad890..720d6d35b0c 100644 --- a/sormas-api/src/main/resources/enum_en-NG.properties +++ b/sormas-api/src/main/resources/enum_en-NG.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_es-CU.properties b/sormas-api/src/main/resources/enum_es-CU.properties index e1d3dc4053f..6a0a5540958 100644 --- a/sormas-api/src/main/resources/enum_es-CU.properties +++ b/sormas-api/src/main/resources/enum_es-CU.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Eliminar entradas de viaje del sistema UserRight.TRAVEL_ENTRY_ARCHIVE = Archivar entradas de viaje UserRight.EXPORT_DATA_PROTECTION_DATA = Exportar datos de protección de datos UserRight.OUTBREAK_VIEW = Ver brotes +UserRight.OUTBREAK_EDIT = Editar brotes # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Investigación de caso diff --git a/sormas-api/src/main/resources/enum_es-EC.properties b/sormas-api/src/main/resources/enum_es-EC.properties index 4e4f0b60b82..6649e09cf32 100644 --- a/sormas-api/src/main/resources/enum_es-EC.properties +++ b/sormas-api/src/main/resources/enum_es-EC.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Investigación de caso diff --git a/sormas-api/src/main/resources/enum_es-ES.properties b/sormas-api/src/main/resources/enum_es-ES.properties index 96b852ad890..720d6d35b0c 100644 --- a/sormas-api/src/main/resources/enum_es-ES.properties +++ b/sormas-api/src/main/resources/enum_es-ES.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_fa-AF.properties b/sormas-api/src/main/resources/enum_fa-AF.properties index 4c963925628..9859fef0367 100644 --- a/sormas-api/src/main/resources/enum_fa-AF.properties +++ b/sormas-api/src/main/resources/enum_fa-AF.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_fi-FI.properties b/sormas-api/src/main/resources/enum_fi-FI.properties index 04b553858d5..a1923a2312c 100644 --- a/sormas-api/src/main/resources/enum_fi-FI.properties +++ b/sormas-api/src/main/resources/enum_fi-FI.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Potilaan selvittely diff --git a/sormas-api/src/main/resources/enum_fil-PH.properties b/sormas-api/src/main/resources/enum_fil-PH.properties index 96b852ad890..720d6d35b0c 100644 --- a/sormas-api/src/main/resources/enum_fil-PH.properties +++ b/sormas-api/src/main/resources/enum_fil-PH.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_fj-FJ.properties b/sormas-api/src/main/resources/enum_fj-FJ.properties index 96b852ad890..720d6d35b0c 100644 --- a/sormas-api/src/main/resources/enum_fj-FJ.properties +++ b/sormas-api/src/main/resources/enum_fj-FJ.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_fr-CH.properties b/sormas-api/src/main/resources/enum_fr-CH.properties index 45a2fa06bc8..df2d8fdefbf 100644 --- a/sormas-api/src/main/resources/enum_fr-CH.properties +++ b/sormas-api/src/main/resources/enum_fr-CH.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Enquête de cas diff --git a/sormas-api/src/main/resources/enum_fr-FR.properties b/sormas-api/src/main/resources/enum_fr-FR.properties index 18ffd099ece..48952124932 100644 --- a/sormas-api/src/main/resources/enum_fr-FR.properties +++ b/sormas-api/src/main/resources/enum_fr-FR.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Exporter les données de protection des données UserRight.OUTBREAK_VIEW = Voir les éclosions +UserRight.OUTBREAK_EDIT = Modifier les éclosions # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Enquête de cas diff --git a/sormas-api/src/main/resources/enum_hi-IN.properties b/sormas-api/src/main/resources/enum_hi-IN.properties index 96b852ad890..720d6d35b0c 100644 --- a/sormas-api/src/main/resources/enum_hi-IN.properties +++ b/sormas-api/src/main/resources/enum_hi-IN.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_hr-HR.properties b/sormas-api/src/main/resources/enum_hr-HR.properties index 96b852ad890..720d6d35b0c 100644 --- a/sormas-api/src/main/resources/enum_hr-HR.properties +++ b/sormas-api/src/main/resources/enum_hr-HR.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_it-CH.properties b/sormas-api/src/main/resources/enum_it-CH.properties index 60747efd0bd..71cac6f073d 100644 --- a/sormas-api/src/main/resources/enum_it-CH.properties +++ b/sormas-api/src/main/resources/enum_it-CH.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Indagine sul caso diff --git a/sormas-api/src/main/resources/enum_it-IT.properties b/sormas-api/src/main/resources/enum_it-IT.properties index 95c049d8b9d..129a1d25bff 100644 --- a/sormas-api/src/main/resources/enum_it-IT.properties +++ b/sormas-api/src/main/resources/enum_it-IT.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Indagine sul caso diff --git a/sormas-api/src/main/resources/enum_ja-JP.properties b/sormas-api/src/main/resources/enum_ja-JP.properties index 96b852ad890..720d6d35b0c 100644 --- a/sormas-api/src/main/resources/enum_ja-JP.properties +++ b/sormas-api/src/main/resources/enum_ja-JP.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_nl-NL.properties b/sormas-api/src/main/resources/enum_nl-NL.properties index 96b852ad890..720d6d35b0c 100644 --- a/sormas-api/src/main/resources/enum_nl-NL.properties +++ b/sormas-api/src/main/resources/enum_nl-NL.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_no-NO.properties b/sormas-api/src/main/resources/enum_no-NO.properties index 96b852ad890..720d6d35b0c 100644 --- a/sormas-api/src/main/resources/enum_no-NO.properties +++ b/sormas-api/src/main/resources/enum_no-NO.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_pl-PL.properties b/sormas-api/src/main/resources/enum_pl-PL.properties index 96b852ad890..720d6d35b0c 100644 --- a/sormas-api/src/main/resources/enum_pl-PL.properties +++ b/sormas-api/src/main/resources/enum_pl-PL.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_ps-AF.properties b/sormas-api/src/main/resources/enum_ps-AF.properties index 4c963925628..9859fef0367 100644 --- a/sormas-api/src/main/resources/enum_ps-AF.properties +++ b/sormas-api/src/main/resources/enum_ps-AF.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_pt-PT.properties b/sormas-api/src/main/resources/enum_pt-PT.properties index 96b852ad890..720d6d35b0c 100644 --- a/sormas-api/src/main/resources/enum_pt-PT.properties +++ b/sormas-api/src/main/resources/enum_pt-PT.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_ro-RO.properties b/sormas-api/src/main/resources/enum_ro-RO.properties index 96b852ad890..720d6d35b0c 100644 --- a/sormas-api/src/main/resources/enum_ro-RO.properties +++ b/sormas-api/src/main/resources/enum_ro-RO.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_ru-RU.properties b/sormas-api/src/main/resources/enum_ru-RU.properties index 7b85a5bdf0e..875c78f72ba 100644 --- a/sormas-api/src/main/resources/enum_ru-RU.properties +++ b/sormas-api/src/main/resources/enum_ru-RU.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_sv-SE.properties b/sormas-api/src/main/resources/enum_sv-SE.properties index 96b852ad890..720d6d35b0c 100644 --- a/sormas-api/src/main/resources/enum_sv-SE.properties +++ b/sormas-api/src/main/resources/enum_sv-SE.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_sw-KE.properties b/sormas-api/src/main/resources/enum_sw-KE.properties index 96b852ad890..720d6d35b0c 100644 --- a/sormas-api/src/main/resources/enum_sw-KE.properties +++ b/sormas-api/src/main/resources/enum_sw-KE.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_tr-TR.properties b/sormas-api/src/main/resources/enum_tr-TR.properties index 96b852ad890..720d6d35b0c 100644 --- a/sormas-api/src/main/resources/enum_tr-TR.properties +++ b/sormas-api/src/main/resources/enum_tr-TR.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_uk-UA.properties b/sormas-api/src/main/resources/enum_uk-UA.properties index 96b852ad890..720d6d35b0c 100644 --- a/sormas-api/src/main/resources/enum_uk-UA.properties +++ b/sormas-api/src/main/resources/enum_uk-UA.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/enum_ur-PK.properties b/sormas-api/src/main/resources/enum_ur-PK.properties index 37c23d3146b..0dd4dfa5a51 100644 --- a/sormas-api/src/main/resources/enum_ur-PK.properties +++ b/sormas-api/src/main/resources/enum_ur-PK.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = سسٹم سے سفری اندراجات کو م UserRight.TRAVEL_ENTRY_ARCHIVE = آرکائیو سفری اندراجات UserRight.EXPORT_DATA_PROTECTION_DATA = ڈیٹا پروٹیکشن ڈیٹا ایکسپورٹ کریں UserRight.OUTBREAK_VIEW = پھیلاؤ دیکھیں +UserRight.OUTBREAK_EDIT = پھیلاو میں ترمیم کریں # UserRightGroup UserRightGroup.CASE_INVESTIGATION = کیس کی تفتیش diff --git a/sormas-api/src/main/resources/enum_zh-CN.properties b/sormas-api/src/main/resources/enum_zh-CN.properties index a2d5881713f..0ff0cee3d1e 100644 --- a/sormas-api/src/main/resources/enum_zh-CN.properties +++ b/sormas-api/src/main/resources/enum_zh-CN.properties @@ -1415,6 +1415,7 @@ UserRight.TRAVEL_ENTRY_DELETE = Delete travel entries from the system UserRight.TRAVEL_ENTRY_ARCHIVE = Archive travel entries UserRight.EXPORT_DATA_PROTECTION_DATA = Export data protection data UserRight.OUTBREAK_VIEW = View outbreaks +UserRight.OUTBREAK_EDIT = Edit outbreaks # UserRightGroup UserRightGroup.CASE_INVESTIGATION = Case Investigation diff --git a/sormas-api/src/main/resources/strings_cs-CZ.properties b/sormas-api/src/main/resources/strings_cs-CZ.properties index f6da3ca4821..466ce65c8e3 100644 --- a/sormas-api/src/main/resources/strings_cs-CZ.properties +++ b/sormas-api/src/main/resources/strings_cs-CZ.properties @@ -938,8 +938,8 @@ messageConvertEventParticipantToCase=Právě jste si uložili pozitivní laborat messageConvertEventParticipantToCaseDifferentDiseases=Právě jste si uložili pozitivní laboratorní výsledek na jiné onemocnění, než je onemocnění v případě události. Chcete vytvořit případ s touto nemocí pro osobu účastníka události? Případ nebude spojen s účastníkem události. messageConvertEventParticipantToCaseNoDisease=Právě jste si uložili pozitivní laboratorní výsledek pro událost bez onemocnění. Chcete vytvořit případ s touto nemocí pro osobu účastníka události? Konečný laboratorní výsledek vzorku bude automaticky nastaven jako pozitivní, ale případ nebude spojen s účastníkem události. messageContactCreated=Nový kontakt byl vytvořen -messageContactArchived = Contact has been archived -messageContactDearchived = Contact has been de-archived +messageContactArchived = Kontakt byl archivován +messageContactDearchived = Kontakt byl dearchivován messageContactSaved = Data kontaktu uložena messageContactsDeleted = Všechny vybrané kontakty byly odstraněny messageContactsEdited = Všechny kontakty byly upraveny @@ -973,8 +973,8 @@ messageEventParticipationUnlinked = Odkaz mezi tímto případem a událostí by messageEventUnlinkedFromEventGroup = Spojení mezi touto událostí a skupinou událostí bylo úspěšně odstraněno messageEventDearchived = Událost byla vyjmuta z archivu messageEventGroupDearchived = Skupina událostí byla vyjmuta z archivu -messageEventParticipantArchived = Event participant has been archived -messageEventParticipantDearchived = Event participant has been de-archived +messageEventParticipantArchived = Uživatel události byl archivován +messageEventParticipantDearchived = Uživatel události byl dearchivován messageEventParticipantCreated = Nová osoba vytvořena messageEventParticipantSaved = Údaje o osobě byly uloženy messageEventParticipantsDeleted = Všichni vybraní účastníci události byli odstraněni @@ -1215,7 +1215,7 @@ notificationLabSampleShippedShort = Do vaší laboratoře je odesílán nový vz notificationLabSampleShippedShortForContact = Do vaší laboratoře je odesílán nový vzorek pro kontakt %s. notificationLabSampleShippedShortForEventParticipant = Do vaší laboratoře je odesílán nový vzorek pro účastníka události %s. notificationPersonsUpdated = Aktualizováno %d osob(a) -notificationTaskObserverInformation = You are assigned as an observer to this task. +notificationTaskObserverInformation = K tomuto úkolu jste přiřazeni jako pozorovatel. notificationTaskDueGeneral = Váš úkol %s má zpoždění. notificationTaskDueSpecific = Váš úkol %s pro %s má zpoždění. notificationTaskStartGeneral = Váš %s úkol by měl být spuštěn dnes. @@ -1224,7 +1224,7 @@ notificationTaskAssociatedCaseLink = Odkaz na související případ\: %s notificationTaskAssociatedContactLink = Odkaz na související kontakt\: %s notificationTaskAssociatedEventLink = Odkaz na související událost\: %s notificationTaskAssociatedTravelEntryLink = Odkaz na související cestovní záznam\: %s -notificationTaskGeneralUpdatedAssigneeUserSource = Your %s task has been assigned to another user. You are no longer in charge of this task. +notificationTaskGeneralUpdatedAssigneeUserSource = Váš %s úkol byl přiřazen jinému uživateli. Již nemáte na starosti tento úkol. notificationTaskGeneralUpdatedAssigneeUserTarget = %s úkol byl přiřazen na vás. notificationTaskSpecificUpdatedAssigneeUserSource = Váš %s úkol pro %s byl přiřazen jinému uživateli. Již nemáte na starosti tento úkol. notificationTaskSpecificUpdatedAssigneeUserTarget = %s úkol pro %s vám byl přidělen. diff --git a/sormas-api/src/main/resources/strings_de-CH.properties b/sormas-api/src/main/resources/strings_de-CH.properties index 12c5a4abda1..f701419570c 100644 --- a/sormas-api/src/main/resources/strings_de-CH.properties +++ b/sormas-api/src/main/resources/strings_de-CH.properties @@ -842,7 +842,7 @@ infoSelectOrCreatePersonForImmunization = Die Datenbank enthält bereits mindest infoSelectOrCreatePersonForImport = Die Datenbank enthält bereits mindestens eine Person, die den persönlichen Angaben des importierten Eintrags sehr ähnlich zu sein scheint.

    Bitte schauen Sie sich die Liste der Personen an. Wenn Sie sicher sind, dass eine dieser Personen mit der Person des importierten Eintrags übereinstimmt, wählen Sie es aus und klicken Sie auf Speichern. Ansonsten klicken Sie auf Neue Person anlegen, um eine neue Person zu erstellen.

    Wenn Sie sich nicht sicher sind, können Sie dieses Fenster verwerfen, um den Eintrag vom aktuellen Import zu entfernen. infoSelectOrCreatePersonForEventParticipant = Die Datenbank enthält bereits mindestens eine Person, die dem Ereignis-Kontakt sehr ähnlich zu sein scheint.

    Bitte schauen Sie sich die Liste der Personen an. Wenn Sie sicher sind, dass eine dieser Personen mit Ihrer Kontaktperson übereinstimmt, wählen Sie sie aus und klicken Sie auf Speichern. Ansonsten klicken Sie auf Neue Person anlegen, um eine neue Person für Ihren Kontakt zu erstellen.

    Wenn Sie sich unsicher sind, können Sie dieses Fenster schließen und die Ereignis-Kontakterstellung abbrechen. infoSelectOrCreatePersonForLabMessage = Die Datenbank enthält bereits mindestens eine Person, die den persönlichen Angaben in der Labormeldung sehr ähnlich zu sein scheint.

    Bitte schauen Sie sich die Liste der Personen an. Wenn Sie sicher sind, dass eine dieser Personen mit der Person in der Labormeldung übereinstimmt, wählen Sie sie aus und klicken Sie auf Speichern. Ansonsten klicken Sie auf Neue Person erstellen, um eine neue Person zu der Labormeldung zu erstellen.

    Wenn Sie sich nicht sicher sind, können Sie dieses Fenster verwerfen und den Prozess abbrechen. -infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = Eine Person, die den Personendaten der Labormeldung ähnelt, konnte nicht automatisch ermittelt werden.

    Sie können manuell nach Übereinstimmungen suchen oder eine neue Person erstellen. Sobald Sie eine Option ausgewählt haben, fahren Sie mit Bestätigen fort.

    Wenn Sie sich nicht sicher sind, können Sie dieses Fenster verwerfen und den Prozess abbrechen. infoSkipOrOverrideDuplicateCampaignFormDataImport = Die Datenbank enthält bereits einen Datensatz für das Formular %s in der Kampagne %s für die angegebene Gemeinde und das angegebene Datum. Bitte schauen Sie sich die Details für den vorhandenen Datensatz an und wählen Sie Überspringen, wenn Sie die vorhandenen Daten behalten möchten oder Überschreiben, wenn Sie die vorhandenen Daten durch die Daten ersetzen wollen, die Sie importiert haben. pseudonymizedCasesSelectedWarning = Für massenbearbeitete Fälle haben Sie nur begrenzten Zugriff auf sensible Daten. Bei diesen Fällen wird der Wert, den Sie in "Ortsbeschreibung" eingetragen haben, ignoriert. pseudonymizedEntitiesSelectedWarning = Sie haben nur begrenzten Zugriff auf einige der ausgewählten Entitäten. Bitte demarkieren Sie pseudonymisierte Entitäten, um fortzufahren. diff --git a/sormas-api/src/main/resources/strings_de-DE.properties b/sormas-api/src/main/resources/strings_de-DE.properties index 9b056b87ed1..359913eb093 100644 --- a/sormas-api/src/main/resources/strings_de-DE.properties +++ b/sormas-api/src/main/resources/strings_de-DE.properties @@ -841,9 +841,8 @@ infoSelectOrCreatePersonForContact = Die Datenbank enthält bereits mindestens e infoSelectOrCreatePersonForImmunization = Die Datenbank enthält bereits mindestens eine Person, die den persönlichen Daten der erstellten Immunisierung sehr ähnlich zu sein scheint.

    Bitte schauen Sie sich die Liste der Personen an. Wenn Sie sicher sind, dass einer dieser Personen mit Ihrer Immunisierungsperson übereinstimmt, wählen Sie sie aus und klicken Sie auf Speichern. Ansonsten klicken Sie auf Neue Person anlegen, um eine neue Person für Ihre Immunisierung zu erstellen.

    Wenn Sie sich nicht sicher sind, können Sie dieses Fenster verwerfen und den Erstellungsprozess abbrechen. infoSelectOrCreatePersonForImport = Die Datenbank enthält bereits mindestens eine Person, die den persönlichen Angaben des importierten Eintrags sehr ähnlich zu sein scheint.

    Bitte schauen Sie sich die Liste der Personen an. Wenn Sie sicher sind, dass eine dieser Personen mit der Person des importierten Eintrags übereinstimmt, wählen Sie es aus und klicken Sie auf Speichern. Ansonsten klicken Sie auf Neue Person anlegen, um eine neue Person zu erstellen.

    Wenn Sie sich nicht sicher sind, können Sie dieses Fenster verwerfen, um den Eintrag vom aktuellen Import zu entfernen. infoSelectOrCreatePersonForEventParticipant = Die Datenbank enthält bereits mindestens eine Person, die dem Ereignis-Kontakt sehr ähnlich zu sein scheint.

    Bitte schauen Sie sich die Liste der Personen an. Wenn Sie sicher sind, dass eine dieser Personen mit Ihrer Kontaktperson übereinstimmt, wählen Sie sie aus und klicken Sie auf Speichern. Ansonsten klicken Sie auf Neue Person erstellen, um eine neue Person für Ihren Kontakt zu erstellen.

    Wenn Sie sich unsicher sind, können Sie dieses Fenster schließen und die Ereignis-Kontakterstellung abbrechen. -infoSelectOrCreatePersonForLabMessage = Die Datenbank enthält bereits mindestens eine Person, die den persönlichen Angaben in der Labormeldung sehr ähnlich zu sein scheint.

    Bitte schauen Sie sich die Liste der Personen an. Wenn Sie sicher sind, dass eine dieser Personen mit der Person in der Labormeldung übereinstimmt, wählen Sie sie aus und klicken Sie auf Bestätigen. Ansonsten klicken Sie auf Neue Person erstellen, um eine neue Person zu der Labormeldung zu erstellen.

    Wenn Sie sich nicht sicher sind, wählen Sie Verwerfen um den Prozess abbrechen. -infoSelectOrCreatePersonForLabMessageWithoutMatches = Eine Person, die den persönlichen Angaben in der Labormeldung sehr ähnlich ist, konnte nicht automatisch gefunden werden.

    Sie können manuell nach der Person suchen, oder eine neue Person erstellen. Wenn Sie eine Option ausgewählt haben, fahren Sie mit Bestätigen fort.

    Wenn Sie sich nicht sicher sind, wählen Sie Verwerfen um den Prozess abbrechen. -infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessage = Die Datenbank enthält bereits mindestens eine Person, die den persönlichen Angaben in der Labormeldung sehr ähnlich zu sein scheint.

    Bitte schauen Sie sich die Liste der Personen an. Wenn Sie sicher sind, dass eine dieser Personen mit der Person in der Labormeldung übereinstimmt, wählen Sie sie aus und klicken Sie auf Speichern. Ansonsten klicken Sie auf Neue Person erstellen, um eine neue Person zu der Labormeldung zu erstellen.

    Wenn Sie sich nicht sicher sind, können Sie dieses Fenster verwerfen und den Prozess abbrechen. +infoSelectOrCreatePersonForLabMessageWithoutMatches = Eine Person, die den Personendaten der Labormeldung ähnelt, konnte nicht automatisch ermittelt werden.

    Sie können manuell nach Übereinstimmungen suchen oder eine neue Person erstellen. Sobald Sie eine Option ausgewählt haben, fahren Sie mit Bestätigen fort.

    Wenn Sie sich nicht sicher sind, können Sie dieses Fenster verwerfen und den Prozess abbrechen. infoSkipOrOverrideDuplicateCampaignFormDataImport = Die Datenbank enthält bereits einen Datensatz für das Formular %s in der Kampagne %s für die angegebene Gemeinde und das angegebene Datum. Bitte schauen Sie sich die Details für den vorhandenen Datensatz an und wählen Sie Überspringen, wenn Sie die vorhandenen Daten behalten möchten oder Überschreiben, wenn Sie die vorhandenen Daten durch die Daten ersetzen wollen, die Sie importiert haben. pseudonymizedCasesSelectedWarning = Für die massenbearbeiteten Fälle haben Sie nur begrenzt Zugriff auf die sensiblen Daten. Für diese Fälle wird der Wert, den Sie in "Ortsbeschreibung" eingetragen haben ignoriert. pseudonymizedEntitiesSelectedWarning = Sie haben nur begrenzten Zugriff auf einige der ausgewählten Entitäten. Bitte demarkieren Sie pseudonymisierte Entitäten, um fortzufahren. diff --git a/sormas-api/src/main/resources/strings_es-CU.properties b/sormas-api/src/main/resources/strings_es-CU.properties index b9959dff711..2ab228792c8 100644 --- a/sormas-api/src/main/resources/strings_es-CU.properties +++ b/sormas-api/src/main/resources/strings_es-CU.properties @@ -842,7 +842,7 @@ infoSelectOrCreatePersonForImmunization = La base de datos ya contiene al menos infoSelectOrCreatePersonForImport = La base de datos ya contiene al menos una persona que parece muy similar a los datos personales de la entrada importada.

    Por favor, revise la lista de personas. Si está seguro de que una de esas personas coincide con la persona de la entrada importada, selecciónela y haga clic en el botón Guardar. De lo contrario, haga clic en Crear nueva persona para crear una nueva persona.

    Si no está seguro, puede descartar esta ventana para eliminar la entrada de la importación actual. infoSelectOrCreatePersonForEventParticipant = La base de datos ya contiene al menos una persona que parece muy similar a los datos personales del participante del evento creado.

    Por favor, revise la lista de personas. Si está seguro de que una de esas personas coincide con su persona de evento, selecciónela y haga clic en el botón Guardar. De lo contrario, haga clic en Crear nueva persona para crear una nueva persona de evento para su evento.

    Si no está seguro, puede descartar esta ventana y cancelar el proceso de creación de participante del evento. infoSelectOrCreatePersonForLabMessage = La base de datos ya contiene al menos una persona que parece muy similar a los datos personales del mensaje de laboratorio.

    Por favor, revise la lista de personas. Si está seguro de que una de esas personas coincide con la persona del mensaje de laboratorio, selecciónela y haga clic en el botón Confirmar. De lo contrario, haga clic en Crear nueva persona para crear una nueva persona para el mensaje de laboratorio.

    Si no está seguro, puede descartar esta ventana y cancelar el proceso. -infoSelectOrCreatePersonForLabMessageWithoutMatches = A person closely matching the person details of the lab message could not automatically be determined.

    You can manually search for matches, or you can create a new person. Once you selected an option, continue via the Confirm button.

    If you are unsure, you can discard this window and cancel the process. +infoSelectOrCreatePersonForLabMessageWithoutMatches = No se pudo determinar automáticamente una persona que coincida estrechamente con los datos personales del mensaje de laboratorio.

    Puede buscar coincidencias manualmente o crear una nueva persona. Una vez que haya seleccionado una opción, continúe mediante el botón Confirmar.

    Si no está seguro, puede descartar esta ventana y cancelar el proceso. infoSkipOrOverrideDuplicateCampaignFormDataImport = La base de datos ya contiene un conjunto de datos para el formulario %s en la campaña %s para el área de salud y fecha especificadas. Por favor, vea los detalles del conjunto de datos existente y elija Omitir si desea conservar los datos existentes o Sobrescribir si desea reemplazar los datos existentes por los datos que ha importado. pseudonymizedCasesSelectedWarning = Para casos editados en masa sólo tiene acceso limitado a los datos confidenciales. Para esos casos el valor que ponga en "Descripción de lugar" será ignorado. pseudonymizedEntitiesSelectedWarning = Solo tiene acceso limitado a algunas de las entidades seleccionadas. Por favor, deseleccione entidades seudonimizadas para continuar. From 867629109320eaa64a89e5657f9add96aa9a532a Mon Sep 17 00:00:00 2001 From: jen kins Date: Fri, 4 Mar 2022 11:48:32 +0100 Subject: [PATCH 252/253] Updated version number --- .../resources/doc/SORMAS_Data_Dictionary.xlsx | Bin 264179 -> 263611 bytes .../resources/doc/SORMAS_User_Rights.xlsx | Bin 19172 -> 19121 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/sormas-api/src/main/resources/doc/SORMAS_Data_Dictionary.xlsx b/sormas-api/src/main/resources/doc/SORMAS_Data_Dictionary.xlsx index 5602bc2417cfa04b9bc8faea14020888e82ad1d7..1b0e9e59d211353f32330cb2496780643a8f0cbf 100644 GIT binary patch literal 263611 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
    7^=yAsOsiEha#0#9sI(v_O6~RVCw~2t zOn3>YPXP<4?_=`ap!j#j3e!5pl%D4$Rj_2+n2wqRN*VCE+Z?stl!NXu_}qbe99>Vq z0q!x89+a`@E4&EqarN5XjK|NrZ;xaL;kYx|_@{xG5VZ8c7xy^FYr#%IIFLsn(SFzH z{BtA-P78yWl;C@Z4O~DMNgPE*87NT4$$#|&hP9mD{|cO{R-jQ$yBJAH{4rJ27Dz`?78HYDGY-7;^DWT+6iD|)=Liak~)>s%T^TMFR`@>J-R4t%P zBQbBb45C!)9~;WN$< z^CTPu+Xsti0SB?Ai|4q&*DsPV(`FOlhL%Y;= z^XBn$;qnVwT^w?{QnD+whZel@Av41|#Xm%DfHQ>s=C4aj+aH{v?l!lY>XDEPjti9= zfT@U6+e5FhFc1F4YmA6AboTu_cEa=rzg<<>YkV7&$Mw<$RVN}mL?TLs3f6r5S>#Cc z<^;|Hq}rq1yN(hYZDU^yA;M6`1!2e+5Qe}?Qz%mXDMr>|fLLM3lm#=$Vf|epmqO36 zb@M+Ja{G(s&9Tr;d3JD(!+Bt!{rdGL!yl@v*IBnNLHhvs2`Xd&+6TZ-s6rlrRmdQA z3RWRog9`aMsE~bUy!`Q&N_n@qUMZd<971Y}3w;~xH5Md1wfgT~W9Ex4FRF_ zOFjA{M8po=vTR=zWU19BRHofhB`)|15%)RZPo$i^PFrr(JW3D7jHai5)VV0CHp3;c z)@Z0j&!hE&j=p{Cq&0KaE>6(p-D4R9U7lq9!07IQ zfV4dst*Qmv7U@V-00@kL7p(a*QdwC&%?T1CUWemyNPry6B8;rU9s~S_AR8OHHB=|B z(^9Ce5P|9nkjM(v6`7!}C;}JRW39;nsw)Dax&mC}+5Dr^3BcGdLDW;MqYiy;$Zo@> zw~OsO&FXfM?ZsbLmcI5tnAqM4A7+Ir)!7yZpsy+Ah9a>OdJ(q}C{+sK9-kn~1I0?+ zDroeGrs{&L;exY)!}uIV&9<>;!h;5^|HVsj+31ZxL{+g*Kf;){T~o)yBx3K@z-Q6a zemG)IW3Xk;(;Rt#6GF4Zn}w(wck!tQNrDMLd|rbJ3S`4#8qXqs$eLBrZX zA-~?-pgyEkxjRs*B=EXWT(A;k9>q<3pjli$?B$Fs-@%C<7pGj>t$C%$YQk#suB`gD z6WzBByoqY|GnzU^X=LT&Xt$3~T0T~g1M(zrWR6sWJl0_hA|y`!_d4JE`A_E71;HrW zmj2uFa|LLyRO`fc(4Mym0z*rW;%`8XOex+6AB~VH3FUQLyQ+4(?$lzA(|GyU|1(#D z*=?4j1o0sB+tn)z=HHUoKPn4bo8J{OQw{8-&u+U?gZixwR2Ddp^0;rG<@rj%NDm?` z0EHleoLswJX}Tq#Zu9i?4(v_VRnG1Wk;#WD3%*=HxKd8(idPC0U)qHS0Vv#k8arrE zSlzMXU^mE_`N{g?KI}R-{C%C%K!Wq~@qy=ULV1m#l#mGAb$2iNTXZPX*R@@(^OBpp zdA`MijCXQc9c#@FU^CV&(6jZlx%t+fY}1$I>)~BT*6L1JH@%ts2ssb{f~zw6tk+IN zL7e3v3O6Y`|17M!P&|WG7lx&vx=_5RE_RI0zoJ3ag*k|`90N>zsJhUH=0Z1QpC>~v zhS=3Ve3xs|l?33O{_HNsPh`ue zM1W|Mho9B@bwcxFf^uI)TbKqO(2ZDa22eoQ2$ZkD)<@qh#^>_(P{kj`ed8Ith`3cL zhEg@+ z@b1~OAjk<0z`_hq^e-rg=|!MAk+jUI0GW+z0|LBFT2D1&y^P2<(*t@eZXq?!;mwdx zHj}v4p_j|qtCa}cqG}B3Hn}F*uGFz)QtQ?DB2ZY_cKk$4Gj69$a$gOLPFP~@A+Eg( zMV3)nqOgKqmMYsGdm|UEcX`+nGco*!YpOyxceU^3FYO9z6k&`6@0QD_r@SK1OA<1h9iWulm-66554G#{&p1bw&SO;K6zdtkA1}e= z?f^FIz+WthAOMF;fAwF$bJc@)$MJ`MHW#NvNTSVLoI#+_TqZ^HC zWVO<{%|0c3uDE^j=I;=pVB)0kF0x^~EHi-P_3 zV@dYAyz~W2yAduk?%lYJE9D#s%)KSfI`FeR^4T{_&EZ*(W8JV0q`-QB>=)eF8_n56 z3davv^dB8&=4e+N&F@5ofly-bzI?+tNsVfw=H^)TDnDK>9tOVpt_>@>UX|bOKUz+fN|VB{?{zYW^9@} z0WBFfAZsE2sDj@X?u4eN$obd2#bkE<#~XVP>0L6R_&+Uu6Lkj-Ac_#43=g{qaW2=+-dV&aZYChlGoTuNDWk z{uZ?GJpysA(D}|zz~WrxoouE?g}_Q(7t|v}mqCqCoU8b?yzy%w&Q-qafnD20oNL{C zP>%?|N7q`1sg%X`7RaH&^M7%^|6wDkJ%vwp`G8;ZdX$iT&nhlmOswkHm$<}&@ zAi0;Q@prpM$ll%*rE;e0#eYgX`W{J-0^M0U@)pJb38pObsKVQ0_7q!j<8UV{?0b`p zix^A%i(%KqvyYra0zw^4OH<%|d*~M4-pakc$Pzf7rg1cGY7mDIlZxE#gnO&gf!IM9 zUT!tFmL;#>4=qM~P^mHn#h*nJ(sZ0t);J}dJe7C>eZWKpHX3Lu3z==Z`~7++1ODjB z4>-$3dl}Vd1@b!}oipp1xQC)}2(gr37Dl7Q=vKiY7w(rpHoLEFuiGmuEx#xoWkg4s zRsCS$Im-oFa!j*WS`!m!WF5WZdjF1k`2ZTDE?0bSN~lrl+o?7Uni zu?m7|8Iwgkr7wqkZLsG>bypD%7o05Vm7f=uORMFdueY~p+0-6Mo@V0S-64T}kP-NW#e zg6ACT`E2I{pFLc`;r>Ka8rjvtT4eL&nT$}*wZ)%BlyG=BD*fMudy~{nn9;ms@2g6Y zGB`B``G-FyV=xkXJJG%Cz?Fzw<8Kp+dKSU4E|y$VW^GUSExX%$N#hNu4mT;%Cw{76 zb$@EFhtnHoGY^$~R8p~8{l*z6cI;?Zft7XOlu;Grbda~n?|mp=ip}y=KLs6S-Km13 zQe?cKolD3Z2OZ6bsMS7WMnvYh<9o@7QBDVo)=}II6vj{1rZ9^oedhro^t@cXqhz_< z8~(X$>A+UGXxqbYAGFxHl}P@|Yr#4>ObBPhU(AynI{A1o2f~csTO39}Va70R;6<2m z1<2{>eoX858_UNCEK+htLtvz^SSy5MXtVRHv~T}bCu_}bm3_? z-1mG?HeQ>L%{^gPr$Vm8OY<`3RAFC8zo%-iX}0uY*^-ho=Us9Rd%)N6tY1Nc z5$>zs;D7Y3OxQu&KX8Eh@@@!zB`gTmeX$*=FTpxX%9CnuyEKxKaHOwwjeB6fb{eMG zfeu(Fq6=!9DIuSgZsLvY@1|l|=$h1ePR5gGtz!Ss|d?qDE{=i+?DfmK|q zuZXjnb~)gIy^enhqppR1aixN4ysPgESzt|MMD*WdCy+8@U9EMo%L=LfaK@f&f_L~L zJ+#Jt+bZRy#+$yARWNo+elTC!Gf$R%C|CY`B*}C^O5bww=3%pTy8LuD7w`zPN3GM5 zp9GlRwt8b%aI)d^q_a}Wmn0TC=Z(kBuyK!&4%G$I^& z*&*0`mp#s*q0QMli;o0$cY_+Xo4TzD)JqYc>}iXHp1{3>RxQIoXj6O)qY9Lp(vL$H zVd<;C6qhT*za42HH0hae)Wt3Cy7@$KYtRnnNb8=})^+v2-Lk>CCOs&F*N2`{t4JQn$gq3PcLE${nJ15_4RGx!JE4lvgg!~j?7<_sj0*%7E6bB+DcyQQ-HsYzkR z;;nm{TgEgWE3dwnRlL_r^ije$z|SEK5gPMxZR!SIlTO`jO2KNTmoXuTKFFZFL;ofr zR+7h)=R@8txi^dOY{<3OHnH#bDJgkjkK@AGqN8aV{ak;9hjqg`WG;MPfvu1n!Zh;6 zekviYpWrC&o^*zCNJA>NCQ=crp?kP)Xsy*=x53f{pQE ze2fD~Wi7eH?vuVA&)EBgf$2=1ksD@ncZS*A9T)g!R3MxCC_AzH!8KC?Yf+XI^Ug(7 zsH(vGZF8^DgnYy*J~M(F4Uw8%PQVk3V&OsZJ0 z4$&2y6a3}w_TK1y$KkZSSIy~s>eHNV<#1uhSZVQTOXY8#clE&)SBj+bEn`7A|6C$8 z$!K%H^B$wT?*~WE#22HVOUOcw{x%%MCo$a^4u*NZs-+(+lDy-88+~tc;sOUrBmBLK zdC*Qi{O$c|c>BO$RV`{dbIR#XY%Qm*0_}ma1^}}ADZiV)F}bg6kM;C)n6=WkonKJD ztF9xDbQZLBKdxe57rrtZKesbl=)Z55UsTS(FlakJYqI}ZPQv<(qJ*^ZQ-t0*p9_9j zc!Fj7*ADt&j7n^|bZm|(H#Dyc@s473@px$KO9R1z$?- zk6S}7SZf#({%?(H6)Q8)sItPPgS!)GROzlYs+&s9E|fRB|C8rY4U+bbBEApVltl7T!NM|F7D318}^;jLq zRI^yjXUt~VkrPgSk=kl~XYBR(t{D_?7IQj><=b5%O8pxiY; zEtx5cvY;zd{?RkZ0IA7+;2rBPp1`gMc+qQHNe#$dIxq={`q^Xzu;=wO$iFULNEcoH z1O?U0fTLv)E|0{@#sCV1*QO!msNh{PYhQQh6M6&g@@qxW_z5M|I~FrCJ=r)VC8u!& zaBquHvxl47t{k2x7s-(%Ie@AGDwfb~auA|^UDB=n<+lI3y(1T_OALvyh4M+?EL||Q zH91@G-DUpU23dnYXGPkR7O9hRaU$7(*@@QNf3?f+vdfwDiF9yr1jtLh-J{{ewd-YO zBwNN!U0=f;tr|;0NLV!q1|xk6E4Zn+na|d#TcC>(V0AtPZ6bRJ_F1Id{De7z&U z?*8(Kx@t*uBH4Sf6L~?clb@5FN2XPy%S>rb3~3Zz_GlcMUw)~!x|WQ6Qb5@sAwKg{ zKY-0TDue|CAgRs&J0I--dYo|mZ;k23d_z&;tvj$&4ljRdOJAKUPen=3@3^}}x+6ev z*M$(wQp30Ck2)Jhdr5&XZzDXkEBphiZuX1z6^oksMxV!?9Cr^2IF!^RDlqZGc;3u$ z51O7@2n1v)r+;4EXT-FdMvW{Hy$~Zd|2V(9s#K|2pcUi0DhNE-zN15s2Rns>NCtSY zBdkWdq<4S^yR_LL{Rd+K7099Hy%ScNfY&GX@HTl}%oxBwc!Xt-r+~$nu31n!f#(;lD#y~|7v4@oq&?21WFM}mnag(bLu_EC z;U7d6muZPDQLbJ&c5P^EOg~yR3|y5*0LLw9BqKDDyl6V}@t0Z-Vj5aap@C z(u}%->il3oZRvSQfiOM9i@II|eLpuWoNA|DkesPX%fXED)k$^(;lwX_QViwGQOpC< z(ghnoC9GAx4|~`aI25G9UK7mMT0LzJ-!MjS*4lr5);DX&LCEj!zvqG8e;SF4p8Xb4 zZ3F=9WgZR3Nb?4%bwAy~60y}A56{cn{4!(f+)bfi2IY_Z@Arz+!CL%K#v3LG1flXC zGZ6M(nN2J5y?(E3@vyYMv*;TgGF-jYN<}}$I#)I3U-_trA=NArUdHrw0lWoE!Wg}{ z+eDoiGuAyGq`zX@FxjnZN<*DI1lnX zSP0WL$Lf~#YzaQXzrQdR$ibGkS2N)j;+8ZSNBaG_XM(Ir2oHyarl_na)e1_j z^*%_x+W|&`7G=`{tlV1~Lia}m*aHN*bVy&2h$nIw?ENY%jaOOBTbr~gZuzA#@k0$D z1V{E$iod`teA)z3lF)nQ*`L2xU`=Sq|Lk+9PuV`&8wFR1=O7ulTo)lLD!uh&fz!Rg zZ7ooQ;u^R3S6qATei(4Oz47jwiCzlsO7;OoX#3&DaKq*6A&r^Ok?TpwIRzk$Dj6wH z#WPOsHcoHyN161g!!tUpj>-ap&h9Kv`bW&s2P94hl}Immc0ws0eEj_+Gp#e4Pr{QL zF&2wBh<2+L)F9sof>ML~BPij7ynh*2N_DLzuq!`HWi^py(@3OxTVz$?RL?{7?5mb6 zQ`#Y=>(s}Z%Q2ue0SbsLoBQ}tshYB0-&}+0b`soLps|$&04ZTO0OcP{=}tmny#r~4 zAyL{LQs*AEN8gB4p38=eY>>KgEY^#QLjMXy^I;1VY`;*-$_fQ&H}6thbot*2-MOwe zlaaQ7NsZgJw5Ni*I6PaQ&sA+Y$^+z7N~dsTP1O?Un0a2!SJRe3rf1l@p54OEIO8*Q zre9EHR9cP5PR{>^K$Pm93w3>5w}3$)>K-H01``l)c;ehGWbA-JAf5pTL?i9FH{K`y zIb@ygT29HQzK_fZCnQe&5pB2v6nQvK3i=+&BGF9|dgnjG{c+L$fgyU$ScZgFxeqgs z$|8FJ$;z@siGjqXC=YdsUMo8#G#b8t)XvB6x1s~e&$m9LTQsdGjSelo#J*Yh$ecz~ zUybwxou01KntoYCNMSk;2WDR6X3~O|LQlw7b0vTz;r7PGUS3=B;zQYzQd-E2b`7@Y zfVJl{JA;5KUZ(S9wXN1}exs0_C$;xcZCF1|+71S^M&53_s$zoyAmDX_R3HEZ@Ef;n zZ+jgO9suNSWtA@d^lwX5`;h7nvXzZdHvkByTVML1)sFa|{~vDloBuY}Xm;R235C$a zU>!2nyn+%6TW)sqC+r~f*TdPVT&>5*X%BG=F@ z?rtmb`E_M+scYKL&xPAB@hcG6mHzsXlTuThy!D>ivw2;hY~y3jZS8u`ByuoX?BuY^ z16Bn0Wha=3yPxmD+okze{T#4hLLCd1laR?hBNLcy2~BU;1~LqD{Q13b-N*ii_;m!A z0`g-sLw;-n+em4nl_$muj8|?tV-i$tZ5T`Zv}t#SZ>Iq+-mxe@%d%nQU*eDkD8)N& z=i4PR(a)LW^(4uhzPDL5Ekf$>yJN;D;kpPcYUY(fLehTl)trr9Y2tn@+fqb&m78F}HL{ElA~g7{>~G;cTVMjRBuW3p((5gagwO z7o|fe$>n|a9UqPSIVGB%pzIfnHZOwfwiDbi1Au4g*|4?c)>oHtBPGUR~n5o!GoTcg+0At#ZMyAa20s{zyYszGISvQ*?>uZ=0zGDp~#~@7d~*q zI?w;KguQ(f4OAsyC=SMnP_||*<>0O=2=@WaD)n>I`BZ3e@xOX3uFm~xxXkDAUH za330?_M3Hems)9>61hArWmG9*Ua1NZ;!`l3egv4(NSy!~qa)uyx)&VoD5;V z;sdfvW7&N~8dE-mO{gNSeq#UTj{~6TYt>w_ny=>P`OW6}!w5J_*9O_&zn$S~VL(M*C)LN23qLhLoNl524CE#Oxqx&h~+1<{8%ZcUtSt=85%Ikns) zar$Nu!7vdO$}SaV06v-pHiM|eqB~1GXlfEByl^Y|a?73^+QMwHRFLIv%Zxj^1+Kk& z!#H>z5!WfaOT${~gJFq=a^T;UK^atrwa=6$dBO&G%wX&Aw0kXpJMUhW)r;w!XwySZ z>m%zF5Lrs&9I}D9x&OZA>&2t3#7Dmfb5cNJ-5u^-0i*Xk-Njh^ABS8&04H`S-(F*p zUF!Y7Oa9&}>a~wKcR^)HAfGQZf>j2KT=(T_4j+8S53zf%a6i?mbp20d2mqBK8&(;D zna}m0%5eXWD+BlSV)8#Ck7Q9G;Tl{_IBt|Th&)>0)k<^#Y03X1Tzh!Z>)^zO#P7?i z(;I%`_K=?HR*YT3n`3)Qk+84#UMJEBqEZP}^-z6~5GNWt{bejnrV?qVg61?+hA&nx z*wcSgCW*|`%7`HxX^_aQBE+}HWqQV%cS?!AOLhBT4F5tFiA{e59^+=X zh4anu4XdEpXIj&V9|%$Azrx+D>sZ~VV8XQk-k0as!nH{(YvMKEb5B{1370Y(kGk^R z!$KWqmZEa$BNSahoY*aii9pJg=9Y#kz@u+}?;SIs3Um)TM~#mPTL``p*jtw|VOn&- zglncl`|2r9PL@a~pE62HN0GPjv6gz@T^q2kEDCS`cfvJpSjXxZ@sI9-<3iHrc{DD6 zG`Ek~myD+k8aw5zBkfXaS-&m{9LcmIUmyzDBQM-x)zFjthyXds_St2;p{N)@eDL_x zxcH{lwSK@w3Q7bx zjZ%Qqu)~_wWJ&>Cq|X{c+!SD`1jf8!QN}|M7YS&8tRbAn4p&KvO$gRK=VE#|uCwk7 zv_Pqg64B+jHW%E7SvI94QLUQ&fvcM({Nt^zUEywy<4IW0)ddwqkbevI=2K@rU3<^E z5PpT}Tu{IyiCraV6N59sht8OdJ$;nY_-<*QBa;}&y~Ax4DsK-5EQ)l?T&o`*Xs;># zmnG(AuL%QcJOaZlV1+;2*_tGZ}uD;j6$w7X9dH(YzL<^UOhZHoPqNo>ZqZ6Xm^TVE-Gn|JX+KP?uK4RW%YZzFVwi+<{kbShB^AkeRg<+RgvC z!@8q-Hoba>hkZ_VEgwcJ;s1wLQmgU+m_o8e4isIZT^Ydy;2{Ne?lnv!@fxO)W4i$g zxPC$*D_VTZ{l$qI(Kl8BEx*y%)PYBDmxn^jh@RzL>Esq&@li1K(KkKYvDX)4uIIdG z!%6eVCk~&_3^AsvonIC{rSDuU-X3A1B<&9Sm}gnnxwKc}YI? z-^>o#+!w;3z2<*WV{Z1E|Mo!+csu|DmjNu~b__uf!DB(%^F;b7-`~B?E#T_C1zf$c zlsCU$us6OwVda+Zp7s}i^{<;=pRfdjiarGfT-e70ci|+sezm+RAz@iR_(_z?W5*Xe za0vNeCnQKOE&rG4Z-mEpNfA{gek31-tC<@U*OFK#Uvpt(DJ;V{VSq2-TM&lakVIf# zp#h8ar%f5y0G zbr%;&d5$6{kZ2K@m%Y(`C8@xZ=exz`?JNTpL?xwAPWwl#$u`2 zM-V%8;9FtOHFg9GZ2GuwuBXk{u8s8x04Le7bSM@RC4q2a8$|M^?SJQ2QM&EPnzB{R z5eOfX%e%DPdDgkBf^A9A?4xThr@gOg{xj+($oOul#SyeXe)8vc=8e>~^(l}+1nxb2 z%;n5P^W`QV$7r&RXmMWvZYM69Vc(8{O%>Ov23g?U?on@M~ zA*w->8&5*}j`O~49q-OV-+fI+7a7Sl*GTUk`MlzXB@O}Tn{ITT-DP&#=XB0gxDLf{ zomCVSIj4-6#6euW`0!_`a;D@`?(WQ`UPZSFP%-K%>_+xPdSpm_9WqFrFpTar$!Yf| ze3XAIYFt9C&h9JX+91AF$v=sDD8l~5o6kDweTT=B0bsz{VdH2I1r^!VJ_dA=^$w|C zs6XAJ##<7@i1hMard;srB%4M5HFu@c+@w!PCC zc+VI2Qu~FchHfuOeiVjTr^)DGv~;Jt%SK5HPYog#fjQj*QoFjKLu%Ip>V)FJUR=#| zvEq$`$AB6;o0$#rS*H%=`#~%ki>r>cpZB}G)K?UT=po=$of(n>30`AC)3O5uuTU%+ zqx3EmB`OeyRR^Il$JOn=f(5-kAT5BRoYp9ut|Bn=*KbH`qVjE%29S?spQ*Ul%MR3n zQnCJAcY}evCO=pY?AUh=YpC2%+BlL)vgZwvvU@8kNPEiyRz~W?yA*Kd=(>w`u z7;c8nW3x5R^z!+dOEp`*5i#-9x}W z4(>U_#t$QWb8(McKJFRGcV*<t*xl>30bj8dbF^Db0jM4S!ilV%&PbEn(BA z$w)FmgL%E6*HXOaG3a~5*f#;ugjV zAu6~-KJ!3K?6>iJJCb5_gej`d9J@v4(9ETGBQB~Svvr09GDP~TB~m37 z#4ae4O5U#+a@v)%Vgf$0Ao^h7>s=VLD#pR`1%}Ai%a0RI0OIwQ{pXkN?NEG$kUnGM zuPD+}o#%oeRO`&M_Z9V)U+a?sojp%Y|2p{m|Cz&zJN(f3GG%t@vB{SAizk`!|e!@4Hi1;<1s%@S|T% zF&r6qO%`LP9#0RGd6T?|2c5nE)9E8l5(L=Rtk`>M@Y^}|=1(4W9kpo`GRo-vt z>e5)F9N>$Jed}hDg?~a@FW>dU9OBk`4_D7o|m@@Ko=X& zS#gS=JPUvVoq@ZlAEx|sT33hU@u$_Wy#kA_nRE+S;#{%$O#*T#@)#U=S2Re?V|IvD z6D;lHbKQx5^7jshWb5nu3{3w1dvg>5NECR8nOr5r;A%JpCJ;(Xl_TiJoe$?BTGX%!c0ZG zI?>FO`XZuOnejoQQ%4~S(=~ud3|xJ$z@W}&?Ta(#1VuV3WTP4P^t#7tjz2>{;v{QL z+%%x|yN)X)JA577e1>$M>(&iJd$QuckjJoH5XN=r1IanwoKI|%*iUhU0T;q=h)18F zymgEE6CXe2i!<|=kF&qe-(S(%V-D?0w|kR);xi{sFT)Nu=Z>YZcH4RSC1j%62Dz)g zagY1;ZbsFCtQQwhtb)QHS7n~R8@;Ds0sQ#X{V})Ow}*HDJ2&wLVCSd;0Cp~fUW8^i zE88oqkel#r*>Q^f#@d15PZN2&jz_bCXqg~))uHZwrJ$6{lILJX*Xr)7tEqmi|{bo;x#0~ zRvmn0<^e?5lTxlD5M8LBnet5RZQA`hBF=}T?ys`<=51G=Qi9V}{W-3VvRciUuDV&V zDch{lbdV%sa*f#9OsrnE9y#Q@@hE-ZR^@^kkv|tP@Z78-<*i`!CMX@m@w27UE80#R z#%YRz9gifrfi_S7l%Pqkr5NJ;39%b1xs;np{0Ep{u>nJ_qo$)=8-pgECoD%uiE=} zT=@k(4W)}7_$-0iCsX-Opjqtp-2fc*SMGr+ADBP%5SJZL>ntB(H67u^$hrsMLI(ZT zGL&Z$Z_|JslJp^oyHkMe0`x68c7@&){dk|E!o5Z3bfQ?KUi8M*1g|5SgU!Ml>6+1@6G&|B!y`gmdG^1a$Ljq+t z;j}bx1H_OM6;TDhjZ;tp<^XLMCpc&KW!^p%m45Ei@K7Fe= zVa$%HBhLHu|L<163(-Rq06jz%&_f!z(gYVsNMZC4=#}x~+XnBOz(<$J6%;N{7M{~d z3UhP^8l^*l*g}eojUZR(biUpxHO&8PalNu^(+`YE>wq=~_zO1k$SiC0m?>+uqZQM! zCpK6bi9gj}C1#Rza+TRCfQT#9|Jv8C%s0IFTmbg9 zo5*bhfKYDaR*!tB6gfV4<;GQy-HEmc8SsE;Bn!M1yc18m8d#Jwa&eM z<%%+XY1np_E}h3o^OY4Et$8n9 zR(fL)+kWA^H{~@3UPsXWDFNcpORSj(`N@1e2jBQOxl_w9dBCzNYGq%N1lSDFs<(+` zx>1Z59pm}IVN0xN_20s zn5V6sj^@Gh@l3!5@I;TZRDr$dpqNxvQ`lk43Xy)QUw8)&`{qT5B>+iAU>8G;CMS)i2)_*JJcfym}a5KV(av6W(0F`Se#1b~y+ z#8Pg#9Si!5u#0ex<)B)7;c3Uch6GM`V(20~kf4K;rQfs=c&(FTk&Gc<<#U2`kGWjv z!x|Qm0E*Epf5b2kJ5j@5p+!04Dx`WJq~=9_e)%R9^sde`I`R;mb);qL%WBSXD||P{ zHvMOy>H{}p#MhT+RIKKAE10-pE)wZ zJ!_ghydQgV-90D??`5VLf1*$E9W!<86(`FW&=S-8sjME;aGNTUjVP`d2WV-TkUm3K zBU?3>(V<4m_fGJN8Xfk>)S}^A6N+ZF#FLy%4@#PS&B_?syaEDo)XeduSyCB#g{Q@|I>pg|@W#gK`t^R%f;4%svS z7Jw@7a&8hN!9nCbKUP?<6E+m=loXp`XTI}_)#Jl2c0a8=Z;xg?jWrFod1dI8x87hs z>lgQUSg-Q>H9h=#l$IHs_MemYcwt>(%&0DSO%ot5UtGPj+cncMgPzkO`cw_^L!g+< zB9CR!<<|eYFq!DLWqJ$>f0MbSx?|;GwshrXR65cqc58 zCI*EQt3!!;g+G<R3Baoyfz?vVSpS6K!fo zvty>EwJ_QBB*7X>R%-dlqJj|jf-?kvT7@H1tl{fiql%q=>GDAfk$M&54m&Vb2)=IyHhU<``(EI2F8&j|L~P48j_`gM{{S=L6Y#^1J%rZtnFFZ z+4k>}d!Pf^b9|HyoVd{+|Gs%)Eh4Di(1{1`owBsmrHu~NQ|E9d`%*P%F6@3h znSiRdO3H7~S5*}pC=F=q!oz68vZhBknKKj~ihy>A1>*Oh>U|fu)9XFFU7fgK!El^3 zQF!cOG2Y#DC9?U?}oQZejov~b4ErS7QAJKX`d@2 z$e+d3@q;ePkSv!Uf)pfS6(HykgiNfwYy+Jl$e-;6SwzP|-%0KzgJnw5OR!9VRIHv& z%O}%Rz?LwEV5?lC5!8^X*#kfrBw*%o7p%j*>@0>is*Y~3lF6YYQ`L4&7xeRay7Ef= z6T4-~4;5>G5l=ur&UXDX2;j5(hwOZvT6P`4M~mu%2dQn8{`{!_uZ3a_$D>Mfco+%8 zNjPBAIx|~3w)V2|sv<^R-0HrOS9O>NXHuH1XsG@@4bH4~9|g1?iEN!sYLBJvQzL<} zUDFohKh%6ikdD3;`-1E ztvMTWt-iN@OMcsTNIOsD;ssPUd;2u{tX!Yt$C3Gf2#u*MK%jG8vj_u-&{mv&huCVG zoyn&-*%UxDTh%FZtm>ddTa(AIzl_ZPp_^W$1 z>m}K^Gc``1Vuw`72Ga5Rj3)S23oZ>#=>yD(n|*Y=lxbafX}m(!E@6Lx0B6}^XwUxV z9&KJ&x9S-2kAE0g)*ey&mqAhqKHLYF2sYI3Tt=X%BWaPtf)N; zw(LE~cWC~Q!A6DZyzuUV++>8k#-1tv1vKCy(si(;ELwHJ5|p-nq^9K81EUPYfT_z* zF~{vG$efd##bPV)T`IcSKDia~*O&Y!X_jv0c5W3>H)2;6@0Qw>ha+>bW#kSe2OlPd_o{6(7EtFO6c+p}^gE78u8JC-Z&;Hmj=c5ZzdT=9llq^);fc@kcdXvXVcf)MmB3=OX1r`ACo>*2 zp{;wQ-AWY)keK3W6oLE2y~~zB=BF|%ljwn5+OT>^r2exrvZFzaq0oE4)|6N%QXtkA;4}AEPFvzxgD1)$8lKBV#EwEYHVbS+3lzetau&R)CdJXCd`s zGCj}TPfF{+B66S(L|HZykk5!Qi*+A;sjn^=@A?RPxwnQ1*>IZgoD+eUdk(@rgQ|0^ z6pA71?3(gc{CA(aCwc-u@A8q>S{p$>U=OgCjC~ytmQ(F_L2R?$oc>{()QvIghyaBv zFW`{)DC7a@r|EVm;K`P1DrF2c^zr(W;!9YYL}hs!CPn*miUaS>R#E}FFFW_H2*CWX zSRD`Cm!u$FIAq5o5zG&Np*2Klee%$l^e6gJ!M=B8dMfNx^=p**C&N}Y50g-ES9mz+ zlLj9Kgz0*I@^*BpF}zfc?qQ}nLZS=(Mv$8GaigDGF6OwnZH?3t-LiM3z=bGy-c@Qq z{%)gl8`s%sGrDfwn$AiK3YJ;BNbLC6XTX>GHvBLpz%H z{Cw(;vu9bADJuk~`wC&K=ZXzRvQ%t9oV%J(st>*!HW9xd;?DUYZtXOWCT87YpfAnW%A5^Q?K}E6$C+)KVf?h({LO zgHv7s6H*2iSw4lNXn$^h=e;po{yW7IR}1|g^MXhVT~tSbUKKgT)p@ z-9twAHPR&SQo@+q?Es`UGf&u;O4ms7@#3y#wzF)PGn9hB8TJ-PwT~RCr{%UlfaL_q z9F&1zC1>>cwjEi#K}qGRlLGzE2eDM;zkM>IU}*@{|2qvq`kyoeVepp)yF4eOZZ6JQUuh<0>n0k0E?@bBi-iqq=Us295Rs{7vqyb`kj{akpsV* z;d!l_h8tAI|6EbbccXZf1?LM~JXeIHi|<{dtEtFTMI*u$aRN@7<#{_mdR7xt_NV4h zF~!2RQLd#~uJ1FK{a@Cj+!cppz_u+sd{C!k`+3`(jpGIC(XnY4z-%bFN>Ct&yD-xU zg)oe7^%6sh;%i_dsfzZG5VHF^1&@eP@!b~Q?afi88<*sW`4`dorEf7;j50wZ#xJKd zs;MAB3yc^8uYNTF&QTUu(M&N=z0z1mu_c#;U`cOU_TzW$Ke2Ul$am^~_vjKO5DJ=T zmI@Xy^idlJH{}$EEP8^5M%}A!YuT+j>JI3pWToUOwqB`+Zpst-?w)jqH!+7kb6_Cw z&2%uNx%K^Fq2LStYgKX7tgl(-#&G$y{sE7DfC_SU|M^pd?`EUJ;N7dSCP98Ua5?;etHU3W2k+SPMXp2Cm4#C-&BLa`YzbP1=evAnyj%Tp zX10>=H4a7jlf*v7c~d1dh|O4|DZ2vOVXIp`M@Bc#WX9V;kFVS_*=tGAPIDTq)vfJ9`ayd?uYFnxsXf;*2dlEg#&1t z8AdjY>p=GxB4DG-Kb+=&xwu|dw%L@E4a7X2m>QPauT-&P=AeN&TaID|_QWQO&>fNb zg`4dJwgmHB^2j+aR-ZJJNe+RTT&cbP! z;)CWDk}QL-@LClKs{Wz5O+Wey)JZ8fs(I)%0YSziS9B*2Kzbm~z~@x@5@bW9!SreV z&DZ)ABha*j9-*eVI1>R#S^3Fd=}3`E$An-_2t4Z;fRq)GES>f5G>Q49CTWXQ24L zdv9*~Dc?@fTLs%*pt0;S`u#KK=dS_da|8Lq(1+$v@S%`wsf2!>9l95MN8bhGb2M(L zmm=Rvd1B1%-(f_((#%H^Lh0uGihe4c^IMrR5&gZQVrehtP`ze-%{tbmh`C#I$HPMP zis6c!8b;J&>KSV3Ys^^>n38MWt&Q(VRP^X4Oy`Ve0nX4eyo)IpogF0Qgt1q*~!6fCdF8+EqnoIXCZ zs{b!e`oo+EpN@u@D*HIELVTM_FiT(qiBxI2g0QmNO-@pEcy_u zY{(>6)$P9f2fef?PQ*1F!)La9t?ctMM(5i*t`Ps9D801LjxFsLt z&M$b5YD}=$uD|+T&HVCr;pZP|v);PtD}vewI8fQ)hvO}Q5>=J{{MG%BLlUMs{`C&L zSWE~XL%H#==&|eJ$#msMn%|3&6>srub_9nVQl)c0+Gft&zLvxqUjy!Fmpz(lDcXx_ z6C*Dtpa6>t4oKzJ?f$@Z2#RZ})Y^TXEec0jaW5u@U`h4~qUnA0RR>Z;ZiyZLBSl_F zJ5OX?Gy%(0i;T+C1^=y<(J)K`#zmxJ68`O_-%h#Ml%U zc81D3NyYT~xTx%RMq~_@FAsFgRHWRvuS*^$0U;qWV~A(F_;oW98T74P+fP#G9DTp*z7PJ59H@uoAS4Z*-Pk+LOHAOQvdb=2 z`fI(5yv8y)R~V}5I+~+T*Zhj1hf18~IP5{l7L5~qA6?xKJN}4183fllJ(k8A=L-*e z!|m7ocr#3E<1X|Yrh#A6hTemJu5WvA-8q8A{>^U~00h1DQE!-4wO>58hbrXH%Pq_v z|7xP|&ybXBtlAT@POSk}o1)%DCJBJx9@R&^!@mKtgz%qNL&2&?g-B~j>2h&s3G{S| z^eZ-;i6VeX55nD$aTLs@+gO;h$?fX*<_<^In)j_05fd)%#trC11O0?Obw)w2A=z1= zPNM2V&GkwwLA<0#nq7%+VLCT;%?a#7q-tmkh!o*Wt`4$lM&pv zOD$)Geirxf`Gm{cHZ{NFbA3&4dj|!(0lRw@m;wU3doBVJB__FEsk6u%(xyUwrtaCj zDFKOHY?-_fiEoEkARPFrc{xk+E9ryE+)9LDzfcjYjWpYG!iLk4!q|FO1AXMS$1+in~(q9|_?AC;BsxqeR*>LF-cKK3< zqD4#wfv}!Dl%Q_0wyR~E%Ll<2b=WaV7ugkzE00YQ7&;F=X<*9Mq&wRQ`uhK(e1e0H zFSBWRPohVrlG#BgfB>YB1A!YzuZVdP10q6-@vdx6)itxx#)1lF2CEE?X{>|Ih9+Xg zBI^=?z|C`AK5gqT?FTP)z8{ZQbLdSA1PB^BFts+}#5aGW&6jPcXCJv!fivz7 zAl$=xsI;PWs!}^L7ny0txL{M_u?*?k6gpDs^<5c2r-{zXMB?`#L=Nx<_QA9YuF|#B7 z5KifiW$~hj#T)eJj?YL+`4{FS*20NtQGXBLyW^q^X4y5$$}=AT@SOFWJ6{|C&$(>q ztMD8jV*%j##{(Cd6kdvV3A+#Og~)Fik2bLR?j+w;3LN_AO9q~QQKD8KZSmG^sV)wy zK|Ov=MN}_bDbPKSIUuZjXE06Y;mhv~5)W|?-J;go5>JUJJ;;&40dvj;Mse~O)Nn`C z>ZvMP$xd&vc<_2+H}KpA1lH*J1!ZTQEg^12MHsnwE^HJ-AYb9*t->;H) zJr@9^^AE`+poAq#4!*o_+PI#HqL zf~_ts+|`{=y!tlo{s2uBH5&Iip6jl{6m7p5l&HW55*4<&1-;My3ObjA|2n$;$bv?h zW>Q5)UQ4V~PT@0^HN8f?p?O&Shn&e4P8E24`Y%+N-IazqkuF^%s%W=S6T6D50`TSO z<--dkGkEx^Gy*1Fx9+Y`Rp?jI9gA?+`nq?F6g!r*q67=*_l6@?siQK@Zv807A#c$C z!D_m_ix6e$8RfQJ%Xem33#Nh6C_n@qMaI6SyV{EdQWd~7@JSPIZH?&1_JzpK)`r1!JFB_oGJ>X%qhx$$_E{_(#X20pm)PX1%h29Zy1^}~Vv9ST)I zY)ULo8IwQBoJsM$I%Q+B=5Bknc%AwQ!6_1+cls1~C z1TIet;C_$zN{p`%;GcV7escLBfKDTQY`QUn8ci?^Wh~8jhK~gnidq`C`kPmZF`+O4 zmzo76<W<|2`|Gs#s{7Cj zoqX!X0Iy*6aDxRJhb}wBK08@tJ zcyGAw8#$CVT!(RuAnSSxoxMKY`Wf53kdnu*R*ioBMDmp0d_UaxR`}@r`nVN7-ERCVo9SM$cNohJN9>-@FnK-!lmB2j=k0g3xz-tI$&bEd_YvfPwF@ zq#T*8pHe+g(jo6W$?M91?@&^XGyRhd#rk%ciu3Bu6#6y^GKoIh|V4%FWdK)%15$ z1a#0Qi>Lhi$x%O7GbgtFhghr-JN!_I6DLgj$dI<33+I^bMJDn0@`cEmz$HBO<{v^~spXwsG>hQnJ2*+iz7Z9|mWj-OuI>A25-3%H~dAleTKAtY-@`%P+=)4F(tT zHLRE+*|JlM=(lrbj&E?J zm}-FpMxGeb{=ex_p?HGJ@#Rxah) z)zzY0h+n!a2=BXNWypEiRs7H|PKDXBALr!)?q%rZ*r(2qfIFZ@8hU%Gk#Us2EL(tK zUh@SBZ6epo;;+ooXStU-q1t?Eeixx9H;?Qus$U{OrTsL>U&avpALRbH<9u-4 zaYp{fSMrT2!$V-BrjAE__-JORx~rsk=Z@Fn;wPvb`^o+*P0Ra7YKu`GAS zSE#ZOjdSeS`r|#f$1dIuMK#=kXkzwnB=G2w-^Dj$=6>g(=daN!I|}@aJ8u1PI9h^D zl!ksRv(9y_t5OX5PS22dJ|aNhDP3+5e5X6$J8e|Mw`d_|vL_?*tVJ?#O@5H61K(*( zK$~%NVk}aQ2S247uZg*`OHhOfB_ay;okj`QX(P0%Mk;e%8c3utgDH|kP`E*$j z4Zf2R^qs(>JXel8mU6kC`t0v3_*ouX@^hV|3bCyg^>6WZM&;JQ7OnnsR~mX;rI#gt zf2Txn1w*0P+P!?xcS^~+dIwDgl>huY-7HT3og9xbcXo?4QUBiz4`XTc<)KA!3 zb7+!xK1W8FK4E^lFEcTphfKTZHOr*)q?TK9$nQ}uy{ZHbM7XL`B;+{Be+Ln+#_7HD zHQCYIUn%1Cy=tVY!b3AbR>iG(t?v7oaEh@>zPwMeHqLy*Nf{sgo_G=u_Al{Fignsl zfz@fLeYj!rGKN5^e1D&b>7?`N+s+g;dmKhnI1UA0bZy37xq+oAeCfFb%FeRg5ysmS zHV%7n2ykUEt+ZFg|E%WWReZx`&T<>Nm9_HmQ;n_GIUbX$9J4RC5xrP{7mLIPwgzrx zaCIZqR5FIBeUN=6oi~=l8vOEU{KD1UX8Ohb=Q`L<1&9}VAq8HUtY7e1_l&QDDGP09%z?Qg|hP4?g0 z!yLhYO_|>yL_Too%dG4EYnjK^KjBI+d_Tqhp0GW*r_W^nIdL3G1C%?an{tN^l{=^3 zp{4PBjY{3cNd>J}8r(k=D&ZO=+MO#_??Zp1j;(`XNc|=G=bz|$?fM^|NV~cfC|7;e z#Kh#_PyR}GoHMtGq-PVc{ZuxFUTt^%H|jmsM6WLHHl;|%;FZFJhZ&Hf2Tr1qzj7vU z(u<#R*O^tp#m>V2CA;#&!)qDFP1Fnk+{9KFrDF3O2{jp6d^Kr@+4ExtB@CO&4l)TD zB6|?xcFw1G`(OfhE-H|1xo#l=b|)b&s5MN-1*UL#gx#sUYWe>-`wFPMl4aclcXx*n zAh=7Agy0^626uONf&_vEcMlTW-Q6v?ySux*{gcc&bMIUCyf=3ii?Din_wKIluCCry z^?ek6OB;TO)qY2T_}lVNv+rp*lL)~LxMOkDaUBiJuraO?FJxDSYA+^2Dq}U*fmx~q zW@%^E<=8_~Q2&O=0=~htpWyCKVHd5im0k9%u;4dvB2zUXJ?Kyp|L3#xC%*Wviy>V9T}0U5K35ZKMTqH4 zgpQ}YxVfv7LXT#rb>9l!aw*yh3c^^2=&~vN@Rr~@>WjEtp90ZnwSe2Z^q_5v@B36= zj>k#IzMz4B7ESdpAB>BLn)_7Z(ogPdmz!09(Vc*Hp=1>qg=p-hJj4S`lc)i79mEE8 zJbOescfx#m*7Gzy!*M%DSPNxv<$vr}Bf()X;i0R{$t)xP75!n0K27OsmyIdKCdsEV z4cVi27;60PK-wO`F52yvZY*Ucy-Zd-QvT{GzRO%y6dFsWj6=SXfEA8f>;8k~j8!NX zkm&%wRScL8iz1Tsfa!3TmcI0<7?Vg{<>*1V`o_Mff@QKp?>a=a9zlaXAcyu{tG&+^ z_i5@Q?F&KS;UFznT(rF*-}Ml#>g!Z_Nzr;yykUwGW^ z&!K*-ZA;3!z%>1H+kxxP{rwk!M2aA^bcHFqDDrnct-EJFEr1XadwYpNb;`(WgXyx= z{UGsX^%I;8n0XDbnV|l)nGR5vWVXrb5?^t{fpDel1OxnNGlyHvSP+0P@LUK}P#Aa@ z?TWXqK*0T3l}{!tFinFz!{oqjLXd|XHDJz?04Nb{hvo5WMD`|K z-)+)24`r3LsU)&C|C(?|V`j+1Ee|h@L8DlG@&+AY%l{Fy=#MikfqXdej`hP zGT9HPei3~}NFLY69%uUfYOkfw)Sx+?)vP%q4)N^&hI&r=T{{v8pYC+G-J z+I*v^B$N&vejtNmKs*wNq9H$j-fX$5^6Xsd7@%H-Q{83do9jb7+_K6*ViVc`Lg9+s z(wd%gAyO^ZK`18Gzwvl3qb`@7N6rlYq*Xbp`d0k!Nc*^+FYf;}9&=zP^LzF)$m?Tbz4Y=m=O+G??laJ#W!brk@7N;LK8#|?DDEXr7hT)j#m zk`t)4@!)6EFg3~gL3gy^iuohPTs-1FVB(+O6dH+cIc%fEJ^T!UVuvvbsDs=}Hvyz; zO*lKv`s}iC1&ArP=ZPT zlwj{N>(r}@|7FPd%WgM1nJyWN=JaP!f-8SJh|ta+;>y5hhnPoq-A|Cq=AVBe= z903B?!1xNFb^+uJUjjb>mq;;D7`zt4PgV7WrKYB?(ECfO1ghjQ-6?kqi?*(BQ}oLv3)@+ICA6w&EE>- znZ!lsY^ssOk>njnMN`2Wixr3m3>l?rV47ToWN<-;hjj)67s*G^1qDw>)%Y05Ghx(y z&NC6d>Htmy?VrE}1?s?EOBcAH41*5s2>jzZPvbO9g5e#|1;r1PXTrCA4{oyC*wHAl z*B@HR(A<-0)3qCi&}?m*2%sHfWoKiiq-<;xOsf%Y0f{E~ z0tw83X*Cf$KvO(ny_Ria^@J(qENfaqH|}OibNlSg$9`OkHw30i>7VPFKiRYYqTDe! z%=+Rj4)`R(;!xPWEJoCE_p|Q|XD4G`9njHAu!7uci7dVGJ5Hy@tatB0I|1E{vHc8T0 zSHG_YQYu2RPwg}t3rfEXbus{NIZ-fwd`}ejm;i9(-}^&xeEjBg3Vc=}f#7k~;-?dO zrm@^ZC}l`Vma`AVbvOcOEbIFlT`a(t5XVsD-<<;YjArSVY^|hS>SHlXq*S}EyBVdf zTa!vSd+g1$U+qALZvC0bR_ooHwGeIS8ak4x7|q>hM?T!n;Ep$qqT=Km#%P{wz>$yD zRg*S9_=v6fOUvn1sOpr0*Ilt9N30RNLqN=t-s^Xudj{0|$~@3LPD4jlUba&F@YqL-lI>7#86+0$jVf_V3ZAylV~UF^Y3* zt7+7ZqsKRG(YRCaO7?ch8cO0i8rc)KQQAF-hoPhM=hn}fm)jU2Lp z5Q)xDKT3%%O91>kXCNZvwu0iO1q7fH`3ncl?khtj0HCt4Ree>`XAx7dh)7Wv754oV zT1mul*buf%`5W@A?5>=#pfVg+nD!g9Mt%^%GbMnY!omShnv?U38t(>5y#Vkkcb?!O zc_)0y%LJHTP_2*E0Pqw&iHWk|N^JzPz4=MNsVw{H8gMG(-uE>RQZ^1fj+1cc!_nEX%ugDw_IcP)k=?&sG>0Se1jLl8X)p2d0kW{za#yUn*K zjv;8&`Y`ow8BlA5?+yW%=RFkC0T7jJn!Z-7GV_eXdvIA?{=Xu4W@h{omHc-{51ooG zjH=Fikjpdd?=H`vEJ5(!Ir#(9hMJS)sX*=yB`JPZSQ?Fc77z@2XW)DXQ@(1@x7)7u zg9dhu)rVY*ZspA|ceI(cs|0n{HKDwoPyj%52NAaRG5)c@U0s1y6N84{g$4MZ1si9&Y0 z_&j2VS|tIpLr5)g9ONh5^Jb8{vkRIJZ58m@d$AECG}X)^1D0ZzBch1D$-PG|K(9lU zuDI#6soV5PX^o><)ApG@yH0M_XG<7BSPHZRDTN+zt!IR8>VLj;e_w0=6~PIz#L2T@ z@;EW62+B_uHH2lX$jXm0hiKU6 zh~+4urnh;HMuyN6gBsAKTc(%V>i1`@hg8fRF?M!~fYPN&TN0l;FXPv8APaJwB}sd| z8~JHWEX%kykQ=JTFOUmT~Yh>fT~k;t6us$975>f68n2I)>6eaV9i^;n?b_Iw|Gr-cF! zimCs{&_B$Kf9|9IV)Bw$%9{Hq-zJPua1q!`~-by->y5=U=+D!_at7uQQFBm;r%( zJo3_3=Nn}-V;JsT4LxuvH56Rb5q@w_V-W&<&aU=O^`o|`^E^y@z5iqb{v%nU;T-r> zTA$W(loQ%zX0EbiQQ&za1Y}`Oc4cmdsNNwgBH@~{F0|@{KN8>6dYXSnz-mBI=WL7{ zEn}YaD(c`%7f-BW`T(iza21(?_Ok))t}+?O!c@vgDF5?0`{emMoLjsl8pv4u$ANCl zjQ{c|w}aA4?gRTAV-De8s=Q4P5fk+R$5#uVsx!@G&DDu5^^_5rg6#lhm-OknGCxq8 zpNn~gIO5$l;*iSQRE558tdB*D}g((({XG z(yb@fiQVI(KAP2JJc<8<`@cX;pU=uZ%$iG3DAqsDwqj=dD~eg>-%@tab(55!WR3H! zuuk)#IaR3+i3+6_193jrNs|O}-d^bLSu<-k(BL+P+qW4Z^-}qLv$KFpr$HK?o48@4 z9WAfzPR5Ad`6QKbP3M&nH$yLhWlxPDCV&>d$tl!Ld%D7?o~9Zaxx;NkuyP z^pang8>#YYFqkQJDsv=6QsAwfxGv`H$JxNzE;Otnic|42YXVK?uO9^7c26cohiSi( z;6BI-FC3-slgj7y2cof>zl*z6AEc9NJ@a~{nL!7L$f-`lEupAKLx-*LT%1;26qT+lS?2O z^LX{>cCOHiS^Pv6OL#Bew;VOi3m-zDsB`w{OZpAZ*8l6c5!Pf>L>&VO^OM$F%D+Kw z0-Ts*Qq+5uX@@(eSVrPtaX^M9J38G=mb`C@e&a)1o?;>jW))k9HUi~M zlPdFep(B#l0|=@RJ&#vH4YA`xje9)Hz(ot7=o{`M@sZUQm1UM7?q=3Y!p5XmGIIBq zfmDbxiyS!sa+5v_d7R-Ha&wEun%$#xF6k}X{?Pj--b`L6g7bS>n!9I3UppE69Tc7a zk1>#$8GpN$0UPk&>$*z!%U@LH+slDvljg5BGQ`!Y9$dlHDN#1Ir$RRlhvuF1-q5AE}=W>{+5I^I2R!%UqT-eV642_^YbpV1mPe5^avAp9o5aZ^z9db ze{2iH<`2Cu;?ClAvN*s0Omp`fn>ANj0S}5t`NwP`%#6=>%#iS3AnaIx3owxJ$RV;K zTBYvICps8~4n8Mj1Gx^gCd16l8ZG~ z6?K}SWuRn~p*JX~f&xz#`_>K%L1YWdA?wE5807Z~hFPjo_D)10-8Xu+iI*gt`dG|* z2d)C2+(Xy|!Sa&rgVqy#l|u{wrgtF^BQ8;Zfv6TzmApQr6gc;j0b+tkLHIS9l5mH% z(`)K1I&zkY5>=D-ZK2T%WzI4A81Hd_7#aW{^Dx4__zsPDg8$8RSs{LtmT5oWYhG>R zA(z28OSNe3l&8&FifZi888(0%!9`!-Y*WcD~)>8JhdD^>va%NF9ci5?5p1N z3B;zWYMbwOz)@oP9RMGL0uWBc`JONJ&4oAiAb6&K3?0GD_b zJfej*y8IqmX}!_{|BY1MwEq4Q`u1BdoYl<+4_aOatp2N6LCbA1?)(lblpq-MO&fEG z*D1iFrYV)A$3o!t2_K5a>6{`vRi?6LAsF6tY!}1nWn+Uv3jLUYhCkiNM}iuK)2AEF zY$ZWf_VlW?Cjt%AmL)c#49+yo%XGv~dc_TqAf+j4+{rhITCgaDpz}m>GObV)Yotuo zw0&EDw6-|O*i=GxQ>9;AvNQDFv|QV=nwOPo-BN2DoIz{0yrYIvam1=-o6BGnkaRpC z>9G_Enys72FaYNiDbtP7$r665KD8}`o(8E;zV<=Ib=Bfy02qRHEGX+_{qhYo8^Tgc z6YpPmy*JN!RI4me09MZb0#1*a>5rH8FaET^o-4G7swgrvdHz?Vq|`5Yl_+M&6$$4m zIqnp?H#$xJfGXF4PKQj;`#8sc1$GYEv(VpfEMep(dY6 z>9#M1i*CaAs#Fc$b>AqfCuI4tkLSTy0>|Z4$TE$HtApH)XWl4W#d!gIuX!`-hm{+O z$Eqxd$%p=Q6}}H|IMT9h12{M;v?a0aZeb7sLYT?yi?NW}*i`HfD$nTjHwa1hT=kzt!yI zcU;awjFOWpZ8bHL+^zFD06(mOI z6eZ&@1o#A1Q7HhZvgFxYMF7FN9YC-K$QyGfXl2GECgJqcl)ru7R{_HH0~g)&?WYpL zqN-Rrw4vUe4mXzlI?QSH0Ka*`1HX_=P7kH?nxNA)MJF5F)+haZR|Zh^s<^{;q*CYtCecm(R=;t5ahvV@^ZV1zFeN(zLEXI zmHt6x$O{B@|BplBn3?{h$pWe#1f1m_XmzMwWf92~gA|YCOIjuc;>t89k@{e>J3p5= zQ%NO#%=~nNqZm?1zBGwN9yTsX^$S6-qAy=ppv<72&_OL8AdE@4iD$B1luP+d zFxxQ}N8ihWz5i3nw!MM@t)19ZO47km3l5 z;g?xsMEQDjM^i8#JMN(UGMr5QJxS>&$glN#HG|*CznlGRdAzm%R4U0+Kbk^KbHugg zywuTH<7R16#WCb#9u!PG$ZViuE@9*-blK4K;E|wC-=yB~`Kqq;GFr%aFQ@=6oqO1} zm}ZR1Q;&PBi&AwD4|8?&z-EanLtGOVJ>e~O`Ha{il~H*+($=BpWyu_!k*&G?QXD%0 zyLGlADb^m%wp-P;+)N+Pr}klkGqSn7*+g1RH3S)rmWCUKl@dL1=;_4DS&SL8kquGK z$@`mrm5Deq)lQ@t2OGhCf*_emJKWA=2=XZmX zJur>-%QwrP;KXD0ug&0m>D;fp(!lyQF-cEowH@Og>u#;8j)JBY8wGK26hF^{}jZ z92Fc9T9Bn`@z>O_(?Opp9PCRXS`h8oX%g&1!a2YHa}YD~2#jAVs$9DE1>Re>N*yGK6|J~C zSPn1&5*Uapsj+H1Wk_kwuyf6*$q_VkiuWjBlhOxLgbc~cd?oNcBrq`GMkCU5luYp6 z9)!0ckBRUZBrtFibCl6y!C%N>coG)Q@6iNEU?HZKeSCTcLF@pp=xMXqT&^1$Q8bwzZUVAmv+MNBBOavF{t+_vH{0nFN%_lHb`Ah;5GM zYkwb$C4a~dIiR#5s3*`Je#h{5e^%TEFk=Er#%J-sv;j~s#IQhGz63Y~#tRr2m={PI zdh)#!Y`;4%^WB^y zQGLf^_Vi>s;d*dqXT~ZLsY5T7ZMbmBf427e((H-l?%+o#IF#w>N&<~X2*T7l?mH2F z>7ij)X2Zn1QxX?X@5Y{DcxRgk?B2v!u4}6{8)-1)YxbH5XeDO`P z^nQVE!v_cU5#|5u*Y;W{G59wWK2*5hzdizgX%Ig6J3^zRyOCl1PrpX0vEM;~{%6-0 zm<@EV7$jb(0)oe`m+=10mMwKFmiQ%Rj}B9rhEKr^8qb%AJ%f6tQb6NrVgILz$N4?+ zAdP2hq_1yh%kccqv&|H(K4*h365+m7taa=zHI8V+NiK!(zPAGgpQ&`pP~``0r|1u# z%LQ*AhR4%lhE$nHXM5Ybo!h z#Y&n-;mA`Qn)FA9PtIrkGY7>SO0h@HQn#l!w8e^h= zUp;x$-9BJ-Q6e|@4NpxyIbC1W zUL{6eDG}3q-nm_+P650I?zbCj3yrI@jhly*jrEUicL&XsntZ(5XXoqv8_i7*PggQW zM|@2@botPj&36ZvhqwJt?oYpnHLqD|-VOD6nkYIaDLjrB+;ZkW=6*h~R=krdpA0RZ zlqsKtH!vqMG*2>Er9ZlimHBIqj)VCdD$Mb{m*nvA; z&&&qB#hEMK8*}JX%|-Pl7i-&xyWYX}>;}zq?c=GtqvoY{F!T?eUH}msPrZll$lh}Qy!lZv1ra#8I6zC^cNef3bV+|&oqQwJ%OVlL z_k=}vQN>_?&rU8BLn(wcZ(H{nc6>o4MM*CJLoBF2^*DqfWdr#}E&$_m9hu>}ypXU& z*8H)X5EuL7r0sRE~!p49a6O;b_xViG?4`Y^MP}cC>z2jBxpXRVA^TN?`gzMZj%;!L@|mb2@T96N;brhWTd|_NE=#_`gtD?oizA_dqAj6c7DR!Aq=sash7|cg zX5tKUx>Kxc*S%D%|5NuXo{tTgGjF&He>h{fMq)CWiNo$py{Q=@P?fgr)?`nN4N3tb z7@5UZU3c%J?nhNO;_@yRx^Tv1jYI{qI;Q;d4);iTUHlQ8!t79C1I065D9At66F&mQ zaZ0GUv8b>tJ5sVCs45D&Ddm<4CT3tEzf5is^bFXhaK@1s`345;L!{EXC`RJ2QF4_~ zU?aB&h1rC+Gx5&s+{+b0%=vX|X7#w{yz~C_`!Gsg_aj#rxnd4QF`-Q{A@k-yBri0@ zI1z-a2j5KOa!P9R=7b(cQ~c*aR;YaSmTN}J022hhrx9wMZ++FUvOy72$$Svch=r zmw?~tpOzT0I<+hV^1)?|5eRWs4|7!yW8zpeX==^c#GkP}D%`}c@IHF0 zqPgcCf1&RG5gX_a%apzHd;izt=~IxkQ;@ho+Xf`Q+0oe~&J=_khDrjjPqB>(8P6b# zgmN&o+<+yZ;@j@W!>Qvm{$mQRb_y<@c{}tp-Jk^?&JO|7hxR9C`+!XmYYxtHv*JD({ydykPVxy#2(?NG z@u%C-d{OAiseK#qlIp_)!z>tx4I0dMNvaI_vuS34SS-p2h5hxx3mgVC*w;1K^~AF; zu01GAu#lYjSHjY*!Zv906MG*oMxH2@kHEV8YkRZVIGw+oFuA6O0Y5vO?^O{Tz)W+) z3{&>=wYG3gAT?y_Ar=P;wxD1;!9W`??t7XtsJ`(>7vqoHrOgfu`w)|?g#$bdQ%JsN zU=v;iKT|vmc*js_9bc}s1A!T>FE(BVhjs>ejRtvr2)(Fe(xxoAy(n8=PV?RP;^yUY z8_!^s#n1Z!sBD$ZnggxnMw{{woAQ8t$or|89;nKE#;T!;KLn5Qq9KKi8tBSfZ@3p- z{+~aWQNxPAz#;CJRFajshUZ0?s`5>4+3gJaInh+!7Nyzr{^522yJnJPi(y)Z^;ME7 zV#K32pR!cl-NAKD$52ds2}oQ;VKc#x zwU9cj^vuP$uiIBe-1(4s^+346=8zN7PB9oc%grv9`^akXq?dRdq zJV=>K?OOOhbzL;thSFAHU3XwzR~`u^DsZXCklt%9c5QmtdiVrz)SNB_|&0&{)W6!J#Rpe7gutYC<(K};U zrC07=L>jdB~!dmaAkf@YW8kFL2N-zZE`_$0R&Ot8$(h(P=N0k^k_~g$+(NI}H zziofSje;I4r6Yx_(4b`%53HQfp)8p-Ocd*uGCsc7j2YVsVd<|OO=AYNjUk6855>sG z?s>oDLO7B$EHp>u0JgW*wVCTMneAh%(tZ%x+`4bePdbu@0@MeNLPWTiIK-a|ektyK zeV?(fq)O@lmgqjTzEjj)f)-}U7^(gdmNf_BSrfYWiUZPS&w*18ZDG#d#6HNFhBc$8 z_cb9P!t23~LuE+Ef3<`I+bx09Ey^W4R2mCaxYZbflbOd1b`S&UEu{og)k<8v6^@8b z6)KAktJCDGJ@+t{v3M-tgHd<^{0Qn#<#>KhWV!@1ZQchr12fx#RKB`5T=03ckmA>z zW4Q#QIaz+G_%e;q8*-c9D%oeSHO(B!JLG$cAxF0(_v+VlQlHL!FC!@=C1iQriR_TZ zmO4kA#he`QsMiNY9_lL$;)jEH3=oqVZ~df-UiR78Pt{tGVAnFa#ek*FsVC zLpqWb@YB2GX>ka_m|>ytMmq6+_*`_zHiaJ+l$6O1yAL_J8lxR)`lU>5A*hHFDEv{W z31fEW0k?sd<|ZO=rI)C%EQ-S_@}We1qy&xtmVw8HJW=C~`M0$KSi1C?;z%uJ#29Ub zZ5VyAdc(zYTK8&F&s;hpSFZ^z+~*!lsGnqiQF}fA1#Ay$-uJtsFYu-liz3fq@UryN=7dE6?-R-!c%)!yj99tk_ zM;kZ4ir`!AK3b6ZMY$M!C}%r>DIl_f`_pVv3%K-pR>h4WLy1emoAWQPqBeGktiX^t zPZab`O2G14rPHAa(rJ}scqv7BDaDa1QH>Z%@b)pXQ$RISoV~|w$vlk@}J5;F-tD|yE4Er>+7OoKT)j;ogsh#+q-e$}}%(tcPs9L*=8+Z@V%c`&w zi(X1o=;xYqBTJzlWAg9r=&tYR?(`O}!1kJ!{2o0(vR|@nU9y~^+-t&CzItFkzXCP+ z=mG!e(a$$?$=hCaB;ffD)bpe2<)iBTNb@BYvpc^3N453HN)El}j)UF{Z?O&T*}S1j zY4+E%@)j-aG{-G#@9x2y=MIHY=MRNGf0g!x39^IDl%OI^jkyhR3(kjxIUJ=sc`$~Y zsw!j_??w!AkO*9M5a^>ucp;#iNkgK}ztbaYYS^t|UH{4m)6a{PcC=MNH$QMRyuK=t z2BZ4!KvA0!r;UtIZLiXVif{>IU$M1DRR{;ouS67D$*6FWim=wAzWsxBbs!@nf_6Ak zQND`#$G0}ililf{dPL9l1PUplz8^+a=F?y}=EL}OpkVDR<7H1^WzCIN*DEj{Dx&%Y zlG1Xxe<%>eq1hfC(MiS#OjO9^R1DS%N74~$Q|4E)!m7vlU|k-F(H)3NJIepNV!zG; z`hTl9C5C1Gd78#TF?>~-$y?~{H%wSvNc9EfigfMbn$JRkx}7jsJ0yza!I*YZI;ANu zIv1$_UQtZ>{B1zvss*NX0ZuC!VMm~Esdv#6jf1oAe=D1%ncPbQMo2&-3`nAsOuHa0 ze?L&28Z>H9*}M@#DVc6Tn(11gJvSB5owYyR!3Db0qgb%T4-AIjc`z&XBfzLn%XN~G zfx)c*HR>*9{;5FBJnR%QMxC`?Zp-(>^L*WWQ;DQEg9%Q7mCgz$ELPr~HLr}|5V-lg6a zU2hzY3xEj-_%i_*zywfAom|nvSSZT=H3N{kkP8o=_EA)T<@C3=#1=)xU(tY;$)DkY zx>FUY13mh;;lTl-na{X(#e{Io|Ms_+7z&rR8~>T*4Ma>78fu^-MaDF0<*ETD+h5&g zQXFvy(De;SfG&nSKiz^q*7@SH3{JSPIMCWv3OW7K1w+GiTqT;iDah9XjByoVt@HaF zFwCOTW};Ry#_PSn#{`_4&ZT~!4f~LX3t*kKXeymgb$n%TI4=Uqda^uueTCj0PhmdT zZ%j%~5v~>0Piuw(OPq)7Bx=E;YIu5(y&}=vh+|I30sMTu<6g^Myh^v>`i=pDBXve6 zmCIX5>o^|Koq|axh>eR1FhM){Y=L#L%%Zx@GRMMK{`L8X?kv7#Mp96^LRHr>7~3<_ ze|eKdb)Ut*Kd9sSk=!n!LxFa(G`$AbBPe+j)JbD@yM&OW9~b6S7SiRN(ve!%3xaR0 z5)hLqnDB$DEnp4}2)U)=`Ig^MEKBnR^YeIAZgq9&s?`Pt4}a?(gQo3*;OX-f>=Tsl zT|Gecz8eY}n_oGlB`TpsAEiY{eG_yg0%M_SNqDypY+SEljf`Q9NSVt=m{#+>Lfuqe zV2?Uclyw=B3C`0l5|h>lMcLm=>Va0f?BuniZ%sny-75%=Py!Zye_*4LLiDBu;3Q6f z%F4gpq`h^2{~+}qR;mY9N^rj5vJat??y;+41W;ou^#_a^DDLGZ;2j#)jY~8Dt9&va z1~M2Fnjm^9XZ{rl%po@e5)Kb9qB;=-!g>G&nXO_y4!?Dy0ad5`FQ5Vb24&p_<&^z0Z&75!SpHHkt5^dL2}qT{pT9Z+6(uVLLE#$jCpQc+C~7#WaE8u^W? zAFNyp1p{v?0LAX3seW>M-7_D&LUQDP%l%Vkwj>z!TrW|f!*>ZJ$%6MomSj2>7xWOVAaz^%?JDuhbz;~} z;wBS5#J3UIy@;v^N}L=CTY0R&-y$t2|jngp7#H%Z@yp5Ia)7)Q$kY~OE~J=oHM zyM-X(fK)w}wI6zzA9|S|x~wbcEzep?XkZ0me8qQuMG#_X_vf|uvld46n{)vo)&r%Y=QWn7S z%RQg)E477XeCW(`BiK=|5;@Tqs%K?$R-4Y+jF^B?Ih}C)u30*b2`qNuAdn$|UllHu z6mX~-(pgl~SkGaA4icz_eu&wsq}`H9cST_SyCJ4Tkf4scjP%eAv+rgjF}m^_aY?() zbksepT&LIsosIC zr4$sHCB>)0Mo!0Wr%GFc&cPyG=_3>@uU6exKRMucCbM+svx0ap$)qizq%DP|Ee%Es zRlhH9mOj_oX`y6}oOm2R!Hf&O8w#dxjjHVCMpq+8RXsS!;qJ=6zyTB{@8$%OHY!d7 z#i}L<3?el$`USl4 z*KD&#wj|Ss<6~|JdZ+`IjgLwfm=^c_kUAH(Is!JyJdB|{jDcWT^q%5y&4hp#vjw&y|6gUGw+vG2c)l< z6*Gv0pmX=p1+|$KyqWd?U3hcx-}?w0(Pw)?_oE2+qrvy1k`N;XjZDAK^1rv~oB}$I ze-EYu?)PB!LSzAZXfqZha2=seWqyWZi%I;9e;wN-it@pjl1i0}I6%Km{-~}WIt3)B z#^ujtIu?7tSV$B}s@c$QDn45VKbu3!9p-~A=7WDG3uy26)>dV)Qf2u)s~25Vzqj`M zB!Z>*5T-6t6153Sg%RrrZHUSwWpylW085L1ZDnZo%ol@-ZTc;=`23*e; za0mkyV4M>7vra(-nlrBYU61aMQSysXkx^>OMHho3-{>z>%CFR0w0iKl>>F3(Zyg-9 zD48_(Zvkd;fM;>M%HlxZdT#GurYv0Mxq-*$+`q>0Y(>8pwxsAY2MOliX0Yh?U`LJl z--qG080@wv={vXC$m9*^bhpLdI-SpwqRsrQ{6j0SK=^=t3KD86$C;|i0TMW9(fqp% zeWhv!6AG{$|MslLJKLc;kIf{u%`?zkHk`cWF;oYYAq{_?TH)Grnc<=tF=UZdi4+bZ zT=TFDS$(VyeYp5BRb)UiZa_Y6pwqy9G=nzJqa&FETJ6`S|1NVh*e}LLHDN(9VL>xt zX&#wytpZF49Q5Z?kO+u1s6)lIuh$ODhsAG%Qk^84MMP0%2^WvNyt=81$m`so!M|EZ;!e_vfGOJC<Y0_AJr!+NEiaeY~9{l(A>hlx* zJr^ujLjlKQ>f_1HZu>&DOmfP+8{qFFUaQ~JB;HzlN^y*R=h<|7w=uXt7c67paew}} zu`{^h{$uz&b*pu_e|gLP_>BGf#^v~IaCvKNd26n9xVbr74+-a?%lMq;=dYtA;pX$J zYW}43-Qj1)X!X0R{HN#0a-;kEkne;qUS#+FC!g-C|I4TQ+pqs`&+fBVzj1Qd1e_EF z>R2hf)^TBhJW=XfZx)6P-43|2<0bNff~;ynb#a&kc=D*k7CD*6BTkc#|JW9D5HfvaOh}lD_*JCfWBXt#aN_+4zOPbw%B4^ce}O z+0iD6B+9s8VUGH)R%MtwSIrwr6T!d8=Yvy|NJu}*7{CGv?W^{p3Z=h0H_G?p(UcVSK z<=1vnPO2YbeXC#D2|3|^!1k>sM%*z{CR80Q)wi$6%+R;r7wtY=A~-$Nwf;?0r8VGE z2nl$~Q(^v-RR0H0`E%G?bey{F4`md9FH-5_yyfy2lFad3{?(oqc`5UQZZ=tY6G2)M zYmdiM%v-x^v_>(NrLn<&-Bf|S{r;ol^OPRdjF;?^Jjwn>O936D-sPSSj%%zB^tHOr8k(Xn8dpi58vP1RXQQS z^~<9(ILLaEij;WMDQ-(y?EIMTjB2)(w@5oNJ*%*{YM5>osebQJ@Yu(&N4`LuhZk`% zPGNqkJM*YeR-yfq`tyDLgQr;agmzJai;wM@qN4Mq=9QvC!)teoSpD_sCQuXv`_UEvTAMMr|d9{p-fU2fLg#w^LJ3)~~w@J&rWC+g6Ju|bubA2*zC7 zy!5Ye4;Ru#g`v?%wl4ER_ie>gjY2O#A`Ld{G6wFEWN3Cu+R=x3J6lQFx=B{{eE~{_ zN!cy1ZOegleXyWr<+^%tIk|dh+!eK>`SO#7xwv$bKHB@3tzs4radQ2=CeqqEQj*$w zGyw&XVlQl&T`lS5vCRr+TW3!jCPP=r`$9J0?bsObptq~}Wf6J!TYnO<=-oO(jo)wI zAPKENp>B2gruM~bVu>}j4Xjw_KM4?p6T(T&zmy98 z(2i~OhSlRGl9cF(FT_D07u53~QdUNcd~nV=8Dp=oc5JN!^t!~c=mOy|V;o*p!LB8> z2w>frg`17`e(kX{;%9!4)Ue2%rVdsHGeD9_Bkjo)!3p2l`Koug=NIVS8vM$vHJ%uH^kduCt?5%bR5Fw3gz?FjDCd&2_o-joF~tU6{PV05vsSj7Xvi?(j2B2`z@{1_CmqyYRi~vin-s z-2%2%Z4Uc=X5;m9P<3{^=F4)37cU_HV~EgyJWig~-|yojydMr=ArkU@J+PRmkVBSj zA-Ju04&G&V+rkbTPj!0*HBUuV^J{`p?Jyp^Tt%~+UyaJ@sK8InfTRac>8fhNYTA+# z9);l7Bqyf?o<&Cqy%IMbV>X;)qhUBs44WO(ZPq8Vw|L=MXL@p@HH_utiIkm$w1UI$ zHujvC_uLngl@F5zr3U20dd50}g5`AjF$`OP)06!_M&$kvC&6<}Zgi5W?VK>$*QG0^ zlItc4gBJ)dVl#n+6D+b!>dMMkP}GznxvbDAa2iBl3?ACzv1DsTgd-V@@L0HUb_iiN z-#?u4+?tjy(kd0l>RyrJhhi09<@;~!#rB_gKDwU`yWICryrXX_obuC6!Xkm;`;yxv{at{uDF2%QY-?msC$)IBOQ z;i;|T+`nt?@2n2N3%w-XI5WA}dh|bBu}M1MNRBhNMAE-6CE}$e+R{v|eo}F-2iO>S z%pK{Yfp;G&4JWpHiZJvyI4mX0!2vi4d!|Bqc9*MNK4@~?<)SU*a%b}1bDcF^`JZhKBsN^Fr~4S59o+BgG~TkS93|RRZ+jf? zSv=JfEfRBis_SD%HeW`5pOrU7s#G*3s*Ins8850-OmoPnM5~lhfzMemDg014rV=u1 zsbc!E-e*|4>zpKzB{I35GU%aKr&xlar{_(cp8lOWq4}lA)g8Ou&H%B>`f`!RKqMxI z1Kr|!B&|J7`;fGq-jrq8MKZ!&JBnJbOwsyrZ7ybZ&L@_Nn=dru80Bhey>dmj7aQI;@ zRMixzt%;-57fJKl%|gWz&P1%+L^Z*iT187S@Qr>SMtu~MP)uF4wjm{+oZcQc?qwF! z>m*6o<5FCj9A-uDH#ym_tgt$w!k9bh^(DizEcB;m0=h6}Zl(R)8MEan<*2Wx1^eFQ zod?YIC4BIomSkAoo~|qU#6Hs*A{9MN4h)Z#y?4@)d7nmC&b=%b>eaT7B)`3xoH_jJ zVy+zfN)zlHhlBl^935Y82|iVjdqm-p9jcr7q3N2Mtxb{FF78MUb6O%X_f%$5`^3)J z!t_LlZ3ri2yG0tUgEVMxOE{?xOxGB+Eb8WrGidtg3@mc;FcgLcZ>o)uJG>KHc}L!L zQ^p49n#?0gvZv%89F5m_5@(oGhYE}!x*0_fOtTyAt`a4;qD`{RztlC;f+ii`Pmn9( z+DJ$?Q@8D7`>AF-$rdn;^vQ17_lr#@YU|7wQ}r{kDJ$sj>iFMIq7A3yuNBuUw94$I zHZ0i=lckoW$!dI})K6w2^!SiD@xK(BQhyz@dF{%IvYX#RluK3Awa}us7cRbLGS8jZ zoeW_E9bd1r968Y82yPu0jw~@f)JDj74(*_ob0iPI1z6;8>L$SL0hRHmlGp8_!yDN5 zMP^DoN$By%`ZA4cz=yMwQP-2jPk{kq8cND(YlOHOt~EsR9FdewZ5j#A5QKnR&&FXz z{2$idI;!e#+XJOj8bmq;q#Kk*L6KBCHXz;I-Q7qx(%s$NA>E~Pck{j*z32SS9q*p^ z&l|(QIp&)2nRBi+*LJV9a@J6XP8>zY>}hujExF{9StNa30eeI5q)uDBKWV^oqUbE^ z@4IP?o*%gNs^?P;!DTM@gpM{hUoWdDvbVe%7|!#&%s z8cLvO=2iGez`aquD#sz*rb@WnzT(F6T>KH`77xM#ihDCvLaRn2TV{*#cagf}{sMg+ z=jz2`eEav=uY%=Tz^pz;uh*OrW>GXcC=yE790@XRtVdl~SG@-sTk(`u)DPuO)I%FR z>o0?HgRYDgoe7SbyPVNZ8osGVs+H?=3Z8MYrG;Eoc_&I%@|5M|+mr$js~IPL2Jn?li2~pjpLOHe5m9B!r8kNnGXWB_9GHOHL?GUu0icmlW>>@7?Y;pj@eUG>^99 zST8{8TCaQ~l_8jrtIPfUN)vieIasa+91m>m$bn0+cH}s0mONFDYGTST2t%T@mOIv`bSy1tnXtOo)z^G$964|R zL@q{){%bub)Y;s+F>dkD)~w`OeeJu>W5vd3-+?+PIQRE;;c%PPGb?1+m@;Vu~HgL0TxLwGLNN@-Vi|K{bVAlTsJ(O0&ZU z<-8T#+=Pf6-Ki@ZrO+MdC-+BYaba*mveHEsnfspDfagpkTQ28mr(WRxRgl)+RJ@`- zFtvfi37|5P=@QFi~TALt0x)y_u_+W5mQgGQ%~8S|NO>FR9G~+E102(s)2b! zcZL0H;3u^1`*5lqgAd)guY8PrGgTtn!*1|j3=AdX_2ra+$L}M-HbM~-XeCxto;6cP zn1V2H_M*(WeHCrnXYfW*KC;%TMLNN3zsu1Ab!?I=+6r}DNnl1LP?9b*kkd|Q6Gy+1 z19>Q@H@r@`Yxxw#1+WP(3rE&MR5?vtk#6N2MgI!TSBg`kVpyGnfr1b6vmi~fn;^$R z#SOzKK}W~M4|L%$Kq{yW7swb=r2N9^Cn{GYr=-TdOM<^@KrBd}AgwEc*~EfF@*VRy z7OClV+c+=u2UZPdy69D~T#s70RR+kgO%}qaxB78n$31dI;%%z5$FacOx^=+=D`3Z9HnoRfDRX008;ICmqTh(c)Lua+Jv}KjJa~ zk=QQ=`CklVv8R<(4E=yZkzgmSglXvHaW&_8WrZtt?k2U(XIKE-*aVde8$9~&zl(_j zRLUc;mL?{gBXOOI9p~?oE7Xo8vL|>lYpya)Xni_oL(~I{S7iNn;5Zz4ue%CTS+7J7 zxspURg#*4F^V2ND>#$z&_5Xh{X|f7TfqnSrK!A2I4))<$e7=7L&Ji^89B;YMzYRkR zx`K=!8kMM`OlpxnTuW)aqA0f93xvl(S zn@$V$3K;d*03u)|*$x_pR9l-Z@BVYJJR%RLYxuuSF2z17g!m^Zd)fO-Qz`9i`M>b} zD{ZPwd*X`b-;RAgY56HJa^q+AKapw4rD!U}Iof++H{>b}xRLVLjp}t*l%u=(D_@z- zmeS}yk!Vq9D&^aczf09QynFXIUdG*b@BE3L1Ev9vD_C!_g9h~2@RCMU{n6gv=mRQ@ zA>OS78j5kcru{>O;1&~bko$&h%xI!XFzSzU$y4gM+6W~BhQ{i|5Y2h?g}k9T7M+A*<$`T#ag~J znL}*XJJMn69^O&?^^BnV4$i}jxSbRzX|ca~A$rmRnVuvN_>c5?R`KqsKPXmb;_7c~ zS7?^GAZ#Arzxtm z*2y8S64W|#v%Lzl@StCTWVEujyD@!5Kc^rc4oF^*E)nDOPrR3ND>ch}Je^&*A6&n> zxg9*UWxH*fH&bMa+t}}XbXwRjssZlZMo17}QHO%3{9lUYE z40tLydjWiW_T|5Qg!W%|lF!?xKRd~ZW+ULNZrh0>My+B+N={X`Rjf=O{!jS2fh{yG zap7E_Uk4O@U%gR4yJ7(wkGBl8_O+Jiib#t*g=BGf2o*h3&88eKX)Wr@LKYuXH&*El z>##aYXv5hxCFm9}QbmlErpLOs1!A-&#slb6sFSEdktup?P>N3tMrNaEEA}OQS5V?P zyECTIQEgGzeg1AI^-0}`Z~P@r*jt=$2PaAlo!&d^Gg8cPQ#j}e4ZjZ(`4m}HQb1XHcN5GbZF-Gc=@~4zxD8KvU z_xo?oR|kWmvKn)XGih_zqm8&nW^QhG;TlIzqX#52NocK2t?m&&kK;zs02lXiN1t3z zPC9=atG8TVU%K-@J%ytk9j>_Fv8E9Jz5y&+T5-E~*Ld7{JS5@LNP9SyyT6sYmzB;g zmChEpkbAt9dz6(%(MZF8oRr;|$?eI_?Fq}xDV3I#mi7(H-7J+JmX;nK6{vD?HE?vI zK^qmgIM#K2pi6ti4qn^YaJzH#T2}gHMb-wtWbbk-4vAo>+aG2D%AfUd;=k^`# z0}1@oKqHpO_(}QIgP9vw*e@8Z4)gqJ#5ZAY%NuS{zi;G!2xHkBxGP=WDXCrUj38| zCo@I_L!E~qdO&E;=|wFR7H!PptqbZ`XU?}M(pLBZ&hmVs@)v$vzu5_`v{VWlr3Qc5 zj5QE<7Pt8f7#j5NkXEBn<(`O1QCOB5_2d=IZ5zeP5BI#6k&u`g3QR~xRhiMQyYarE zZ0!x#7XJ!g?8+`CDIJv<;5x-CDt|^5H%W?bn}8~YQ7**4JR>zkX$uxUOd?U~CM)~Q z&nh+y@CUk%m&AM-k2_O~_)fdx@+l|~c-(A0Fd^%&g13Fq0wWA!L{*n_l-0aqMr4;F z_6i^TMOyQ_9SEgwB^ms)uH_3{0R`3UZYz5ynZsfUYwz@0-}>EYc{v3Xr)5rIos{lU zmksP9n#G?p)vwPe#q@>l-Xr~zP!l{v+9>V{8t_*)Ux{U=-u(7-${I`Y;Q^a9ydW8> z(2l=7FO{|z!b->LR2O2%}Jrosa*iGTyL6K`;x|ITY zd&Pbuj5m)Z$%jde{+#O6u!Z2+ z5+U2GLb|2pqeRl9x~7ba?{mkz>yB=*w-6CXs?&YD;mrutKVT~a)gtk$9Tojy#cL~XLEY`2@4CFbiYreuci<~z-}0g z{v5idoUPD@#U57=^9ehCSqlU7u>j&%3G*`2Xv3sl1U@Bvmx8>}#}0Iw5Dgp9driZeGsm`a&~Ob z)Y|VO(t=6#tF_LwK;lMN_?_lP_#!n>s{GpqR!-n|ul*zjQyUel=tV=VFw zM7?pB?^9~bllEg$0Nq0>Y!?M`Kwv!QgU;;v#QP(!5K{UEgZ5a&0f#yc;}<0J@{cXZlRjv2zn)67Wgvtl zj>mlP(HN9a!lO3D6c_=;nvY0K3rLe{M#Ga3c?aXN-VRxCmRTA@=aJtgdWC7sA2C^> z$@F(;%h~=1;;}?S2$_W+xsWHHpw~aN`n{p)%t%_?M30kuW zC)GBeg9`}&!L<-?N+C|%f_Ua&8r$4&?GxlWFYkc;c}Ato=k8{tm+ zpw@+3{dTB3bJB<%aa|yFAcaS2{4rZ=qXPm+v^7z zJ$5Xwo{m~|3?-ldp$rjHi)n3Fu^Rsb*W-K|FF?fNo*BTK4~?TlWI(%*nujP}#zXom zGboRuLwa}#(qT>^eNz~jls(`$`s4LZz%iEZqEm?;j?#?#SF(;;CKM4L%&HtF{y3p!N%!5!&M{VLG4tN+c99gNW1SCP8~SBqj@%^>Py4 zs|o94YK})3b4+5m(;`wLWuZ)Fko0{KOt{mp)nue3=$x_$?Bj)f2^r61ptv_)I z8U7(GXeyn`okd~!3A=y6lFaKP-?)X8Z&$nAt5Z0~q`Bs>CNhpQxM%aVOg2%#++0}{ z<^cDea$d~pmvGzUX!yO7Np0DDjNt~Ii-uz;TzVbM=X!aSlmH{M5Ur27(?^Nvduc}# zygD9B7ya?5!NQpglTq}8ZS}dWXNx!nD>AqSKtW~g0P>E+kzu^#Uvx@8PAPcWA~QQ4 zmuQUoeySVNyZsR_aDqGJ1as&=`5CPQF)9=anAzCoAdH+(bts7XMKiZoP+Jg-?tJpm zSCdTD5~E(rDSpzxRbNe`&>>-7{ydcMD#;lg>_hl33X=ZsXnAz%u+wAjocja{Ng8x! zebAi}cV2Ga+<-m_fHUlZqA9|y&0#dv?H9#E-*@ypZzWiT&N#k~t0vC(k7VcUr3~W} z-qr#T&2%BP9i6~q&|I2L`qEsdk!CudA@(Vg+w9<)BFwgLYQ+6qymxjCD`#Mx9?9DM zph9ZNnZEc=@*2YYy4*+n$d4H&0oj^rq6#}bOX)13ab2SsF0^f!sF1#;<$VtYRNP$F zg0?^hw7F)}marwH9IlK<>DIJ@CkNdiU(yRa@fY!_?}nlHa4{9|G!r}pRM9c_S#{{? zk9EjM`h|0jmqv2v3a`aKqat3@>Efk z5vvUP62b7~wz1pXNG_)fnXI8Oa(;q+F1m?j30RN$R6d-(kF*hQaLS@hp^TN1kk@MD z?bsabS(P9-j$-v%a#5&Hwb5J-6u}`<~T}mf>s~nM=2!??xB#CcslN1eB%cf9u@nn zj>kzVUmi(Vx?4JpDy}O4g(eY_P;=^5;|ugjWWK2$C_W}m?{wlG)j-@EI5(dg06H|{ zNwkkL0y5u=>E0E#6@eyZCwO%d_9i9ixmy)_w1ByR7Fn_z zk=CTs+|Or1$EW2GEiNjj*e4;~_Xn>a;soDhApusFM~g0C#d~Iz{TN=zvDAowh=czl zQRbyO^B(I28uW(;pd!#3CrP*cPxu|i1PFzm1i#cVf`D1m%PIZf>!4&lS;IDB{fsXz zeFM^YCxjt@ACOTTeNceezPDO5%)|l4p%$>y2=>Qg3)y}mJrYu#b5Qjnqx}!eni(t# z_*dWY-@jzmG%VML?2LqcL19_Elhu|eg-Wc?bdVU7gV5%SU+hKJoXIHd&v={0L586q@<~!7pR0+Yk39p!>g7QUcnkSp z0dw9dA(2$VV$z_Xw0QLjN(vE?57hW(%oT94N+rID{T%Wd}<`&7Oq*1mgfPBv}GmHVZ<0rP7nvI9r#US6A}4> zqq;ETZvhZ187TrrzBPptr-XmB;TP3X8I46O(jV**zAxM~@WF8)&t-B3rEg+-eIf*M z1uGi;!#eZw$MCLR3QQ8Lz&7?!O+I})V!mn6dDWb+fs)J{bLOQzC3g}s%x7z|;Uc+1 zuEr@&P6E0<2KgLNCbZ=^`wA+L`h!H3+;E+8oQVdH{;om*DrT>ae)KMFVAzLaBkuK= z$!ktD3#S+5<}iNfy!>&4Vuw(03>SwFHUZplkODgRUz*)`8oSZ3*FZ}_?KyQQ1-K1s zaY%3WA=|vo0GE&YllRq=jn5|Y({RAmgM$G-amG#Gmgc?{Wr0JrRaCk5iK_`?%OLWQ zpKaGJMc3~0L^wvO0El)f;wLV@{nTDb)P*b0+aC$C^kAO za)haGO<1Z9BFN$g0m~neaxZkoK3kM&4VG(PxcaPu`gZ2dfteT|2KXT0b5Z;xsRLN_ zF+WlJ-G}iijW%D4D&c|r4Z$av^2P|+CAx?+@j6mF06nelk~ObcqMo~7<##q+hgh%^ zPA`phXQiN}eI1mqzA<8T9SV;gzS#>{@&vaXfw<8aU5Cue)Zt6H6n1Ge+_ek+Fw@n* zY|qjdLh69))L@~QzQyXbP4tKN17J^J@q9D%1jeW|w$$Eup}c1GZuG~YU%qlu~BBOLTzA}HkDPe#< z0%lK63$u7;H$*H7c9mUo2;B_CDk?;NJJA!i`aczcA#@B>1nuH9;*9OrW3yb~P^qj+ zbZ;*sc~g0Ge*)cpeI*vtL6<5IkFYJc0lE8?ackqVi`Bhu_eosS+LtKfc9NHxf{A%$ z7NbcTy$PsZ@btP0MtX050wZ4O@wv6kl=GmFOCA`^y;Wf0c7+sL_l`Tw6_9g+M3jQ?L0&b zMHuLUjM0HEhy&r|d2YxT3P1x(1`_W?AF1I$l+)7|Me7o{I@^5|eFK>f(32Ma$~`AtH9W2uYOkV8EuiqAVQ+H>&(Ra^!56pg6&WxKD*#P2f{;Ln zy;dP@4+Tp6n-?=@dWCI?a6`m~xcvOw(iG?W>&IbvB!6eAe4)u_OFkd;LF)w#+1^;= zD4luKYbyi)pI#A%JKH-Gi8mC1_q>v6`3yny@RZBrY(&xxVK*-za(gmxzk%5%P8O^X zJn!h2YQjNim?c&90IcZgf}4X1xvICw7g*dCV4Havj9}LOiHy>oWo_wEc&sBbb?@QC z&An;0l|sM+yoimak_>%xW45j@0O{q{iIDK&b-cjy!mPUfK_LR+1neeW>q$sNkheLc zHGcK^{Rtx$>xmrSgQf(dZ{4%L+Z6d1!e?oU2q-@DAmFw(@cg(83mFCT>PTEMs*F&q zql2Mvf0?J713}pdNguZl>wEhA1C&r4AtloDl=O@Ai^oaJ^}v&r4y?FN2}h5Nns-Px zdPtg0?p=kTUOG0%5RHt@TOlI|V0#+ckN6e()lqQTl5!ZYrr1z*^=k~Z&Y)~`*R*}+ zHK=@#uk4cheXt(O;Nm8T#`*=tyo@VQTuB)DBpf%IeBQKLP?rz-xZm1#+VYdFcn{&i z^O+Sl8q?<%VAWXB2y1i0i#MKl*DksDZdVsKU_T~xNA05l+WDU?+jr6`f52R?M=O}q z!9KO55k#|hiUF|1@Zl3AEh{8bqgF!=Y=ycF<`QrW->cW>opGT3Vj)-23 z_g#%^A1t|TcJAISu=jW!F!`LAZ-lZ?H&SlAUQ@qZ#Asq76yI~~leYxzYapGRib<2I zzYJK8$=vz&@f;Ow$>+uRZBi%ylMxqr5qQ1^?v|RuU2Lu?dbI{~xEBPrz~n_Sswq6XV2gUd&CcPd00jahCY^b!g5u` zK!8v+?o{|S{yWIEZPgz%TR4c* z;GM$#x@^Ljv;Cb?W!CxdBTSM)Sc08Mw_uAA#Bc$8Oz6 zIQ*=bvt5Nd<((82pA-}slGxt59H}xo`Q;1mKO?jjn6JO-U+xO~jC`Y(VmOysHNvt9 zeTW~M*54<|VJ|*X0W1odegA9`JYV851^+3W`)opM!>f##*+485KB~HT7~>AR-A|^( z)SlSBStaK&pI&AK@O7{H7oR(b1tEXNSO~yymw%(Bp>;Ur{4?68P;yMSO=cIt<>!P$ zoZv%XOx})-VzAck7YWHAao&1DXuY?Pm4xd+-1fzXcKlM|)J(nJ*ycYSiAk@5psuJz zGZj=-$(19>bGR2H>g2wxeeELjS4H<{d?Osx>FOx$q;64-m^0yf*a|!GX*e(@=Z&qR z`??1n$_2%t(I-OY9~p368M)JBnzCBESofOBpj=(AJsUE|vWr>4W`O-S8wmLLSb&9t z=5SX=f*~mXBTKnr9C;R-Cl;c4NC6go${X7kjGr(TaOosftG9PGB^W~T{Vf%-w0E^6 zOhev}mgjjCht@A0iG|~qaJIi>_$=v*{I%HS z^+QMF=q`-7`ezhBQ&+Dc8-BL@kh@J1D4*->pHr^T6zR|~}OBNY2l?~+z6 zr9Mtn3O0wwWc_9Y9fapUv2X|;?s`ZtMC8L;9Yf1QIulzHtVUO7RwEKm+HmmajP!n< z@J>vX@NFQGz1t{x?1jX_*|k?Qa3DfRb?b%1Cx$n>AvkYaGr|I%q~v&s>eO|FNuERcdGdQ@?gUFz(>j`J zBsDJnCh6>A{9K_5H=rU9_N0?ZXSV=L0)(96x76`%Mw`NLetzQmm6-YoIJ1NT;=MGl zHe?Lk3Dch})5E&Z4AYDYB`i!CK3r`o*PoOZ-|va5xjM6=n}mi4n1~RA0^&V2oqx$} zhZCj?S*6EzqwP1|4!|g`2wRZs`)IWB_lr(W)l#pusrO$4<=XG-hX{Wuj_T{z5Bcr^ zZr9D2U@&BUI4I<9%Wqqzk`P@}v?P5S#jy>_P%-BQ668qsMIZhNQ!&S)L~ z;QYtB)8Pr5nHoI@Bk2pTlGRQKSsK z^J_t;ws7qa6G;pE@|tU?Cf33W5)2zrICQj!Y0E!1OQ6{7$D9}i;cGZ#^y{*WA@#c% z#HkkR3)?%09Iy>sYv6YKV|k--7wN6cOt)P$e0_N=$i}{zpiG9)8-I0GSezuUeemT~ zx9%OAqSracowT7}$UX~7dKxx$|Kjb-bBv4k0Bd_Upm3d2XS(>irZu9saNo1DZ<{%9 zT;VcH&f@8G9@U!!jUyVKuS!_dUx+BXg4)AtAq-^36M_$b)Y`YrlqW5BStkuLxt$&WE_BN>vqBB!rsR2|0uqcLX)8%OkPJ0Dau9x8aLuf;yfU{}X>VMLp1&kv{ zl`Ut2YD&SNJnLCHOKm3pXz?F35I`#s`AZujT3jWjI>)i;begt`s$9>(kzG)n1hUno z+o#3rkaN_I>wgnVjz-ie$?FWeCoggSz?4y%Zd_5hG*|S$h^iHp)0V(#@#6UTmgnrD z18X9(y^KO`2hshLhGkQu8jWLLZ15M&_%X$?*F(y5G$TQc3RQp6kk|%JhHn&Ipy+r1 z=jaUc8t35W(MXO>HCRZvaQ=8Hu%P6m12@ff+uZYxx=QNs8BT&Vt!3sPwdn*#mFB)k zW*WaFD9 zEbgEDL+Gk8x9e-)Bb z_{cQ#t~0$4Pi?^b9DWXnPZheB1Fj`!jA>$Z567G2`%lCgug0oSJCv8P?RrcGl{c83 z=?k>_Dd{{UxT!L$rGrMDu)g1f3Www1;a29y5OV~?7tCff*U;!GmIU=zsDC`VVw$Z` zXI#3n9^76b`b9B%CE0+qb$Msk%Gji72-}tCdn)0Odo_7+*;8GFRLh)COuXt3vQ7Do z%Z}lvt%dgb6(eAmh~6#0STBk%xJ?71hqivQrwy`gS{o*gW*hRyF`nVAnH7Dy5|nJP zsbYO3-!sm-uouR<>_l#;iZWe90_kmn@0Fehy~i0EIRx1Bc{BE z2fUe9fgiV5xbqjS?r?hJnUV@xL)YHd?73x#iE_t2UM|0H)U=%-a^UZwW<7SLX6LB3 z;aH_}KR#>nzvlz0SM-1Ot$n8l_$OX(-2OQlj{ zbAR6|Oxt`xIMTN^1T%>?2XpZrFeZan!hy4x zi7Jc|*gy+{9{ih{FimHA&UO=Bg9R(s7Aq^}4tb2oQW2T6&OBA|j$su{qvw{3Ozqe4`>fhO&Q7MzI}TT1m8p-q;VOoBYs!njBrU?$&U9%rr#ftF? ztwGwh22rp7{X!HtcKZ&3JR{vVLiPnCobBwqz=05ymyc~h@Kx(-S;YIBY$@prV$ad1 zeiBC zd{f+cn7g~)nv;_D4w6?#0X?cnyr!LFR0f%YSV;G_ct;35Jeen9CP}7)V^m5J1PeWl zVDFkJ@Q?ax<~UJIz20ukaxQZyT|;jWjXQj-8Llxkz)};K|I1gt%r45gTx0o6n|>bK zT#m^h8Wv`{H%3+GR&`*HqW6divx4Y-^dY0t8Mj^1DWAv*01Nenoe|vfPC^?G2lUb8 zizZo(Rg{aoNTUx2!-w)TYGq!m)u4;WVqtV4&K264amvMY(Ho^l7;8v96`OV5g2Ug(|ov!u%zNyfb zW4gMBorUgbd8In zIzwkBCf(>zfrMSG*0 zb#}vem9WJ`kll$67#u~-6P@q7q7z8%l63RW9z$z*c1M3HAdsYk;VL%3l~(u$EQzpy zeg7}Q0Dou9VV)PSlJ$NBz?EQX3PrBlTd(I8dR(3tFT;UV>qO_*t|-rSDPZz~q79C; zC{1d}Ulbnc{+G!B3i4=w*2sT4YXK!tQq!(48Fo?572{TWvr4 zKUD*&ig|#3X`C?yoRHT@^eG{73-S9ZJYbpG{~;4(ocjm(7%5R2K>a(s{2CTR!S^(qfXPK2YoIkOk6`_y|5-q|GmFr8`U+4ZC3n_Nt z6oamJOi@PJ@U+?VuQyosh(QV@z0!-X zX-Oq(YK!ZPM2u!~fk-ey*hAJ+XlObw1QjY|+1VNal|ycU8_9DD`^*Nr0ek4=BH}ea z*UMt@v8C;@21l`2v#AXfUiwLf{*D{&5O8t1X1xF>AA}2Z1C5Y%1QCA+8;eXR%6(fi zgE5`#e@iJ= z2qlik$h1xpcwr$PuSRtGz*S8rQ&?8^A{L8I1`8(uwZ;j!mTJWA!4N#hSZO^NuHQ}= zgc_zMS%@7#P14feGqkOE-80-f;c7T{ysj3PDP%r_e{h!V`jm9HD{7o_w&;T_ZSiOX zOzE4vT1CSQCO=F^XJO7l%S{`>Em;ju=0TWNB7=^L9(cGWcX%T(8!KKa@2-Fa=0Wr|7Z2NMib^i zfw`yAL>EX>{vF*0n!DN=!@G7D@kWShB;-NO=5h!QOIJg&RMvKp`I==AY#t&KudI=1 z%T7Wc7YD`4WQdEb#xGEMfJrmQVjXL=A-&m@d@?>zf3-{XPKFj6n70rKBZd%hUlcYIP zzC;T+05l=xvPSDrQwEIy=fw}xrbef1syuf|rKiL?UXFRUJV}cO1OH{v(pN0GR;nU5 zNws8r(~px>@orUx8enuEVeYbXh9avE0_R~S!tHvWHQlv^<-e)4Kc4+U4KOZvT66&q_{fdqV15DY|5MxiLRWUR@3sgv(AzwGR6H>C znqTm#u670p_nAuLf;o**@WLl&CAz; zyQGa!`8u%yo#9#pvyyC(FHp-o%u7nXNp%v_w1uzG)RR-^bpgg%=)q9kIz!FQeV*%g z?ezAI=zvgn&H8e5E|jLM!~OEL8Xi8`MofU}tXWr%$z_>ebf???5WY~e0E($Yq_xCS zSf^r)xyX~Tuy#85yhuB=C{%2WpQPaI(qj}3Jjcgbd^xLMopH|b<*gC-PT~+P*1nlf zr6hCh5@P@W0^2Jy`T)rvv$|(=@7f8)8!2nR`s>OmIYSBM7JN(IwKLjC9%Rmf!?4qn zIol;)ShDB^oaqbJ0?*&Ek>WxJ)+Q_XJ#~fBd(+GrAVre0XgR#wbpFbdL80QMIAbgm z5p`-xZB;5cMpSW`w8S!gj!?qc-EZ-gk`_2|h>v)EKA&f5VB`xB3*{!dj47NlI+Urm zQ{Zuv(7%67k*UAo6)HCBP?=&sxeZWPv#3G5blruy`(P{l+wTqrrx1}&VWMkV1-cvX z$vPkF1p?V5F=wv4LSp4k%E>Cs+I+nA2 zz1~h<7w2UvnN&}~0K0XYQJm8(Oy%)G!vHv%zP$|qvCL=&AaX?ce?!G7_|JG)F}Qxw>H;+bFy>jWvG%oM z0F$`^lkxVcUvg6w2+~)PMie4PO3b&Uv^91 zfNX$UH5Yt@b8Fu7mjI?e{9^#X(6*I;`_Ox*8MFjo{!weo>*!c{abH~`gj;odWd`yd z$$R%I17yvNr=qTBD4c(39)oC?Hlj?eByhH9=B@0Tpid(+Gz-IK9sarT%a#e2MEimy zbKx=Wqq?h;yS25uqw~{cqq&>=-Qci$Q}f;LPV+SN`-98J$IFdcCTVv^wT!!)%ge{j z!;@Tiij{=4HO;M>m&rCd+Ix5po`LNpd1 zE;<{{HI_|}poZT*@+my>$v^TbKDy@J-znW(<)0o||6Yk3Xm!6~i}RQ_Cp2oc%6k~e zxD@xFHzzV`waa^0&bSN){y}Wq>R9wx4F2A!~vh;fRDd-8)yvTy(z_{PWswclSPs~ zzX4zUT01}c<_^EYFdesHrzivipCoH=?bhNJ-+w=PYZhLkKwdpB#1&_Exi;IWnO9(6 z?q&2@HG$XGSJ2yniId|FZ}Gv{*$dgBSUmpN0&zp9$#)7w;f$N#v|5YUzY&8})VCC* zOPuT(jA?^HQ{6{ouGlKAK?OHzrE+$b)`R(SjwR8~1l-HSI%m4q6)q{)OlhdVQOJAj zg78S!Ti;bq1w)9hf|%MmV#f)u*4W4-Dq>%=#OqLqYq9hz#Oj2K*;P;yNL0kVo)gAY z?TgxH?*AOC6E61YJItPsj;*lLrGmnxkFL3{uJpBC(eZ)ioT~C1R%~-j4BxkZ{}_hY z-vg8Dqa*9}Ubup+9gl1-WR+i2=MJI-TC@grl~ePv6lJ^dsej}7*&5V{T?cXCPL^2I z|8}6{|2Qu3{9tX28pxXbEv8GWhS0Ga^lq%m5>^dYtX|V02SK@|CCO+=Xm8hi59H9$ z<303{OpG!EirZXFf9!Ycf}$##(QYPp0Rfa2hUui=yT7fr`9u7@y9bwc-EK~QTV1EQ zYdlpFKU!Uc2Okw)Xe9M^Yw^tTJyp~b@|)F`l6?FzytJ|I*m6_m1Zvuk@SnPMY*~7! zdt{w&D#1Ow>&)89{lY@5_+#tlRQI~3qxa&iaS<_btbOp#?&03qy6#;~pVJBZ%HgaT zaa?KA+En+0mH)vG+H|o0;9BV+a2;{y_*D0|y(dQ86)q#*+1BXM!YPeAl7_p%HHW9| zK3->6&66!Bi&lqtch~txSAcW)vmdlk%N4X?wPZtM z0$hK_f81BmhAdxUS0Jy_iJf*+eX6qb}HqF{{G%Z}+@fSoOgxpa&=}B&kLb(B$Zs>9-tPf0 zj9#kw=!GIqkFcewZNFN9c+=x!X(vWa2-U;iANpFWi9A<%G>A&isF{G{@OIW>cJi#& zh}W4wJNdh+eP7~P=y4mOeFxh*jPWbmbt1yv;X}=hO}WM7AXPLTEUw&j@Xw)1N*4aa zycQ4I$;jz@<&C<`k#v(cnK<=umqoxE^hLG!_O2!p$=~l3HWDfy7Xl&ew}YVL_xr+7Gv)L~aSt?4PhV&serHqMC<#vqOk&+K;1^lP>sSShre=^g2kRCeJ=eQSK0Qs?5|!;|PFR+k^= zDk?Bd`1bd?qsSvep1ueHweIEAA1m%#2JzkWiQLJ;S_Pj#XTvBPF1E7g4krATWq!@C zvWd85o$bo(f9!HWfPRczU123t0?o zwkk%B6@NB$mdXg-Si#5yrKrrWLu2%l^v)rbtB__1uVr+osL}(1@M85}`o6So4Ua$IEg_;Y%n zxLgg)!4E5s^fzh{XP(dz$heHjv})O(%mP^lX3DTS2ww8^DDMvxy~vf(p<`8}#bf-U z2hh46;=40!UT9k%BXH?6(RIGT zP6&Jv_t|d{&Yn~2V;x2#Sm3>|iq0$@-lg_p0-J~B2t-=U8g|go2fya1Z$}pTBM=?+ zfAnatLv zU+e&w_Z7FPVx50=gbEsg3ooJ=60k%J<+uROVbbA|q3U%L^M4YrJD#zv;2;G+%!gE; zf(XYSB~oSBpo0Dnnz>5)tH1J`&9mTOvB#>si4(+c(xoJ4S~ zlNCO_!FCKBfE(klh(y4jf}Lf5V;F(L#F)(5Bt*%z8Vctg$}hBNt)$XMw_*QY!B>_h zN*+b?voCZ((T=xvvZ|yon8u2Qg9@h6U*%VaB;EHFfYHzF5X!d@jQKrM7HerHjHrwQ zhF^}G1_w2-g3}g}t3FBo8B|~IuWRYHtchCEWpAI9QKT|vXQ=Vj-k_9>>05881lR3| z#Vh-i-L==`*@2#H=uWjnf4q_}cw-10JX z;|oYkG4tZ~4;@YL^vi?)CL=d3UYLl29Kz-(tDXqA zFF6xNV|-(5*p2ZH_^*279f#>^8|)2&e9J)4yVV*u^r0xsN(F#XaeODQ$l^nxv5FiX z*H8tR#5T2C3Xl?hQ;o-3zHE&Do3cNm)&f`uVY74>DL*Orfn$Xi_SuhOfSxO)CWN4T z5U7-H0a0|kl9(4W8%0^@Ll}jX{1cIGauV9bKvHaG;-*}Ka_;U&l zxHvup7{Bh~Kw_|O0RY49N3sMLYF9PpI==6;O)2Y0=2v}Rus0XfQlA5iu~iPeO!0tp z{^!`@9Ua|89YKWvS(?X_Xavh2K6OH^gGA*F8=Ira6<@(sdA%ljvqt64wfO7EFR6$C zNImhY+WsXJuA9a+Dtmx@=$BM^=tqFD1b5_DFK_Er#}(QUl9a9o)~$-ME{bT0bxLB_ z=ROOLlzEfr?uv#(io5bXi-x;$iwRts;=;l1jTQG}+0_JE;gntZ@>A8F1ToNRPM}E# z`yZ_3uW3G9N{12lEKKcL9v>$J5$TE%m0{?w#SrG6DS z^M3t;_QXk|>2cbmcx7n&TzXjT;rYg}jv4OXUyvanQbhk-TmE0SOwY~vpDokma1d}~ z7;w%T(RwATxMo1>oZL&%l7uu#N}xWEDxD@!}8wZ zIxg3ACKUflK|`N?Ep#;j_JsIrHkqzMA2~{Xg>bB4A30r?)caUvGD&P|@k6 z_!T{(kgN0O9-x5_#`BNF+pPk}zBhnt*8cD3H~)`)3@7*j+8E^pt4t+q*R;}fhqSi0 zYLfY&;y};XlHJ6_LAEa;a)nBQ?;dWT4Q9F6H?y6SY%i_K7gZJdt_P1EMy_LGF|4unk!y6BR*v8xh8MSc^irfLHQvs75>p>H zC5R-ue1vmnujH}NA-LjRSCxy((H=BWFe|^*+QV<&%ogf;+j#fHpfR%$xHDUvQaDq< zc=?p#CKp#aSAR8`Jqo&&1&!1X-pIu{A6f}a{Z46YlD56sVr)G+HQz=W0ST>Sn{6YF zg1)WbxGl23;|jf{nz^eJpF2vccz6?7kcRpS%~gEm&V|NRJk2(--^`2T=ev}!!S!L9 zg$$EV3+u*bkHar&gU^hO!izObC-9QKNqjL0W05R}4|$92+!Zfg4%@>U#P@9|SIMW` zLyM(HILNhgHb6_<>R>3|$73~Qs%}BG$T^sU{{T+nA*6jDYV)Y<%m2gKTL9(pE$PEZ z0t5*V9D)Q09$W(iC%C)22X}Xe;4TU7?(XjH?(Qz%KyrV(cenmqU)?GSUZ#3_p6=7< z>7IAa>8YF_SM?o)n_djFexhZx?S<*hn#KACs`y5i0t==50L#Jns!RBnP+f%m=7k!I z%r~bX3?H7W+5zlOv>H|yEAFzv!J;?Z5e$BD=i;1bTo~{bmgOrKANo2Fr)nA*D5LvP zjk`3el&!9{ja5o~!%HJ!1c|bsdhkiKXGwxR#)V0c1lAJ0r@sNj<{ zO`Mwvm96|$*N{f|B)Y&07qFNcy=hOqnOu)U#5Y23nAp5-V;i1NM{YFW2(*bP3FFZ* z@q&H@>!wpfh*A9(an=+W!9tQKbxuSds3xt^GypUAEj_h~Flod1BWC_82DU0P!-^zT z>YR)|FiqOf8jtXD>14u0bBI3(lU@);N-)#yC1XgIK5X%73~w=IhevJ9nylmSYrv(i z?-TBNGjO5;hVQIQwd{V5>J?BJ&sh5QeNKi_oh0-;Wbf42E8V2T59uru6Au~UQxnwW zDQEEsRI+;7SC+{MBIIfm*}>|db>~LMhdy~rD+m=WXXjRkn+##-+Ke#aGWj~-H}Ek- zI4mwYEAKXoCTaV;Ho{Q0&YPQVdtK7pUA)fQk}hxELv1&LpYnG`fsTw^SadXxtntx@ zcI=}uPLa!~ei!b5c)Gyk$lx(zno*=Cu zV&G^_sGm1fkVFK(O`1-OTo?w*kcHMf6iF;xdt2;E8QRY%1#p_^cc5ac5}!@e=)lN3 zaS;btzO8A|3~@wv3zMM0#0zn?#F2h*h`PB5rCDff2``6tMw%z=CEP zt>XMvz0e##HY=>9y|O0U=v&C|qx>a<;Y?)=Pujj5KevjJ(9&n?Lw%fA0z-lV@e{S; zr}ypjb$fFY?vt!4+DIfN4Ew^jEUMY-3g=$<=u?#mo6^*{E7cK|=`51H0uyxxtJ1+S zn`f=qAA3hphEdtg+txO!ABP(U8K!p6DeuE$YlywTRDK z;;ZOolbWkn__#tKHr%CJ1f%4Y| znA@)nFp0^l)LMab^&d6BWO_|k@$;660xzwQNrA6TwDg$kD6;W&6nS6TU-}uFd=f?x ztO4nEczByJLd?67n33sLXZX$c3cl|C;=H8Vbwjt3JXBhFk+~`wH#O+;=!UlP`PS)F z-@vWzdHtx7q*;ERt+-I{u{2?BzRtBVStM`!higw>;u-@7V_y~tyyBuWg*wrsalHOM zoY9B<>O#dJV;GS?yCMXCGA+8g8OyGsGIf6gbE@btH&aex3r$`>X(yd-c{BaZ+w$ z0V6KTpHpvaQ{BlKQYsyW!S^>% zoiPYRw30MB>Kd2OZ51%@FvcTkqG0FY>G116)kBveetBy$Jpkvf*{wy6R;FOZ+jWcB z_vMoagcJ*=LZc@&16as>x`koAN&m1)pl^84;&QqLC>(j$XpffGFlXs!?*I{GjThAu zC>jko!QWd;#Pk%d*qe0OdVOr@uiasaI^iqAGT)$(RC-f~2LLS>)VSgtJp-4ePf1a1 z=ZBrSeSYlE#1i=a$f<>wd7vRHi~0qY`HES>W0D+7T3zCuBN=FB8}twux6d+tQ%ApbMKm`G)NMjh)&wdn|yhMERPlBt0eBWUUOXc%@N&nlJ|Vy5m}=hn7c>` zlbA^qRo$UMkzWA+dI3z2{3{JdhL?**nm!1M#I}Yx0{e8H0u#LR{m{{x4+WI~A18F1 z&Mzu4Xt`oM5dyBf($>aOYlHfQD~Uz8+T-0zn)URLal#FF)!)G1zQvO<3s}>^lc(n1 zmnRVur|I;5s7{NkflRBzdWT!YtG_1hQVu~<>gbFHHxU_yoR)#`Ii8%9lvnVRkdPD@ zOks{6BThE2b-USs0^E$e>v1^d+7DyK1H?D0u(XJK{bMpP+#9Lr7EW0}&#ADOdeW*lS3ZTGmGduq|C zuC_=veh!TEPziWfYmS^PbZ7pSUqzDGv}RkUj({Ge95)sOKg(K&F%rw6|E6c?tl{lrR&;$raKBF6NA@Ad^p=65sS9o zgkH#M3l+EG<&A2`>es^5M64OTme<&%x0PF181~P*-3W>wD3&6(TR6dg<`&jSq*w5Z zCpyOOwAZ6`^EK8T<+T0{dLbpA4pG81l3*rBM84!6183m!8}ueWb1{67i?5W$e}D-R zady-3m(OUu$Q;qb?1+6}kOv1rnbd=e?tslx75~r1bcdRZF+ELtV_a1kT7_u)`yLw$ z#qOm@HWevDeQIhO_pb!XKEp$Cy=ldz*B{_xW#-U=N!S_FE^hqCvz#0t%FX4)y#*PJF*>JI6GH^9lH0n{^P8T@OVw3OZ z=IpOgS0*R^iWf*s%Q-K5oIsx6nyq^-8D_Gn?yKq>|Jkpqf>yk}u=R2Oz%bRVzpswF zRCeiTO1fTTDzL!g_|oTi(C1iu806e?y>ck3J-i`^rH}a#9%;WozRf0Wyqt#3+X&SA3*$AQc+e|u@O>m7hQY%A> zaJ2)RVGKokCh4p8Gh(QC%xQ%sb}{q|0h+2sR}t-FKld0+x`$fC~dQdky@3|aLC3f!JmZ>{qUO6qEAMTl+KA6uw4>y}VVca*XJg%?V zR6ZG>&)Cc_9o=jX>ONc4yWFy&o0#I(Z#thFUXHOJ_dFUkCYjlB6yZW7#@aA7vx+Ev zgX>!zfsZ-ww0i#GGrWIYP+HflzF<3@KX2B5U#Xi)c295^5Q`MX{Y|qCfmm)%ctwr=i;FH!*$(dxa-Y^$Ew+)m}jT^ zN!!Ol)*+WfSseXn+=R{0@&!LV*>1&2KfTFr#Y;cE+jR=Jgw16d@{jsH;{|KjxZ@HFcl0 z@TCs-p^o*r$nTme=~%u!sP+0Wg8<7=4$qi@JY3ayE6ioIfZH}*G30=0kgcp#4|JBd z-2cFC5K~9`W963T3qyz`+m8h$_tK_~YE%!T zvdGFNUJ=Ofy&ympl}(VA#Vmk^$@0jP7^*6jUA<1{&+{~vd^9^y%AzQndKHd(6`qPK zJFu8;RO!!^HgfBVnoPq!2Z%6@R&>d4OQ=IK zOLs}&GOOZv7`(MT$;^vm;s=>^E;R-5cI-ee>%l5|$7ldZHkYhNY?jHx6WRg02yb`4uM; ztTaW2q2>qC#H%^PDz?I?=&41EXq?-jwC1DXpA^ijE(KQoa-9GRVcmrf#T{w8bZZAH zf8=V%$kK%%aO|=M5fUkbW>ww=GA(yBzCY-`UIIy|hH8001r1xqH(#Al_D0(MS|i?X zhQKM@BsukA3)NcjT{a03$~)H2nveNBke;PtX{W>zhtFvnltf6+X;C)>YA?o?U3 z7rJfYCbn8e0y@T)HHk|Od~Pa^IwrRUdiVY#wD&va%*97+tBKeIM_tz?6}YamI_a|f z4$wT+A3*Yd9a+&SA14A@`Tp0{z=*&9&(l_PToWcf08M5uT>{tIWlmiRoz=Y}30@(5 z{d=a;Z4(6X_ampag=?FsYtq2lj_b-Z7dSD~fpoo&|9PzD82H+FT5&m>Wb4E7bl)`t zb9^dTmG_|bZNc%&NQonoEKjd&bX~A(jbHzp7%qI(i*x^)M7}&d*E__vL-1b~060R; zfwTUb;eZre(#$`)T={vOkE4$t5yXJ*ym9wSf0Y4;*qt5CdtAh4oP|FBvC65~`M5F? z+l{c~^MK27`5*sZ_gycw2GqWoaQ_N7;JERuv3Lcr(!2K9<*)H-w@cIihQq}`_;$&O z8R#b5k@eqH;dqB>Oi7pfT9f0r49oJm9-`q!p z&$*a@i+=h$0>7MbId?w44oVm>P=GQQi6(eF>+_5V>T8#tyKg{<-h3ljhD4}aZz2X- zI{%F)_`YjU0E7wRRulYRUqf!*gK*nr9U}sv{ol`{bNM-Q@yEgmeVyoIaHvMw|2p&+ z*5EWD)W4ti)onTL^WPy7zX&`|KXZBWJMmZyVXNuq-z$FKyocgu8a4);+Wpt5f26i6 z0jFyJb*kj;H_ws5bEUQ|o|*q2C;k&CxY5T1P>XEE{{jKbs~l%suAME1mudN`NlIN% zqUk5#t%jJA-G7biKM?+Cx>0?5>XPof?EZ>j;aU`cbr)m&t4aNi)@|o0t{4|}IB{uu z(zaen?aD9p>OSLs(rCUAXxW=_J~MbM#=&NDJ>M?*xO8_&KIwOAduf?ee~(ptUM#+t zdVXn}-qm=y-MOgi#$HRlf`01~f72-Z@N}53f2ZR$F27j(=bJAk74c0RXb=!=j{msy zeyueBmfnNVV4q$}@9^5}`DxT}n}A=&6W}682atz(%&3=F?^L0ccBF{IHJ_f|Q%+YG zp#Z&lne#PC=n!;5$T5`-nQ^MTSfD};U`&!f!`W#m6vsFj(PW_%VGZLmP#EWEU%+I} zOiX+d-tNs3+~xM8QRT^GOQ4g>;8%>vKbdpC&YD5NY%4JM}7l90e-==#o?7x{j=H;csv6M<$mJ%zWYC|y;)vs?__1G z1^yUsp!O!YX+njzV;iEl2i^wrc8luy`ZiYnxvsAE(fV=oQ1Pya#mVM!vwI&twdvvE>Y({~|FL;k-|cpF zdFjCwcqPp1`|FC2y4`ABoUTrfj;4>*o0}d_*C)68=Z}lr8t*KZ&&MwZxBKhw+Y?jO zm!BN1Y;ITgGlrWROcV8-A8*gbW6RB;mzO6DRGu%!vvG@;RG)9=xAUp&mU&H!Tx%QZ ze_ma!XRDhHyV{?xj=L=L+!O=H9i6VGFCKG$)Rj+jG~C`*KW~pu9#@aJUY1dQgwS;HhbPZ+N#d)u3grv{8>K7!I1Bi zH2IjT__$v1BtD3VqYvk1G3BJ{9bSH@+0|gF;c2=(qq_;^Uh06gyNU6tvAv1%>Jje#Zsr>2-gm~%!$tdGzQioh z1>=5e#;&F5^A&cxes)I^_jXGB^!2QZki~t}8tQj=I$h&TQ=yq#+{I#3T(O~UuBckO z!|C!3V^6`*vm3QdC860)%BsUbll5P20qx(O{4FY?ZpWuBKB+EB*VWyClGH`l3Enp3 z3(8k#2W{-o+ZS6#6selbC(d@3jyPCDxg~w;EhYb468Yvz{M|wOccq;^)!am}?(-%h zkH-|wi1hL6#y&wXyV4(KdT8C;79X!pyPKkl)W#UtGL8Ll-6`Xu>vn@VaE-H{JBcIX}Ckm@8iN2^dO%J(7FP9@w6Mgx7c zkRoD@E*jqS+VM-5IkcPHpQ+x*5eviBy)u9xCakO?&8 zggPhP#x~vNrk_bEdb`DnwDw~2YoI|tP=k>7$*ORH{;K9;tvBcjttI8ho26*ulKLvZ zijz^Jb-Ym|{Af8{i0}Qzza`LexzPR1$o#Jty~M-eU0RIaYtYEaGLliGRGRDtR9CPEb`xkvR*r zz!#8IBg;-m!-Ig$&GOM*ArYGaUs#peZCH~jWF%8asT^IG(Pp?RVkGD`3KE~ZC4FB; zTYv}q2grl@1qf2;C-lb;G8YDR7X}2-u+GA(u1%R0dbMUacVNyX_{&nkY2U8j-niS^ zjtcB)w9&jtA9juYK9~G`P5=^Iy<=e*%|f}8;L8aV`5B)HGJ{PE!N?G0LOAIe0>Mg9 z&6f{C`QBq~Q#>0!9>tnR+r~A8^DZriemTr%41jcE4Y-Fg0wtyc(ZU)LuLBzQyUfLR znIR1=OzF}0oA^ceQK(QpD8L6i1z4 zNm9_0&za2}N~aHx{&sG5c#D|&N4O;C@dR0T1#5UkI6To(?568d;*Wg)jJNojoiXLx zIa+(nPA!BZL#|axP9?0Mhtl~Cqel&+U6ap*`k0sf@p7G5Urr#%`{LzVvHlG71qSQ@ zb5&<@fSg16qC; z$=oYg-763w?aAE$5Qm2OAQ^8#H2G!^i$M@xjQc_FSnVSkTvZb^O7^3I^+$!p;c!8j z<#R`Eep(2sfftJYP_pF5TFwQ8BeAux=*fBo*Fj|nK?M-3% zPCRUCU^vb?Nkg5vRo&Mh4iEH&`S_%TNOqFHc7~aDhf#8S$hD#jNDNw5t9F9&}$AqsM z?+x_np zl#6)re2WBNlRxlOBk@#s4CBk=U-m~U@WEmufRp!CDwJ}7I${B4@%Q5DeXL)D;LA22 zIW`|*I*mNJ?0s~0xso*>0sk0=e|+2w+#Hj@8h`-Y7H^OH3^>fi!Y@spe#ee}M;c&4 z({)$1>dQLxREN{+B1l>dF10EQE>Y|-(28;x{tu8UBWO$nj-8&a-Jahl$1~~O?{7U1 z^BD;oLBQoUV5Ufnwm@KC20Ahdq65l)6xA`h%yHAtb=&V-(N?CC`(38eFD7!^NU;@2 zIh`TPe+*1aU1|m5;=4HiIo7+Ia9)*RE7`Wb$A^NV;``(`PZFNUw~EP<6Oo8+%C?%g7y+80aBk|%+pQ}Uxqc@#;snN%<| z1_YjZho9Q%@8#3qKl>dhEfi`~SM!;KZAGz9z+q^eUd%iJ2h8kBvf)HdNMV{7YL2!s{i5%09R$tf zt{mq;4NCAhC}}(szP7*u`60Mg3zY5-U+*Fi<1rM&MdiXOphM_U<-~lczKuW-TLJ>6 zPqoUEmeb73*0wcn0#x^cuWu)s);F2fw`OY_Iw1PqA(O49jX-P>B&^l5L5k7y?)&m%?SZ>c4_p6!3G2a;9GR7vDT+{i2{4f zC=%af65pDpZL%gQ8qmbXTtwzKC~y_dnJ9*t>1mJ+ zwImYIZ4=Pf=2CDS3m1lmm;A^Q(A|j?!c!Zu_(ZWs-c*!_@E;>_BJqS1L1YGKW(Rzt zJi3)GUKnPWEPzUK0`)=#GOXUmZhXmLA>?&2 zWNnq@{dq0!=Yry(T>QWn+076d6yCptQFZj5dL2D&6fQ+FUTYyaB2`Xr*L#@hZETqHedhEL=UC8uL+6G#^u^GCPdevm#1#E=>y1<~6e zL&zY~DTv-6eZWL6QCSTdP=ykF4o})ZM@le-7aR2)PJtpojISgPnIa3DBCBQ~R*Cj# z+o@A0=8VV=1ht^Y4kkUP7QE!8Y}#=_)%(appTN2qXt*6nT69*c_hZww$xB35g$7hU z3_mulktr~Nbp`MTS_nW^oiZDNg0)(6wOWDs&XlIgwdzHRs=fV92XACr9W6WSq{t}c z>OndIni$-Yh30Enc01uY6wK9{%hd`rcBXWDIYFU3G}h{Uoag0+qfNAoN}erfAdq?z zzr=%QxnCL59tZiLb#+~`P1hAp45R35OQUd!+>9wm>D&P}+N?QgpLUkYVj)qlGo!rI zlJbnR^^98!ObJ>9=Kozn9wQNv2H-wGHi1IHQZ8^nu=cQuAmC2_VTacdtE^8w*l zm9>;Uw`%rc>S*?2>q=__ z>Gkm7!1+kxfrIEij|e-Oy8r3VY%Y0@RroBOhz+a zcG@jWg76AZkf1FNps4xP_F(_AONgf3N~YZcm|3V4pnSm{6+R3)2?+ADNQsxx>3bQS zfirxZIE$p9C>nCz0ao1si$N-?wN=+8i=@H2rH%I_UMLRTqrk0(JMBx#yo*o@bRVwA zw;SlgJ|Dui$^fCneew4m*-@Ma>kD@Q)eDh1qSF;(=Lf*vn31eA!*N0P808V&4Uyd+1v&FFa@6xOwxG|TFddnGH{;oD1wMvg z2)qGG{A_ZQI1BG9LpjuVJJfgr41XKM>vKoPBCT)?1#c7wc7PD2Tkv1BT1|ll4e+7H zhlIanR^+8!!OsD*6AQb1X-}{zY6gjM3^Xd}OS0k9w)6`{)fI-}3wQV)&f*Dz#s%=P zc+OTHdnm>gvp~3U&=M921S)`{OTmdz zKthR!67{bsIQAP5rR+?|;Um?aCDjffHz7R$ZZEPaW$!Uy4)lS$3+d#v;JVjX9!4cb zAqi3ntVav7>@2hD{2+G=6MIy!Fl@ZeCx5ob4h{r=11+PY;}WPWCu?Hu9w)d6=;3(U zo6>_frPee?YUh?5#SW=={oCjWZ^+LQrb#JPaIId$K6MaYQlksF`Q*FRn7!55)!uk0 z9DaN#Y?e7~1#{*MROvliBH3ek>-El~TSW^GJllPfLap8?Wbuu3V5h_SZx%Hqjv)KN5s;!FmSsrf z^K0q@QV)DGS33TQxQ(~54H}W#&Sy2|Tkck&G(-${2Ei_B;7<;sfw%!wniwt9C*OWu z%m?~OhJ7E~$e%HyRC#OVk%on%LxtzSOTf;|%#I^5)xuI7knd2GrKk&n7I_E`Exwr+ z$QBdHfnTM!^)qf95$B@yYr{Mu!h(+nJ4?{jI0@gJ@+C|sqhaVRT z5nKa;OYrNlP-#29khd71r_@0n{?~{CDLC*X;VU`QydT2$kTHIl{?==3HlOUR_tOj$ z`ml-BN0;{S-V%B71kVYy2!lleFQE@d+Hm0l6KJW6kM4gP4vWCkm<7#` z3#Gx2yv%ztKOE@UaQJZ66bi%7$<+2?Y#nczkMpVY>mcm36 z(B6QeR9Dn>XGUR^JplBM38ZPs8Ssi?j;h1IFH1BX^MCIo8m@uU9bv(MCqloVR%59f z4O-@FT{Sn`jU$N^6_4fb|)I}rdf&fY3w&J zPb))sAFd=a~py-)SY){{#mVwF-0o5%t z=LxB9j*1eRYY72AwbF|9Di|oJ8)$K~VgQe`ScgU$6b{Nw6a9X*6+ekLlfEk;fgZo} zP2{Udq(srAUA5lnqW0FEY8@D&5Kx`WW=B58#!HzRC_`zElG73*<}mQKt9o^U1X3bo z(!o}c-ekQ*B>8Yx&u~YB8hnjBjqOX|n8rnw!j06Z-!l!ZzAI># zwmwt4sqG;H-@q@nf)_Wy#o?Rx&39O09lh6lAaHvLUk(C1Wx5>#ob)l(N1cKWB>RAD zgXBel%Mf7D9Fmjmxj8HlqZu4R(wT)!?ZXZ)_;Gn-R6C_-<=8OPPv3N{k$yF1QUR;z z1MxWiYIf?qwT4f2qN+_58UajKrpE2EAaF63tg=pfTAcNFB3;tfv!)#(fT=Fix532p zm}ru}k1_KtqJUVh-=+Ks#im<-s`Jo=gdUo`(&+LWa3Pfq>X0>3>%;N5x>zddv|26%&+=q-cuX+WFTtVVt?Q+ZX(8Kn@FSt^EiM7ogqKg zU=`IX>AEA>Cks1pCt4y#ch(^?IPh+9rCTxqvcI!UL{ft39KejvkQ-~UEczos%an?( zh{X-WDbvcn7SoV??}dXeOFTOBpO9uG74OPq^AL4_PFVoZ#%|Md#%|ju4jA^wX%F-w)kJ1fg84N(2tYu2Ph&(8Ta%zk&I-||C48?S>GnFv zN@TO`VODjx?wW}rJ|PuX^@b~=RMvGr_&lW;O?*KH2n!cjkpF{Wo=G)cKUmuVtp99+ z4_N*|kAugyp46s_6RxiyW1rPk_wh3mThEKX&P3$5FxCxIS|-@|+epjgEnFo8*;jUanC` zJB(g@{zh+`)X{}WrMkKgWHtV4^SQV0Ha;1f_KW@cBWJJnr;sM55U)F?v|O>-gi~x( z%CK=R2}dW**8s?1gP?~eW>V8Pd?9CFe3i1>$EFS3NuZ}^Q%3kSqzOSl4Ks6C#(v+x zKn0-E2>ch+@o0xG=4|2;G4WBBhS4zrz!8yHva?G5UDD0urg}KyW zn?Q=o$=< z{b)Ih4!+7?dROh?lgZnLlzx4gIg1x+Zcv^}d$}e>DZ%xQU{06FU%IeLzeRys>S9S- zC4MKwM2#k|@6yG783jh7%g`2s*>G8m?)tBD3`}kzy z^KmLfh{oI^l##y1Ew=1@%cs8ic=8x{!{mEO(@09iK{;&2IW+38jtlA4{m@F(u|aFt z10gaaUGd4RgGmyi2MNa5#gsNcr#FCY7f4;?*((4sC5uiJiRqI>LICP6qCyP+CC5mBgyTtl#wh| z-pyRT5J}b-=luY{`ZJlE3w0&2d$2kMK5f8lyF`PYg|#`RC02YID9K^V$e}U(3po?c z5aPX9FM2t#xt{oFV#DfMNi?MS?wUiH>kiS69!d(bVL~I=IZ4ZQFB5G`Lmt~*bq%!j z@sySvcE0>Gel-FjaBtND_By=}i*tN3Gnrk*e+`TjyfFDm6EA`}fAyy6kW?v_NeQJF z+*>V4wXUCV3?>M=apI=>H8i_6Xag>28#t-Dy4XE_It7Ytg`jeuf&50>PXYXP@qsTA zm3wNY_J7DuvU?Od1$J!(0C&?hgw~f;HplWG@ z4r`X9vJg-W6Sob-^p0qf9<$;tG#fodouObrK<}t*k_)ocm_; zg4OeWzsNwzVB?(WtSQ;Aml^q>M(CqrB(nOV^dM`$UAe-i+e@03@#LNJiZng9xDrJl zxVQ3N!3vUNYfz4Pkd>GCLoJnrH6Z=AhWi`=d=&b=Ow^h7+v&UDHR%c=ag}}`AR3LQ zN8#!^gL0NC;TC&JVE$$;v+IDS%Y+5X+jxrzagEQZX|axDmcXR$zxc{@>ur06Pu72d z$>Z>fdp97`%3ssKsQ=q}FZv*{d4l+;G5c=frh$8t;?P}v;sicuX^wb3W2BXflTdDK&j32<_ClUt-HJ(C*(bUXk9_5Px~M z0b0ggXjLX|pi7koe4;7;m$b++P$TCa7^DVgx`2t_Ba1E~#Xc0$a-NK1^crJI^0`^` zyYZS=bnSloJ;{!v!@Bqx^;4dSU25>M3t0O-GWIgkG)NIGr$NQg`M2M@jsDOfQ!`7i zaVI8zchqb_q5iPxSUq|G6~ZYyitufB9>l@DKr8uOqwp6?l%PJcDgT5CeEE^S!2w?2)A)i>*fl$gwCPEMEm6kDBr~klE-OpCa8QNA15Es(yqIOa82H zdrTXE&X=Zyrq3%%gqTj$L4pR5(m!e?q$_^^QG4`6zv3f;&rq7Puo&_}qvPHa8(Nm} z9m$#R>|(gxeMG>;22}PjT5vT>%2i`tCPeYyZhG@CAsC=!YtiTh^| zK>Wg+L=@49TXiB}>muQd6^@}02A2ym-ONa|?}MP%(Iq1Vb&}p;baw(=7fknQUBo7s z4t#y!RT2_veE|5EV7(-VIuvnIWT=Okjy5!?SI3gSD?Z#}>uXoMhsBlvmJ)k6xcBS7 z;T8%q=-n@dtq=4tzZj;Ign^;&S`-D?MSgBDL1~!b0@;gyWqei=`xNlRKUYF0(%QDh zbXU>OF)ai>5D@}N@xe-ASM0+D-6Ap_1zl^hv*;*=s+`a^EuNq=4@;AN9qBiP29N&h z1W!`fgpaSbbruM&7YSOe23u9GvY1-&p3DqY!o;wvl!|;e)5_Fb-twaI}?b=8x?g zWgizEZH?WQdN@;2yE#({R8J8;?YGLkKYKI1z)MtB=YZm(i-abX+7H6Q9(xwMZ3WYZ*p@aY)ova6Gb*D1N{B=6%>{YdLJmVR(ItP*1S+)6L z(+Z;njTvs_25{QVSO4Pno3_{@WKl`C{?4Ie19#tRk?ZOcwPn|ax;iI22fN$$M0F~+ zrn{g0iK!eewJw)G_v`EThs}l)j&X1nAFW+n>}<}>t*Nd~_s-hKTdCwZ7F~c&_Iq37 z!?@1|%c{?J%-2s|OR7)nvH8tFYxza)`^mxU)Nc*!^}V=K=;hDXSMkqF?B~n(`cL=O zXE3m9m&emg&kuL4Za1&*K4%=susQ-Z3EEuz$7`uxR}TGIOEvy)d*apWU-raL^WkbR zCcA1RdW#^tIDxClm8^88aHDUfE`QD+tUT`U0jnM|>d}SpEU?fuHiqkNKibE7^S$D; z?NEd-7LCbNzWN?@7K*9T>vAdstqbAI8Ttu=*X2~3+&_WkRE2B_NK+Ys6p8sK&7i}g zrBn>wF7d!lh8)tDoeU5A{^Rhp>Ut+&3stT1cgd71DRsG+uKF0tg>`kcb%q)$q40Ls^ zt*BoA&``gws)}2*O#F)Mb380fy^!jDL#$mdeINy8O*C%kR1^^YBdg1vGvNLPl3G(( zxucV*w@cW#^p?WoWNke4ET>_#jx=vv>N9*@-pF`WU(mQ~?$ZO}(|&HM+%pBG>|;HP zL|>HcL#|>TWY^HogeepFih%^bJrVK3viv<-?L*DR=>#j$@&=~p?}H;Y-^t6@GSrZ8 z_E|6{P328?v*wy&E;@=nF|g|u99FR)Z}Y2uIZK2W zENMB%AhvoNBDR5)dkCw_!#<-BJkRw$1bi2+M(k0 zL%psLX0$Pds5Ul|d!|xVzg16b+1*(E>V3|u#?a=J^)V~lr~PvZ9R?99;fmwau6(8` zBw-u|Q7elZw)~YkjEizQ8@2-Gkcw~9VxXo&TQWSMbSh$w{AbV+vDnDG@bEz+5Th>Z z3+Nvy_KSJCJ3?GzF5D$QuAz%{VEE6<3jo{5iId()I(e?Xi!xM)HXlF?C9Mi-ngi+0 z8Lwo441H%V@i75ml{e`PPe^(bioJ5Dj6U{-vW|K zr~gYb=1n)w>Wo(XP8%3ux@>jTc1tPf`@r_KqVyt9!9d+;gH8V*hiWn-hBEb|Hu_i zr8l~4oAe?TCaEo9obh!ZaLhW^1K`$ud~_O08hVRH9B1uYAU9Vbr(|%pzzq?jPQ9fQ z*r?e&XfFxBJ_&TA&3D365UxYUa0o&UwuHc2OW^ErB=xmh<9+d@O)(d;*02ZD-4nKk zs!nYvrGe!|JO;jN=-M*pF+F(S?BBXDsAht6rQ^L!B-qb{pu?>KZx?8d%S3+Arm}Dd znKwgm5DsO62BrnAe|5rxyZ^>cZ|UFwT=oE#k)&hoE7BEw%tRcCu!|zo{T*lHRi*_M z^R|h2v+iXRGee(n=bT;IRq|8okJPgIJgthO(77PC5ei)RQ0wkH$vi3b<=y)P+3nVO zHG+P%&|M}-aH%1|r(V2|NqW%Z?kkmlrqC&(9uSonw*I}Z*5Vv6{GQ7Ga6 zVhD9hU6X&~iB}G-4C{Z{3dZO5d0;66Roy=q3vnUPwIxmrcZTQ_65sO@Clf02LJg*G zKf6`j;MJ(znwW>OK7+_V1iC%$S_amN_#+^>JY!W5c3#UWb8A0uf9LKT6ipB=9qWAEvc`)KifULZGN`7oql>S zJAOLbnm2u(Z$GqkVrH#+K0CR3xH7-FTkq^__nSWix_QFa7td3D-&i+wb8}&SvU=WK zTithcayg&aeLDA1r;|I9>#H97(Ok%zd1c>w{5&XxqrOsU!CoBy}!LP558Kx zI@)i)t!HAg`+h+4Q2uzeK7XFN@H2A%;kL7$NqqQec=2i;d`ADL+2-`(QFXUlFq7FZ z+D}ocjKfW7^yit>MH3FS=cn6~;l=8~tE2J5)ws+pzicsF+f>|?CnsCC>$ryV^85W~ z_Q&V>#lh99Lk9)6t@HL{c)!I*w^a472X4zv7cNJe>W;U^dnjs-KEQ8v$Ij!u$%YG~ zrhNJPv3&MRBmIj#HAkClHBX3Z%_~{R9-B}xuxmDi+gR>A~yCi)a~phH&j27LdIe|rz|`_@TLyuifzU1 z?(WPsXKcy$CZ&i(7MKgkmGq`*RujhYFOlhJ?HNK9wUb6%Z-fG!V;2N1BdSGdyH)U# zk|rL=;v?VX4*x8)7m}|qbJv^rpozvNnkPE|OKDUdN~(N8ZR8MtN;E69#Mt|hj{UQ8 z?yW3sHVIEI%Vt*T>ezr1BO?<%joe`H0zE0y1-0XHEQVP`;>M520h)1X%g6-v&sIi+ zOoyaQg>bP;4`mFs??j${5D{TI?pJjQLY-0fF~`bOlFIgew9>T5lRD4W5i88dW6jJf z&&Br>hGFVB%BMUxb>?}eYG;TS&Y@M)pTsfrzRvt&)O0MpE10TR-pDn2AUD$aGTZs` z3JxKg@?Dl@`JO&(VH0CT5691Yjq`cz&3$W#Q zD3y^X90h=6yzcu4ya@mv4RV`^p;>5)UcfX|>W)whjgb|3Ai`qn1S!vPaN(F3 zme>R`$Xv^?JQcQx*AHabxk8Q$id;*5(>P{Ju@ZItr0QEF@{=16P~EwS1pU}MmL=UL z&Jkb3wlu`WI%|dZ78F|-%Gj80PF>!LsfwXNs=b+dPx!T7hkLkoLdHV~(rKWJAQ$ZS z`>P9+d700;M+Hiz?Ad)rR$Eok{Q+8nG6kWuj@}|8EP;z2IxoV+x!{xUuQp_=>j@W< zQO3UrL+NL-imycX8|n$FN{eE%a}(`+( zf51{n&h&k*KCf!~dk^&2?<=elHyS@@ZwPJh&RSEF`kZ5}o67s@e=yr5yQr6WZf#hH zHDW?4rK8x&ptENO8!tM^j1IV@|ulc$5ya1j1S0n;1CB(&2%fz|I zg%jJVxu4g|GLyom;zc~h^nW(gN1x}sYWqj4?5@*{L$y%z`VY!3$RQbiL4DfIPtsG` z%_|~V@eZA-+O$Au-wiZgUWSjXRpGZdN7iSJn7vU@VETm2lF z@EG|!4!;4ovOD*L7mX-)?81~?4oFM--qw0yt>4(3Oj!QS1=C*a4*wr#Zy8lr(<}(% z1U7J~`}HQFQ&tx4xS!Y{!@8|<@5-^l77-pXFU|ve9bg*>kNS(PZ^ddoiWlKiyaNWG z2KTlk%LIQ{i>7!x81jOhV9fiNv#IH83-573yX1*}vNEtIg#Ee0NGP3RiT{nuAv3+9 zP&(Ptt7{jz{h`fx{8AA3x4u@qV$OLU6M^c z_)hwJBEgn8QAU&cA-5?_Um(b?&ZyG%uuw!tG=)9@u{L-cvR$UY@XMr*=(t6p05b^K zQAW2`?nC)lSVW>D=2^AFPlE0K{DG3o$e1HA_?)NxA4WV_-seWMb|QW==_5Ps-{LdR zukeCHGBs8j(?vj;87tHUh*boeZtj4Z0P~;r2c$QlW_nKovghV0ii=Am#IUHHD|$6e zq`BxIo=da?KKksR>t?+@(@*>^njC0qwZuY< zkaW)_0sh}3xt&b{1OO^0h-{=?qD-*EpC2~i?7i5XE{xNgC#PV$mj(>`RBjkCY*SZf znmlg@Hon)3W^>%oHwfMXv1na*;;fzapl#LV-R>!`o^+^G;mq6_*&UMX30f-O+iNi6 zlr8Wzj!1hTjDFoNe$=M%HvAI%b6?S38wF<%ibTlm)!VXz`XPbO6YxC5V4KmPC<@Fe z$R-fS4MZtBNZ2uMK1EQE$ls%ZN?&cMrCt`YgZ$J^xojfv(RE( zmrqVZn^sRjLeC<+2p{5}`s~{Ua+=f3XWuq>k1*OZ1N6J`BC9e^b(WD!=8=V*sO-~u zG8=>)kQW43!Iv&*IRHVC>09RgN7HEz6$%EF6Thd}cMg6$XQTdyZ=kZYs?3MMOCyNk z>(b~8xWQCf6QvHTHBT!pP8^@^>)<|oy#>zVtK#&254Ic`ETyMs^b|82Pmi&=<|Jk&gbM_AdZqhb$ae2L~JE72N zwZsb3P(!?;@5-w^6nz&!_9(hBkbfK(w<=rLU>Ru)w2NGbQmT=OTC;B)Tq0w0%D(xB z?;)7)1GCw)snKuDVirbwrx`e}02JU2wY^hh1$;0*I3kBJ-*{9M6n3-s6Hey+n=N~%%{r)hlxFPOvGSK8-)Xdl3|&uQe(_;kT@$ReNUY(E1#?4nCOK6VMhOkp# z5))@;gbi=VQxyG}M-+{1BT9Tgqyy7%Awwrbb~UqMcHDwQMKM^i_-g9!7T(0584VVg z*)eWtX=svyMfkNn!SOa_*(-)0x@UXR@|6--6MgKHp>wT21$=vxl9gU)vCl%?MCzFH z+oW|8T}(e2r*H`Xq{+G}YxBKi3ly+8MivaV1Tb zzB9o)DPq(7Wc4dFh&OvZ(ln8(teXr6^opAnB?%K0Dmq&_yM)I*_X9 zC@zAXS`{)ozP(&g&1K@96d*-S>!9&YzI(DDq4lVRI4a>W=5SPf?j#(uot>i^L?+QR z7EB0|D2$*Vw}oe0s=4WBfuZnno+TFZR4~k? z`9HWkSA?3FJdy9vG%NFuT&~at-E~7gMVL%EH!F$17_UgW9|JvEMj?9K;I5|Gv%wC* z8|%ay(}>))>7?tZcehzqne{<8CzG%c1Xu{#aAzVxsf1r5?-g4Jf*G@C2eW6_5{w!F z>3X(1G7j)$KUo=?q3r3Q>@oBXq8R<3q@45&9kIIDiJnfd)F4a$g1V}Jx^jBIG8^cs zv;7C%eABNu6ZtkK{8x5GnXggX`#!%}9!7)}0Xb`#TI%!s=I-2heY_^D=0z1Xkg|{2 z=tzLJ4u2!H`rJsn`um>)9blWPxYFXp3w>FFy~)0Mbm6obemVOqz_8Y3WL3cLf?M|X?Uj#T23lh7~|y<*1=L?hk$XW z8s$~h6>q;N1%Sc?XQ=_66qs$U89CU&(p9vj^J%}Mv8yu5*-eZ>aYpgmU=2Uqwo(Ex zDN(7`=i3yvV?@dlhavvw`>{Mo@1x(oTeWW#h9LFfzIZ(ayYVq$PY9Nymc-hl<=?F> zRETull{{_pY$UL)t()N+ZlraNSVOuvFyMucqW@Z?_YVyistp)f)f)J5b6r$jdx!4qNFVr6%I| z%vrXfSRu^L5?agt9nOWF(z9j&jlQl6Jo>{qG1tvirkHj1xssA2NGhMPb;`cH>LkT4 zWw6>}(CL zmY(+hZP|RWf(t_ao)6wJ3XmnGk>~!MW?ygiCjrM>ofzO6BA)|UM*JHF1}~rwJ^zwm zB9Tf$lSuL>IQ!tixx|qr3>U}zBVm+y&!UOiHnu`Hvavdu^LArT|75i&pKGuA7-_w}o@JM~B#5~81M-il5DHs+buvcTsvTrXTv<;H z3y)bFzWbEm1|7&Odn-N-NoBb)`aISo(~eVun`wC->#4XnvbPf`ALQk!P_}qxWM`Wx zk~g4v0EHg=D_G-J0pF~VoDM)nC5+B({_bD!O~lC^U(?3V#(Z+|fl=C~F0pf*0r%;# zEf)Xl@^`keQ%JcYvg3VoGhnS>mxC~%Qk97eWYbl?8O@sOltoQx8s=7OhF3G&96DGKCArmS3ya~4?xTR6@Z513o zt)iH%H+9bO3UL#H&Vl+`Pl>u=0BZj4cQq#8$+CzNg5 z2~3*NBJrUc{)#ZBCATza(k5t0a98wSIEIFwXgE0^#ez_UkK2_qB;3(u*==&4Zk9R5oG{(9ze2=?$6Tees&9k{nt9MH-y-`sic=#aq z)EBN3m^haNTb8B(kl1=*fH{m&NFEPG85uaxczcD9h^hfJ0@1s!cw_U>9_|7@_u)zOYfP$ z0L?4%WMkdAk-wxIFnhWJY<~Im{CNE`xttVSt>Y5hdGd06zY*M<>p<+%*y;S|uAFRo z)w3h za$m;L1_aI;tY7D!xofyK(>1N&XcHrrfBbX4Mj-3nTXvPG^KwK(d9eZBR-6pJJ^2IP z8x|f>V(-U~lgaPdxR z94t>mK97=iCu{)@D!z5eA9N>VFP@aWhfzhQxZ-1{6$>(tFSPw@>dCA zbLEil@9~xUGJ`Dtppc$=P5$kyQ!V6y@dDakj)(v6?D_xNUuJpTUryCe{_lb5K*q^bvPo3QV=zYYP{U5jkPlgGBI zA1%W?wO8Y1x^t9fjA};HZVaxuO0tSbbuva3i{`z@fFgbV^Ody4JgKJj=jHveKi1!pQm6elQ-E}X zr@erA^Nol|iD2{Nr(fU7r*)M|E_byqRqkW47ki~9KOtI6O98ga1fIF)Y@&{u+6Df& zJv-@bPQ_UCYw!|E%7NN?mJex{qqzOc5x1Tl+?akV_UF9>Ro*ZNkcHZniI(fcZ zEU~a7lGahN#(Avgyn*nkVn>tEPSlSLd4pT z=TN*{ppUu!O$nPYDA=?x3O9+4Y47an`3T zXcX(dqpFa*wf&S93JM;iKk%m`)zl5v$@<^r99Png*}!sX(szS9`;h8~3`kO23RaN> z$=QlT=p2SqpQmUXDc$`ok*QF#2T^*WU2MyFy`L2pHf?;X1=*X$L;ll2A;hNeqCR0ajk zMYJ4_NKo)4UPSO=AtMwTi0@q;o+10gN4~?f2;YS4 zfu3R}PS$o?u4s#le21nPnTm;YTr#3LoQgSkT%wIfIEk|DNS5nRm@hgu4Kq(ygr7J) zK2G{mz$^nd|1X`y5twcag~E|c*n#VdeD>qlB9*V4^m(}kK0h9|9F3E!cpTU*QDg;WlQLtJsBWM#Q-t(&kbZNF7;lGW6c3!oB;7nd_VGAcb@QNHoc@01 zbV{*WoIa$^QIB29{*(>%4Sq@&+0b*L!5L?BY^&ZlF@eF*3!^AXRG#-=o+uFdoT#qu zv=wYvswv|J>4>tuKih6n5$V$q$IuF(l5)Me2lAo7w9knNQm{7EeKX)zAlAysDzAE^P+Y&^#MQYxYxTb4P99 zC|R$Z_nnrgWJQ(l$hGSju+3WI^5u!dm`PamH0+f+lYa~eZoBVrdLtD#j8ig_{;0q< z4{Sfko9+zACGEiKudy@!U@&N9;LZx6DaSAI6X}XpmK<`90(kRIXS3rqZD2K;o_c_ zx_8{S8m;VaJq{~(o1Q8mQmkE^?kcWIK(pA}-8EseA#(mxz5DWd+J=NF8Oaq?G!z+> z@&DhiNB{fVf!8GVf4?ereoxzD{n?i88oI~vp^XC}h5F_crLI!8J)&5zZizK`9&0oQ z2Y|T5U93j~E?rd2vuIiu-`kA`I%|V<13GIH^DgZ9M3TQpasBrtJ$h$V5XYBRr7$T8 z=qkrdOL21?xNtL+hznEex#)pv%e)RM=zK}LBDMg98W=hKzePivZn{n@SNdRN&iBBt zipzL~;Z07U=eZ2ddi+vx`dh;+t6D<~`_pcjz_&)zy#AX1^H;^Juc=&p(H@k_Jy*-K zuUfva=HfGMD*C*|j4zs+(ayvoL&oyg{1kb4Psgb2l7&liM`6Y_S(=-Bk~y>12xxVd z@y`-*noE4FEU*UJ$Q}_7OgsPKx_P%;1H1mq+UOE&Mi(|Umn}K zy3S!XKG`Y=;5@>qB~3Gyr$tR~o}Fo8-5+fI^1w4+jS6Z6Hr|e)Sr=RA#~)tbTtUviudh6|^}m0cppV?TxJ(R`^F>y=AcuD{tkNjVW(}Ze0o_{xmXZ1BQqQPPaVN zUbwuzsu+xZWF%C#*rmc=Eov`P-DQ%w*4aM%J||#(@a4zZ&eoNz0HO3BROiK9P#uV* zKRnNW8nmXf?2b%`z>Re$@FA$lu*BhI@ ze^Z%q7g2HT#woA6mRE75z$yQ6E$(&7*1#13N`_C(Nf)b`Reu=6iiT0e0iF@78eY_( zzh~)j1<0A(PF~(B3FZC=$?;NSx#yMjUU8kh9rtdht0>+?8H{rQ2IBe(k!GR8T*l-# zp$5KPI|N7+Hz@`&UDyQQC=%`IW9D!oBglVa-lBFGLXjHbpg?YY=nmxLzCd$mP*0}DlNmvaDtCK73*bx$gPHaksR<`5)y%s~ z)hn~VWq3h-IPt68wEh(Ms3%zub6zo`c`i%%59fnd&XzypejSj&-hY^xUT+Ku*r!v8Ys{H^v zAQ;a=y7C4%J&%{zP*kj)rIJjBnOm&>4EuBzqdAYL(D_lN{%H`*9 zy82nd5|J&VDpuv?NRD%{$k~5pxeG&fT_dahk)#Gsn=%gZ<4br7feh3k1cL41TeGRb z66gfc4{RQ$3qUIMNLWZpqK#w^bWvliLc=d<&C1~^OTo}bRQR*^6ez5XGy@k%H{WMMKbN;*stD=3b7y3>f_aYiflC^?M-RzfPpDO-myn zKficg%P~Nbf=FEvvUcu<6pOB&Qz>De z(zxXnj-^0x?Wv>i6ER@~bu(&RU#e0M;0{-JADcybZYDBBbh3P&6kPejNryG*7Em{?3di2%)2wa>FoUu$aL7S6v6+8(i&4I z$w*7FS4L{UIt)1N!<sG2y1SYcX5*$roXlTnU0YnKl1E1| zGj`js=`nf!d_NtkV>$Pt*ZutZG_E#@<4X@pzu(^f&(rT~;`#eD{(lth?%pHyE8c@n z-@k@lB;WeJw}@{mSF!e8;Z5)JC4QCW>Vvc#-a4LXg3{ufY$#y>dNQzzZLBU zH_ZT54($K0qTR@#qTRRv;U4cm$)NXfuSL5x_+O80OB8=*|#WiF0{xGmKf-%b;%X=m;a%kGPTSvZTkQj=krOX+@@16rOBhex%d$C@TtfB2rg zSIbg|=ag3DMha#dXm0;xteO|iZlHTa#wJnU=TJL^$`glOFv-0HfA^D6Jj*FOL&tKK zTgQ?cr=UIf-i0N1PCFmv@27f^{kD>U7g*^Nps`)BJ-YK9uFlK$2fC;<%Z)Ik4BeW-fPV+f(R5&8mG}WM+!FifH?-YvI8i8#*PZ99 zF9sRpoIfpyn|?vAV#`{7|sU)>5RWgeDv_8JLt@52#P5BqC8h)S7qtQ zYx;&Phh!P-b)xH$QEI+RmxfFReu=SHZ5v7cJfjY!JPAq}yK%B8Rd2xe5d(7z_p<$o}R|NuijK4PL@AWW*58aArFRl8QQnhWg<{x2F(? zN?b&g*kvkG2XobsVuc{gwjN`inxS@|W3ArysXECdO`>3U-%lbKo?s2}Rx21FP6e0e zPhrctkoX}FBh~R!+(^%8w6y62f)tOQxaei=8nmk=-wuQ|-@#n|4hcu5`>*$!$kOXG z0YS101ZDFn40D*`_}%OtG(&otV_h_JL&3DnvTNaOy18YJAKI$)Ln$bB*vzIdfOj3t z46vH(rs1yPmj1p>r#XOaOS3C1NYvV)&*yi4B2pRKJn|y(9`pRbfbax$*h~yeF6bnYS8fI53 zO~}QHd-dJ-5iYXpztD;30_CP}l0(OW?PMex>35WZo82HRA$qAlm;6F3Y=CRXBazi!M*2!oo|MmEkiv#_hVRGj+rb=%yPb|K$ph z!G7Y?mg3XyIo}mN-~)@`8uf?=Qp{$%)HxNyEP_Tu2mnw(ptAonh;+!*P`RZCxlA&` z2E*2O=;^P$GSp%5s&#D-p)56X03)5AdnvPDACLDbyct`zr!Q}0d83Rb;~y&zmp@xQ zHPEMh=V>wDUd6mG@~EVn8SWo+D!LpkrD~+nVXQnhvApQjI_ED>Rj?`c*ZGNhL@4IBKI-Cs!kN4t5qFT8b7{cJ6ww#s0KdWeFg|9i}~+v+EE~ z%S>;6sV_~NZdz`#Jb^nb$WLW*7AX$)#YOGZW!Dk7(J{FjYch&_xN&wQl;l&C*TTs>ZPQ z(Tlel&tb6Jq zjRUyylqCvR9-G~QUa98^i{Cj*k`08wg>>(@^<$jf$Ne+cGf$0Qvm?KhvpL37g{+F$ zzb(|y5SZhrUlw}Ks0$v;TTqy@mPW`v3R@UVm8~@^7?cUck05g_AFEq7VB;^-e*7Mp zZsumWrx=%IZqrOLJjz|@pinK*U)FBRanRG9GY`toEVFsYCh)XK2lK@CcL~VlF2be} z$La=^>{mHiW^O}S9bG+%J+Rx3=6S53vkTC1A{jCDj7D6%vbauPP+McyYa)0y8%DT} zkVRf32lMin*18BQ45?ids4~W@Mc}mwk{Qe+B%NtG=id`A;c-8S2hB2?N1Uo}RKs}7Yzol}O$6{sk;@f(zO8bmG? z5SdVih@Fb#t@~}A`*2+(z>+)RI$10^S)^-Uj0(~f#$c4%2mks)$Q7)HmDILod^l}o z9K;=+;cF>D3Ee+cLDTmnluot#rQCc|$x-Vgoo+ANMqs3&_J&|&1cl-iMPot-wGN#0 z&>(VuQyXS|X&-lCZWm=ybm=F(1STY^9VW_t$y?G|G_Hb;=ns^1PV4c^@ZA*n!fstX znltaPqcD05Gw7RG@@JU`4?6<3sPzOa=-D~(;zWwx45<2SQ0r5Rq9LgnAYgg++snoe zs31^9k_OphR*>s)uB#0vWUMljcoep7b7O_aLGozF&`SGNOz@lUu zs}e0ZY71eW$ilpx6{mK2#fa zk6kzP5t@?R;mj)Wo(9Vk;iB|Y3v50fM6rDlQt0>n*T z1qSP!L3TcT9;eT_ucfLBES!%G))~XwW&4xMiz#DYu<{VAv}+n9?v6^)hAR?_^k-l> z)-+&&NV311k|7j#MYh~>Uz9DIxq zYYDiOK3{hnqr^3xs2DJynXsX;l+gj%9B-FlzK)DA!ZWQ$mPk(fa>P z>51@n#z*Q~YSH@9f3qUqCfcUHRa+?l1#**1*e$BhN$yfE!M4D^MG%hnh|gUzam$iF z&&)bop-B8>;`$z}v7}A|E2ITXIoO!s=JCTu-r1`62jiPsDbX9{$kLSMq4}b0R73eXE5&r&kkF0G^kmC-FYd4zVvyoQcPPGvcE~B#IX?-1!@8(_dTk2R#U=tBp`?t3rUE`Z?n9wKaCq>VhN*YO=&t;{=&E%?AE2+7^YER5J( z6Q`=a0(}k+*{BGC;nSjzyTi*DcFT|IwN}kM`+%r{VVGK{W#!?U>HO#0Y2bLXYoYbx zvfQ)w<-?CF>!lf)$A#fE%UvDfBBslHtzx_K`wGqUtF-y=J_cK-|C^aPdhUovIaWc9+EKxZL%<-X!o+>hYt(O z`P#5km}A?Mpeus(b_JLE2b|EzLxW4HuR={0gOKefmCZFm+~km)CF@8w-2tqVhc;4H z0{lIBM2oyRXEss^;=b)4=XPE3vvWm0H+~F1>t~R#ba2l`FoPEa`KDk)5Dg^yed1}? z-AKG5r^St3BMSsu({H3EH5S}F2>bH@a5D6TqokMRq=7Tuta3KqD*~?@4yE5N-ZX;V zLaq&8d z?BeC-PZ$qZU6wY4ab~%f;vYVw_X!$hq8mDi=^Qgv=NAr>1UKE`E>ejs1l`9uCjF z{C!kWtpiN8wXFg#2A;PUS7v)D;mxirn^`VYr)8@;&oBGyt=50)np*D9&e!+yUJ44t zY-~O*e|)~(x*X2El$H_Dd4Amgy&iXV+fRqn>)rFML{y%g#$A5h*j?YdN6-%GZ}2J&E0Ma~zdfT=T2@MQ z!F?+YiNJp3)sO35NnXt$sK%{u-8tG@Ho@sN!4Y*-`WSP~+L1GQ^^IwDJjMm!R#4AYadK(u4gnKluQDGBQvIXDMcP4Mj!2|#=A|Y zwYd(uI7JqX&{Rg>-bmrT#Vi&B(e5x*T zT$v~W(oH9sdLN2Sykk%)zhmdM_654Y+Uaw}Z@;-Xkisr+58x!R(J?yYT03m#DKqHB z?Vtnh<684DvJsk?R@+jaA|BL1L?W$mnN;yG`fNgRF&1tjA_2yEBKLjUsVI3RZ0E{( zP))h^<1|eG0C>+NlJXTpCk$J==-O;cK1?1WdJ$CqMuhVv;yEc)G$Kl8j1Ts?HiqiX z>-)Uw3G;Go147!(`v=q{J0vzjKi#O8_*9(vwapEuAnKLj`GsV~YM;7R~uI26%Rxj8&Oxyy|>$K6-V zsYM72L%792EdmJ4g_oF6JCt;duh~W0ig8GWkj!9*yO}1cvW|a~;4@fS=DWe0eFhRl z3`k8cpo&KvDD#$aec1q1at!)|n=S`<%AQG&o9~w>`AaX{wD2sZc8QtB0HO$} zZFo1Q?abNnW|J)3G}yC=xv6&#_2eAS6uEV$s;|V%53laY9M+` z?Cm-gWVVn2UQ`%JF(3p=Tat)Zk9 zaKzU~rbv3xpw3JfSF)U;qh zP-9AxG*OaNT|eu-YjJJ84W3-$D*3_p&)F`TJ%TcKWpR@x>2BW$Ub|W}Zyk1MHHiyY zbl$F5-p>+S)%4;HMBZzXz)&KUq_L0e!XLFhZOmtCl73=@yf|2(D)ZNb+G04!^(!+( z&B!}W0a&AWJvDP>I-#;Ah1bwoKC#mo`mNJU&BBn#K!BWom53Q&6=dSqq-yD zns79#&O#+E{751#E%$-T-41F?L-pY@AH$!ZSkWmSzu;6ot0>l)5UqV?#a0AaNEL~r`gWI?7srtyG&osc4V4JEIKU%&g)=mRr-*~6^n<%5^{ne; zR4W<1KNA!o`b{FxPj2}>K!7jaGVTqU>^l;h4Ed)r*{2ctr*UV*j;f#Sno@z%2dFwPUg{6ADCgAf+q= z*$eL`F>tQ1e%FtFB&MCoak_i+5@XSDBm#gg5-)pnZl3AlhP} z$&m>hqZ%xuLe+rF;(FAM?aee|a2~EPEpJ1fZuH|p?E?{8WO9L_hW*NLaMC41b!PGs zK5zrZMhw*@(I6Ct2_i;dq=w(~fD%Ydtkbu8{Y9W9HtKYXE=DG>k4j>TN}z@Lt}Apc zmf)ns8j4irA(`J5?8Gh5V%>j0NpeAABPMgKpm*F~@I-qmO-0lT+-Z{bPFzYWNr+TTK$G=W1= ztuleD1^o*Q=b5(iG%n3sS*a#>K$Lm9+Yc`=;UK4^m9#*EK0Qs0Kfet;zlFEp%-VSe z+;FJM12v<1q+Bncvn|@v5<>dzbL!vJup>5%edZZmt9|dKbLT}|vdQ%u7r3DSB6j+* z3cXAfn2zIyI4#o#j%JH4Fa$;Ov_nM;IfUo0vQ5SQH4I`)`exDkX{Tri)j%M+{W^`} ztPm8$#eq6mnLiA~*6=%J7p;DThmnRzfG4uRxmfQ6?+*N5kWaY#AOyi? z215{cr_qET*_>kSZBCZe?NkEyst^2PLI5$yeFOB}eT7jWc@S?YKCDn!)`_Q0zp<>;{mrOJwbz1A&JDht>8Eg3=`NQ) z=Uo^4dx_TFw$;6{;c0DO+zc03Ckj3&2sfu;43$qC5EsT;3JykM6z&??bkk0t*h|uK z4=&{8e9wnP5-9(rg~|%zZ~DI`_<;h-OBn2<37@~$mS_(gA`93>{=OozNlLS|TnR9E zq+E(qzKT``WrUqjy7#3JZq;Q!>#NA|nknw({Y=ipBB9))dg$zYci%L7vVIlk;g2}r z>7xa$2o7CN(Mmo|*QrWdu}X$%O13Do>BryrCP>IUnzZ;5)~88k`Xsw23ztzyBEW*j zz`;j<@o6%WBC{7GtCAuE)$w1%apNl2yeQ)%6((xOOG$CXn^uVa3Kk`#fFuUOZLkqN zR1-ba5(9xom+kIc#mGFC@PzRPqcCYZVoItj;4q=mf++Vn@mGYSpR6H^zV2VvW zU2HX$|AMhpG*t#?53z~CRYg|klQk$Eq*Ap6EP>L&;bh=n){HmlC<4rKYE_-fRM!Nc z^c0;EQXu;b^EW%aLXDYTr1~Ey^Z6)G8%LIBF*^0YR_wpZ*^ZAgP z(7YHU-Q^N1aqwHlMA23;KJi>`NwPMdNI_A!K(!L^85H5_%GbvIFjd1acl=x28XF@{ zoDwV7;&MTXKJ4Pa#W+Nt4vA8N1^={Hky=X_{gY8|@jk5&@3M(x3*#t|yig~D6{Zaqzo2Q~d7OpEzE%<&Yx~*RW zpcwZzgnShq42K)O?=-~HA#M%XY|ls3j1a)*Bltlzw-#;Je7N=#nhtaJSPVsQo#OT80sbds-(vR9c3FA<_IxzHV5dQ$+;ErZ!lR)Jv z%K}6bs0KbYtObI-KMzXmHd2P7DLilwldX`Ri`fXBvgkqW6D}uyAMp8LxUb$31eFz| zUBD_+-_B(MAu+Z6K$f{C@&`h0S=lZGe**1xtkfrUTAsb#3Ne^d`1*lOM_@zZ3^y2j zC-57)d*yp$>NkBCIZLJ@CSsJp71W@K%2i})cmgOXv3B2#srca~~A+7dtDOqBAH)Kz7PyPwBx*A)Di zpReb9p~zfv^wR(kv~E0UXV&(qVo9$w?$<16%8Dw32wdbr_iQE&e!>>gu=+CXb@MF)reYlxn0ctSLT1+=OwK+UY>oV4$yb zGG9;_h@hO@I2q3h-8YTg4()nqM!c}DPinM&yg2BQtR%uOLbINKKnRQ!BJ#}66i zN5EXBtbow$QwvJ^FEGsB2g8BesMR3NhLd%KOSLGrWZqsBSTfSPB!lo4L9a}^o)Gk3 z*pmD0gVj_|D*iP+M$b0+vLTg+>afT7RQNrJDeUm&`yH8}c?l{4zwI8Io+mtUtAk1z z{?E_7-fJ~^q4et$Blly-PfE!p{>Ep)J~Jt6BY-mO9ybKlrAlj=I{^G%omYryM(D%@ zFvxEI3}|`+38Fo0Yd|e!%~98=RoC?RO_Yi+ghhFn-FWvt$BA-If;W|TZ5P|6WU-ns z0Q%RJz?EqR!u^F2VNc%s>zsNjMZGFUe<$2h*2*-%7EVuI!g)?TD+r0oqeKk%Yvi-H z+0+0RtIapwnd5ol4#)*z;xE5OEYW~tO&=INUjV~W-x1@S#(eKT?VZC25K@+dECHzYj5 zg1kk%JPs!x_I#J5gtp)zfBE z!hpe|H^i+Gw`r9~d6u*uEHPs)+ncrpYn^vD*J4BqsA~Cf(51duXL{%kl#$Rryz`o3Id% zK(mU>AJA_=I_du%@70fRi#S=y*Pk>E)@kt{okBo58E=QCIn##^7KQvr(9cVBlALGc z&7A)yDcn-%BR3=1tp5=oH2;DUmDzG%U0K+Tww!-I&m0};30D43$JhqjSCtS`wcQwT zvo#z;>eQ0IjEI?+BkYPMfudljdXg>*68g#n70m@{l9sz4L%ipD#Nrg2J-MYHu2Ceo zF>qfdeT$o7(|*_Kc=^?^8jf`u$(e0p?zPN}F50sz4CWuy;9p728q|JQ}n2l`ct07ZbCT*Ch-2zE;+$f1_^Q_|#x=S_iXtiCcI~No+U5raOj# z!m2y=lxqQhj3-GcJaqEGc+oi7A7~Z?_qDUwVTR=9IBa2ThlMCc(dN46Bwfc6jz)|OQ z%~~__ds<6tamUdAhzh6MN znZHW=fMXj7nGDx=akAJ{3m514cG+XAd1_J&pzY=Z)7vr(wD>R|oTd0>Ln0&YYA*qP z@4*!Q6wLALgxOWWo0K284cQ>Du-*tB+v0(|I&~!)rQ_yP7Uc|4-fl=7eNF_BD6EMj zYP*2YBDUHA*-ccTQ>XWiVVE1++XjyAgaFrI;xoDra2 z0YJmq(r(XU*btE*0Zrl0z!viP)jiy#OJ9Vvv{u!ILW{I?P{wFWU4r_%N?l-^XVOOq zaO~zof0jciAmO49Q(rDu|jc%;X#P{d&vG)WNnzaJu~MHoW1wqD4vYEuSFv z{h0AOU#t8(^lT1xxOY%D|EA>grxT|vIu6zocl-*teC(L|~ zhZ)(C^Ls#eGLb_aTjj2teEU3UUsAw&l5FcdRlueEhRcA6y`IYZ-8Z}xxU=x+_4q#i z5J}DPXcd9`@WCAGvxxq#vU7KxlaOR$uSuwx(AHf< zp_9J*Hh)vuCHyP)IRT-WSc6yP%hM3abu^zMl{1Uof+6=Ar9%rr0W7NJrhK$SE|7iNHWX99JZg{17&9{DxF)3Zvlzc^75h@It*ZXHuNit5_ZPoCCsFzX zofoStmOYD=sy?$d?1?BVI6yf#G;9Y{^R}v(QJurr5naQyy~yTecd}xqlfE%V^`y|2 z!Rw&{d@qzLVHWd1lX0Y*Y<4AP(IWcaOWt|VB;I46qM^}h=gz{FlPtfqhM$Eqq2$E3 zO2b@|sBV;Nuc&?Q<9{))wu1c$VU@B(e%FUE>yEeD0=TQpM#LBA-XzT#MHX&8!mj66L-AH8F;i0dy20QNj`Z z&Kj2Y=Fr7eo6kfr4#s!7lt|Ubbo%na=m|~+aq{%biKWBBEYZR;_ZUt z=w|19va;rUwQ^o#Z6DdP(J{f0S^D7WcwvKl+_wPcIMB&hEIIIdtLQ~QBXB@1ARC`~ z5udry4-V`H_wjphKToYdrH7yMnu6-HyYzZkM}}a}Bzg_eEv*pvNOU6dxHJ zBXOai_<#Ptf8u=lw)fX*XRtX85enQPz|8JEAzd*Om!u^@G!?_|vygr#?CdD7nNm|0 zB?&Y1OLBvh*y}#&VEO)%O?DMs7_W)t>#OI_wAbcF&fs*wU}UzSr0*7czwvQu^#a!P zAN*pauO#rg$wJarvVDni*X8@CUvti>T|U?5-||TM)IaxYpo{&WT1=fk z8`%U3Ju|6u<3CW%{BpOrdS&9+;L$8_@UXFz_<(ojU3b|tvtxd@0nsm?K6mO7upYia zp4%JPXw$Pl`Qegc&0nH}3FcY1s`5&)b`~f-fKN?4Gw^b!baTTS@6gBN9ZCe>)x6~| zTVmD+Ww*A^t@4E9>mSqqeGx|TfVCh!yAkS&X zw&x3v3~k%mUs@lS)g5TJT(Cau96n5~@13tS9(=iRTJ%`5RF!>jznO5l^R)f$SzHvU zd=^+VU*7Lo&<`rU4J>Ler}ikICMaGlq;Afk#xEW%EOHZ@*i>WVRt~>!F5tps%O?ii zHy7dD-_jrp7?pG93a`qyHdVsH;e;iX2p}l=BgT!1=3aQ@Af!K*b1}( ze)jG`L7>#kX@Re*mcOcYvIIwYyreuqSeSnnC^dthp>FcLCAvx;4~)XQmZZoz*L9Lo zRUByErlQ`SiBB`1Wl|M6_m1r-0}9DrXKC(_(*=Tjn3*T-?8XNs9o32o;n67;Mk|wH z77JXYDoUVbEXeOL@IW|*%)hAv4wO<%o*b~{sW&KJnBnuh?>L>p_vdFG_#Ufe zjy=>yqiHAjwPBb0^OibWTwdYP&*JHy(imFBN4uZG(iNAWs89E5?SDuSaPMoKWeh9Z zVXR)EITspo&*e%u7Ak0OQ&wviDJ4=*V;*79f5$JARNr`2v8~}6sr6g5Fqc=> zOyex0t1;zJB0OKat6JIos18yaqtWK$4l}jXm)+EYo=7X$5NKf`qj4Wt#vKiF(mBgw;)$vWlGsE#nB8r6>MW|`lA9?fv z|y9Q?YZ{mcowrepq7$#2%=0`_1#&172z)z4J+Q{2!4Tq);=)bz(cD7YrmX=-|x}zFcz6fJU6FfW>M^ z=cCZ);LRaEO8Q0aYz42a$nu7ghZkw<#mh^AAghdT(SsIdy0DK~dFD~(a{%4n2p)~G zB+$d~%~brm>WkZY{wL{)#w?cWe`L!|EV6fUkeeumV}2lrGarS=vNFD+1sT{4TkFTHnLS%8{u_o@Rv~6E{U!J}0 zkMWfz)y4~`Q$4%LiayWi3oeXI?^g%@tDaC_;UCM`ZsdM@K3>$DuPz{{O<#Li<_-Qg ze~<$2N$^jFbC!#*D4&3?c*->*1GW}51e5JSA&rmuaRI$KfPvz(d#s!be8R54;Po_; z^`A(Ej`*Q|<@^&Va>xa=55Yf?{;~e?KS+T(z$c&-vF>rw`=Nll%le2ze(FUrD7V$e zdcMfNf{qNiK=sK0>iO*V4Ie`U2Ij1K!hWTAicsx0ABJhhg$T5lQfs83gV*SE_FyCo zMfnS0=JKkAzPl|50zq#&M6hDOYyf*`+AY%}H$?Ckxo&b9#P9y+5 zc6DVcS>am#Bk1WSswO8S9%dIE;r#?Pa~XgInIV@-bALsOV20joJ&X%B938rUx#Qvb zjo90sx*p?}{PR*knSUxi=H%5gaS!alqI=7)yTp*m(PUk`=XB<<2=bbRhgen3(of!GI!(=Y0Be@(6#8lBIj`CH+S2COix0Ogo;3^V&>4jEfyEuRg+skQl2%U4Hds;k zvJBD1Iz&5*Xg36}6IxhA-an3dwUEqeOUi}F|>bVbz|eTy{ME=ks63RH`fp-yOIBJbuqDYGX`3G*juRC+n?$Irw-l! zW_(yVx;;JddN|vgnOO@2r{1LYaLkpZ2ErWMHZ-)%fV}2Cx!rH;=jP}68R{SGAjL&| z4J~!37rgle5GNFQ1#Zu4 zmlhum)>Us7tW&3|7>aLqs2{Y8+joi%wTri>l+TKvt6r%%mKE2p zQP=1xKhzfqlx{z`jU3j0rsIjppl9@>FQ&4(~m4ilz+#OQ2b9ZeWva1~NWP;<-(w_zpjub|Y6qYocmg}NOWkfix zmTlom_$%Y*2%q;p6vy#J$o#C1=%6ZB$VSiC?OD;1bVxCDz*(~zNETr`%nL6kvPe@#us}=w_z6Ey zu^%}?I?W3|(4MAzE24bsdqbKsti6ikwxXE#QBf$M8|SHtU=gT(%5fhcikGa`6Dkdi zEqk&pvpNAx8QA3zha1SPRPMG&*Jy(=mEoTT`~2$Y|gF zHTbu|{a->qp0zLE30@4j1hmo7`_ojkg^arhT9heZMPb)d$6$r!j~gK1(AIuAx@E4m zg<06QoKIRpTtrTb6|2SOPz_6^>87)V4o~&36k)YQT8!Yp@B{XD79b>WbyK$OhiDb~8kOHQXz}vW9y68JS>nFTxu%jRV@6kc_ zwX;g}1z%6FO<_7!G+m9F>Y%K9aMtRtT&L$~^+@mF-F+T0Oh0dRajHkQu_amFmC@6) z9jM*-MK|+`bNcmq%n)X} z<-XpIrm}?AgHI-KQotkeXD=`sNS#(*ix_%LH+sM~RXbX|R=btlX#O#az)&l{cclcX-JblVO z8M%N2IlTv1uj4*|($=QiuJ}^pjRD1&nFxcLNzW zfxa)rcm+sa=NeTmD%rGxG0E-{3S1b0dne98jQBY<0T31jC_4l>{w#GY^00LaOQBw! z7(=kTQbeXDPUOxCWb`LdG6J%=~K7_?&mx8>g?t--0;rp7px0Q)#0} z8u4Ol{dL8{0*~;Nx&tZK{3m|-jz!wav_y?g3om~Og4(#SjNu3rk42-7+Iz~D65*Ua zZ{T}X#Geyt>N+QoDBDH6FLCqHaR3iqN zl{+==w`TTe+cHkKqIvn3mr9R{)O_#b3BH>oBnWhqT_yZn!X~LOg-CwjrjOo(Hsbkn z_dcTa?>|TB`pDQHwPqr?NEQK?U_*p$KYWcEuOqlXW*P-|R)J5JRFfrpD7kE-l6qbk zkx~?qvYO3qE_Ut;D>I^1*9t>IZ1nJ+F;j!LZ57&*?>l^X=|q-|x0>8O zGR(=HzTkByeTn`wv^qzYb!;;X1h;n;rlu((EVKshV0z)Tc~khf4##1+#_&4QOtkI( z`%=jb>O`(_H_YUpR&6ZVtaTd*iK)$WZV5sqrbixG`>iYuCmYQ((Kc2}+Ui=o179aA zKV&%~XUv3GpSCg&2R>k8ftd@=Xk*Ozd`z7T2M~)$)?%QAM=D>N;|7ydu?v=jFMP1$ z*y-go6;w2*Y#7V}4AddYSs7k@8cpthlFrmWN^5Z~cwJ0t#OGVM(T3^173YnUJ0=U4 zn3jKFh32iiLEG=ad%N-aN3F{vv~qe@HWw4F49!c??p%&0H5j{sv)680S#YcgYgcn) z(YAd)28g|YRW%r#0_gB{m(t=#TwOR(j~3xroosx1Uxv3;$=1AmevSxbZdR1WuBZb$t)G~Kw* zq#f@CM|ju(3+LZRf6BpV3>=MSb=DdQJ}JKC9fExtoqF=mC?65&oALXB5Fm!W)oQ@W z^fQ`cON;5q>P*bI@Cx7c1mP%-{z)6FoOzMaJO8EIEdJS+Jihcp=Ofy!QkwKohjshtQV06c_+gQHkqu()-^~$j2AyNGaMD_2 zT8(ta`bbraqWrr)$PL{($yZUfkdD&cKwvbSETdCyWCM-&y!O`Gz68j*W^*lq`Df*5 zjC&&eYp)k6yyoJZims}0d4Mu5RV9qsEaG{8I}hdtq(u2i%J2PFy#n5BR*VQ(KlHJL-iSx7ywvUc-d0Tz=^pqKD z>cYb$tuU1zg>5&qf`FehyN&tY+TSMf7#nhK&alnA&m4}%kX>x8Tyc$`ZRDpD?i=eL zBkPRHah-x=_?&ygnSJfsWIkNhd?ToRsq;n7^%Sho>`>na>uOU;jro~Y>i+p5!&mQw z%R1;!aR_NxPVd@V$g0|u55IXU=XfXF*Hu1>@t?#P?aGIoo)cfaRU++GXDQKH1wxF8 zU&VSKcDhYudsn})8TcdYdJ=wfnaJ|4ChTq4H1dOpl^YoWxCnYm-A=&?&-Vx48b1nc z9)%fxrEsTUO!$59AEAelzFQ#DIC9`wNArshr%-FhTbR0}4#}VUc=SwFxiyKD&P_2B z#d@^2Ts~WFRDVQT!d|1j>L0i?@@tfjqv*8|(N1o*XS{lSx);@)Zft7yAqD|wjM;NT z?-+S=j>wZ|V0biv6#cTX>oG4u%}1X}khbR3of06V$*rjLmU7G)DNofE+SC1; zwe>_3D_tLKAF?j_A)eH|@9hQULzD8wXgw)9sep(2{Ue^G&tHz0G#wcbrFez7lXe3F zyhDErG`h9A#yu=1z?&JyAjE*0wFK-Kui(!*4DSxBc{dvhUHpCrGE7ARHihmE)dU*p zkVi+K@SKsr$9l^N@J=FI5BN7{giw6+irW!GB7gYmS5Tk5*5UFZSc?~+@9 zs{wzDAJyWYYidRli_k8RHMsOR{2r-yscp2fd2~X?X7r^o1?jD3=h9(P&a2)fNN`8T z`q_C7LQ1po{cziF(4n*7JyLp8V;+O_uT#1cXCN%W2l(*^2y|D+I-9^pU_PloJmz#; zQt-~2z?@f0=fs~J$iSI5Qr^Y)cj9gE#ObcTM_d!&bJA@NWg`-|?XG$O!*R$STBFJE z#Qw2Ud@~5gU;F!45iT&5BXNqv!Y6XrcT06MP)Zl$LxDsde03RD;~j)afc-L z0v@r%hmb-WFvLq9<`gIp~kspBfnv5GMVe>g8$?u z>dG_y$}{%LGxf?d@yavv>MrW)ZpUKys7!$8{>I?o0r_#;ByU%I^$-OLD#r5PwoU$h zKj~@n@E8H8XI4=8O7D1ns>vJ+&#aM}YDw=mP z!{8bN=gSldI}wnm1?h`^->)Op_|gn3cOD*QJ^=+%#pD)p?T9dV=M5ZbN>ViX*xH1J z`hEdKqBX{}o6x2h1&$v_zg2pvFll>&(?+o-NQybjk{@P#ddRt|&~6Jc1c&=Cu*u~5 zv#*mF=aGrnStrJBA%_gsbEUX!%^G)HIl(O```UW4q_}2 zin3#rMJp(&3t3`}<@>lv)G^{&-->H1RrGzBd?43H7Pz>_eM}#nouuj>ule79DI;Oz&n-)OP#Rr|tF0Cy0mjm=n2g3eefPH( zFt!(5bY|&^?`^(itmQe5mqdG9KYnD*u^u>s=%0D8JAsOhK3;iL)_c0#+p*t+TNobR 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 literal 264179 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%0Dlst#&h{y|7}5 zcX+Tv4hY37tGzk?SU3NUB!OBMNd)zUBx*J?^4_)2?q-)G$(QHfOR3FSZNAm-^0J%_ z(WwxLQtd)?+0Jt#ROA^Dv6)8R{GbXj+j8nSBzridgTO97JOqfnC+upcr8Xk4XeROI z3;|)nR7&?fl}$>*i_+>(4zd(KIOB;cetT!eph2n$5}=x3#t|*0#0R=$1TOw_ao<_s z-6RFxO+8)@49L3~gm&TG9P!xxE9wNP40X?U9nDN{>|q0tFYT9g8m8?awyC8#Omi?1r3Ir+qB7WtPsA57;hBA?(;SA;ZbafT!FPA2@ zIHPXeCFfk{MF;lZtm+`{VqoSbLJL1qW#VA$0u=~jSm15vZD~ycVp&X@@S*c-zIkAi z@lNlQ71yUvDW8?_%{#dprn)9Ytr07slJ}6{zyLBl(+dqbX6U`*Kt!w_L2h@EFb}|rI zwnNA1Mc&_t0NY0J{x*$GCvq zhT>HJM(T}!KL(883xx@mGv`)(kyLQoKTL_tro2}5J2NvLmY_D^+(&znpe7@+5t{Av z{W+mYcqP(3QrzLE;x>ao$2JahY_Jux`7OE>ix4zA$54vvV3l9@ox201?0~mZ9v1IK z0mXZL70$7Rfqx)?J-(xcGM6kc$%1QEulhrMWezOes}`1^2Hb6e+nHVpP=Xq?!l)a( zDF6N*w?T~d-{>n1~j?1R=-{-uZ0tPavg_d~^WK zW7eb$cSWl>phbTAlB8D#v||=+KX9?OMyopfX(j<>)IHJb5!NA;yv}j1$Jy|eN>|4Z zK=PUpfh==8p{MY+_}-{%3_EXJ?;XZ70lLDOf9ro%vLXGCY}?0-qld5MNMM)?YVeyyKcWl)>;{p4}VTj&;9&o?q zdw~f2@X5Co$}_(Z2fX-NyVNrhjRI+im2A-@$1m4($x2@BKj}AT0j%Uv!Pc2PdMBLf zpO0zJZ$huAhEK$MO6X?3`boq3&DeizBEqYD_Tz}*g)$(knC9O7>~f+g@t6JKeQ9z7 zA696jl|bT@2S z3?jP}%FoDKlldw81E2UEhQ3;0F~Ty-u{T}CmUB8d{CN|BX42>(S^88}-_PjVl|8qV z@3K7`ao5U15GY4WVx%sa5d8RsW(Pk&?gTHg`coHY>pEWci%nGZO34Bw0@)_zTSe;T zZZUIH5juB|$acAp3zIc{LVhFo^L;}ovAd~FX=jj}mThMWxLuOz2s>_GyecGVi(AGt9RO(mC2e>DtU)`HJH_sMH%O|kmSb&^ghg*oykN+- z#IhSrmoLwmDv5j}_;DE3rhwc&x%BbaYtq5#r@Q8>EYcxn$C07= zyPiZ7>c=4t4zP#=-igp0-` zkyy&fRU(GW^oulx`Ef{UKxBRF7Jr7W2F|n4SAr8aBrJu|Xj$%ZSlnN-*m;tt>WECWJtA)zhq5tII~bZIcbrA;t5@-9aNPV&)^=z) z6x1c8H|{qPEE$L0!#(E5JCrz{YaC)NTHkVB{3u98Yp|=wqNM#-ndp1$n(K2yU3Ill z+R$xpWvXolCBG_My$-+ZN&m^Z2UVi#lSs38oS1H3CyYa_zg6Pz#i+{sI~LnKqjqWH z2QyHL)L*YdT&aQs*|K>{eNuaIeRH3<2Ve>X4=n(FoO-)3dlJ9?G2rQ`(>p>!d`Gpo z0g2$-xnwu03~8;K(Qe>nIsk1Ph>$|nc+IYC0xMkb2|-Vaf(8ngs*m5|fHn@RVXKcm zhVrmkEX_8LM;DG((@?w}=hv$7Yb}!&Q;1l2Rx!084xmlzl?%IeAe9uPbmgcRHdv3A z;B6Soep^a@fTvtNabjlrp@|6m6dXufHt?{cNL zo3Be`Eqxnv@ugvf5M)PZ*z;bM#VJDMFx@iq*=TB5kH1i(k$5@NS>%R8>axoR(v>#v zk1B8k;h0%r3Bpagjv-vT3C~f-LDgd2dvVUY()^E#jq>&ur+_lfSF*KwAe2#~6#SH5pI0&VeUug}C{B0!IJ4icTxyjX zj}&xHh5g=ac?_e*w&#`ESRkVf{VZoe3dgHYQy&0i;t4Ju;A2UTABF+Q#OkegkhksPwqA!HN-0>nyh zTD*--!SVyjUO4z|HbN~+D*?aDU9&96hhoO2(1SJf0~bBO3&Reu!~0E1EiV@ zy@hO{={fX@UcETvywubF%jF;_C-fQ9Cn^C0{RSoB*B!dKX&H{~;=Z}(m2@T|;pZF4 z>t`&{n*nV7Jg4ad;-BpsBZ&1GK2*n+tBsb4GD<&sL|LqbM#&vMl#dwHE7ZBL?C_H@ z1it}2R{kuf^5I7{{Y1*QdtKP5l64szHaxFF&vqU6N+j`Qtia>Se1S=W!6%L(QTRj zJICTnRkyw5kfQxVhcMjgAwK`1uaGjXL;}oW10nthuHWsDTt??rm!%$MJx;Rx@eCJlFhhj@nwK(b%^u`a`mo443iY*qE+u_dD{ zK~qV_BJ1T`d~-gh{}V|nNH{X8-bw?}er1&pV`8yx?=&;xAn`GtjndIf6Q@&}T;?Zs z|H)63{U<+>H&MnAYIL3t#LbItI)xdwe4X8#f?R&;m=T@f&6dnY+l`P^E9#LYh>@~D zcuAkETVy-5-9E4Tu=zAv5)l$DlR>fy`qfEex9V8@`ChA{Beo|XsjCaf<<2v`B)$MP zO|0RHp<^EqYJq*iHuZLg_1HnyWr9YbBs0wCaP?s<=Y^6s>K|N+Pc^#~W1 zh9d|$o#@zx^u&1K)x@+wY-=BDwv=`4HorQRu%CVNuTt!F?*{F{%DsOe>zXK3dB3|Rn)+C{5wCBUcVHK!Q2SubiYh#~HSKLxxc-eEr zKNj?oqaiPBu2W?gi*rGi+Xyc2&8nBl2Ii=P(V!9bSr6okcRGkOF5(?TT9PVK z$EA<5W>R0BA2WbiVW;)dapG#?%#TlVMio?G^@BW*?oZqY^3xsS+t21s4N#zzq>+;x z@qAw92__`jCpW@Z-feBZKp|Dh7@uxV&$zkByCd!yrN30HNQ`>3Q>*lHk|hP3WTApd z7NqI|Q$iX4fxGJ& zL|Wq-1qpVDE{Qbzr6i<3TW$Ica0(93HBmqi&kH2&CdeRwnTn&rpCTI?LG+F2pY~0S zNqfNf6N%{tD#5@Zvw_53h5aVr3nuF652+IJQx`tFi9oUBGM(k|RI=6GqTPo=-+FGU zFY!D+P>5Yj>&|;y5+SV&Z$=vsM@5~=Ay{$9bH^lH4gy8ok0x)phY+)-hJw}*JMIfI zWqyobPFSMc20T|6w0!2}frg(F^!trmk{ZX|m?pu9d{D3&A8f#4JZes}u_*?Sv?&Pe zlO}G}ITsm$uu)c*#1FxR^i_(_UYf1`ATOH742-he;C`$FiRc(CCkfVxt}e!lKm(Sm zOGG*UbfW(WVjrJXkl=t$`cUV2M|3eb>UqeNIo#$5JL*5FU;NdIgQW0bQ_?%lu#_aE#;k*D#I_akL$oJs^4kg?iKb6Jag5BAqM zc;%scyuL6U?cMit0ugtG3pkBKnBK(Z`w>l}NE@Mitxo@Dhqz7~KnglhS7dq@nTxP5zTO| zdnSXSiGJ4-Bi2$Xf6MKn?B5ATtKf-WhC4-L+~^ZGW)%vtsNg>;(8PFT$>ejyUtV#C zqv1uD`EnH|Li5g3v}*qqM}zi~<2$3f5^1ScY zVv3P$Wse&TF41u7sJI0+LSpau%fbn`!I?iF%5S0cYN_xOBFeiv=WT>XtlF_3?e#IjBGWd8_#-h{d+ zQ(%M&&}G8k{-VoN7*b?3_A*7jw#R&_U!K*O!3VsW*h2&+s4h zn|UyBalc}h3dT5gy)H_OnaCU&aAHd&5W2_f;+CN1vh1b$C1LL-8Jb$)5-6LHvSM)G z8nh!HISC&R*62DHt##bO%FGXoDUgG*C1t-TlH}_gO1r;cn zqN13+vv5m_LvZWT#V0?5A}qEueU3Z%A!tPP#J!={pMe)a|@D>MyJz&E4lKnz+UGOuB zU-@U^g7w4p|3*k-BkoEyI4!$T*6ETEMcceB9!Fr~cOHQH5-7)wBM0*Q;MB z_|`AoV!RRA7Zb$WP1JPq!q*U7e3RpRh}{akAp}_@xAsguEAd{$FlTY{l^G+GEDG*$ zzaZy+#37P^fjw1-OhQSWo}Ei|4=KJso1ws7HuY{6>)0gLwc1rZjGMv=3Y1o?IkB-! zEB9H0OxSGuixhBT`Xp5IOucx5)XlQU4ceboYv}9~;n@)r0f2E+)eWL=lhZ&D55UEO@AKcApqsi?k@|YAf<M^u=4yneTUj0|P*wOwQO{Y+6jY*%R z6B~gM?Zqbu%a_xG^5w9V)jO0KbUkZ5&qnoJ=x)yVRA}^jou)ES5bMTTCBh%t;`5T$6^XX0J&?uhTb|1&bwGoOsrha!jReK-}q+cqbK984=fA81uRM z`)BD)Obyc@&Ol$fbr3N3-6Ea+Qv+o!6`FawWEBgHxWm*~Ra;TU#-n>mIAQt!arPEa zc_mA`aDoSS_h12n2Dcy~xVyW%JHdmyTL|v%794^GcbDK6Ao#yu$ec6h``35wojZ#~ zSUtUacUN~;SMRENo*SQVg!VxMGb@A@a<;J|FBL%=_A~-;BlSdVO&n(<3%pHd^S$iu zbo>2c0&}|d{v5kb>QwmliQ3cEd+gBhGoD3Emzf0Zy=S25qG3~C@r+U$Gnd1fZ&RAKEP^c$5(4zE1K-uG~>0lw~AuWN>{ z)juDso`8|M88-l6BvTP>02nDM#(zPe!mNwT-=Qp*7NalZ-)4ja_h>JNh>?5Ki!JIx z)|f0VV4?zECd}f$$UOmDA##ba{gC~JMwY(uJ%g5ldy2WN7+^+-17^hga@g9f-k}&j zk$yA&)<+o|NJo$vQ4aePECW}kBPzPn#2OE%-}{`M2uEJ(_x3cH(r9R@h&!|o(}ql+set~BPs;3Yiw4Q%q~2AUu*7Q zW)PN-`|0nwN+3!Uic)RVY=^7y)4@~sCt?6-Bz+Niip2%*Uo87^^*1&4@^Bz%B-ei- zfRG8a{JrDbE32IFT8rQsJBi2ysMRv34f5=mun+E z&E_C!tQoV*{vfvxTCP>E%LFP%j6VGV}XpGQ9E^jy$8KN{gH24(<@%o zFo1>C)GOP3r(>T3Gk)!31D%bRx>wV zgUeN|U5cf+xN0E)D?&NZ1l%b&@Yo>W$?ecf5!DFVP!j)qL;bnZ{|6Rf3@?OYS`oF7 zK#|H==Q3GrZwyg1PuAu!V@~1w8u1klWnTS!5X2Jna}E&z#Qa2){%JlR*!v~xr<;t)8%-W|GVv07Jq4zPCveg`=9y?4BG-w}W>h}qAdw*<>P zzO+5%RAd4)1_0x6-7^~DWzyxU>DW1C>A{mhU17=z2a4u=_m92!98cHz{}Ih;&sq3~ zCB0$S^G_b)-T{CSW+;)S70_~QzsfP-ajN^y{Rt!NUqne5Csl9gm{c}*jO{^R5Q|9d zxgfVIF>TlejF42JO60Pps=R^h74#|vHQCG&$rVz7C;|(^0vY%a&O9PG_a$0)Q>~`5 zFde|KnzD8^;ragLZ^#VmV*`CY%p8o+$O1AwuUDHKnwVKD#vKzNB-TFiTEx_}0c0FH zF`twRn`65bNfWAafBWYr?RNv84}o};R0^vlc4=)0zGVZxiaf22Y!KSAKTWMA6?IVW zA?y}7f*+V!Avof-SVmapl9lB1m+;Ho7la``d?wGJvioCpY9PPPKmUBl@f?mEBMSnS z2mnEZiLc~-3V9D)EEA)U-+da*v2cF6uprL1*R$7&&_?oHHMj0uIxz8Ub#i@T)ey}D z^2FDD!W4!K_hLsae>0FxtUg%zTF`&ns5BG?UpE!;IGe|#cdsMa&O%WCLO z7jq((Rql?Jnv#m|rNq%=%$pR#*&K3EcsZ_wnrjbSS>(-N5olR)UTphbHZQ###z`bg z0*>!~NZ&kuOY1zLWbus;MR6wKmjjAfPAlxN9G_>^hhE(yU6eobL=?Ti0?aJ?z#*C% zfzM-Ym7$(ivp6(XpxY%w^foAEMZL>;fQ5Yt3C{$w&))4@n0>G;SB+5^9OvVw6gPTX z>pw&ha(^R=a0(GJ{r$2G@8=3|EZ~(u&>DPA0gi=%3HVa**h2mO+K#3ll&{d7fDecR zX=iE#Y))n`0k~y4dNYK&fD~&>$fv+ihEAv)Q(&@G{<*gKlay;M4#p3_20?oU87}V> z<;FKq>caXceKk9SL+tH7KpXb0T0UW#PCJ`i`?xsY zqt3m250n5cD?14F5>l39ojV5-7l*S<2#>1~NLQr24-6X59un{Y5}>{6xi*1ht^pOL z&23OJ*SiP#d>ValaZN+fZ!f$yhn-4Swfr8TZr+|yI6B5OSOgc+zR9=%5LcM4u;l;; z5!Bmy+O&Lvj&=ZrTt%+*v}3!>5tNbp2G|#!pp0BID9BAYXp6G|Zk+ap!*_&Ame`RK5RR4Me zuH$YwK*jLo;rdd)_+82xSHmsA)gq5XUSCQ!k4aaKh|OXsaPb&O3kJ}Z7kavor6+Ei zgLAnMKW{|<9{+IwZJC9zd>uuYgE?ekf~&M+3VRGYIJA17Si+aad@2b!R#8TNA{N$v z5M6F&vZ)ze55S4^j0u%mb-v*l`2GDwIW$<*21{ z<@z0;c1$?>Hu)yoeFeI+DeEX9Nmd8I?Vm0l{Ur;=pFJ-R!iv;~zPKYvkIdN>A?FG10itctio0kqv6ra z(LSP1C(-0uO6lh5;(`BR`03*D&%u^Co^J7;QUA{2GCXo*iI?jU3PGh3K{9jCq(FOO zgOp44UI|DVlRE_*Ovgvn)oR{&Z`(jw>aYOQ=2Mn>hMWuEHqvOt$kDMg{6PYD%W-7E$h zId;p$ec5~iV=kRclK{z^MBW6YDL}NTG+Q+YN~qYkWCNu&$~H{f!P@_hz4FFsiO>`T zSbYax09pOzsFC269f2FD<&5V(b8=KIxE$9D=W<*&`MXm}Rt$Ju>6}ye0Ro33jb}c$ zdaxLK?>*bPicgo*k?@J~8VoKE$^Y^!J;|08@;5w)XcPaR9=%Kq&sXoi1<<{7-{Un2 zC}PK;Rsd|9UmbsJ8)Jdpm5rD@FceI!-y=A~I9!?@YOx+V#E0qr01f1;rbVoI0sz1Rz=% zXY5I+%EtgUYFy2dI1n2(E~4+=ry_tXxfI3rL;^r)F(@>fEeDZNn=d6SzXQmqZ+ihU z>bvjl!ynT}juc*hegayKGj#(2Eh`S64%{T&Mz{)m_j>>VE!Um-jQam>9LUujr1YaN z`vppf+ZXJSO{VtN*nJN|0gflJIIrCcXM1SadSat~mskT?9+1#(_KY?JQ&*Do|Ae#5 z#PF}U=D*=Azg5$RQP+Eqinh)_b~`V%OL6<-K;pwgYiO?ECE+<0vIS?KUVTZ$A0(K{ZU?UpET` zfOEthLeCj9#!!z&QeXi{_Zn04U=omSCA>Pn<$Fb0KLBFSHf0$Oz+}-Y;=B|GFj=VF zY8%}g4Y_^u;eSZ6IR-}>fG3i8OM>n-=H-+q#>LmvPZ z5)J|jSph`^**Un)fh-%Ef4+R5@4A1BqyQqCEq8=K5zPR@rpCg$- zr+t;wQGVCQL*U>Pgz57LSp~Aq@yPSQD`VdFe8kf)g9Z_~O|^q;^Kg)Del8gi@D^a# z{9~K%1p>4v0K4YjY;%*l^-Fai!nWPV!&$=pB+C zQlH>upFqhZj}3{ao|!s)lU``0R;62pYjQ0_M0#5rIz-FR-Dd3kY60$cv4TBgh&f+< zKeGS4#(pXNLD&^#ZB+7%p*!~XgH_2u!ppC!{(?YwoIiJGd56glwxF=0l<18Z1>`lz zIj>efxtteaziSP)Z86s5_T4sJso!P+P=;o!c`vHFTERI%8rn0HD$fc z){t3M-^>1?9y?u+x3A@;WuqHb%P8u$F-_-JFZdnzgR{-t>V4$hV*B(*DEkaJJSj># z6Irv3_wjm}GKCHc*lTGF)wiPB$oVa(x3$S?e%Iw{tj2%7cdtL)R9ViU`a!niKMs&% zV)&Qyxr+fl@L1$7sNXr^2(F{XK>#l{3JRLFfwbIlLBv#!oKF8SBccrL^I_6VWIO;5 zaH)uUD#~kOjPc7I1*R%kymlDl89OJmygV;VT~Ht&7U~C#f4)RVmkqaT%dww`V*&h; zb_E$E&7v2#JWSGr0CeYj;)5Qs^Hu~{SO5viPz08m5lEw`D>N8M>>r-kVN%FoK!8L^ z6h{2|Qz@a~ZMS^M+}m2+GbSsZosr301X9~tLrDGKv5yizj&oRVL*73?LlK-r@CW<)^S=24gPAqY)ZbrL6!FLaIsfD2EhdJ)!l3`25cKvl zk^fsps^C{HUw%%(AJ!}x@TDx3_P0CN#+h`3NFeMj9Xm}B2Z#edJ6OSH z(IAed_VgeOjh|N+_Lb&{pyLOgVv~xK2Q@GJ*d!4xBcb*;Cp*fNK?x$a(pKKYSBlFr zBP$(?#h@Y?e|*^?%!OEcHSEurIFmDmAR)-I{xYQ`Zo+0P$nX(<&SYmAQQ0w$V8-G zFo>Z&z-mS_e{8KZ4bg)Hp`0C@GgV&)DgEFAp?pS#>3tqUuZzpuKB>~u(&*ym;!BO5 zr3y0`APJ{Lb}eCFq!<|f#Vd;TSqvu)wV5(2x=YMrnUE1eR{y9X3U|0OMNaMtT414 zaA^ZjiZ*NHf9p_lH4t^hm*DNi3F_C2?}A^1;!|gVT>^QZVVQ@l`BDhY%u&`zrbvX) zJOE13GlEO;J9ZOL3jaR_VP;}@_Cf17G{^A#az2iWI6xK%BMDHin<19d?}y^480{Ftp{fH36&yLI zEJBDhi1nhJ=_{0`1>!(%Euyr*>!9%2HomV{UwiSdkduGBqh-wi<<{by148~C4CK~I z8Kz^Rizzd&aH8j0Ba6}`^qyjXgp3K~)+U6ERhF=6s7{$~WOq6RvJb5)KOAPl3(y0n z>OJK6O8`;z=~P918xV=750H%^daiAPPSvws&KuI%(L{V`J5DMOhIj(Na1owHfHYj0 zT~gzez9$Y6ql)xwL&-j^UfM#RWJvST0G+Cnpi}ko$<;4msLu=vVEM=NCQJ-Z7tiqM zAD{r14=a$5BnQn)?<{i@tU?sv1TajC%b7r&%0_Gl5+(QU`V;6qu)Ig<%r-{{4wtei zs{}lz#_>O|1W>+6Y7|+Pbq^ZZvS3#KKGXYN!Gir$A(#q3^qYQOwH8Z4@^x{@B5*Je<{{mAJT z5^r!IC(E~R6x9!ix$PNt9cAo_XcQD{0f-A77n^J{+F`C+2W)kR-TjbQ?bC1HXzaDD z3Ma$XtD8tK(oskI0G2p;TDY=R{kAYds%9;aHVKM_D8 z{|v}7YgnVqvatKy$kCP@a{wUJ(=}%pZ$!;rtNqN4DYn?XF*v8m{ffCUulL&nikX5Q z!omzRnJ=oKYk?e;m8j6AHyM?x+*ds-BRM%GU4(Zw2=ila(#n0hCK6+CBctR4`fH;B zgjKoeFQp>eV^!*=T|W)S8|l+c&BbN6)ds~RdLr-4s~hSU4)6ffErvZGEQUi-y+t%} z6ZW)U=*+vx>N%j0P}9-e`13o_eh`th+%jHEeZc-w(Vu6##4uA2| zYNyW0XGUcA1))@xzUTz(m^OV-B+FG0ocDXtPJo-E!2r_V0UWa(!Nf2M)s?2vbv*Fh z$4S9aP%KL|K`wujSdm1>7=h%rs^uqgRuC&KfBnKaY%h7ZaETDh23UuStf9qMAypA^ zJw-7GbBJF>HkXGpPDc1b0^9O?O9CAjlfv9=>I5t`FX>qr44)8kgs++`56p+9lG^%y zr963|wwBGTAlm_V;a;1zp!jU2-IKfUoghtb9e;kLjBF-3kmka7sB(UGEEk1aIj@O5uFIz#$&HvnHWPG}!2K<}d9fYAxQAhe5z6-FsD@_~3Xo6zt z0DAYO6bdS(mNe^;Z^_Bm>s>!L34p8$JCVQg{I^e9G&ME4Ncs3uV_hba3StBk@}gXT z9ccQhf)3f+U3ZDG$K_AK^n27R3N?w6hV9T@WuV5W~C95I}T2qqVE! zJO-SsCD2;_R=~;1Q;CkyeT^y1H4U{R|LSWSU0%abixC!QY-J*eGtAg zTvmmqcLC;92ZS6^5vg={_iD$th?FkLj~+oD-T;Q^6!nb|fJKBa z>_;M00Ky{LI%!e`D1ks(&e6YRum^kvxkE_oRO}k0V|MkKddU*gdO?>MZ~}Mvu;Q|=<5jv=~PHh z*P8#7fSHK#SCVSLlBuk*tY9cAtc|prFj;2^tiGGIp2RzP3wDdpO>jb?U?1IZ_&K1W zj|nR&N1t$P2LP}L=b|g_lqZ0>tR65W$!_hW)Jy?*-j(gtWo0ho=icU?Ptw^@1)R-p z)7UafrS1hPu=YHjf?}YtxSbvL~2QH>e$UTe|+f1@qFd%C7 z(N}f^3NfZ2g%Ohp0K5TC*Iuc$78G=G?J5~pbk`^#p#|^qwjQ*$(?e69*7mqjXfBXj zPBNfj8QcXia&}AroxUOKcMlc#_JrEOGa9?LTTTHz(mfcb9+U(Cq_hB7#D?6{(K>uj z5bKXNK&E%NgTdWXorTL_8!&)F1$7$4^J_?3iEd!`G0_) zB-^v+LDE+GuhK?(@#2Mx1--Miow=U1wK<)OrA2rGzw`zJa=WE= zgfnq+J!@&ZXOyPHT4~p8QN3!ayo~?gxpAHYpT#3BUoI|B<87cm(M_qoZ-%ixekixX znGLIri?&CNq3RSf4V$uA(bagH$#dWYH?N_-G?n)%NHVQZ;q%lDs#+%PgF>BMiA={y zwM7D@x}s}rPH5=E09+E=Bl$t1#O@3CYNb@}0XNMMf5G9*_7d6JfmlV0=4H%BGbBn7ZulH#ea7hdi9F}qi!8*lO58~1y2Uht(%H+`Dq7CgIF zc=#n--!V;y$Ig@{iNN+2Jr7EKj=)6m;>8;aO!m#Nh86XFuAtQZk1EJ?M`1+*bM~^| zzA@D4QL$%{){UD(ALe-CXLr29+h_O7$|SJp@VD{puktlA2|QbN;bYO4U|%zEB__mU zAWlO*10xi+8v>_%&t2G5YSRS?<%>qDL>=d3jEfo8SB`=WC)LnEjdDBB7A@L<~`qKA%dx%-P|og9XKpjO;e{1*cwG4-?{^(*f_E4NI6G89kvcRe^#L zEQS~WDA_m{hxZ{v*6>3@6lQ+S2pwZnQ6tEyt1$U9g!p=e8eyv2=T(&dr}zMv)TJ05 zGNbpXP#LYZD&bv;WOvZDx_leT!iOg^;%Tj9bLAT%Ol+;VM(m!Vt&?B+e|=C<`4hQNk*p`Q{3E<^;$|jNJ0sTGep+#f8dZJi@r2L~}AV+3$ zNm1u-#rRYM%lqk`PXBo~<)x1+`2n(g4egG5i_#I6Y^j>NR`X}4KU01W@9xgo#3FVZ zWU`Ewt_00D{=T$$WWGK88VL?%ezulE;}s4+vx&p^kzZ2_vGLGo zBLoMU*9iQk#5IR9@lH&}x#6L|3unVh;+p5)>ggx{G;7}%Xm-4?U^2-6SHFI4L=u62 zM&?Cey)WT{+O5Ae zty$w$SUfn*J(}Rsu>-2kXC0JofX%gOr}ViJ_r`J^j-^PsUTc=7JUe z#~4p-ok#xFTSPAFrK!N24hMNA_enVT%Nq&txDR1uxMVyTqeOCFlXv8BXxnGsWQ-i> zFl;E{Q0{MKK3;E~hk9!)FKTIedpgEE)Ns1mUSHf_1QnO_wR2vtJi6WzO$=meKi;;t z-W}d-AJ=En(I0CqO8<7d-P@d4TB7Gm%UEuEbhzGHzm%S7*YIln$g8#D(b&-ZxHCMO zU*Eo{q2=+Lb$4)QqD8G#x?MxVljpjv6NycHy5ZsX>E8X;+{LXn=(*dr{^6~i&}MgA zYd+0;JNL7jt)OD}1O5jrwnQTB^gHrDpTN zce_Vg_J>-ISFy|5-fj1nD_GiPgy?Q(>w`Uf?e~xM#YoPXTIq39ei18=Ztl+aTaWFJ zKdvuWpVVRhkhcM`dhu+ZIi(Zeh zOWr~bPQvFOOs!$iOIy=bHR7&b4`Uss?^tu4r^Xm3pn5*AsO@QL@BOwE389q^p>5c4 zs75VluH`Q8M|~56naH=MuFXA2bk>LZrpn>NNPl5SSc2P3A}6N2fv227kM>9O%GWaJ zmE{l3-`hBgqe)F|m!g?N_ajQA+gDwQ2tB?QmU`c45)q1~nJz~y#LnY-skP|@=|m4V zT8|#LV-|*ECJx_EW3koNmeuic4~gWO?Pq$;1oauYo8RZ;u!IyXN4&pq+TV$+cIAVYMn(6)cE1w8eb5xRF_}yw0ewtTW(X7 z@+R9XU)tmgr&@Y_l3^ zlbkN}y{HiQ+J)o`&7fBfN$-Q0tCA7XepWu}N#v``5um0h24$4if8{*D zxyI8fE$B5;DlV$5i1>8OIaIRE2`~OiUc` zwuH{yNH2UzbxB)UxyUCECaaxiW^sY4s{R*K)3IjoMKIVzM%zuj(^VESYgTd=;q(ugl`$3&=y)V0@8hNlgiC&5q$iduCq||Cks59mHYUoly?bL+jJx35 zYg0R5R|l#1r{9Zj3VXlU5sQ|{NNRCyYH=A1B~!X1N)+(GT;6$9QFid~d3O~LSb1<& zrfsJ*0UXC~4BTAWmBLY)WW!xqc_oV&)%cxO@dWCd_Kl{U z2?TNhL8e*c2^OHAec^PO)U_k%Tmv^6R4+xxo)RN*XKe$13+8?+Hf>|9PBEwT>pl6@ zvD4JcWI`K+d)`ER)kLgs)iUMbCp*kmwX>`~%w__);#ku*4avOUjF?6D=~UOKY`@|Y zqIiK|IhKqji3oRb^a!mME&Scl20x^jJ*fKWM78 z1BX9hp~K_ALa9p81SW53n949dH5(805y{nN^`zikIY5Ji&9wD{#*>P&f;WDUIk_n# zIn$5|*QM3qlA~Trsg{2Z5X+(gR~X_T6tH$%E&73GNF9k@h1V|=qKh3bh)&AuuzRZDhtDJOt2hAaYCmFBr0a?5+Ia)jR- z#GzW^_wqY9Hc==RcrF%r0O7v5ey5bq#lB%j2mh1|5+N3<(4O@!HJaLMi=xju9E(DU@r$LX6Z z108ug8k+wD^A?u-E^(`dE=6_35dw!N42ju3)(P$ogQCUnw9*Ak+YL;cDtDUBC;i)W zP2Css&j}~#J=!|q=5TU1U~hox_MMH>#Q8x$T_|lgC~d0zX+;0@Z$^>!mO^#4!~uyH zzkCjc+{(yA)^t6RVte8tIJmb@OFT)7mc6+U#f| z^R&Rs_Y{rKOnCVDilZjZ-JH02t23^q1*DLG-9|gD1;@b?7CB{qGjD$*#!;Id2v>sC zu;-iB7RbTl?PFOBh&q@5sjf}lyZ&8WkCKdunT!eLqrLh|%fM0}cZ$eq{c~ouuG-!e z9X0i+E#>|*kT^zaphS7YA{|eLGB0K)9>h%R2{(@+Siv=;E+utui+jI(t=j7v>`*%O8cg|h6>OAJg}?Hr zZr>AC?+dxCOSvq$qB2P+E}!8d<0@Orx9r6y724Cxcv>f|1E0|$yE4)OI6x($^(a6Xz61m^=sQ2?`(3(j7#D}t zJWaHx7Hh3UK$Upk^gCB|#y-qE0k$`D?Iqdr#7vKdAD&N zK@3vWy4X!!hWfc9-}T)5)L!;}j5g1y*P>Mro30ht1NQt{f&Fzul_(AOQsTwX9DM4xaeREyj3dMrPFXe!gJ+y0tXPRw`l_tnvuHX z#49=!&0kPWWL`aK!V8%A7h#c>G8h$vK86y*^z$Dp(Pkx_UQMxczl)-0c&#PCCfvq| z8j;8l5p5TircaNcHtLSYD57WxG5;10BDD-WwMV|tojF#(_VAXvkb;bvfO6wiqC1CHlAmGOQ zRym z$1SF^Xu*`UI>4uDfX8j^mDw-7r?b<)d1pjlk>SZ`VTT}-0Cyy$;-~RTp~ET!d6t&g zjpEeEze;1tyo`+)i$l~Bbr!Cq=WQ3o%nQTDCM->9pzwovJM!%1J^FW+_tz1DM+2&#jiG#xaT;yeRlTtie2`P; zz62}oV0!97ar3(5%SN$=mypv44X+4}VSqPnEPdKoI(f^xCjz1LvFcBu-$KdjE|tE( z$_RLU0-RpAXx(q*G(t*~LD~LBhY53VC4@F;Zr?!fL27u3)IdUSh(Hgv00qyp3N-1) z)aYYiCphaLo&3+2AE^eXcvc|@ZPtswPwGG_`K1dWu?wh{ zWw=R2xk<$ln!O&=(qWl>Bf;}j^BkgZN9bW(%^3oy**R$s5;TT1P;(Q%RuPz!!`rdb z2w+O+;=ua2qU~$oXd&u6i8z;0zS}wWartbd_j8yn3~A{sTxD$#WO+m@NC(%;ELy*j zof?U2{nm7hqtqx2^a#9@)kkA9?=S|&$8p8FE6f>q4-c3H$;MKQ^fcmA&HAi%qAXhF zt1I=BEA`8Prenxy&vu0SdywqgSA5%7s-&kq=_`(IEq@+^x_*C;d3T@SS#{_hXt@&f z;05aWigm||^&I6woAK)C?EPeID7K7HQ5 zp}p#t!buyJLaSiYACNJ3QAHAEIC#)ueetUBloqlC7Uvp)zw02rw)Vv2hN6R z^C=n5wl}k-zP9xt3}o=S(THVZYNfKAc1un{0qa&6x;ogMqy!quwew#bHouid3WDl! zKh+CVlcXY8dSkAvOm(D$0u@X`JKn(}QT$e{KG)j0SZA@66dprR#p=diC7MBLEH|r% z^9?#%v50L6b_XdzcZh$bZ`mrX6QlpS5yqPcjMqRPpDQNzG*SM~im|lwRTavMC8Rx- zdJv%w$TXJ}Mua!TgW1TIG@%eqe;`N?|(Dh*2 zmj=}j5&Atan7hPE24NTun#z@QFg^Fn2Y`m2M! zmA*#^)DKE99mCXO_%y;5BG8pzbxOYAxrY#N&{!$S{v|_5;4NYD2dk>U1fc$z04iVt zq*B(8Rgo7uz+lCb7x6vfaUbJx6o<6VLny{Et5aP19iuevIj8-(vs3PB%_(C_z0iOig`n9^Vf-Co>rL zER1KN?TP$0)qA+N`@lN$X)pU(9t@{_@Ke*adM`@+(Fi8gVYQs*X8(I>av4{zrgLRG zA+W?rIojCUiU z*NtgzCj*$Ep`P2oy7*>XH)dRC>|q4w3HnjrX7;I0{+wn~-+P2j|3HD%F>G8nYmAtP z6?}Rx`tx0Iu}X=)pe^$qCf6{ilM@y{-{En5*k6!YOfw2ir|39o4t7|5hsP6F6c`AuHpTe=6fpUa)uXn1g6gB=D=CQ4*Jl1kVsm$+BKalr*KJqxcPuF|pc z8@sktxph=2a#Sfu?9memgYZ$I z&kd?Ad;&J1RQtb^`$4PyYsqOcj4ey()khdBLJlKeL_p;Tz{K#QF|rne%8XFX`5kXQ z-K2g(O^HHF0iHjM#|crt3pdRI)L57Ef^G}(jnNd;=hk(%cIA+PEKW}~*Q!E*A3KVLalZkHC7J zlnYM1-_;=Ax2a&sG)rT}WsMdDm&}WfwB7@?0r^9$IP)CNii@726x7po$TKChXmOwn z&C1y}JvXU|6Hud{vHG0_iQ67g>!f<*mO78XktCwoQ=;x+E zz((uu8p{KjYs^d4VGRCBaS?P6yV7^^w=p;CfQ+9ik%y-pp*Xtpal zh>m;B0^5pbl?$l7YS&gcew)GN{6Bi82T;Q%4O7j?5cMLMu^yneRD!v-1@|{hWoE-# zDWS-FK9|k41yePG>ai7ne$@_=q>4}4ict6Bo+ga%le$GYW_x+cMsm)E!c*^t<+}>n z?JC_5lJ6fS`yVBR#!Ht2h#S;D;L~8*ewy$v_XAXt!qUH=Mq_`8!A^q3j-vawr=g|Z z!$|eRNC_=GJ+1md0+tXskGf$uAt_0Zm5v1fMMIhgg#^e!53ATK(~?x z+JJ@F2t?SBl3HH?f*7XOOF02ef)cSjJ4*V~TZ}LmRb7DXi%b(mpZ0lD9V8r(`lnro zrzA$8G(e#IdinGgkd_Kf>Uves^{TNe7^ZDX`V{g>O_4s>fPvWxK-rR}SYOC{bbt<- z%FiFtJ_)BqeN6j&pni|8{ijJ(<5g7SO;lsjTO}@IrA4iHT>D^v|n9=hgFD|=B=`&SI5#h5M>7W@Kpc#J!8i7?@TxKGw zerklC>LaTyMU!=HwoH%bPQVX6U{ojT*3UKdD`|km9)<~;Ha3gbsqAP=^|+y$w(ic> zLlhu^wtUB(>rVdJHWgutq3oTe&w2_7YBl^vKgEc|RW0S4FlBdUfrz>8rn}Y4b$EyM zFo$&skCmdJZug#xHH(PdZca}!LIx-1Y7^Iv^e;}moeiSm1((zP^V!QO@DR%qIcn~< zM-iuHJ3}F%Yrr z2^f@_t3?%)!){hGY;G6O%)H&T+<(_YlbTc56}FB!^tn`Xk)hX1yxp!t)J4Hwq_R_I zj+RbcBFSo)^Bl4SS|#``u~}zCn#tNMC}4Y@%vkRTQufTz3n{@K^CjMbzzLAF0MY^d zcF$!8h_8Bvi}bBP+x=Vi>v|UE>&cDq)wbhxT4$7c7I61>%-IuRE^fU$5?Q0k0-4Nj z&pDzLQ9CA<^_%ru<`4)%nn#1thCkem!{3dE-Hl5?j2W>xP+583CTWA-W3$#zKP>dZ z(n&CAecN8oYZvq$?bq$^&|cQ4?nL}wm4V)ps@Q!u4w!5{?ZRHB6ksORc$^@!;{Jlv z%M{AX^#5FVzW+b_2prKnGoin8ae$xe++>(9!*2S|rpn*jJm&_E(vauDe8zYl%rss$ zU=Iz^g9P3k5>n}_wYpToCJa~>&&M`@NdY!ZQkhvRBhc^3zf7ba75>c$qo=a&#c5zH z{3Y+L%qh-HtCz8#%%RH93n@MeDSsvlXzzJz*BPzW89mSHez@$D0TS9!inAP-M$-%H zrfc)p;}~k7Wt}g>B;iUtocF0Q(dqR9@@t`kHwHDA1z$cNs;eWi<^vVBG%g z*%q(uG{^fP4)dWM&|JD~IJ%59fyxLns>{0Ur!T7PmA;G`eXXGg$K>k0U&igZw^RtEtNN2#(VH zC&%N+lXvWHYkg<%v8CbqdT;+QG_&mZsI0w(Q}uqA|B9%*{Fu&~@WHV?m`_v7!{w%L zXE4%vh1cdt=0D4SoVv|pw*G~eSxN(_h2FTDI8F=|IMxY`v2$FeRl2t+qwJX*l(R4H3KI>hB{G>ZggH+B1@J0 zJdlfS_jVUt#rYCxNl{ikrM^5$96Wtoe20wG>jAsXF9^tZ2t|UowNv6(j3XYyoso2s zIk9tfGvV*fvCKC%mhHfJofZ*foaXpld7b^5$}TV*wm0rh>${1th68Qd$5d%IEX?#X zR`_xA^E~J{M^#oPkI_%J61GR^{`Sf~4L=!lv(F z&hn@DxA-K@$ge5@yfE9`a`x1l!PYbzQVO;IYl+GTu`d1mic6mO}8A6w+5dQfwwku#7d$w~N5aE9P8$$+x9 z_(Wq-{`HDgwPRENjCJ2H1;-B|zoHasm+Ugr#T|K<3~Hx;D~C96$+w5>%rYog@>St$Y(W8C;EO_ zZa0MMQe-FLRr^Rkmp4DEAaCtbw(^~t?_s7@5yRRvbHNbDGvQPwVa_-i$xziZ;X)>1 z$#@RQki#>9*?_~@K=P(!Ad38`-|m*yx!;aY`s{|xTBPb=wA%mS^vyn!D!QQadw1-s zP0wFJ3`YYKO&JzkF3}1D9%`Fdxh5%9bn_6}`};FIixz2Djl5IKsX1EbhLSpOqgcSr z;Z&I`FGC6eINga+MB*KJ+qv`jKHppxKy|9Xo0<5Q+ma!&Xr1%di>ji+zt+{2FG1RY+y% zWoU3q4B=U&SQ8aPBS~V3YSJf2tZd7^P)1rAb4Xp69>^Xrpss$bZY2~g=9yTXPo!cM z3fR6_eU!SY3Q+fTc;jXdHs*87@Ngv ?m(dk8CL`)LYyUdLO_eA`xmn8Sm^t60^` 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

    }ez`qlfgz~iqb3s;UNdd4Ls|0C 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%0AYcpn+w>nW~p)3RJTTFH$i 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 LB%4YRdiVbUx+~DP literal 19172 zcmb_^2Rv8*_rLMRTavv>8JWo@A>*y=w~>+Tcd}=hkv+l(B_m{{vW3dX3?Y>4QFe)n zkd@89?P-%p?4|MuwKK5y=EUgw= zo4k$A5`pp+>Rd_peVjUc@0q_@etqbQuz2p2Bt`YdOYh`xl{HY6ec~PdYFaOb)z3zg zg!mws2CVcyOJXY41RG5{CSWUYI^>b{l3Z<%FRJKTX2ouf8z0{P-cQ$0#Ar%>e^cbf z@TsSKH2wNtH~Lr{Wda`P@5hY>4zWaDL-ncCtt%Zh|Fkeuz(iKw8!|+7ioT zX5pPys4ZpaakG{9_66BCAK2l2o@crJ=iku1_P|nA#Dm-N!4*fr+7+-cFjRjV9WwA8 zx~J`I9ZhT<4K-XZnKQqM^s!dYD+61Uv9}J&gT5=JkP^^H(DK zh?hKiv1z4(&iIGh&#HB4c5%KO`SkpaB_Y1j7s5lcnAug?$zg^9pFKA8h92$9pV#Rf zzI#De@}jY~2V*H8DZZ_BVl zVhC=0DBay?j`-}r0gs!uv7v1TnfdETt@3W1nW&&wL0vuI%<_(qph zNm{B~{9P68sED>N>E?HB!mti^zBr2?crOdl!%ML@vm{G4Jr z(Z#b2)!NqruG}0s`-GZIF6^+R^R0`lWFMa-d=y;Y|LD=XLvQ~Pp6yPGmBMd5+LM5h z(=R`wQsQ;3U=4o3Rc!NJ>$F$?G=hAcZ;e%0CXn{trYVadlz;>m98XD142)FRpAtX} z5@2k1QPtk=k^}dJOP8SND_yVN_l$@5%(SO;L&d;2;!Jy#FFffpLV`Y}??kJ$)MEvS zp@hznCY~GVrLXedg|U}O=JfZ3k;|P3y*_qMoUUh_Nwh-!^ga?Y(WZN}Y)|YjTsQN! zrkZEzF-d!jWN@uvPNR7yARH2dGCUIewpBp3D(t2VZT1q5Le2`cmKh-x-hixnxKZ&C z`P$+>&jTyi&~o0oyS%;$oP7fR{=S|_b}#3moxKUP9-Ht!g<2j6bMK$Ny30t~%XRNK z{2zi`w!r{n>yTGIOuYk7gmSEKDC}=GZN92E9)DFG`Vm`-Ho=C6gIxv{-QhQRaIJWV zl8U;HDd*Px{MO;4XUZ+CMg#0IovU5p7T!UR>t*h``>jTm(=%lq2@N%2u|8m^&%-xr z_Aw}CT*+DTWa@`n$p{@5dD9DTwT_Cj7wSZBh=qnoa$p^$e#lOGj&HVx1)B{9wd>O|kMq~KaYZ-vF>NOzbuuvcd}Org+uJ@wyR)ivbuD;?=qd|y zvvI$ElXSLvF4MqrHrtERb3osmdrrztvTQXzPWPqYa{ky?GAM>r$`Z$MKuJ6Te}5lC zauCBS*4z%}7wk=p)gA3EY|R{?Fy`p$I>gISdJY*PmObtxoy{z*Ue1uqoM*f#Nzgzu zP0%G}lgSFFKA3RDb3Msc^2t+?e3eJ$%{?AdR3c9*JtfGS32fOiU)&IqsJQAiGR&7( zl+y1}uANTgwb}D3&&8`OwZLgMi=*#`(B|554Y!c8R)mDe=Y<;^GjoB5@VpgPW=w~Q z7AjfEZcoo(wz+7ADV}%Dy^U@8)+|51wY1t?agq8-pwaBx^;JU_yfZK2%XAf{Z2QUt z>%zz)0jnk!xI7{IT3{GwbXzFJ_U(fn#i_57{(%fedH0@O2=57z?%_ndrqae21Rs%?(HvCiWIMUFf{;64SeXf;$v_5r+byVWe;lNHI&+2rKyePMA| zf{xu7(=-X0Jy$clbPcP@t2)*Gvd;;H(rHfH*n0xgw9zy+lJVT{2zUpp30{n{-?cgY z`V9p)t&r*qTZ(1N;C$)A;n!K+w0@`c1#=ufu_ek%$t$K#*PfIgHEmW_Of0g$R_QHz zJZWPvQNB^aiSVv2aeVEE=AMM{Hx^k~1X4K)Gc*x*7sk~sCRdiRU&vz~Np>U*UeF}8 z%$7MnzV zmeTZ8RlD%&mDWqr%0+%-EG@@0d6!<}eg4dF{T5AekU81Nfo2Ew!wJ0)0_ol7BL!mR zqpG#XP$}-!RZG_o-8-$@>1;n$5fIN*?S~>}%_x_QA`Ln(MtSUsa#x|N6LHg1yo9p1 zO)Y7NcQq=4$K{A>Dn<5tQ6Td#Rg_ajJ3Olvd?RAw@>=emSk3Jf0>h|Iaw_VkA}!9C zQ|8@w^9t(lN;+e**(j~8gDk}Mn;$SzCFdSEW1CXhNWV61M!d#!Fvxi7ITm;05y7Jz zLvm#w9=P|NelX5)FyL^>BO#(AI08=^7vJMp(VBj$=l8J=j!*PuJI~c~;ftXV;l0*p zFY#~KdD&at@9#HIO^ST%m5d{FEu+%g<^Zo3rk+)bn_lFC!RL#u%XP|9|9ly#Rq#<| zP!+7uzV7ChlYy%iiNs~&-lyK9h{@;VCvAjHc%-W*P`95^jV-RTq|~>vRzH`L(&E;= z)A~UMC&J^q?xzc7*CX!)oV_h=DCKob`XB~<7~kdLoP1ZOmD*l}M;cc5F*ARGj~?E9 zrfVcq$3IY+-+y;LeImrK5qtH8(ucMtqI~l9Qtfp?%f+q(G0Ft^1_hM_JOqYUv2PEG zad{*Exs-m14=$$~X>Xq2b&oTl%#JHXwn9eW#Y~R3srFNfvm7l}JQr{B)$%z+590Cg z77}5sNYzVPpRGAWd|pt50H+OsQ!0vUI2EfobcVy{xDHm$+4<;^E9ANr<`bV8GWBlt zDrCS#FwRQ*T|a~@d)GNT|AGHe7Pk`jc}SP_8{E*-)9iWgQP;3? zxC7rwI^Eat(>1OM#^+N)t~$AD<~8EdR$q0m9FB&!emNPEoEKP%bImKz@0nfo13#vR zm!43Gw}q3%D{08)2(~1(8Yk57I=+y=i^vvtifl0zE(r3ZpnjV&7JD~MP*GJWJ4_%U zG=RoJ{@JI(+38P&@20g|>P`n$SAZ>FUwKh6uaAu;YNJgFul((dv$KTE9-+KhmbNh_xX};9sk>p zEaa6fQ$+fO(^B0AaVLV%n@NTx6dBecylo}YN>8ff;-9Rj)gM!S37DiPJ=-4b0_<7uJZ|e;_VKmi`V3S zbvB{%fsJ5}@NET)yQr&h(}^q8CtZ{71Zi`$@TU5$X|I1pI_n?hbi425MzrSDETbpk zKqWOfMo1hRmL^0`b4xJ$IYOEjIT7HX;C=Dqi+5FubtM6$ceDtuh*~ou;cJ&}BWOym zjnAFG#)Y6)joBw9f2qXjK*s0fucs*Q;)RoGq`p&S!dYe^HY4>5(hWam&e6kQuC6Na z5sOkqwbWg}NquocVDemo?Qy&7e&d{$Z8EdMsL^_&hbqpM2JX#_OLeal67CLP^C)mU zp+D1=Y1zL&|E!t_&P~D-?;q0KV70?A+du!vMDbw4OYx_K`VE#ImGJVj$EcL=nV%WA zRS%~{Ua)?qtZej3WwXt@CG&yF^J@tY*wveseZMd`SF3azyl{U`oq)S2>dARO(tXKS zp69ScBFTvO3%Rde&$MJjb=TTx$<>!QY#ootzW9J!ZK^-`IH*SN^oPq@t-TSav248g zJ$QMrXN^hm@?CEmSMam#Pf8_AztCd@Gf^5a_M|JB5m4-&xlebT()Q!>N^5=eWl#Np zBhy?}!k;|V@0w;0emoh@H_3az&U1g#8-0mz1Kif|#|E}jxJLdXMJH{$9wQcfRGrfs z8yAD-ZC@&1%onW1rqVGyJ>F2gNn$LN_58C0o_!*h>!Ew~7ZEr_156JiPXFUq{!Bu9 zwhsG=pWpjg8Ii#7BDcqJ6rUNwyGXqZ5zdS6P$oUxJ+D5o+&c2Y=(%lJ>YayoYN%xi zLaS3XWd|Nh5Ix47ff@0dJ(6rwL0-pre)Cwt5g)whD5{)`19c=*iECM88fvaxf;Aau zS4>v-X*A9d`RE)VxKTV?GDMM3=fA3SWyN)oIckQ0BinxLX_?#y8sjLr9Hyk0uhbO8 zIP~#w7e5#iK_I_WZg-9tyhd41TC%7?{MZGDK zUtz0uTqdJi!STF_;T|cdfm(W#?nKMfQ5A_VQa!Q`BWBN|x=X#T@9^ksKW6V+rq~s` ze%#Uv3PrDrsRW)8Ur4@QU>f+2^xb|AUYq5T-kMu?v%{=U9wcDP<_I}Wl3M$)q}2Qw zkHIJ(CN)=MSU~d3y?%`Pt7mg@uHp-q(?r*4<3Ffq9fVo2*9%?H3I6K8gw1!NpCf9T z{)Xw|6cSTNnc%hHxF-|CNix}{cD6$s?Rw`E=R4@XlX9x9L(Zd&5O^P?7Lub zoTmKUqs=_Uo@}7#HmBA*Lv9F|7qJed7GsRt~oh=Ui1?^Q5;vgShpClTK}?X*;MEki z0Hm{PIMx9F#gcQv28rp^yqXp-G$TjuJQ;n1Ye;#AZ^EtGR_8e_mhWR>+r){d%)vQ2 zEWu(uht0Ouk##!4@-Rf#?5i~cF(rYNUeG6U!%L3j+Oi23WuhM<{5<+xj@K(>BUpx$5b8!# zxrCoo%+7P3T-QBWbvs+ttmE^rTl?e*LNgW0S}OTlCbz{IXecwrln?Dwad_~7@m7$amNqSGNS3s)KQT#9E|SXH+l1p_&*D|cGdc=v^ee@<`G{5$pDz)Sx(y3 zfos%WsWlUExgt_3!CuH}Yza@xdM1oTL=8fxT2Yc58L`Ad2Jf`Q7W^pShb_s| z8;Qp8@Mk@)2;2?cZyFVRh|WBdvXJUA)h1KOfrS(=tkt=QinupHj)@;VglJ8Xj_yRS zT|XxfzkRoP=De7p4}Tn;Hc9K~pdz6^WkWI!MiDRgpNfQNt4Lhz?5&LK z?5vc_KDxHTU2?NH}%3QS^e-cd8Yn+U-9RU!Xx63B#tRj zx1}o`YWNh(6f0CBJXr%+>1qxfI4^tXjkUu5r(-0zZ+3GKpLF z$l@Xb1owSJ9g%EmWoUGNtbM1v^DV8`7h4>=4^7N+TwPh{I88KYOHY6(-1y_zc5o|B zTYF8rqlMmgDvVH41T(PYrb29)lCJcb6J=B+U$Z8Ns3R=YiQiCRv{6$)bs}y@n|Ahb7AhAzHxpq$CCRGucUz;Td%Wyj}9aN0G z#Z2v6A`}m5;pm-nxL0X@v4`;1k$WDAYz;JJ233eVH!M_)jE{Vpr5NfITwloB5F0ys zm2vqP_x%#b#v3TkF;lU$^&aYqlNFP!P%YuKpEB$R5vcy-b`$kZEjgH*m^eCsDHmLL zp`wZ&(9Q3Zxji+ry3P)ta=9v>HR3-R9M!t)F5cf}Q#u)2^a-O>jLs|HTSv{*l4G;K zDK^uv;svQD(U)ejLeI77&Gq#=c^h+6HT6S-n=>6&6Wl6!h83$LcGF(VlQ+E9=1Zr2 zH?Lk@AClO-L$~R^`PNH(V`XX}UF*&|9i5lk`b4_Q=1Lx&=hD&>!=d$!uOo(on-c?c zcj%T^SBWYs*XNgG=r(3*>b*R!EPjpQR#{oUBk@{AC5Fz^YqgIq&ue2QX2{cPv3?H6 z5PZkt9Rq@i%GyH{?yl=KEfSt@YwV^s){2*>wOX_`Csr3X=hi}&V(u7tiN8;O;$<_m zJ~uEVUa`71p+dK@KDGQt!d!*uDQ(8em+=@EFR#^UFHg(CO`3|;NxDkUl{KA~JBFV> zu&z(8OGtPw-^ugboLr_X_gq-*+gzWm++3TCQK{UR?{&SFxAArQ#+|`UanE%LF|MWA zUztGPhw(zQagRxt$VpIzj=yavBL0k{c7FD)5VbWE0wQ@ z7Cj#sVvVj2a(^9JH}V=FMNzuW(@0f;TMNpoZhjy^!G8m zIP8^wI!bg3+> z1kEzoHdS`yEFVu?rdSvwAQV00diBOwK5~rU)tE|^Q4*uG`1Nt>M~ki+A85VkQ`s&V z+^cHa+<$J9?+d-*5sl3w!|twWh0NoIu%=p}$SR~1e{d7i3Fyc1H#RW|MLt6+@Mkuq zY$$x@JS)x@7FS@}9w%=nK80erABQyMi@#A88%$hPTy-T-W}i=oB0OQ9SkRX=-;^{?-kK#iF2yt=PTrO!ATG*OEl%EpFVNdn!HOj@Zr+qHw$Yp= zGOlTC_3))Nop$_w2EOz7w#h5I3P+ zo(?oIppqhD(^JOS<6ITKht!7UTaKQV`MJJ8htza;L{}Bz{UD-Lev3BnjF9Rw;hn@! z0iSaX*g-vX?TmS7!EQh7L+N966H_dz}z4zV}Hi_Sb(UK znA2r*8@pBQ0a|eh%TRd!j1RsyzEAMexRD^9cvviX0xLGlcXN3a+xEXg& z;!rcd?eS-?-=rn6`qcWkFsRtPVq~%@q+7TMaV9ow^A&AH14a{mbpkw=Iu_WA-5*OE zixo>6yD#=&EN(1i?19)Lv6!(x8EZaB;&y1}9@k;RrWo0-oclN{LAOd|MzP5-$gs#T z$*?0aBC#SdBeB&n)Unht)v-G;I{SWCH@$3Jhl3~`lnBc0 z(imnFO?3iTtDY664BS`GxBMcLY^{!Q!92@|w62zIb|{sNK7MKFRw{0lOi^sP=gV(~ zQa&(7j#9=);vfl;*vCh?_@p`WI1 zBzbg;p0fhSwW~Y2@8Ek)T`k`uDJHpg%T=&p9fsI{5jyPr-EPV0xXI3D0k@bNvw>Tj z@+fx{7D@`mh%!QvqSR1)D0|dClmhA)%96m5r8;3xLi_LRE)Spf_CrxxHu@zwss@El z%pX;;Mt+x0-Q=_QNCG4tlBoIAc0&2NtG?xP+DNA_x@a)BJZnPXY9IP?sDNWDp+3Ps zN6V%)7q*21vm;yas*a=D!NG$`1zkHWgD$7kiV6xXCw&V)XJ($KHdBE(C}sHAnX1|< zrmB=GR5$kX21p$G^K4^x8f3evWjllD<}NU!0JW z{_gXU?nB}t4pR@7e)s%z0D^)Y$(aV&}JVX)*Bv@+*e}{AB7O+(`uK>?ys0)$-IUCs`jtl$O3#;*52J0?E(tcMhnl3X|7|@)8FU}uxuM>Hiu&1+9{h^?7~KsP8JEZL+)P8JiI*k zJnSbOaL2Y0I@~14Ls)!ni$D0ig^%)(@$mBy@JJEACw+hTs4!Fawbc7U$8%Vn%swTg zgsaBfI`HxQR&GUx4;}Z})kq!o@uY)J+LKkC@Q3WmJvgi=JAGb9rMG+bcz}OV5sXvu z8&BdD9IsA*HOW^e>~BKzceN`h7SzE@NocA}F#EY!U_5tp#u zkH1TFh4Zw?S0$iTQbIb2U{BT`n?1wZ2MmuoiVM2xMhR9{9+noL@_9arzgBzccRl(? z_WV+EzKZsnf+MvWnJw6|CU2?NJN|AKb}(j3)>NHgZ7qg5kn*tNIPd|1>9F1NFOA_g zZ7Y$gIN2W*rrd+DmmSI@?cJ0yYUp$FW&BVttRXA>y$x*Y0_NENYOGM`(i5Mj=5TVQ zqR$ABg{`vt2)sloV~wGE^zbPh9_He6IAfhCyC(FAV-daDU5lo(b5bFG&<5L|fK zwbw#Vr1zbgC3Geg;PRPK0q*T}Y`e4W@bO<;YEJMLX6K>d5k9E`y7U$q?^UY1sQ9#z zjb4)T!Ii!vxNKOL=9N1^^{wMu-`OTC|co|T}QJpB%-TbLGfP7`TYRG=dLjd z`S&65`KUZtZR*wqs<=(-@334dX5b1yk@CS{6N!tTzg6nq~7FgR`T>e>r zs|A#rkvzlQJ;oftjXbQF4r)BC*beqQ=@<@RK)RH3uxWd2tB%9tF@rgPdHhn&&V&Tf zuh9g<<+D^VF_Wqj_qe$3(4DyE|7K~Z>FuTq_TTsF=7Xf7VJ|~Ui`@~1bmypIsJ^qTG3toauHEU5jBY61!OoS8?Q z2NU4E4adEnIW}^q&x}Q(ltKUd{geuzkQ?@L0%S9biz^Rg6S^c{cEyp% z=c441-QEpBV_`~wD-U475{(65Z3|de1YKIThqy~)Kmb=KU^RgqjH*IQp7h;&NljoA zqq=Zsa|&8-c1|FeqxB4)oX&{{HSGDCn)Jj{yuYh5n16G(H(8)PAio|1Z{h#Ra|wb> zptTBtKI8jT9AF>qq8GH}zu%pLO0E=?TxQ72>`wHBV^^I3X8-Ft$pdu~kFFD;J$0h> zO?7>n&GWLswqB3rZ?}J-qWjsH7KHr&qE>rA3)I)uQwV!m2F8#bIRe)EU5-F|aK1g7 zKEglAk>VDD*l$~0khn2$IT+(&bD3R`YkFIAZK;RcVNtH#?HSBm4*!BcK*<3+K*0^} z1?pcWK%U{U?xC0`&`S0722-{!kjUSbm$-Z7WvsfdFh%T7JB~l-xIs{CE>4$S^TB*c z6(iJITpqWI+5+s~H|SU0QqMfqsA8T>s;&Y-vOP3Z#*KvY#P6Q@e~Z>#+q9&hE4Yoc zL*}-X60T>~Ni>(dB?L_JeVYEhvGhCnOCz3T58*U^u(;q3kb{#<0pM3XDxlz z5DI|wqJa-hGgWcAP*+9aUK;yx+ZO^>nh@6{tIcKCTT)UG&5fd+f{5;$xqmNglu1zo`w-4&*xuCQh7SNq35&Za-K zzp|V_{~Ru^>At%~;Ib`^wto9@SuR#-e{M8rfw7T3!osoY=zdUqj&Mu>rHtMNYQktf zSsH_Z9q!#*$x|x-ZW3PvVY`o> z#K9Ro$sB-4@^5#`p&{!BQ?s^He*fur6=)=Y{<3R$ep&Y4@GkYtO@||2>z1(T?Q+HiFI#;N0xp?dsp!xrv4R)k&O7Z z!P-zGUs7K+Up`-Z-+jIczQ=qmeGmHT_=@OpTU&Dn8A|4kindBG=tTg-kiyt(VWGcK@OgxmvYKajq!as z2p!8udBb!C&DO}L$~gM1czkP|umS}BKKy^+|NI;{xF!BLd>sEE{2)G9CB6=v6pNjT zy(KvcUSiE?oX+aj-jk_zc0MIf9ibjYe<#^HIXwBJ&wdi4q^NLt_P8jLsK}QTu;};p z6bQi*z0)j(FelgojPU*N(KrDTfykGfFnph=kSH@%1%EvulE)p4ViOY@nKEwOJ(UdjUBUKuKndHI_$Egr|C4+>dD~onlMnKzfF5|T@k&RR5pp0H=VOgrW%%E zIIsYiG^`HB3`>14ZepzV6Q4{iNwS2&lwhx5yDHDRH?te^4&>H(T-q=_!Wr@pW3MsT z=zDt{#CD+|I1z^tVkL3daX%HxV~cbh(aFw`r^?a5H;+UGu+k+)_5Yp-s7^EiVkbMZ zpDHs?Y7nfUTz{~}$Nm%gUH(udT>!J93t4&U@}gZ>hQ12Bd1*==urQYvu?DFIi3V9G zaVKdfNoQodaJc+Y1mH~s0YZv?lyQ_Mij*PVIjgWkxndjuHqi~(Oi8r#$&+Jdqi6fh zON;D)m|{4-(eM_VG`^w*thpDh*NLxoC>Of)W@>?KDuShg$^+i9Olo-l=L(*L0;ika zdyAX_R0=Q^U!acp-|E*GIAkH^!Qed@!LjH1<-+ha4J|?+=O|!vp8ra#Uqkm`1-v1;(RX#wK)r5wuWjgpp zc@|`3S7{JA(lVgbWLQRx)etP`@_-4xA4c;L0vmw_X^F~Sly2Lrk6=8bn=X=)xG!7< zKz>QG-irWpOF!VXG^8XTk2R$1Z4K$5H8iGxwyI~lBO(A6oUA#e5?E~#$E`nzsBD8F z_U4w+Yj9qbe;QLj|I*_+8fnj$Nguhbne4y(wuFhz$Qay2yIkA5Gr56g0wv7bGcKjVRb=zcxn1cimvB=oh6dK%l(O62Pr}ZXUfn<0`B>cU zjXkl$r-Lv}X4<<5#5J#IIo?2%7^RoeP8uczjz z+o}0~oX}`jc4~0h)3PD?M5eK~RgnEcJ8fqIa!nsvCuoTn%MhuxE93l?f{i%(zQ7_q zY2G>OqQyjKMjKMKj;uYIY#&R758=bam5{Qk=7LwyZ&G-mL)s`yX6dFd+lY}p>{g%x0#hz9n*5~G*P~bG~ zD%v9qFuNNMzp)p(HPL<9RywrqJNCB52u+W+sVp=YT6W<2^B%%F05Aj4k6=!>|CKS& z$Hb-qAOQG}7osmnG%q=pE8|2;@v;BiX#LF^8V;aI90NS{>ag(EMEr~P^_%)Y53Wk0 z3+2GMPiSEc2JA6zGxxde)qJ1kezhL~&6;~A!;CzV*_wL8p^DY{?WYg&o@`!;sa*eZ zV`yV(X*_RQ!ozKIRVDAvhW$G2885HRjgB&+mdceiyZhj-_0dtPP4~q`6~oR6EjrKD z`n(&P8}l26LrJSOAFS4vH)=NBOPX6YiJ*sUM97}c)A3_qR7GO_;r$W6dB}zjddSA) z=B_8VZWnc6DA}Yl2vlR@GYlsc+8)XY&SrYB=APi2Rej**V5G!{I^{>}e10eI&fT`g z*N*U&)K$N4qxEdHZ)4>^QI{s~P0^JjyzsFc?z==6`sF@N90{An4>K=mkKjM{&?#~L z{^_nJCDU-%+kN$~)C7TEwO^WL*Z;PMhW!`^nLLWQ-S*6P|k#e?{L6DAx z>XhM^HKL^Tno;fc3=#KpxgFgh*a4E)WaVso=ymRSbCpsACAk#FV)pT<)AzT)^A8AY ze0@%M+)&K}{c02UbQJ{>@N8Ed`uQ$QEOLyUR|)NYjSloGp}ohh7YnH>?!9sM>tCR^ z?Ccyzz>oRGJ9mCGu=|B8&|6}5jyvEPs~_JP^W)vSUo`@~lx63z#ol%Iw^y|Mc>C_> zN1^wT>>Q85>ui4Yc9I`0?0&cqdd_s`paoA9LKeP1b^7D2yPvm%o<7_;5MU|b*4 Date: Fri, 4 Mar 2022 11:48:39 +0100 Subject: [PATCH 253/253] [GITFLOW]updating poms for branch'release-1.69.0' with non-snapshot versions --- sormas-api/pom.xml | 2 +- sormas-app/pom.xml | 2 +- sormas-backend/pom.xml | 2 +- sormas-base/dependencies/serverlibs.pom | 2 +- sormas-base/pom.xml | 2 +- sormas-cargoserver/pom.xml | 2 +- sormas-ear/pom.xml | 2 +- sormas-keycloak-service-provider/pom.xml | 2 +- sormas-rest/pom.xml | 2 +- sormas-ui/pom.xml | 2 +- sormas-widgetset/pom.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sormas-api/pom.xml b/sormas-api/pom.xml index 214eb0b788e..02b1affe8a5 100644 --- a/sormas-api/pom.xml +++ b/sormas-api/pom.xml @@ -2,7 +2,7 @@ de.symeda.sormas sormas-base - 1.69.0-SNAPSHOT + 1.69.0 ../sormas-base 4.0.0 diff --git a/sormas-app/pom.xml b/sormas-app/pom.xml index 3bb68392128..7fd4a78f44b 100644 --- a/sormas-app/pom.xml +++ b/sormas-app/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.69.0 ../sormas-base 4.0.0 diff --git a/sormas-backend/pom.xml b/sormas-backend/pom.xml index 48b45586014..2a9aa3a6b9d 100644 --- a/sormas-backend/pom.xml +++ b/sormas-backend/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.69.0 ../sormas-base 4.0.0 diff --git a/sormas-base/dependencies/serverlibs.pom b/sormas-base/dependencies/serverlibs.pom index effd624397b..fe4a847d3c4 100644 --- a/sormas-base/dependencies/serverlibs.pom +++ b/sormas-base/dependencies/serverlibs.pom @@ -8,7 +8,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.69.0 ../ diff --git a/sormas-base/pom.xml b/sormas-base/pom.xml index f5dd10b65f7..023b01acde3 100644 --- a/sormas-base/pom.xml +++ b/sormas-base/pom.xml @@ -5,7 +5,7 @@ de.symeda.sormas sormas-base pom - 1.69.0-SNAPSHOT + 1.69.0 1.8 diff --git a/sormas-cargoserver/pom.xml b/sormas-cargoserver/pom.xml index 8c6009ec75f..943d84746e5 100644 --- a/sormas-cargoserver/pom.xml +++ b/sormas-cargoserver/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.69.0-SNAPSHOT + 1.69.0 ../sormas-base diff --git a/sormas-ear/pom.xml b/sormas-ear/pom.xml index eb67f26b2b0..aef93db0ba4 100644 --- a/sormas-ear/pom.xml +++ b/sormas-ear/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.69.0-SNAPSHOT + 1.69.0 ../sormas-base diff --git a/sormas-keycloak-service-provider/pom.xml b/sormas-keycloak-service-provider/pom.xml index 142c2f5858e..714c70cb0df 100644 --- a/sormas-keycloak-service-provider/pom.xml +++ b/sormas-keycloak-service-provider/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.69.0 ../sormas-base 4.0.0 diff --git a/sormas-rest/pom.xml b/sormas-rest/pom.xml index 85e9fe6b41d..c51671a3406 100644 --- a/sormas-rest/pom.xml +++ b/sormas-rest/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.69.0-SNAPSHOT + 1.69.0 ../sormas-base diff --git a/sormas-ui/pom.xml b/sormas-ui/pom.xml index 8b3382d103a..5c0429af19f 100644 --- a/sormas-ui/pom.xml +++ b/sormas-ui/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.69.0 ../sormas-base 4.0.0 diff --git a/sormas-widgetset/pom.xml b/sormas-widgetset/pom.xml index f8d6a25f29d..84e915d3659 100644 --- a/sormas-widgetset/pom.xml +++ b/sormas-widgetset/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.69.0-SNAPSHOT + 1.69.0 ../sormas-base 4.0.0

    }ez`qlfgz~iqb3s;UNdd4Ls|0C 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 P%O*Ko(+;kto~`{4>WT+E diff --git a/sormas-api/src/main/resources/strings.properties b/sormas-api/src/main/resources/strings.properties index 18de9109c38..3c0e4f5c40b 100644 --- a/sormas-api/src/main/resources/strings.properties +++ b/sormas-api/src/main/resources/strings.properties @@ -78,6 +78,7 @@ date = Date nameOf = Name of %s uuidOf = UUID of %s listOf = List of %s +mapOf = Map of <%s , %s> # Aggregate Report aggregateReportLegend = %s = %s; %s = %s; %s = %s diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/info/EntityColumn.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/info/EntityColumn.java index 07e7b4393aa..093b41d9062 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/info/EntityColumn.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/info/EntityColumn.java @@ -1,19 +1,16 @@ /* * SORMAS® - Surveillance Outbreak Response Management & Analysis System * Copyright © 2016-2022 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI) - * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * along with this program. If not, see . */ package de.symeda.sormas.backend.info; @@ -33,8 +30,10 @@ import de.symeda.sormas.api.utils.SensitiveData; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.util.Collection; import java.util.Date; +import java.util.Map; import java.util.function.Function; import de.symeda.sormas.api.i18n.I18nProperties; @@ -108,11 +107,20 @@ private static String getFieldType(FieldData fieldData) { return Boolean.TRUE + ", " + Boolean.FALSE; } else if (Collection.class.isAssignableFrom(fieldType)) { return TypeUtils.getTypeArguments((ParameterizedType) fieldData.getField().getGenericType()) - .values() - .stream() - .findFirst() - .map(type -> String.format(I18nProperties.getString(Strings.listOf), DataHelper.getHumanClassName((Class) type))) - .orElseGet(fieldType::getSimpleName); + .values() + .stream() + .findFirst() + .map(type -> String.format(I18nProperties.getString(Strings.listOf), DataHelper.getHumanClassName((Class) type))) + .orElseGet(fieldType::getSimpleName); + } else if (Map.class.isAssignableFrom(fieldType)) { + Type[] generics = TypeUtils.getTypeArguments((ParameterizedType) fieldData.getField().getGenericType()).values().toArray(new Type[0]); + if (generics.length != 2) { + throw new IllegalStateException("Could not clearly determine key and value generics."); + } + return String.format( + I18nProperties.getString(Strings.mapOf), + DataHelper.getHumanClassName((Class) generics[0]), + DataHelper.getHumanClassName((Class) generics[1])); } return fieldType.getSimpleName(); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/info/InfoFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/info/InfoFacadeEjb.java index 06d86f176c7..a005b9ef672 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/info/InfoFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/info/InfoFacadeEjb.java @@ -24,6 +24,7 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.EnumSet; @@ -31,11 +32,14 @@ import java.util.List; import java.util.Map; import java.util.Random; +import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.ejb.EJB; import javax.ejb.LocalBean; import javax.ejb.Stateless; +import org.apache.commons.lang3.reflect.TypeUtils; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.ss.SpreadsheetVersion; import org.apache.poi.ss.usermodel.CellCopyPolicy; @@ -305,6 +309,10 @@ private void createEntitySheet( Class> enumType = (Class>) fieldType; usedEnums.add(enumType); } + } else if (Map.class.isAssignableFrom(fieldType)) { + getEnumGenericsOf(field, Map.class).filter(e -> !usedEnums.contains(e)).collect(Collectors.toCollection(() -> usedEnums)); + } else if (Collection.class.isAssignableFrom(fieldType)) { + getEnumGenericsOf(field, Collection.class).filter(e -> !usedEnums.contains(e)).collect(Collectors.toCollection(() -> usedEnums)); } else if (FacilityReferenceDto.class.isAssignableFrom(fieldType)) { usesFacilityReference = true; } @@ -338,6 +346,21 @@ private void createEntitySheet( } + private Stream>> getEnumGenericsOf(Field field, Class toClass) { + return TypeUtils.getTypeArguments(field.getGenericType(), toClass) + .values() + .stream() + .distinct() + .map(cls -> (Class) cls) + .filter(Class::isEnum) + .map(cls -> { + @SuppressWarnings("unchecked") + Class> enumType = (Class>) cls; + return enumType; + }); + + } + private int createFacilityTable(XSSFSheet sheet, int startRow, CellStyle defaultCellStyle) { int columnCount = EnumColumn.values().length - 1; From d99929beb3d103383544afccc075e63efa6ed64e Mon Sep 17 00:00:00 2001 From: sormas-vitagroup Date: Thu, 24 Feb 2022 13:34:13 +0000 Subject: [PATCH 161/253] [GitHub Actions] Update external visits API spec files --- openapi/external_visits_API.json | 2 +- openapi/external_visits_API.yaml | 49 ++++++++++++++++---------------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/openapi/external_visits_API.json b/openapi/external_visits_API.json index 3a56731b71b..f05516cb72b 100644 --- a/openapi/external_visits_API.json +++ b/openapi/external_visits_API.json @@ -2,7 +2,7 @@ "openapi" : "3.0.1", "info" : { "title" : "SORMAS external visits journal API", - "description" : "The purpose of this API is to enable communication between SORMAS and other symptom journals.
    Only users with the role ``REST_EXTERNAL_VISITS_USER`` are authorized to use the endpoints. Authentication is done using basic auth, with the user and password.
    For technical details please contact the dev team on
    gitter.