From d33f6447cbccb4ca4d01181f565e0d2f549b187b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9=20Strysewske?= Date: Mon, 6 Nov 2023 16:25:00 +0100 Subject: [PATCH 01/65] #12669 - Sync environments based on samples --- .../backend/environment/Environment.java | 1 + .../backend/environment/EnvironmentJoins.java | 23 ++++++++++++++++++ .../environment/EnvironmentService.java | 24 ++++++++++++++++++- 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/Environment.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/Environment.java index 97ee9fc0fa1..7d2ee24bda5 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/Environment.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/Environment.java @@ -55,6 +55,7 @@ public class Environment extends CoreAdo { public static final String WATER_USE = "waterUse"; public static final String OTHER_WATER_USE = "otherWaterUse"; public static final String LOCATION = "location"; + public static final String ENVIRONMENT_SAMPLES = "environmentSamples"; private Date reportDate; private User reportingUser; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/EnvironmentJoins.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/EnvironmentJoins.java index d110f17207f..45ac3ff7959 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/EnvironmentJoins.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/EnvironmentJoins.java @@ -5,6 +5,8 @@ import javax.persistence.criteria.JoinType; import de.symeda.sormas.backend.common.QueryJoins; +import de.symeda.sormas.backend.environment.environmentsample.EnvironmentSample; +import de.symeda.sormas.backend.environment.environmentsample.EnvironmentSampleJoins; import de.symeda.sormas.backend.infrastructure.community.Community; import de.symeda.sormas.backend.infrastructure.country.Country; import de.symeda.sormas.backend.infrastructure.district.District; @@ -18,7 +20,9 @@ public class EnvironmentJoins extends QueryJoins { private Join location; private Join reportingUser; private Join responsibleUser; + private From environmentSamples; private LocationJoins locationJoins; + private EnvironmentSampleJoins environmentSampleJoins; public EnvironmentJoins(From root) { super(root); @@ -71,4 +75,23 @@ public Join getResponsibleUser() { private void setResponsibleUser(Join responsibleUser) { this.responsibleUser = responsibleUser; } + + public EnvironmentSampleJoins getEnvironmentSampleJoins() { + return getOrCreate(environmentSampleJoins, () -> new EnvironmentSampleJoins(getEnvironmentSamples()), this::setEnvironmentSampleJoins); + } + + private void setEnvironmentSampleJoins(EnvironmentSampleJoins environmentSampleJoins) { + this.environmentSampleJoins = environmentSampleJoins; + } + + public From getEnvironmentSamples() { + if (environmentSamples == null) { + setEnvironmentSamples(getRoot().join(Environment.ENVIRONMENT_SAMPLES, JoinType.LEFT)); + } + return environmentSamples; + } + + private void setEnvironmentSamples(From environmentSamples) { + this.environmentSamples = environmentSamples; + } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/EnvironmentService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/EnvironmentService.java index 69f8b6a3ef2..9f193bfc6e2 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/EnvironmentService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/environment/EnvironmentService.java @@ -32,6 +32,7 @@ import de.symeda.sormas.backend.common.ChangeDateFilterBuilder; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.common.DeletableAdo; +import de.symeda.sormas.backend.environment.environmentsample.EnvironmentSample; import de.symeda.sormas.backend.environment.environmentsample.EnvironmentSampleService; import de.symeda.sormas.backend.infrastructure.community.Community; import de.symeda.sormas.backend.infrastructure.country.Country; @@ -116,7 +117,7 @@ public Predicate createUserFilter(EnvironmentQueryContext queryContext) { filterResponsible = cb.or(filterResponsible, cb.equal(environmentJoins.getRoot().get(Environment.RESPONSIBLE_USER), currentUser)); if (filter != null) { - filter = CriteriaBuilderHelper.or(cb, filter, filterResponsible); + filter = CriteriaBuilderHelper.or(cb, filter, filterResponsible, createEnvironmentSampleFilter(queryContext)); } else { filter = filterResponsible; } @@ -132,6 +133,27 @@ public Predicate createUserFilter(EnvironmentQueryContext queryContext) { return filter; } + private Predicate createEnvironmentSampleFilter(EnvironmentQueryContext context) { + + From environmentSampleLocations = context.getJoins().getEnvironmentSampleJoins().getLocation(); + + CriteriaBuilder cb = context.getCriteriaBuilder(); + + final User currentUser = getCurrentUser(); + final JurisdictionLevel jurisdictionLevel = currentUser.getJurisdictionLevel(); + + switch (jurisdictionLevel) { + case REGION: + return cb.equal(environmentSampleLocations.get(Location.REGION).get(Region.ID), currentUser.getRegion().getId()); + case DISTRICT: + return cb.equal(environmentSampleLocations.get(Location.DISTRICT).get(District.ID), currentUser.getDistrict().getId()); + case COMMUNITY: + return cb.equal(environmentSampleLocations.get(Location.COMMUNITY).get(Community.ID), currentUser.getCommunity().getId()); + default: + return null; + } + } + @Override protected EnvironmentJoins toJoins(From adoPath) { return new EnvironmentJoins(adoPath); From 457c1d7db15882d8b2f84c068481e6acace2e0ae Mon Sep 17 00:00:00 2001 From: Levente Gal Date: Thu, 9 Nov 2023 15:43:28 +0200 Subject: [PATCH 02/65] #12603 Add search functions on the event directory in the mobile app --- .../sormas/app/backend/event/Event.java | 1 + .../app/backend/event/EventCriteria.java | 31 ++++++ .../sormas/app/backend/event/EventDao.java | 51 +++++++++- .../app/event/list/EventListActivity.java | 51 +++++++++- .../res/layout/filter_event_list_layout.xml | 98 +++++++++++++++++++ 5 files changed, 224 insertions(+), 8 deletions(-) create mode 100644 sormas-app/app/src/main/res/layout/filter_event_list_layout.xml diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/Event.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/Event.java index c41499aeeb2..3bef8b26f9b 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/Event.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/Event.java @@ -79,6 +79,7 @@ public class Event extends PseudonymizableAdo { public static final String EVENT_TITLE = "eventTitle"; public static final String EVENT_DESC = "eventDesc"; public static final String START_DATE = "startDate"; + public static final String END_DATE = "endDate"; public static final String REPORT_DATE_TIME = "reportDateTime"; public static final String REPORTING_USER = "reportingUser"; public static final String EVOLUTION_DATE = "evolutionDate"; diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/EventCriteria.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/EventCriteria.java index 5467606032e..d2caba0960a 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/EventCriteria.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/EventCriteria.java @@ -19,6 +19,7 @@ import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.event.EventStatus; +import de.symeda.sormas.api.utils.EpiWeek; import de.symeda.sormas.app.backend.caze.Case; public class EventCriteria implements Serializable { @@ -27,6 +28,12 @@ public class EventCriteria implements Serializable { private Case caze; private Disease disease; + private String textFilter; + + private EpiWeek epiWeekFrom; + + private EpiWeek epiWeekTo; + public EventCriteria eventStatus(EventStatus eventStatus) { this.eventStatus = eventStatus; return this; @@ -52,4 +59,28 @@ public Disease getDisease() { public void setDisease(Disease disease) { this.disease = disease; } + + public String getTextFilter() { + return textFilter; + } + + public void setTextFilter(String textFilter) { + this.textFilter = textFilter; + } + + public EpiWeek getEpiWeekFrom() { + return epiWeekFrom; + } + + public void setEpiWeekFrom(EpiWeek epiWeekFrom) { + this.epiWeekFrom = epiWeekFrom; + } + + public EpiWeek getEpiWeekTo() { + return epiWeekTo; + } + + public void setEpiWeekTo(EpiWeek epiWeekTo) { + this.epiWeekTo = epiWeekTo; + } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/EventDao.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/EventDao.java index e4a245f1311..9b44f2d9fd8 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/EventDao.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/EventDao.java @@ -20,6 +20,8 @@ import java.util.Date; import java.util.List; +import org.apache.commons.lang3.StringUtils; + import com.j256.ormlite.dao.Dao; import com.j256.ormlite.stmt.QueryBuilder; import com.j256.ormlite.stmt.Where; @@ -29,6 +31,8 @@ import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.event.EventInvestigationStatus; import de.symeda.sormas.api.event.EventStatus; +import de.symeda.sormas.api.utils.DateHelper; +import de.symeda.sormas.api.utils.EpiWeek; import de.symeda.sormas.app.backend.caze.Case; import de.symeda.sormas.app.backend.common.AbstractAdoDao; import de.symeda.sormas.app.backend.common.AbstractDomainObject; @@ -173,8 +177,7 @@ private QueryBuilder buildQueryBuilder(EventCriteria criteria) thro Where where = queryBuilder.where(); whereStatements.add(where.eq(AbstractDomainObject.SNAPSHOT, false)); - if (criteria.getDisease() != null) { - + if (criteria.getDisease() != null && criteria.getCaze() != null) { queryBuilder.distinct(); QueryBuilder eventParticipantQueryBuilder = DatabaseHelper.getEventParticipantDao().queryBuilder(); @@ -195,6 +198,10 @@ private QueryBuilder buildQueryBuilder(EventCriteria criteria) thro where.and(where.raw(Case.TABLE_NAME + "." + Case.UUID + " IS NULL"), where.eq(Event.DISEASE, criteria.getDisease())))); } else { + if (criteria.getDisease() != null) { + whereStatements.add(where.eq(Event.DISEASE, criteria.getDisease())); + } + if (criteria.getCaze() != null) { QueryBuilder eventParticipantQueryBuilder = DatabaseHelper.getEventParticipantDao().queryBuilder(); @@ -205,18 +212,52 @@ private QueryBuilder buildQueryBuilder(EventCriteria criteria) thro whereStatements.add(where.raw(Case.TABLE_NAME + "." + Case.UUID + "= '" + criteria.getCaze().getUuid() + "'")); - } else { + } + } + + if (criteria.getEventStatus() != null) { + whereStatements.add(where.eq(Event.EVENT_STATUS, criteria.getEventStatus())); + } - if (criteria.getEventStatus() != null) { - whereStatements.add(where.eq(Event.EVENT_STATUS, criteria.getEventStatus())); + if (!StringUtils.isEmpty(criteria.getTextFilter())) { + String[] textFilters = criteria.getTextFilter().split("\\s+"); + for (String filter : textFilters) { + String textFilter = "%" + filter.toLowerCase() + "%"; + if (!StringUtils.isEmpty(textFilter)) { + whereStatements.add( + where.or( + where.raw(Event.TABLE_NAME + "." + Event.UUID + " LIKE '" + textFilter.replaceAll("'", "''") + "'"), + where.raw(Event.TABLE_NAME + "." + Event.EVENT_TITLE + " LIKE '" + textFilter.replaceAll("'", "''") + "'"), + where.raw(Event.TABLE_NAME + "." + Event.EVENT_DESC + " LIKE '" + textFilter.replaceAll("'", "''") + "'"))); } } } + Date eventDateFrom = DateHelper.getEpiWeekStart(criteria.getEpiWeekFrom()); + Date eventDateTo = DateHelper.getEpiWeekEnd(criteria.getEpiWeekTo()); + if (eventDateFrom != null && eventDateTo != null) { + whereStatements.add( + where.or( + where.and(where.isNull(Event.END_DATE), where.between(Event.START_DATE, eventDateFrom, eventDateTo)), + where.and(where.isNull(Event.START_DATE), where.between(Event.END_DATE, eventDateFrom, eventDateTo)), + where.and(where.ge(Event.END_DATE, eventDateFrom), where.le(Event.START_DATE, eventDateTo)))); + } else if (eventDateFrom != null) { + whereStatements.add( + where.or( + where.and(where.isNull(Event.END_DATE), where.ge(Event.START_DATE, eventDateFrom)), + where.and(where.isNull(Event.START_DATE), where.ge(Event.END_DATE, eventDateFrom)))); + } else if (eventDateTo != null) { + whereStatements.add( + where.or( + where.and(where.isNull(Event.START_DATE), where.le(Event.END_DATE, eventDateTo)), + where.and(where.isNull(Event.END_DATE), where.le(Event.START_DATE, eventDateTo)))); + } + if (!whereStatements.isEmpty()) { Where whereStatement = where.and(whereStatements.size()); queryBuilder.setWhere(whereStatement); } + return queryBuilder; } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/list/EventListActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/list/EventListActivity.java index 8a58e24ca17..2c5ee339e2b 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/list/EventListActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/list/EventListActivity.java @@ -15,27 +15,36 @@ package de.symeda.sormas.app.event.list; +import java.util.Calendar; +import java.util.Date; import java.util.List; -import java.util.Random; import android.content.Context; import android.os.Bundle; import android.view.Menu; -import android.widget.AdapterView; +import android.view.View; +import androidx.databinding.DataBindingUtil; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.RecyclerView; +import de.symeda.sormas.api.caze.InvestigationStatus; import de.symeda.sormas.api.event.EventStatus; import de.symeda.sormas.api.user.UserRight; +import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.app.BaseListActivity; import de.symeda.sormas.app.PagedBaseListActivity; import de.symeda.sormas.app.PagedBaseListFragment; import de.symeda.sormas.app.R; import de.symeda.sormas.app.backend.config.ConfigProvider; +import de.symeda.sormas.app.component.Item; import de.symeda.sormas.app.component.menu.PageMenuItem; +import de.symeda.sormas.app.databinding.FilterEnvironmentSampleListLayoutBinding; +import de.symeda.sormas.app.databinding.FilterEventListLayoutBinding; import de.symeda.sormas.app.event.edit.EventNewActivity; import de.symeda.sormas.app.util.Callback; +import de.symeda.sormas.app.util.DataUtils; +import de.symeda.sormas.app.util.DiseaseConfigurationCache; public class EventListActivity extends PagedBaseListActivity { @@ -48,6 +57,8 @@ public class EventListActivity extends PagedBaseListActivity { EventStatus.DROPPED }; private EventListViewModel model; + private FilterEventListLayoutBinding filterBinding; + public static void startActivity(Context context, EventStatus listFilter) { BaseListActivity.startActivity(context, EventListActivity.class, buildBundle(getStatusFilterPosition(statusFilters, listFilter))); } @@ -84,6 +95,9 @@ public void onItemRangeMoved(int positionStart, int toPosition, int itemCount) { adapter.submitList(events); hidePreloader(); }); + + filterBinding.setCriteria(model.getEventCriteria()); + setOpenPageCallback(p -> { showPreloader(); model.getEventCriteria().eventStatus(statusFilters[((PageMenuItem) p).getPosition()]); @@ -154,6 +168,37 @@ public void goToNewView() { @Override public void addFiltersToPageMenu() { - // Not supported yet + View eventListFilterView = getLayoutInflater().inflate(R.layout.filter_event_list_layout, null); + filterBinding = DataBindingUtil.bind(eventListFilterView); + + List diseases = DataUtils.toItems(DiseaseConfigurationCache.getInstance().getAllDiseases(true, true, true)); + filterBinding.diseaseFilter.initializeSpinner(diseases); + + Calendar calendar = Calendar.getInstance(); + calendar.setTime(new Date()); + List epiWeeks = DataUtils.toItems(DateHelper.createEpiWeekList(calendar.get(Calendar.YEAR), calendar.get(Calendar.WEEK_OF_YEAR))); + filterBinding.epiWeekFromFilter.initializeSpinner(epiWeeks); + filterBinding.epiWeekToFilter.initializeSpinner(epiWeeks); + + pageMenu.addFilter(eventListFilterView); + + filterBinding.applyFilters.setOnClickListener(e -> { + showPreloader(); + pageMenu.hideAll(); + model.notifyCriteriaUpdated(); + }); + + filterBinding.resetFilters.setOnClickListener(e -> { + showPreloader(); + pageMenu.hideAll(); + + model.getEventCriteria().setTextFilter(null); + model.getEventCriteria().setDisease(null); + model.getEventCriteria().setEpiWeekFrom(null); + model.getEventCriteria().setEpiWeekTo(null); + + filterBinding.invalidateAll(); + model.notifyCriteriaUpdated(); + }); } } diff --git a/sormas-app/app/src/main/res/layout/filter_event_list_layout.xml b/sormas-app/app/src/main/res/layout/filter_event_list_layout.xml new file mode 100644 index 00000000000..fab5176e13b --- /dev/null +++ b/sormas-app/app/src/main/res/layout/filter_event_list_layout.xml @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 8179ba920e2ce12e5bbc90e9767adbc41483be93 Mon Sep 17 00:00:00 2001 From: sergiupacurariu <62688603+sergiupacurariu@users.noreply.github.com> Date: Thu, 9 Nov 2023 16:34:39 +0200 Subject: [PATCH 03/65] #12704 - Cases can be created for Contacts, Event participants and Travel entries when the CASE SURVEILLANCE is disabled --- .../sormas/ui/contact/ContactDataForm.java | 3 ++- .../sormas/ui/contact/ContactDataView.java | 4 +++- .../ui/events/EventParticipantsGrid.java | 21 +++++++++++-------- .../ui/travelentry/TravelEntryDataView.java | 4 +++- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataForm.java index 308eed37f8e..07ec78ad7cd 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/contact/ContactDataForm.java @@ -609,7 +609,8 @@ protected void addFields() { .createLinkToData(getValue().getResultingCase().getUuid(), I18nProperties.getCaption(Captions.contactOpenContactCase)); getContent().addComponent(linkToData, TO_CASE_BTN_LOC); } else if (!ContactClassification.NO_CONTACT.equals(getValue().getContactClassification())) { - if (UserProvider.getCurrent().hasUserRight(UserRight.CONTACT_CONVERT)) { + if (UserProvider.getCurrent().hasUserRight(UserRight.CONTACT_CONVERT) + && FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.CASE_SURVEILANCE)) { toCaseButton = ButtonHelper.createButton(Captions.contactCreateContactCase); toCaseButton.addStyleName(ValoTheme.BUTTON_LINK); getContent().addComponent(toCaseButton, TO_CASE_BTN_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 d13e26d68cf..7b50645ade8 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 @@ -99,7 +99,9 @@ protected void initView(String params) { editComponent = ControllerProvider.getContactController() .getContactDataEditComponent(getContactRef().getUuid(), ViewMode.NORMAL, contactDto.isPseudonymized()); - addCreateFromCaseButtonLogic(); + if (FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.CASE_SURVEILANCE)) { + addCreateFromCaseButtonLogic(); + } DetailSubComponentWrapper container = new DetailSubComponentWrapper(() -> editComponent); container.setWidth(100, Unit.PERCENTAGE); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsGrid.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsGrid.java index 66e04d2f6b1..8edfaf1715f 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsGrid.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsGrid.java @@ -80,7 +80,8 @@ public EventParticipantsGrid(EventParticipantCriteria criteria) { caseIdColumn.setSortProperty(EventParticipantIndexDto.CASE_UUID); caseIdColumn.setRenderer(new CaseUuidRenderer(uuid -> { // '!=' check is ok because the converter returns the constant when no case creation is allowed - return NO_CASE_CREATE != uuid; + + return NO_CASE_CREATE != uuid && FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.CASE_SURVEILANCE); })); Column deleteColumn = addColumn(entry -> { @@ -130,14 +131,16 @@ public EventParticipantsGrid(EventParticipantCriteria criteria) { getColumn(EventParticipantIndexDto.CONTACT_COUNT).setSortable(false); - addItemClickListener(new ShowDetailsListener<>(CASE_ID, false, e -> { - if (e.getCaseUuid() != null) { - ControllerProvider.getCaseController().navigateToCase(e.getCaseUuid()); - } else if (e.getInJurisdiction()) { - EventParticipantDto eventParticipant = FacadeProvider.getEventParticipantFacade().getEventParticipantByUuid(e.getUuid()); - ControllerProvider.getCaseController().createFromEventParticipant(eventParticipant); - } - })); + if (FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.CASE_SURVEILANCE)) { + addItemClickListener(new ShowDetailsListener<>(CASE_ID, false, e -> { + if (e.getCaseUuid() != null) { + ControllerProvider.getCaseController().navigateToCase(e.getCaseUuid()); + } else if (e.getInJurisdiction()) { + EventParticipantDto eventParticipant = FacadeProvider.getEventParticipantFacade().getEventParticipantByUuid(e.getUuid()); + ControllerProvider.getCaseController().createFromEventParticipant(eventParticipant); + } + })); + } addItemClickListener(new ShowDetailsListener<>(EventParticipantIndexDto.PERSON_UUID, e -> { if (FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.PERSON_MANAGEMENT)) { ControllerProvider.getPersonController().navigateToPerson(e.getPersonUuid()); 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 4e32ea82902..3fb81e0f626 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 @@ -65,7 +65,9 @@ protected void initView(String params) { container.addComponent(layout); UserProvider currentUser = UserProvider.getCurrent(); - boolean caseButtonVisible = currentUser != null && currentUser.hasUserRight(UserRight.CASE_CREATE); + boolean caseButtonVisible = currentUser != null + && currentUser.hasUserRight(UserRight.CASE_CREATE) + && FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.CASE_SURVEILANCE); CaseReferenceDto resultingCase = travelEntryDto.getResultingCase(); if (resultingCase == null && caseButtonVisible) { From 71535495118be1ab010a1ef1ed96b5c36b4d0027 Mon Sep 17 00:00:00 2001 From: Levente Gal Date: Thu, 9 Nov 2023 18:08:24 +0200 Subject: [PATCH 04/65] #12603 Add search functions on the event directory in the mobile app - added mobile specific caption --- sormas-app/app/src/main/res/layout/filter_event_list_layout.xml | 2 +- sormas-app/app/src/main/res/values/strings.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/sormas-app/app/src/main/res/layout/filter_event_list_layout.xml b/sormas-app/app/src/main/res/layout/filter_event_list_layout.xml index fab5176e13b..e12ec7691c3 100644 --- a/sormas-app/app/src/main/res/layout/filter_event_list_layout.xml +++ b/sormas-app/app/src/main/res/layout/filter_event_list_layout.xml @@ -43,7 +43,7 @@ diff --git a/sormas-app/app/src/main/res/values/strings.xml b/sormas-app/app/src/main/res/values/strings.xml index 43b9ab6eb4f..e48c841d7b8 100644 --- a/sormas-app/app/src/main/res/values/strings.xml +++ b/sormas-app/app/src/main/res/values/strings.xml @@ -284,6 +284,7 @@ %1$s pulled %1$s/%2$s pushed %1$s deleted + ID, title, description ` Are you sure you want to do this? Are you sure you want to delete this record? From a6c291e928e328ab3d7300c7227d59dee1792aaa Mon Sep 17 00:00:00 2001 From: jenkins Date: Fri, 10 Nov 2023 09:49:33 +0100 Subject: [PATCH 05/65] [GITFLOW]updating poms for 1.92.0-SNAPSHOT development --- sormas-api/pom.xml | 2 +- sormas-app/pom.xml | 2 +- sormas-backend/pom.xml | 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-serverlibs/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 7c822c6960c..90ced610109 100644 --- a/sormas-api/pom.xml +++ b/sormas-api/pom.xml @@ -2,7 +2,7 @@ de.symeda.sormas sormas-base - 1.91.0-SNAPSHOT + 1.92.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-app/pom.xml b/sormas-app/pom.xml index ab88cc97890..a8c6ee6ffe1 100644 --- a/sormas-app/pom.xml +++ b/sormas-app/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.91.0-SNAPSHOT + 1.92.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-backend/pom.xml b/sormas-backend/pom.xml index 9f238fb9df0..51f3abf7cc4 100644 --- a/sormas-backend/pom.xml +++ b/sormas-backend/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.91.0-SNAPSHOT + 1.92.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-base/pom.xml b/sormas-base/pom.xml index e68b9cf4578..d59ff72d52f 100644 --- a/sormas-base/pom.xml +++ b/sormas-base/pom.xml @@ -5,7 +5,7 @@ de.symeda.sormas sormas-base pom - 1.91.0-SNAPSHOT + 1.92.0-SNAPSHOT 3.6.3 diff --git a/sormas-cargoserver/pom.xml b/sormas-cargoserver/pom.xml index fff8c9f57fb..5602ea44410 100644 --- a/sormas-cargoserver/pom.xml +++ b/sormas-cargoserver/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.91.0-SNAPSHOT + 1.92.0-SNAPSHOT ../sormas-base diff --git a/sormas-ear/pom.xml b/sormas-ear/pom.xml index f13f0e757de..48dde141ce0 100644 --- a/sormas-ear/pom.xml +++ b/sormas-ear/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.91.0-SNAPSHOT + 1.92.0-SNAPSHOT ../sormas-base diff --git a/sormas-keycloak-service-provider/pom.xml b/sormas-keycloak-service-provider/pom.xml index 7b2a75a0421..1aa75222a74 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.91.0-SNAPSHOT + 1.92.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-rest/pom.xml b/sormas-rest/pom.xml index a080061d7d5..903fb2e8266 100644 --- a/sormas-rest/pom.xml +++ b/sormas-rest/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.91.0-SNAPSHOT + 1.92.0-SNAPSHOT ../sormas-base diff --git a/sormas-serverlibs/pom.xml b/sormas-serverlibs/pom.xml index d23c5a43d89..6b6c6a964e2 100644 --- a/sormas-serverlibs/pom.xml +++ b/sormas-serverlibs/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.91.0-SNAPSHOT + 1.92.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-ui/pom.xml b/sormas-ui/pom.xml index bffb476e826..579165c072d 100644 --- a/sormas-ui/pom.xml +++ b/sormas-ui/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.91.0-SNAPSHOT + 1.92.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-widgetset/pom.xml b/sormas-widgetset/pom.xml index e65d833a02a..8cb3e5806e1 100644 --- a/sormas-widgetset/pom.xml +++ b/sormas-widgetset/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.91.0-SNAPSHOT + 1.92.0-SNAPSHOT ../sormas-base 4.0.0 From b714a75f8ddbf8ed6fc4943e0ed003c23d2746f1 Mon Sep 17 00:00:00 2001 From: jenkins Date: Fri, 10 Nov 2023 10:06:21 +0100 Subject: [PATCH 06/65] [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/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-serverlibs/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 90ced610109..c12e8d3d801 100644 --- a/sormas-api/pom.xml +++ b/sormas-api/pom.xml @@ -2,7 +2,7 @@ de.symeda.sormas sormas-base - 1.92.0-SNAPSHOT + 1.91.0 ../sormas-base 4.0.0 diff --git a/sormas-app/pom.xml b/sormas-app/pom.xml index a8c6ee6ffe1..2974deb2716 100644 --- a/sormas-app/pom.xml +++ b/sormas-app/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.92.0-SNAPSHOT + 1.91.0 ../sormas-base 4.0.0 diff --git a/sormas-backend/pom.xml b/sormas-backend/pom.xml index 51f3abf7cc4..3254460ccef 100644 --- a/sormas-backend/pom.xml +++ b/sormas-backend/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.92.0-SNAPSHOT + 1.91.0 ../sormas-base 4.0.0 diff --git a/sormas-base/pom.xml b/sormas-base/pom.xml index d59ff72d52f..1e969ab78ed 100644 --- a/sormas-base/pom.xml +++ b/sormas-base/pom.xml @@ -5,7 +5,7 @@ de.symeda.sormas sormas-base pom - 1.92.0-SNAPSHOT + 1.91.0 3.6.3 diff --git a/sormas-cargoserver/pom.xml b/sormas-cargoserver/pom.xml index 5602ea44410..1912dcd6ec1 100644 --- a/sormas-cargoserver/pom.xml +++ b/sormas-cargoserver/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.92.0-SNAPSHOT + 1.91.0 ../sormas-base diff --git a/sormas-ear/pom.xml b/sormas-ear/pom.xml index 48dde141ce0..1d172639fa4 100644 --- a/sormas-ear/pom.xml +++ b/sormas-ear/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.92.0-SNAPSHOT + 1.91.0 ../sormas-base diff --git a/sormas-keycloak-service-provider/pom.xml b/sormas-keycloak-service-provider/pom.xml index 1aa75222a74..7e9df7c76ae 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.92.0-SNAPSHOT + 1.91.0 ../sormas-base 4.0.0 diff --git a/sormas-rest/pom.xml b/sormas-rest/pom.xml index 903fb2e8266..0a1fd4caf1a 100644 --- a/sormas-rest/pom.xml +++ b/sormas-rest/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.92.0-SNAPSHOT + 1.91.0 ../sormas-base diff --git a/sormas-serverlibs/pom.xml b/sormas-serverlibs/pom.xml index 6b6c6a964e2..d31c1d1c23b 100644 --- a/sormas-serverlibs/pom.xml +++ b/sormas-serverlibs/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.92.0-SNAPSHOT + 1.91.0 ../sormas-base 4.0.0 diff --git a/sormas-ui/pom.xml b/sormas-ui/pom.xml index 579165c072d..3ce6f516f44 100644 --- a/sormas-ui/pom.xml +++ b/sormas-ui/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.92.0-SNAPSHOT + 1.91.0 ../sormas-base 4.0.0 diff --git a/sormas-widgetset/pom.xml b/sormas-widgetset/pom.xml index 8cb3e5806e1..372b9790d81 100644 --- a/sormas-widgetset/pom.xml +++ b/sormas-widgetset/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.92.0-SNAPSHOT + 1.91.0 ../sormas-base 4.0.0 From cecf568861e80593fe48f9f4ff67ed1a89d406cb Mon Sep 17 00:00:00 2001 From: jenkins Date: Fri, 10 Nov 2023 10:06:23 +0100 Subject: [PATCH 07/65] [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/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-serverlibs/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 c12e8d3d801..90ced610109 100644 --- a/sormas-api/pom.xml +++ b/sormas-api/pom.xml @@ -2,7 +2,7 @@ de.symeda.sormas sormas-base - 1.91.0 + 1.92.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-app/pom.xml b/sormas-app/pom.xml index 2974deb2716..a8c6ee6ffe1 100644 --- a/sormas-app/pom.xml +++ b/sormas-app/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.91.0 + 1.92.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-backend/pom.xml b/sormas-backend/pom.xml index 3254460ccef..51f3abf7cc4 100644 --- a/sormas-backend/pom.xml +++ b/sormas-backend/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.91.0 + 1.92.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-base/pom.xml b/sormas-base/pom.xml index 1e969ab78ed..d59ff72d52f 100644 --- a/sormas-base/pom.xml +++ b/sormas-base/pom.xml @@ -5,7 +5,7 @@ de.symeda.sormas sormas-base pom - 1.91.0 + 1.92.0-SNAPSHOT 3.6.3 diff --git a/sormas-cargoserver/pom.xml b/sormas-cargoserver/pom.xml index 1912dcd6ec1..5602ea44410 100644 --- a/sormas-cargoserver/pom.xml +++ b/sormas-cargoserver/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.91.0 + 1.92.0-SNAPSHOT ../sormas-base diff --git a/sormas-ear/pom.xml b/sormas-ear/pom.xml index 1d172639fa4..48dde141ce0 100644 --- a/sormas-ear/pom.xml +++ b/sormas-ear/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.91.0 + 1.92.0-SNAPSHOT ../sormas-base diff --git a/sormas-keycloak-service-provider/pom.xml b/sormas-keycloak-service-provider/pom.xml index 7e9df7c76ae..1aa75222a74 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.91.0 + 1.92.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-rest/pom.xml b/sormas-rest/pom.xml index 0a1fd4caf1a..903fb2e8266 100644 --- a/sormas-rest/pom.xml +++ b/sormas-rest/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 1.91.0 + 1.92.0-SNAPSHOT ../sormas-base diff --git a/sormas-serverlibs/pom.xml b/sormas-serverlibs/pom.xml index d31c1d1c23b..6b6c6a964e2 100644 --- a/sormas-serverlibs/pom.xml +++ b/sormas-serverlibs/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.91.0 + 1.92.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-ui/pom.xml b/sormas-ui/pom.xml index 3ce6f516f44..579165c072d 100644 --- a/sormas-ui/pom.xml +++ b/sormas-ui/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.91.0 + 1.92.0-SNAPSHOT ../sormas-base 4.0.0 diff --git a/sormas-widgetset/pom.xml b/sormas-widgetset/pom.xml index 372b9790d81..8cb3e5806e1 100644 --- a/sormas-widgetset/pom.xml +++ b/sormas-widgetset/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 1.91.0 + 1.92.0-SNAPSHOT ../sormas-base 4.0.0 From 5c088b0c176424f54684467fbc08bacc7ba51567 Mon Sep 17 00:00:00 2001 From: sormas-vitagroup Date: Fri, 10 Nov 2023 09:33:03 +0000 Subject: [PATCH 08/65] [GitHub Actions] Update openAPI spec files --- sormas-rest/swagger.json | 2 +- sormas-rest/swagger.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sormas-rest/swagger.json b/sormas-rest/swagger.json index a72cd0aa360..01df2b3e9b6 100644 --- a/sormas-rest/swagger.json +++ b/sormas-rest/swagger.json @@ -7,7 +7,7 @@ "url" : "https://www.gnu.org/licenses/gpl-3.0.html" }, "title" : "SORMAS REST API", - "version" : "1.91.0-SNAPSHOT" + "version" : "1.92.0-SNAPSHOT" }, "servers" : [ { "url" : "/sormas-rest" diff --git a/sormas-rest/swagger.yaml b/sormas-rest/swagger.yaml index 2a8e29e1183..b73de56b797 100644 --- a/sormas-rest/swagger.yaml +++ b/sormas-rest/swagger.yaml @@ -10,7 +10,7 @@ info: name: GPL v3 url: https://www.gnu.org/licenses/gpl-3.0.html title: SORMAS REST API - version: 1.91.0-SNAPSHOT + version: 1.92.0-SNAPSHOT servers: - url: /sormas-rest paths: From c969695598fe9754765ebb3f63bc6c51ff9454c8 Mon Sep 17 00:00:00 2001 From: Levente Gal <62599627+leventegal-she@users.noreply.github.com> Date: Fri, 10 Nov 2023 12:33:02 +0200 Subject: [PATCH 09/65] Feature 11435 assign multiple limited diseases to users (#12723) * #11435 Assign multiple limited diseases to users - wip * #11435 Assign multiple limited diseases to users - wip * #11435 Assign multiple limited diseases to users - wip * #11435 Assign multiple limited diseases to users - wip * #11435 Assign multiple limited diseases to users - regenerate translation interfaces * #11435 Assign multiple limited diseases to users - fixed database migrations * #11435 Assign multiple limited diseases to users - fixed database migration after merge --------- Co-authored-by: Levente Gal --- .../disease/DiseaseConfigurationFacade.java | 2 - .../de/symeda/sormas/api/i18n/Captions.java | 1 + .../de/symeda/sormas/api/i18n/Strings.java | 2 + .../sormas/api/outbreak/OutbreakCriteria.java | 15 +++-- .../sormas/api/outbreak/OutbreakFacade.java | 3 - .../de/symeda/sormas/api/user/UserDto.java | 12 ++-- .../src/main/resources/captions.properties | 1 + .../src/main/resources/strings.properties | 4 ++ .../disease/DiseaseConfigurationDaoTest.java | 2 - .../app/backend/common/AbstractAdoDao.java | 4 +- .../app/backend/common/DatabaseHelper.java | 27 +++++++- .../symeda/sormas/app/backend/user/User.java | 44 +++++++++++-- .../app/backend/user/UserDtoHelper.java | 2 +- .../util/BooleanJurisdictionValidator.java | 6 +- .../app/util/DiseaseConfigurationCache.java | 33 ++-------- .../sormas/app/util/JurisdictionHelper.java | 2 +- .../sormas/app/util/UserJurisdiction.java | 12 ++-- .../CaseJurisdictionPredicateValidator.java | 2 +- .../sormas/backend/caze/CaseService.java | 4 +- .../backend/common/CriteriaBuilderHelper.java | 13 ++++ ...ContactJurisdictionPredicateValidator.java | 2 +- .../backend/contact/ContactService.java | 17 ++---- .../DiseaseConfigurationFacadeEjb.java | 21 ++----- .../backend/event/EventGroupService.java | 9 ++- .../EventJurisdictionPredicateValidator.java | 2 +- ...icipantJurisdictionPredicateValidator.java | 2 +- .../sormas/backend/event/EventService.java | 10 ++- .../DirectoryImmunizationService.java | 54 ++++++++-------- .../immunization/ImmunizationService.java | 5 +- .../backend/outbreak/OutbreakFacadeEjb.java | 9 --- .../backend/outbreak/OutbreakService.java | 6 +- .../sormas/backend/sample/SampleService.java | 24 ++++---- ...elEntryJurisdictionPredicateValidator.java | 2 +- .../services/BaseTravelEntryService.java | 6 +- .../TravelEntryImportFacadeEjb.java | 15 +++-- .../backend/user/DiseaseSetConverter.java | 39 ++++++++++++ .../de/symeda/sormas/backend/user/User.java | 15 ++--- .../sormas/backend/user/UserFacadeEjb.java | 20 +++--- .../sormas/backend/user/UserService.java | 12 ++-- .../util/PredicateJurisdictionValidator.java | 2 +- .../src/main/resources/sql/sormas_schema.sql | 13 ++++ .../sormas/backend/TestDataCreator.java | 4 +- .../ImmunizationFacadeEjbTest.java | 3 +- .../backend/person/PersonFacadeEjbTest.java | 2 +- .../sormas/backend/user/UserServiceTest.java | 5 +- .../test/resources/META-INF/persistence.xml | 2 +- .../outbreak/OutbreakOverviewGrid.java | 2 +- .../symeda/sormas/ui/user/UserEditForm.java | 49 ++++++++++++++- .../ui/utils/components/CheckboxSet.java | 61 +++++++++++++------ .../sormas/backend/TestDataCreator.java | 5 +- 50 files changed, 383 insertions(+), 226 deletions(-) create mode 100644 sormas-backend/src/main/java/de/symeda/sormas/backend/user/DiseaseSetConverter.java diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/disease/DiseaseConfigurationFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/disease/DiseaseConfigurationFacade.java index 84efbaa79fd..e25e28fa564 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/disease/DiseaseConfigurationFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/disease/DiseaseConfigurationFacade.java @@ -31,8 +31,6 @@ public interface DiseaseConfigurationFacade { boolean isPrimaryDisease(Disease disease); - List getAllPrimaryDiseases(); - boolean hasFollowUp(Disease disease); List getAllDiseasesWithFollowUp(); 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 db585fc01e1..eebfff17d66 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 @@ -2599,6 +2599,7 @@ public interface Captions { String userMyUserId = "userMyUserId"; String userNewUser = "userNewUser"; String userResetPassword = "userResetPassword"; + String userRestrictDiseases = "userRestrictDiseases"; String userRight = "userRight"; String UserRight_caption = "UserRight.caption"; String UserRight_description = "UserRight.description"; 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 b8389f8f7bb..804916a7772 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 @@ -656,6 +656,7 @@ public interface Strings { String headingLaboratoryEnvironmentSample = "headingLaboratoryEnvironmentSample"; String headingLaboratorySample = "headingLaboratorySample"; String headingLastReportedDistrict = "headingLastReportedDistrict"; + String headingLimitedDiseases = "headingLimitedDiseases"; String headingLineListing = "headingLineListing"; String headingLineListingImport = "headingLineListingImport"; String headingLocation = "headingLocation"; @@ -996,6 +997,7 @@ public interface Strings { String infoPopulationCollectionDate = "infoPopulationCollectionDate"; String infoPopulationDataView = "infoPopulationDataView"; String infoPopulationReferenceYear = "infoPopulationReferenceYear"; + String infoRestrictDiseasesDescription = "infoRestrictDiseasesDescription"; String infoSampleAdditionalTesting = "infoSampleAdditionalTesting"; String infoSampleExport = "infoSampleExport"; String infoSamplePathogenTesting = "infoSamplePathogenTesting"; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/outbreak/OutbreakCriteria.java b/sormas-api/src/main/java/de/symeda/sormas/api/outbreak/OutbreakCriteria.java index b72826055fd..7b28c46d9e7 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/outbreak/OutbreakCriteria.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/outbreak/OutbreakCriteria.java @@ -18,7 +18,9 @@ package de.symeda.sormas.api.outbreak; import java.io.Serializable; +import java.util.Collections; import java.util.Date; +import java.util.Set; import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.infrastructure.district.DistrictReferenceDto; @@ -31,7 +33,7 @@ public class OutbreakCriteria extends BaseCriteria implements Serializable { private RegionReferenceDto region; private DistrictReferenceDto district; - private Disease disease; + private Set diseases; private Boolean active; private Date activeLower, activeUpper; private Date changeDateAfter; @@ -56,12 +58,17 @@ public OutbreakCriteria district(DistrictReferenceDto district) { return this; } - public Disease getDisease() { - return disease; + public Set getDiseases() { + return diseases; + } + + public OutbreakCriteria diseases(Set disease) { + this.diseases = disease; + return this; } public OutbreakCriteria disease(Disease disease) { - this.disease = disease; + this.diseases = Collections.singleton(disease); return this; } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/outbreak/OutbreakFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/outbreak/OutbreakFacade.java index d36e07affb0..f7eeda45fe6 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/outbreak/OutbreakFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/outbreak/OutbreakFacade.java @@ -27,7 +27,6 @@ import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.common.Page; import de.symeda.sormas.api.infrastructure.district.DistrictReferenceDto; -import de.symeda.sormas.api.infrastructure.region.RegionReferenceDto; import de.symeda.sormas.api.utils.SortProperty; @Remote @@ -41,8 +40,6 @@ public interface OutbreakFacade { List getActive(OutbreakCriteria criteria); - List getActiveByRegionAndDisease(RegionReferenceDto region, Disease disease); - OutbreakDto getActiveByDistrictAndDisease(DistrictReferenceDto district, Disease disease); Page getIndexPage(OutbreakCriteria criteria, Integer offset, Integer size, List sortProperties); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserDto.java index 85ebefde8c7..a2e98c0232d 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserDto.java @@ -64,7 +64,7 @@ public class UserDto extends EntityDto { public static final String ASSOCIATED_OFFICER = "associatedOfficer"; public static final String LABORATORY = "laboratory"; public static final String POINT_OF_ENTRY = "pointOfEntry"; - public static final String LIMITED_DISEASE = "limitedDisease"; + public static final String LIMITED_DISEASES = "limitedDiseases"; public static final String LANGUAGE = "language"; public static final String HAS_CONSENTED_TO_GDPR = "hasConsentedToGdpr"; public static final String JURISDICTION_LEVEL = "jurisdictionLevel"; @@ -101,7 +101,7 @@ public class UserDto extends EntityDto { private UserReferenceDto associatedOfficer; - private Disease limitedDisease; + private Set limitedDiseases; private Language language; @@ -254,12 +254,12 @@ public UserReferenceDto toReference() { return new UserReferenceDto(getUuid(), getFirstName(), getLastName()); } - public Disease getLimitedDisease() { - return limitedDisease; + public Set getLimitedDiseases() { + return limitedDiseases; } - public void setLimitedDisease(Disease limitedDisease) { - this.limitedDisease = limitedDisease; + public void setLimitedDiseases(Set limitedDiseases) { + this.limitedDiseases = limitedDiseases; } public Language getLanguage() { diff --git a/sormas-api/src/main/resources/captions.properties b/sormas-api/src/main/resources/captions.properties index c6f11353e5d..0b2c659b276 100644 --- a/sormas-api/src/main/resources/captions.properties +++ b/sormas-api/src/main/resources/captions.properties @@ -2564,6 +2564,7 @@ User.uuid=UUID User.region=Region User.district=District User.community=Community +userRestrictDiseases=Restrict access to specific diseases # Vaccination vaccinationNewVaccination=New vaccination vaccinationNoVaccinationsForPerson=There are no vaccinations for this person diff --git a/sormas-api/src/main/resources/strings.properties b/sormas-api/src/main/resources/strings.properties index 2999a0bb516..3c3879c6bac 100644 --- a/sormas-api/src/main/resources/strings.properties +++ b/sormas-api/src/main/resources/strings.properties @@ -857,6 +857,8 @@ headingEnvironmentSampleMeasurements = Sample measurements headingEnvironmentSampleLocation = Location of sampling site headingEnvironmentSampleManagement = Sample management headingEnvironmentSampleRequestedPathogenTests = Requested pathogens to be tested +headingLimitedDiseases=Disease restrictions + # Info texts infoActivityAsCaseInvestigation = Please document ALL relevant activities after infection: infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first. @@ -1054,6 +1056,8 @@ infoBulkProcessNoEligibleEntries = Bulk process has been cancelled because th infoBulkProcessCancelled = Bulk process has been cancelled!
All selected entries up until this point have been processed. You can now close this window. All not yet processed entries will still be selected. infoBulkUnresponsiveWindowHint = Hint: If the progress bar seems to be unresponsive and no progress is visible after a while, try to click this popup window or resize your browser window. infoNoEnvironmentSamples = No samples have been created for this environment +infoRestrictDiseasesDescription=Mark all diseases that the user is supposed to have access to + # Messages messageActionOutsideJurisdictionDeletionDenied = The action outside user's jurisdiction cannot be deleted messageActivateAccount = Account has to be activated diff --git a/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/backend/disease/DiseaseConfigurationDaoTest.java b/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/backend/disease/DiseaseConfigurationDaoTest.java index 16884a21ab4..401db5d9566 100644 --- a/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/backend/disease/DiseaseConfigurationDaoTest.java +++ b/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/backend/disease/DiseaseConfigurationDaoTest.java @@ -43,7 +43,6 @@ public void testCreateAndUpdate() throws DaoException { cache = DiseaseConfigurationCache.getInstance(); assertFalse(cache.getAllActiveDiseases().contains(disease)); - assertTrue(cache.getAllDiseasesWithFollowUp().contains(disease)); //Test update configuration.setFollowUpEnabled(false); @@ -53,6 +52,5 @@ public void testCreateAndUpdate() throws DaoException { cache = DiseaseConfigurationCache.getInstance(); assertFalse(cache.getAllActiveDiseases().contains(disease)); - assertFalse(cache.getAllDiseasesWithFollowUp().contains(disease)); } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/AbstractAdoDao.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/AbstractAdoDao.java index 5b118f510b0..126b1fcfe4e 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/AbstractAdoDao.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/AbstractAdoDao.java @@ -54,6 +54,7 @@ import de.symeda.sormas.app.backend.environment.environmentsample.EnvironmentSample; import de.symeda.sormas.app.backend.feature.FeatureConfiguration; import de.symeda.sormas.app.backend.infrastructure.InfrastructureAdo; +import de.symeda.sormas.app.backend.user.User; import de.symeda.sormas.app.component.dialog.SynchronizationDialog; import de.symeda.sormas.app.util.MetaProperty; @@ -682,7 +683,8 @@ public ADO mergeOrCreate(ADO source) throws DaoException { || FeatureConfiguration.PROPERTIES_MAP.equals(property.getName()) || Environment.WATER_USE.equals(property.getName()) || EnvironmentSample.REQUESTED_PATHOGEN_TESTS.equals(property.getName()) - || EnvironmentSample.WEATHER_CONDITIONS.equals(property.getName())) + || EnvironmentSample.WEATHER_CONDITIONS.equals(property.getName()) + || User.LIMITED_DISEASES.equals(property.getName())) continue; // we now have to write the value from source into target and base 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 7ce46f945c8..59bc8e9823d 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,8 @@ package de.symeda.sormas.app.backend.common; +import static de.symeda.sormas.api.utils.FieldConstraints.CHARACTER_LIMIT_TEXT; + import java.lang.reflect.Array; import java.math.BigInteger; import java.sql.SQLException; @@ -37,6 +39,7 @@ import com.j256.ormlite.dao.Dao; import com.j256.ormlite.dao.GenericRawResults; import com.j256.ormlite.field.DataType; +import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.TableUtils; @@ -46,7 +49,12 @@ import android.text.TextUtils; import android.util.Log; +import javax.persistence.Column; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; + import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.Language; import de.symeda.sormas.api.caze.VaccinationStatus; import de.symeda.sormas.api.caze.Vaccine; import de.symeda.sormas.api.caze.VaccineManufacturer; @@ -190,7 +198,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 = 355; + public static final int DATABASE_VERSION = 356; private static DatabaseHelper instance = null; @@ -3147,6 +3155,23 @@ public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int getDao(District.class).executeRaw("ALTER TABLE district ADD COLUMN defaultInfrastructure boolean default false;"); getDao(Community.class).executeRaw("ALTER TABLE community ADD COLUMN defaultInfrastructure boolean default false;"); + case 355: + currentVersion = 355; + + getDao(User.class).executeRaw("ALTER TABLE users RENAME TO tmp_users;"); + getDao(User.class).executeRaw("CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, active BOOLEAN, address_id BIGINT REFERENCES location(id), associatedOfficer_id BIGINT REFERENCES users(id), community_id BIGINT REFERENCES community(id), district_id BIGINT REFERENCES district(id), firstName TEXT, healthFacility_id BIGINT REFERENCES facility(id), " + + "jurisdictionLevel VARCHAR(255), language VARCHAR(255), lastName TEXT, limitedDiseases TEXT, phone TEXT, pointOfEntry_id BIGINT REFERENCES pointOfEntry(id), region_id BIGINT REFERENCES region(id), userEmail TEXT, userName TEXT, " + + "changeDate TIMESTAMP NOT NULL, creationDate TIMESTAMP NOT NULL, lastOpenedDate TIMESTAMP, localChangeDate TIMESTAMP NOT NULL, modified BOOLEAN, snapshot BOOLEAN, uuid VARCHAR(36) NOT NULL, UNIQUE(snapshot, uuid));"); + getDao(User.class).executeRaw( + "INSERT INTO users (active, address_id, associatedOfficer_id, community_id, district_id, firstName, healthFacility_id, " + + "jurisdictionLevel, language, lastName, limitedDiseases, phone, pointOfEntry_id, region_id, userEmail, userName, " + + "changeDate, creationDate, id, lastOpenedDate, localChangeDate, modified, snapshot, uuid) " + + "SELECT active, address_id, associatedOfficer_id, community_id, district_id, firstName, healthFacility_id, " + + "jurisdictionLevel, language, lastName, limitedDisease, phone, pointOfEntry_id, region_id, userEmail, userName, " + + "changeDate, creationDate, id, lastOpenedDate, localChangeDate, modified, snapshot, uuid FROM tmp_users;"); + getDao(User.class).executeRaw("UPDATE users set limitedDiseases = '[' || limitedDiseases || ']' where limitedDiseases IS NOT NULL and limitedDiseases <> '';"); + getDao(Environment.class).executeRaw("DROP TABLE tmp_users;"); + // ATTENTION: break should only be done after last version break; diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/user/User.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/user/User.java index eee3830021b..e86b108fa3a 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/user/User.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/user/User.java @@ -15,14 +15,21 @@ package de.symeda.sormas.app.backend.user; +import static de.symeda.sormas.api.utils.FieldConstraints.CHARACTER_LIMIT_TEXT; + +import java.lang.reflect.Type; import java.util.Arrays; +import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; @@ -62,6 +69,7 @@ public class User extends AbstractDomainObject { public static final String ASSOCIATED_OFFICER = "associatedOfficer"; public static final String USER_ROLES_JSON = "userRole"; public static final String LANGUAGE = "language"; + public static final String LIMITED_DISEASES = "limitedDiseases"; public static final String JURISDICTION_LEVEL = "jurisdictionLevel"; @Column(nullable = false) @@ -96,8 +104,10 @@ public class User extends AbstractDomainObject { @Enumerated(EnumType.STRING) private Language language; - @Enumerated(EnumType.STRING) - private Disease limitedDisease; + @Column(name = "limitedDiseases", length = CHARACTER_LIMIT_TEXT) + private String limitedDiseasesJson; + + private Set limitedDiseases; // initialized from userRolesJson private Set userRoles = null; @@ -209,12 +219,34 @@ public void setAssociatedOfficer(User associatedOfficer) { this.associatedOfficer = associatedOfficer; } - public Disease getLimitedDisease() { - return limitedDisease; + public String getLimitedDiseasesJson() { + return limitedDiseasesJson; + } + + public void setLimitedDiseasesJson(String limitedDiseasesJson) { + this.limitedDiseasesJson = limitedDiseasesJson; } - public void setLimitedDisease(Disease limitedDisease) { - this.limitedDisease = limitedDisease; + public Set getLimitedDiseases() { + if (limitedDiseases == null) { + Gson gson = new Gson(); + Type type = new TypeToken>() { + }.getType(); + limitedDiseases = gson.fromJson(limitedDiseasesJson, type); + } + + return limitedDiseases; + } + + public void setLimitedDiseases(Set limitedDiseases) { + if (limitedDiseases == null) { + this.limitedDiseases = null; + this.limitedDiseasesJson = null; + } else { + this.limitedDiseases = limitedDiseases; + Gson gson = new Gson(); + limitedDiseasesJson = gson.toJson(limitedDiseases.stream().map(Disease::name).collect(Collectors.toSet())); + } } public Language getLanguage() { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/user/UserDtoHelper.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/user/UserDtoHelper.java index 290a092c8e2..647aa000902 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/user/UserDtoHelper.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/user/UserDtoHelper.java @@ -110,7 +110,7 @@ protected void fillInnerFromDto(User target, UserDto source) { target.setPointOfEntry(DatabaseHelper.getPointOfEntryDao().getByReferenceDto(source.getPointOfEntry())); target.setAssociatedOfficer(DatabaseHelper.getUserDao().getByReferenceDto(source.getAssociatedOfficer())); - target.setLimitedDisease(source.getLimitedDisease()); + target.setLimitedDiseases(source.getLimitedDiseases()); target.setAddress(locationHelper.fillOrCreateFromDto(target.getAddress(), source.getAddress())); target.setPhone(source.getPhone()); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/util/BooleanJurisdictionValidator.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/util/BooleanJurisdictionValidator.java index 5a0ec18c43b..5bdbee6f159 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/util/BooleanJurisdictionValidator.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/util/BooleanJurisdictionValidator.java @@ -15,6 +15,8 @@ package de.symeda.sormas.app.util; +import org.apache.commons.collections.CollectionUtils; + import java.util.List; import de.symeda.sormas.api.Disease; @@ -49,8 +51,8 @@ public Boolean hasUserLimitedDisease() { if (getDisease() == null) { return true; } - if (userJurisdiction != null && userJurisdiction.getLimitedDisease() != null) { - return getDisease() == userJurisdiction.getLimitedDisease(); + if (userJurisdiction != null && CollectionUtils.isNotEmpty(userJurisdiction.getLimitedDiseases())) { + return userJurisdiction.getLimitedDiseases().contains(getDisease()); } else { return true; } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/util/DiseaseConfigurationCache.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/util/DiseaseConfigurationCache.java index 13cf95d9262..e8a33d6298c 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/util/DiseaseConfigurationCache.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/util/DiseaseConfigurationCache.java @@ -24,6 +24,8 @@ import java.util.Set; import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; + import de.symeda.sormas.api.Disease; import de.symeda.sormas.app.backend.common.DatabaseHelper; import de.symeda.sormas.app.backend.config.ConfigProvider; @@ -124,9 +126,8 @@ public List getAllDiseases(Boolean active, Boolean primary, boolean cas Set diseases = EnumSet.noneOf(Disease.class); if (caseSurveillance) { - if (currentUser.getLimitedDisease() != null) { - Disease limitedDisease = currentUser.getLimitedDisease(); - diseases.add(limitedDisease); + if (CollectionUtils.isNotEmpty(currentUser.getLimitedDiseases())) { + diseases.addAll(currentUser.getLimitedDiseases()); } else { diseases.addAll(caseBasedDiseases); } @@ -182,19 +183,6 @@ public boolean isPrimaryDisease(Disease disease) { return primaryDiseases.contains(disease); } - public List getAllPrimaryDiseases() { - User currentUser = ConfigProvider.getUser(); - if (currentUser.getLimitedDisease() != null) { - ArrayList list = new ArrayList<>(); - if (isPrimaryDisease(currentUser.getLimitedDisease())) { - list.add(currentUser.getLimitedDisease()); - } - return list; - } else { - return primaryDiseases; - } - } - public boolean usesExtendedClassification(Disease disease) { return extendedClassificationDiseases.get(disease); } @@ -207,19 +195,6 @@ public boolean hasFollowUp(Disease disease) { return followUpEnabledDiseases.contains(disease); } - public List getAllDiseasesWithFollowUp() { - User currentUser = ConfigProvider.getUser(); - if (currentUser.getLimitedDisease() != null) { - ArrayList list = new ArrayList<>(); - if (hasFollowUp(currentUser.getLimitedDisease())) { - list.add(currentUser.getLimitedDisease()); - } - return list; - } else { - return followUpEnabledDiseases; - } - } - public int getFollowUpDuration(Disease disease) { return followUpDurations.get(disease); } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/util/JurisdictionHelper.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/util/JurisdictionHelper.java index 2f416ba53f1..51bf97b6bc5 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/util/JurisdictionHelper.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/util/JurisdictionHelper.java @@ -54,7 +54,7 @@ public static UserJurisdiction createUserJurisdiction(User user) { jurisdiction.setPointOfEntryUuid(user.getPointOfEntry().getUuid()); } - jurisdiction.setLimitedDisease(user.getLimitedDisease()); + jurisdiction.setLimitedDiseases(user.getLimitedDiseases()); jurisdiction.setJurisdictionLevel(UserRole.getJurisdictionLevel(user.getUserRoles())); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/util/UserJurisdiction.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/util/UserJurisdiction.java index a7d7a9e4b23..3d17803f19a 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/util/UserJurisdiction.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/util/UserJurisdiction.java @@ -17,6 +17,8 @@ */ package de.symeda.sormas.app.util; +import java.util.Set; + import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.user.JurisdictionLevel; @@ -30,7 +32,7 @@ public class UserJurisdiction { private String healthFacilityUuid; private String pointOfEntryUuid; private String labUuid; - private Disease limitedDisease; + private Set limitedDiseases; public JurisdictionLevel getJurisdictionLevel() { return jurisdictionLevel; @@ -96,11 +98,11 @@ public void setLabUuid(String labUuid) { this.labUuid = labUuid; } - public Disease getLimitedDisease() { - return limitedDisease; + public Set getLimitedDiseases() { + return limitedDiseases; } - public void setLimitedDisease(Disease limitedDisease) { - this.limitedDisease = limitedDisease; + public void setLimitedDiseases(Set limitedDiseases) { + this.limitedDiseases = limitedDiseases; } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseJurisdictionPredicateValidator.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseJurisdictionPredicateValidator.java index 5205cc6baf8..f9a4f579690 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseJurisdictionPredicateValidator.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseJurisdictionPredicateValidator.java @@ -91,7 +91,7 @@ public Predicate isRootInJurisdictionOrOwned() { @Override protected Predicate getLimitedDiseasePredicate() { - return cb.equal(joins.getRoot().get(Case.DISEASE), user.getLimitedDisease()); + return CriteriaBuilderHelper.limitedDiseasePredicate(cb, user, joins.getRoot().get(Case.DISEASE)); } @Override 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 b9f07aee20e..e97ef29a18b 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 @@ -1483,9 +1483,7 @@ public Predicate createUserFilter(CaseQueryContext caseQueryContext, CaseUserFil } // only show cases of a specific disease if a limited disease is set - if (currentUser.getLimitedDisease() != null) { - filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(casePath.get(Case.DISEASE), currentUser.getLimitedDisease())); - } + filter = CriteriaBuilderHelper.and(cb, filter, CriteriaBuilderHelper.limitedDiseasePredicate(cb, currentUser, casePath.get(Case.DISEASE))); // port health users can only see port health cases if (currentUser.getUserRoles().stream().anyMatch(userRole -> userRole.isPortHealthUser())) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CriteriaBuilderHelper.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CriteriaBuilderHelper.java index 82f85b2225e..adfcf769416 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CriteriaBuilderHelper.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CriteriaBuilderHelper.java @@ -22,6 +22,7 @@ import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.api.uuid.HasUuid; import de.symeda.sormas.backend.ExtendedPostgreSQL94Dialect; +import de.symeda.sormas.backend.user.User; import de.symeda.sormas.backend.util.ModelConstants; public class CriteriaBuilderHelper { @@ -195,6 +196,18 @@ public static Predicate applyDateFilter(CriteriaBuilder cb, Predicate filter, Pa return filter; } + public static Predicate limitedDiseasePredicate(CriteriaBuilder cb, User currentUser, Expression diseaseExpression) { + return limitedDiseasePredicate(cb, currentUser, diseaseExpression, null); + } + + public static Predicate limitedDiseasePredicate(CriteriaBuilder cb, User currentUser, Expression diseaseExpression, Predicate orElse) { + if (currentUser == null || CollectionUtils.isEmpty(currentUser.getLimitedDiseases())) { + return null; + } + + return or(cb, diseaseExpression.in(currentUser.getLimitedDiseases()), orElse); + } + public static Expression dateDiff(CriteriaBuilder cb, Expression date1, Expression date2) { return cb.abs( cb.diff( diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactJurisdictionPredicateValidator.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactJurisdictionPredicateValidator.java index 18d684fcf51..c6fd995a537 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactJurisdictionPredicateValidator.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactJurisdictionPredicateValidator.java @@ -88,7 +88,7 @@ public Predicate isRootInJurisdictionOrOwned() { @Override protected Predicate getLimitedDiseasePredicate() { - return cb.equal(joins.getRoot().get(Contact.DISEASE), user.getLimitedDisease()); + return CriteriaBuilderHelper.limitedDiseasePredicate(cb, user, joins.getRoot().get(Contact.DISEASE)); } @Override 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 97f638d427b..57868211d23 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 @@ -1081,11 +1081,7 @@ public Predicate createUserFilterWithoutCase(ContactQueryContext qc, ContactCrit // National users can access all contacts in the system final JurisdictionLevel jurisdictionLevel = currentUser.getJurisdictionLevel(); if ((jurisdictionLevel == JurisdictionLevel.NATION && !UserRole.isPortHealthUser(currentUser.getUserRoles()))) { - if (currentUser.getLimitedDisease() != null) { - return cb.equal(contactRoot.get(Contact.DISEASE), currentUser.getLimitedDisease()); - } else { - return null; - } + return CriteriaBuilderHelper.limitedDiseasePredicate(cb, currentUser, contactRoot.get(Contact.DISEASE)); } Predicate filter = null; @@ -1127,12 +1123,11 @@ public Predicate createUserFilterWithoutCase(ContactQueryContext qc, ContactCrit default: } - if (currentUser.getLimitedDisease() != null) { - filter = CriteriaBuilderHelper.and( - cb, - filter, - cb.or(cb.equal(contactRoot.get(Contact.DISEASE), currentUser.getLimitedDisease()), cb.isNull(contactRoot.get(Contact.DISEASE)))); - } + filter = CriteriaBuilderHelper.and( + cb, + filter, + CriteriaBuilderHelper + .limitedDiseasePredicate(cb, currentUser, contactRoot.get(Contact.DISEASE), cb.isNull(contactRoot.get(Contact.DISEASE)))); if ((contactCriteria == null || !contactCriteria.isExcludeLimitedSyncRestrictions()) && featureConfigurationFacade 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 d8b4cc57835..7b025f97af7 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 @@ -32,6 +32,7 @@ import javax.ejb.Stateless; import javax.validation.constraints.NotNull; +import org.apache.commons.collections.CollectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -104,9 +105,8 @@ public List getAllDiseases(Boolean active, Boolean primary, boolean cas Set diseases = EnumSet.noneOf(Disease.class); if (caseSurveillance) { - if (currentUser.getLimitedDisease() != null) { - Disease limitedDisease = currentUser.getLimitedDisease(); - diseases.add(limitedDisease); + if (CollectionUtils.isNotEmpty(currentUser.getLimitedDiseases())) { + diseases.addAll(currentUser.getLimitedDiseases()); } else { diseases.addAll(caseSurveillanceDiseases); } @@ -164,17 +164,6 @@ public boolean isPrimaryDisease(Disease disease) { return primaryDiseases.contains(disease); } - @Override - public List getAllPrimaryDiseases() { - - User currentUser = userService.getCurrentUser(); - if (currentUser.getLimitedDisease() != null) { - return primaryDiseases.stream().filter(d -> d == currentUser.getLimitedDisease()).collect(Collectors.toList()); - } else { - return primaryDiseases; - } - } - @Override public boolean hasFollowUp(Disease disease) { return followUpEnabledDiseases.contains(disease); @@ -184,8 +173,8 @@ public boolean hasFollowUp(Disease disease) { public List getAllDiseasesWithFollowUp() { User currentUser = userService.getCurrentUser(); - if (currentUser.getLimitedDisease() != null) { - return followUpEnabledDiseases.stream().filter(d -> d == currentUser.getLimitedDisease()).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(currentUser.getLimitedDiseases())) { + return followUpEnabledDiseases.stream().filter(currentUser.getLimitedDiseases()::contains).collect(Collectors.toList()); } else { return followUpEnabledDiseases; } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventGroupService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventGroupService.java index 2f55e28e578..d124520e14a 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventGroupService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventGroupService.java @@ -101,9 +101,12 @@ public Predicate createUserFilter( default: } - if (filter != null && currentUser.getLimitedDisease() != null) { - filter = cb - .and(filter, cb.or(cb.equal(eventPath.get(Event.DISEASE), currentUser.getLimitedDisease()), cb.isNull(eventPath.get(Event.DISEASE)))); + if (filter != null) { + filter = CriteriaBuilderHelper.and( + cb, + filter, + CriteriaBuilderHelper + .limitedDiseasePredicate(cb, currentUser, eventPath.get(Event.DISEASE), cb.isNull(eventPath.get(Event.DISEASE)))); } Predicate filterResponsible = cb.equal(eventPath.join(Event.REPORTING_USER, JoinType.LEFT), currentUser); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventJurisdictionPredicateValidator.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventJurisdictionPredicateValidator.java index dcb45b88c22..16873d588c5 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventJurisdictionPredicateValidator.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventJurisdictionPredicateValidator.java @@ -77,7 +77,7 @@ public Predicate isRootInJurisdictionOrOwned() { @Override protected Predicate getLimitedDiseasePredicate() { - return cb.equal(joins.getRoot().get(Event.DISEASE), user.getLimitedDisease()); + return CriteriaBuilderHelper.limitedDiseasePredicate(cb, user, joins.getRoot().get(Event.DISEASE)); } @Override diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantJurisdictionPredicateValidator.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantJurisdictionPredicateValidator.java index a76d267b1b7..25a3b376a8a 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantJurisdictionPredicateValidator.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/event/EventParticipantJurisdictionPredicateValidator.java @@ -54,7 +54,7 @@ public Predicate isRootInJurisdictionOrOwned() { @Override protected Predicate getLimitedDiseasePredicate() { - return cb.equal(joins.getEventJoins().getRoot().get(Event.DISEASE), user.getLimitedDisease()); + return CriteriaBuilderHelper.limitedDiseasePredicate(cb, user, joins.getEventJoins().getRoot().get(Event.DISEASE)); } @Override 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 cac70f69934..67f2994feb2 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 @@ -525,12 +525,10 @@ public Predicate createUserFilter(final EventQueryContext queryContext, final Ev } } - if (currentUser.getLimitedDisease() != null) { - filter = CriteriaBuilderHelper.and( - cb, - filter, - cb.or(cb.equal(eventJoin.get(Event.DISEASE), currentUser.getLimitedDisease()), cb.isNull(eventJoin.get(Event.DISEASE)))); - } + CriteriaBuilderHelper.and( + cb, + filter, + CriteriaBuilderHelper.limitedDiseasePredicate(cb, currentUser, eventJoin.get(Event.DISEASE), cb.isNull(eventJoin.get(Event.DISEASE)))); if (RequestContextHolder.isMobileSync()) { Predicate limitedChangeDatePredicate = CriteriaBuilderHelper.and(cb, createLimitedChangeDateFilter(cb, eventJoin)); 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 2d2c1fa1fe4..24541c52581 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 @@ -38,7 +38,6 @@ import de.symeda.sormas.api.utils.SortProperty; import de.symeda.sormas.backend.common.AbstractDeletableAdoService; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; -import de.symeda.sormas.backend.contact.Contact; import de.symeda.sormas.backend.feature.FeatureConfigurationFacadeEjb.FeatureConfigurationFacadeEjbLocal; import de.symeda.sormas.backend.immunization.entity.DirectoryImmunization; import de.symeda.sormas.backend.immunization.entity.Immunization; @@ -100,30 +99,30 @@ public List getIndexList(ImmunizationCriteria criteria, In final Join lastVaccineType = joins.getLastVaccineType(); - cq.multiselect( - immunization.get(Immunization.UUID), - person.get(Person.UUID), - person.get(Person.FIRST_NAME), - person.get(Person.LAST_NAME), - immunization.get(Immunization.DISEASE), - person.get(Person.APPROXIMATE_AGE), - person.get(Person.APPROXIMATE_AGE_TYPE), - person.get(Person.BIRTHDATE_DD), - person.get(Person.BIRTHDATE_MM), - person.get(Person.BIRTHDATE_YYYY), - person.get(Person.SEX), - district.get(District.NAME), - immunization.get(Immunization.MEANS_OF_IMMUNIZATION), - immunization.get(Immunization.IMMUNIZATION_MANAGEMENT_STATUS), - immunization.get(Immunization.IMMUNIZATION_STATUS), - immunization.get(Immunization.START_DATE), - immunization.get(Immunization.END_DATE), - lastVaccineType.get(LastVaccineType.VACCINE_TYPE), - immunization.get(Immunization.RECOVERY_DATE), - immunization.get(Immunization.DELETION_REASON), - immunization.get(Immunization.OTHER_DELETION_REASON), - JurisdictionHelper.booleanSelector(cb, isInJurisdictionOrOwned(directoryImmunizationQueryContext)), - immunization.get(Immunization.CHANGE_DATE)); + cq.multiselect( + immunization.get(Immunization.UUID), + person.get(Person.UUID), + person.get(Person.FIRST_NAME), + person.get(Person.LAST_NAME), + immunization.get(Immunization.DISEASE), + person.get(Person.APPROXIMATE_AGE), + person.get(Person.APPROXIMATE_AGE_TYPE), + person.get(Person.BIRTHDATE_DD), + person.get(Person.BIRTHDATE_MM), + person.get(Person.BIRTHDATE_YYYY), + person.get(Person.SEX), + district.get(District.NAME), + immunization.get(Immunization.MEANS_OF_IMMUNIZATION), + immunization.get(Immunization.IMMUNIZATION_MANAGEMENT_STATUS), + immunization.get(Immunization.IMMUNIZATION_STATUS), + immunization.get(Immunization.START_DATE), + immunization.get(Immunization.END_DATE), + lastVaccineType.get(LastVaccineType.VACCINE_TYPE), + immunization.get(Immunization.RECOVERY_DATE), + immunization.get(Immunization.DELETION_REASON), + immunization.get(Immunization.OTHER_DELETION_REASON), + JurisdictionHelper.booleanSelector(cb, isInJurisdictionOrOwned(directoryImmunizationQueryContext)), + immunization.get(Immunization.CHANGE_DATE)); Predicate filter = immunization.get(Immunization.ID).in(batchedIds); buildWhereCondition(criteria, cb, cq, directoryImmunizationQueryContext, filter); @@ -399,9 +398,8 @@ private Predicate createUserFilter(DirectoryImmunizationQueryContext qc) { Predicate filter = isInJurisdictionOrOwned(qc); - if (currentUser.getLimitedDisease() != null) { - filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(qc.getRoot().get(Contact.DISEASE), currentUser.getLimitedDisease())); - } + filter = CriteriaBuilderHelper + .and(cb, filter, CriteriaBuilderHelper.limitedDiseasePredicate(cb, currentUser, qc.getRoot().get(Immunization.DISEASE))); return filter; } 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 365ffcd4d30..1b113f82ccf 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 @@ -561,9 +561,8 @@ public Predicate createUserFilter(ImmunizationQueryContext qc) { Predicate filter = inJurisdictionOrOwned(qc); final CriteriaBuilder cb = qc.getCriteriaBuilder(); - if (currentUser.getLimitedDisease() != null) { - filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(qc.getRoot().get(Contact.DISEASE), currentUser.getLimitedDisease())); - } + filter = CriteriaBuilderHelper + .and(cb, filter, CriteriaBuilderHelper.limitedDiseasePredicate(cb, currentUser, qc.getRoot().get(Immunization.DISEASE))); return filter; } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/outbreak/OutbreakFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/outbreak/OutbreakFacadeEjb.java index c028cd7fe96..93010b391b3 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/outbreak/OutbreakFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/outbreak/OutbreakFacadeEjb.java @@ -30,7 +30,6 @@ import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.common.Page; 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.outbreak.OutbreakFacade; @@ -85,14 +84,6 @@ public List getActive(OutbreakCriteria criteria) { return result.stream().map(OutbreakFacadeEjb::toDto).collect(Collectors.toList()); } - @Override - public List getActiveByRegionAndDisease(RegionReferenceDto regionRef, Disease disease) { - - List result = - outbreakService.queryByCriteria(new OutbreakCriteria().region(regionRef).disease(disease).active(true), null, Outbreak.DISTRICT, true); - return result.stream().map(OutbreakFacadeEjb::toDto).collect(Collectors.toList()); - } - @Override public OutbreakDto getActiveByDistrictAndDisease(DistrictReferenceDto districtRef, Disease disease) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/outbreak/OutbreakService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/outbreak/OutbreakService.java index 54ccf0cb78d..ba46f41b664 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/outbreak/OutbreakService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/outbreak/OutbreakService.java @@ -35,6 +35,8 @@ import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; +import org.apache.commons.collections.CollectionUtils; + import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.outbreak.OutbreakCriteria; import de.symeda.sormas.api.utils.SortProperty; @@ -166,8 +168,8 @@ public Predicate buildCriteriaFilter(OutbreakCriteria criteria, CriteriaBuilder if (criteria.getChangeDateAfter() != null) { filter = CriteriaBuilderHelper.and(cb, filter, createChangeDateFilter(cb, from, criteria.getChangeDateAfter())); } - if (criteria.getDisease() != null) { - filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(from.get(Outbreak.DISEASE), criteria.getDisease())); + if (CollectionUtils.isNotEmpty(criteria.getDiseases())) { + filter = CriteriaBuilderHelper.and(cb, filter, from.get(Outbreak.DISEASE).in(criteria.getDiseases())); } if (criteria.getDistrict() != null) { filter = CriteriaBuilderHelper 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 1d02b0be908..fbed2be0e1f 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 @@ -638,7 +638,7 @@ public Predicate createUserFilter(SampleQueryContext sampleQueryContext, SampleC filter, eventParticipantService.createUserFilter(new EventParticipantQueryContext(cb, cq, joins.getEventParticipantJoins()))); } - } else if (currentUser.getLimitedDisease() != null) { + } else if (CollectionUtils.isNotEmpty(currentUser.getLimitedDiseases())) { filter = CriteriaBuilderHelper.and( cb, filter, @@ -685,19 +685,17 @@ public Predicate createUserFilterWithoutAssociations(CriteriaBuilder cb, SampleJ } // Only show samples of a specific disease if a limited disease is set - if (currentUser.getLimitedDisease() != null) { - filter = CriteriaBuilderHelper.and( + filter = CriteriaBuilderHelper.and( + cb, + filter, + CriteriaBuilderHelper.limitedDiseasePredicate( cb, - filter, - cb.or( - cb.and(cb.isNotNull(joins.getEvent()), cb.isNull(joins.getEvent().get(Event.DISEASE))), - cb.equal( - cb.selectCase() - .when(cb.isNotNull(joins.getCaze()), joins.getCaze().get(Case.DISEASE)) - .when(cb.isNotNull(joins.getContact()), joins.getContact().get(Contact.DISEASE)) - .otherwise(joins.getEvent().get(Event.DISEASE)), - currentUser.getLimitedDisease()))); - } + currentUser, + cb.selectCase() + .when(cb.isNotNull(joins.getCaze()), joins.getCaze().get(Case.DISEASE)) + .when(cb.isNotNull(joins.getContact()), joins.getContact().get(Contact.DISEASE)) + .otherwise(joins.getEvent().get(Event.DISEASE)), + cb.and(cb.isNotNull(joins.getEvent()), cb.isNull(joins.getEvent().get(Event.DISEASE))))); return filter; } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryJurisdictionPredicateValidator.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryJurisdictionPredicateValidator.java index bc8d93a9917..925cf35e6a8 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryJurisdictionPredicateValidator.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/TravelEntryJurisdictionPredicateValidator.java @@ -83,7 +83,7 @@ public Predicate isRootInJurisdictionOrOwned() { @Override protected Predicate getLimitedDiseasePredicate() { - return cb.equal(joins.getRoot().get(TravelEntry.DISEASE), user.getLimitedDisease()); + return CriteriaBuilderHelper.limitedDiseasePredicate(cb, user, joins.getRoot().get(TravelEntry.DISEASE)); } @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 292624801a6..746567ec458 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 @@ -11,7 +11,6 @@ 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.travelentry.TravelEntry; import de.symeda.sormas.backend.travelentry.TravelEntryJoins; import de.symeda.sormas.backend.travelentry.TravelEntryJurisdictionPredicateValidator; @@ -64,9 +63,8 @@ public Predicate createUserFilter(TravelEntryQueryContext qc, boolean checkJuris Predicate filter = null; if (checkJurisdictionAndLimitedDisease) { filter = inJurisdictionOrOwned(qc); - if (currentUser.getLimitedDisease() != null) { - filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(qc.getRoot().get(Contact.DISEASE), currentUser.getLimitedDisease())); - } + filter = CriteriaBuilderHelper + .and(cb, filter, CriteriaBuilderHelper.limitedDiseasePredicate(cb, currentUser, qc.getRoot().get(TravelEntry.DISEASE))); } return filter; } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/travelentryimport/TravelEntryImportFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/travelentryimport/TravelEntryImportFacadeEjb.java index f802e72ff61..4122a7efe60 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/travelentryimport/TravelEntryImportFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/travelentry/travelentryimport/TravelEntryImportFacadeEjb.java @@ -25,6 +25,7 @@ import java.util.Date; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.function.Function; import javax.ejb.EJB; @@ -32,6 +33,7 @@ import javax.ejb.Stateless; import javax.validation.Valid; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -168,16 +170,19 @@ public ImportLineResultDto importDataWithExistingPers private void fillTravelEntryWithDefaultValues(TravelEntryDto travelEntry) { User currentUser = userService.getCurrentUser(); - Disease userDisease = currentUser.getLimitedDisease(); + Set userDiseases = currentUser.getLimitedDiseases(); Region userRegion = currentUser.getRegion(); District userDistrict = currentUser.getDistrict(); Community userCommunity = currentUser.getCommunity(); PointOfEntry userPoe = currentUser.getPointOfEntry(); - if (userDisease != null) { - travelEntry.setDisease(userDisease); - } else if (diseaseConfigurationFacade.getAllDiseases(true, true, true).size() == 1) { - travelEntry.setDisease(diseaseConfigurationFacade.getAllDiseases(true, true, true).get(0)); + if (CollectionUtils.isNotEmpty(userDiseases) && userDiseases.size() == 1) { + travelEntry.setDisease(userDiseases.iterator().next()); + } else { + List allDiseases = diseaseConfigurationFacade.getAllDiseases(true, true, true); + if (allDiseases.size() == 1) { + travelEntry.setDisease(allDiseases.get(0)); + } } if (userRegion != null) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/user/DiseaseSetConverter.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/DiseaseSetConverter.java new file mode 100644 index 00000000000..1e5fb0dd819 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/user/DiseaseSetConverter.java @@ -0,0 +1,39 @@ +/* + * SORMAS® - Surveillance Outbreak Response Management & Analysis System + * Copyright © 2016-2023 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.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.persistence.AttributeConverter; + +import org.apache.commons.lang3.StringUtils; + +import de.symeda.sormas.api.Disease; + +public class DiseaseSetConverter implements AttributeConverter, String> { + + @Override + public String convertToDatabaseColumn(Set diseases) { + return diseases != null ? String.join(",", diseases.stream().map(Disease::name).collect(Collectors.toSet())) : null; + } + + @Override + public Set convertToEntityAttribute(String diseasesText) { + return diseasesText != null ? Stream.of(StringUtils.split(diseasesText, ",")).map(Disease::valueOf).collect(Collectors.toSet()) : 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 a26ed459307..bd3ab43b94e 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 @@ -26,6 +26,7 @@ import javax.persistence.Cacheable; import javax.persistence.CascadeType; import javax.persistence.Column; +import javax.persistence.Convert; import javax.persistence.Entity; import javax.persistence.EntityListeners; import javax.persistence.EnumType; @@ -97,7 +98,7 @@ public class User extends AbstractDomainObject { public static final String LANGUAGE = "language"; public static final String HAS_CONSENTED_TO_GDPR = "hasConsentedToGdpr"; public static final String JURISDICTION_LEVEL = "jurisdictionLevel"; - public static final String LIMITED_DISEASE = "limitedDisease"; + public static final String LIMITED_DISEASES = "limitedDiseases"; private String userName; @NotExposedToApi @@ -129,7 +130,7 @@ public class User extends AbstractDomainObject { private User associatedOfficer; - private Disease limitedDisease; + private Set limitedDiseases; private Language language; @@ -321,13 +322,13 @@ public void setPointOfEntry(PointOfEntry pointOfEntry) { this.pointOfEntry = pointOfEntry; } - @Enumerated(EnumType.STRING) - public Disease getLimitedDisease() { - return limitedDisease; + @Convert(converter = DiseaseSetConverter.class) + public Set getLimitedDiseases() { + return limitedDiseases; } - public void setLimitedDisease(Disease limitedDisease) { - this.limitedDisease = limitedDisease; + public void setLimitedDiseases(Set limitedDisease) { + this.limitedDiseases = limitedDisease; } @Enumerated(EnumType.STRING) 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 832ebba7c29..43864621244 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 @@ -209,7 +209,7 @@ public static UserDto toDto(User source) { target.setAssociatedOfficer(toReferenceDto(source.getAssociatedOfficer())); target.setLaboratory(FacilityFacadeEjb.toReferenceDto(source.getLaboratory())); target.setPointOfEntry(PointOfEntryFacadeEjb.toReferenceDto(source.getPointOfEntry())); - target.setLimitedDisease(source.getLimitedDisease()); + target.setLimitedDiseases(source.getLimitedDiseases()); target.setLanguage(source.getLanguage()); target.setHasConsentedToGdpr(source.isHasConsentedToGdpr()); @@ -462,9 +462,7 @@ public List getUsersHavingCaseInJurisdiction(CaseReferenceDto cb.and( cb.equal(caseRoot.get(Case.UUID), caseReferenceDto.getUuid()), cb.isTrue(caseJurisdictionPredicateValidator.inJurisdictionOrOwned()), - cb.or( - cb.isNull(userRoot.get(User.LIMITED_DISEASE)), - cb.equal(userRoot.get(User.LIMITED_DISEASE), caseRoot.get(Case.DISEASE))))); + cb.or(cb.isNull(userRoot.get(User.LIMITED_DISEASES)), caseRoot.get(Case.DISEASE).in(userRoot.get(User.LIMITED_DISEASES))))); return caseJurisdictionSubquery; }); } @@ -485,8 +483,8 @@ public List getUsersHavingContactInJurisdiction(ContactReferen cb.equal(contactRoot.get(AbstractDomainObject.UUID), contactReferenceDto.getUuid()), cb.isTrue(contactJurisdictionPredicateValidator.inJurisdictionOrOwned()), cb.or( - cb.isNull(userRoot.get(User.LIMITED_DISEASE)), - cb.equal(userRoot.get(User.LIMITED_DISEASE), contactRoot.get(Contact.DISEASE))))); + cb.isNull(userRoot.get(User.LIMITED_DISEASES)), + contactRoot.get(Contact.DISEASE).in(userRoot.get(User.LIMITED_DISEASES))))); return contactJurisdictionSubquery; }); } @@ -508,8 +506,8 @@ public List getUsersHavingEventInJurisdiction(EventReferenceDt cb.equal(eventRoot.get(AbstractDomainObject.UUID), eventReferenceDto.getUuid()), cb.isTrue(eventJurisdictionPredicateValidator.inJurisdictionOrOwned()), cb.or( - cb.isNull(userRoot.get(User.LIMITED_DISEASE)), - cb.equal(userRoot.get(User.LIMITED_DISEASE), eventRoot.get(de.symeda.sormas.backend.event.Event.DISEASE))))); + cb.isNull(userRoot.get(User.LIMITED_DISEASES)), + eventRoot.get(de.symeda.sormas.backend.event.Event.DISEASE).in(userRoot.get(User.LIMITED_DISEASES))))); return eventJurisdictionSubquery; }); } @@ -531,8 +529,8 @@ public List getUsersHavingTravelEntryInJurisdiction(TravelEntr cb.equal(travelEntryRoot.get(AbstractDomainObject.UUID), travelEntryReferenceDto.getUuid()), cb.isTrue(travelEntryJurisdictionPredicateValidator.inJurisdictionOrOwned()), cb.or( - cb.isNull(userRoot.get(User.LIMITED_DISEASE)), - cb.equal(userRoot.get(User.LIMITED_DISEASE), travelEntryRoot.get(TravelEntry.DISEASE))))); + cb.isNull(userRoot.get(User.LIMITED_DISEASES)), + travelEntryRoot.get(TravelEntry.DISEASE).in(userRoot.get(User.LIMITED_DISEASES))))); return travelEntrySubquery; }); } @@ -789,7 +787,7 @@ private User fillOrBuildEntity(UserDto source, User target, boolean checkChangeD target.setAssociatedOfficer(userService.getByReferenceDto(source.getAssociatedOfficer())); target.setLaboratory(facilityService.getByReferenceDto(source.getLaboratory())); target.setPointOfEntry(pointOfEntryService.getByReferenceDto(source.getPointOfEntry())); - target.setLimitedDisease(source.getLimitedDisease()); + target.setLimitedDiseases(source.getLimitedDiseases()); target.setLanguage(source.getLanguage()); target.setHasConsentedToGdpr(source.isHasConsentedToGdpr()); 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 8edd00bae58..7e158c77820 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 @@ -291,14 +291,15 @@ public List getUserReferences( // eliminate users that are limited to others diseases if (limitedDisease != null) { - Predicate restrictOtherLimitedDiseaseUsers = - cb.or(cb.isNull(userRoot.get(User.LIMITED_DISEASE)), cb.equal(userRoot.get(User.LIMITED_DISEASE), limitedDisease)); + Predicate restrictOtherLimitedDiseaseUsers = cb.or( + cb.isNull(userRoot.get(User.LIMITED_DISEASES)), + cb.like(userRoot.get(User.LIMITED_DISEASES).as(String.class), "%" + limitedDisease.name() + '%')); filter = CriteriaBuilderHelper.and(cb, filter, restrictOtherLimitedDiseaseUsers); } //exlude users with limited diseases if (excludeLimitedDiseaseUsers) { - filter = CriteriaBuilderHelper.and(cb, filter, cb.isNull(userRoot.get(User.LIMITED_DISEASE))); + filter = CriteriaBuilderHelper.and(cb, filter, cb.isNull(userRoot.get(User.LIMITED_DISEASES))); } if (CollectionUtils.isNotEmpty(communityUuids)) { @@ -387,8 +388,9 @@ public List getUserRefsByInfrastructure( filter = CriteriaBuilderHelper.and(cb, filter, jurisdictionFilter); if (limitedDisease != null) { - Predicate restrictOtherLimitedDiseaseUsers = - cb.or(cb.isNull(userRoot.get(User.LIMITED_DISEASE)), cb.equal(userRoot.get(User.LIMITED_DISEASE), limitedDisease)); + Predicate restrictOtherLimitedDiseaseUsers = cb.or( + cb.isNull(userRoot.get(User.LIMITED_DISEASES)), + cb.like(userRoot.get(User.LIMITED_DISEASES).as(String.class), "%" + limitedDisease.name() + "%")); filter = CriteriaBuilderHelper.and(cb, filter, restrictOtherLimitedDiseaseUsers); } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/util/PredicateJurisdictionValidator.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/util/PredicateJurisdictionValidator.java index eefbeed0c90..bb299d3b7af 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/util/PredicateJurisdictionValidator.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/util/PredicateJurisdictionValidator.java @@ -65,7 +65,7 @@ protected Predicate isInJurisdictionByJurisdictionLevelPath(Path jLP) { } public Predicate hasUserLimitedDisease() { - if (user != null && user.getLimitedDisease() != null) { + if (user != null) { return getLimitedDiseasePredicate(); } else { return null; diff --git a/sormas-backend/src/main/resources/sql/sormas_schema.sql b/sormas-backend/src/main/resources/sql/sormas_schema.sql index 1d555e2b4a9..d14d05516ae 100644 --- a/sormas-backend/src/main/resources/sql/sormas_schema.sql +++ b/sormas-backend/src/main/resources/sql/sormas_schema.sql @@ -12748,4 +12748,17 @@ ALTER TABLE diseaseconfiguration_history ADD COLUMN automaticsampleassignmentthr INSERT INTO schema_version (version_number, comment) VALUES (530, 'Add an automatic processing logic to external messages #12573'); +-- 2023-10-27 Assign multiple limited diseases to users #11435 +ALTER TABLE users + RENAME COLUMN limiteddisease TO limiteddiseases; +ALTER TABLE users + ALTER COLUMN limiteddiseases TYPE text; +ALTER TABLE users_history + RENAME COLUMN limiteddisease TO limiteddiseases; +ALTER TABLE users_history + ALTER COLUMN limiteddiseases TYPE text; + +INSERT INTO schema_version (version_number, comment) +VALUES (531, 'Assign multiple limited diseases to users #11435'); + -- *** Insert new sql commands BEFORE this line. Remember to always consider _history tables. *** \ No newline at end of file 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 11f52c58d33..781a5580810 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 @@ -343,7 +343,9 @@ private UserDto createUser( user.setLastName(lastName); user.setUserName(firstName + lastName); user.setUserRoles(new HashSet<>(Arrays.asList(roles))); - user.setLimitedDisease(limitedDisease); + if (limitedDisease != null) { + user.setLimitedDiseases(Collections.singleton(limitedDisease)); + } user.setRegion(beanTest.getRegionFacade().getReferenceByUuid(regionUuid)); user.setDistrict(beanTest.getDistrictFacade().getReferenceByUuid(districtUuid)); user.setCommunity(beanTest.getCommunityFacade().getReferenceByUuid(communityUuid)); 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 24b8cccb0b2..7012890b0b7 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 @@ -23,6 +23,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.util.Arrays; +import java.util.Collections; import java.util.Date; import java.util.List; import java.util.stream.Collectors; @@ -98,7 +99,7 @@ public void init() { "Surv", "OffCovid", creator.getUserRoleReference(DefaultUserRole.SURVEILLANCE_OFFICER)); - covidLimitedDistrictUser.setLimitedDisease(Disease.CORONAVIRUS); + covidLimitedDistrictUser.setLimitedDiseases(Collections.singleton(Disease.CORONAVIRUS)); getUserFacade().saveUser(covidLimitedDistrictUser, false); } 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 7900c2c8981..d9f341dd7c8 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 @@ -263,7 +263,7 @@ public void testGetIndexListByPresentCondition() { @Test public void testGetIndexListByName() { final UserDto user = creator.createSurveillanceSupervisor(rdcf); - user.setLimitedDisease(Disease.EVD); + user.setLimitedDiseases(Collections.singleton(Disease.EVD)); getUserFacade().saveUser(user, false); loginWith(user); 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 39f88373334..5156245c0a5 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 @@ -16,6 +16,7 @@ import static org.mockito.Mockito.mockStatic; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -244,9 +245,9 @@ public void testGetUserRefsByInfrastructure() { getUserService().getUserRefsByInfrastructure(rdcf1.region.getUuid(), JurisdictionLevel.REGION, JurisdictionLevel.NATION, null), hasSize(2)); - commOff1.setLimitedDisease(Disease.EVD); + commOff1.setLimitedDiseases(Collections.singleton(Disease.EVD)); getUserFacade().saveUser(commOff1, false); - survOff11.setLimitedDisease(Disease.CHOLERA); + survOff11.setLimitedDiseases(Collections.singleton(Disease.CHOLERA)); getUserFacade().saveUser(survOff11, false); assertThat( getUserService() diff --git a/sormas-backend/src/test/resources/META-INF/persistence.xml b/sormas-backend/src/test/resources/META-INF/persistence.xml index 30d49563aff..cb7e450b270 100644 --- a/sormas-backend/src/test/resources/META-INF/persistence.xml +++ b/sormas-backend/src/test/resources/META-INF/persistence.xml @@ -106,7 +106,7 @@ - + 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 d0d579980b5..d0268d6a193 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 @@ -182,7 +182,7 @@ public void reload() { // Alter cells with regions and diseases that actually have an outbreak OutbreakCriteria criteria = new OutbreakCriteria().active(true); - criteria.disease(UserProvider.getCurrent().getUser().getLimitedDisease()); + criteria.diseases(UserProvider.getCurrent().getUser().getLimitedDiseases()); List activeOutbreaks = FacadeProvider.getOutbreakFacade().getActive(criteria); for (OutbreakDto outbreak : activeOutbreaks) { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/user/UserEditForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/user/UserEditForm.java index e2477298e1c..3691dfac038 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/user/UserEditForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/user/UserEditForm.java @@ -30,6 +30,8 @@ import java.util.Set; import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; + import com.vaadin.ui.Label; import com.vaadin.v7.data.Validator; import com.vaadin.v7.data.util.converter.Converter; @@ -38,8 +40,10 @@ import com.vaadin.v7.ui.OptionGroup; import com.vaadin.v7.ui.TextField; +import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.FacadeProvider; 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.i18n.Validations; @@ -61,6 +65,7 @@ import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.FieldHelper; import de.symeda.sormas.ui.utils.UserPhoneNumberValidator; +import de.symeda.sormas.ui.utils.components.CheckboxSet; public class UserEditForm extends AbstractEditForm { @@ -71,6 +76,9 @@ public class UserEditForm extends AbstractEditForm { private static final String USER_DATA_HEADING_LOC = "userDataHeadingLoc"; private static final String USER_EMAIL_DESC_LOC = "userEmailDescLoc"; private static final String USER_PHONE_DESC_LOC = "userPhoneDescLoc"; + private static final String LIMITED_DISEASES_HEADING_LOC = "limitedDiseasesHeadingLoc"; + private static final String RESTRICT_DISEASES_CHECKBOX_LOC = "restrictDiseasesCheckboxLoc"; + private static final String RESTRICT_DISEASES_DESCRIPTION_LOC = "restrictDiseasesDescriptionLoc"; //@formatter:off private static final String HTML_LAYOUT = @@ -89,10 +97,15 @@ public class UserEditForm extends AbstractEditForm { fluidRowLocs(UserDto.USER_NAME, UserDto.USER_ROLES) + fluidRowLocs(UserDto.REGION, UserDto.DISTRICT, UserDto.COMMUNITY) + fluidRowLocs(UserDto.HEALTH_FACILITY, UserDto.POINT_OF_ENTRY, UserDto.ASSOCIATED_OFFICER, UserDto.LABORATORY) + - fluidRowLocs(UserDto.LIMITED_DISEASE, "", ""); + fluidRowLocs(LIMITED_DISEASES_HEADING_LOC) + + fluidRowLocs(RESTRICT_DISEASES_CHECKBOX_LOC) + + fluidRowLocs(RESTRICT_DISEASES_DESCRIPTION_LOC) + + fluidRowLocs(UserDto.LIMITED_DISEASES); //@formatter:off - Map userRoleMap; + private Map userRoleMap; + + private CheckBox restrictDiseasesCheckbox; public UserEditForm(boolean create) { @@ -126,8 +139,36 @@ protected void addFields() { addField(UserDto.USER_EMAIL, TextField.class); TextField phone = addField(UserDto.PHONE, TextField.class); phone.addValidator(new UserPhoneNumberValidator(I18nProperties.getValidationError(Validations.phoneNumberValidation))); + if (FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.AGGREGATE_REPORTING) || FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.EVENT_SURVEILLANCE) || FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.WEEKLY_REPORTING) || FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.CASE_SURVEILANCE)) { - addDiseaseField(UserDto.LIMITED_DISEASE, false); + Label limitedDiseasesHeadingLabel = new Label(I18nProperties.getString(Strings.headingLimitedDiseases)); + limitedDiseasesHeadingLabel.addStyleName(H3); + getContent().addComponent(limitedDiseasesHeadingLabel, LIMITED_DISEASES_HEADING_LOC); + + Label restrictDiseasesDescriptionLabel = new Label(I18nProperties.getString(Strings.infoRestrictDiseasesDescription)); + restrictDiseasesDescriptionLabel.addStyleNames(CssStyles.LABEL_ITALIC, CssStyles.VSPACE_TOP_3); + restrictDiseasesDescriptionLabel.setVisible(false); + getContent().addComponent(restrictDiseasesDescriptionLabel, RESTRICT_DISEASES_DESCRIPTION_LOC); + + CheckboxSet diseasesCheckboxSet = addField(UserDto.LIMITED_DISEASES, CheckboxSet.class); + diseasesCheckboxSet.setColumnCount(3); + diseasesCheckboxSet.setCaption(null); + diseasesCheckboxSet.setVisible(false); + List diseases = FacadeProvider.getDiseaseConfigurationFacade().getAllDiseases(true, true, true); + diseasesCheckboxSet.setItems(diseases, null, null); + + restrictDiseasesCheckbox = addCustomField(RESTRICT_DISEASES_CHECKBOX_LOC, I18nProperties.getCaption(Captions.userRestrictDiseases), Boolean.class, CheckBox.class); + restrictDiseasesCheckbox.addValueChangeListener(e -> { + boolean restrictDiseases = (boolean) e.getProperty().getValue(); + if (restrictDiseases) { + restrictDiseasesDescriptionLabel.setVisible(true); + diseasesCheckboxSet.setVisible(true); + } else { + restrictDiseasesDescriptionLabel.setVisible(false); + diseasesCheckboxSet.setVisible(false); + diseasesCheckboxSet.clear(); + } + }); } Label userEmailDesc = new Label(I18nProperties.getString(Strings.infoUserEmail)); @@ -206,6 +247,8 @@ public void setValue(UserDto newFieldValue) throws ReadOnlyException, Converter. final OptionGroup userRolesField = (OptionGroup)getFieldGroup().getField(UserDto.USER_ROLES); FieldHelper.updateItems(userRolesField, getFilteredUserRoles(newFieldValue.getUserRoles())); + restrictDiseasesCheckbox.setValue(CollectionUtils.isNotEmpty(newFieldValue.getLimitedDiseases())); + super.setValue(newFieldValue); } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/CheckboxSet.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/CheckboxSet.java index 689b57b5101..24bb6bde740 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/CheckboxSet.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/components/CheckboxSet.java @@ -58,6 +58,8 @@ public class CheckboxSet extends CustomField> { private Function groupingFunction; private Function itemDescriptionProvider; + private int columnCount = 2; + @Override protected Component initContent() { layout = new VerticalLayout(); @@ -65,21 +67,32 @@ protected Component initContent() { layout.setMargin(new MarginInfo(true, false)); if (items != null) { - rows = buildCheckboxRows(items); + resetLayout(); } return layout; } public void setItems(List items, Function groupingFunction, Function itemDescriptionProvider) { - this.items = items; + this.items = items; this.groupingFunction = groupingFunction; this.itemDescriptionProvider = itemDescriptionProvider; - if (layout != null) { - layout.removeAllComponents(); - rows = buildCheckboxRows(items); + resetLayout(); + } + + public void setColumnCount(int columnCount) { + this.columnCount = columnCount; + resetLayout(); + } + + private void resetLayout() { + if (layout == null) { + return; } + + layout.removeAllComponents(); + rows = buildCheckboxRows(items); } private List buildCheckboxRows(List items) { @@ -106,11 +119,10 @@ private List buildCheckboxRows(List items) { private List createRows(List groupItems) { List rows = new ArrayList<>(); - for (int i = 0, size = groupItems.size(); i < size; i += 2) { - T item1 = groupItems.get(i); - T item2 = i < size - 1 ? groupItems.get(i + 1) : null; + for (int i = 0, size = groupItems.size(); i < size; i += columnCount) { + List rowItems = groupItems.subList(i, Math.min(i + columnCount, groupItems.size())); - CheckboxRow checkboxRow = new CheckboxRow(item1, item2); + CheckboxRow checkboxRow = new CheckboxRow(rowItems, columnCount); checkboxRow.checkBoxes.forEach(cb -> cb.addValueChangeListener(e -> { fireEvent(new CheckboxValueChangeEvent(cb)); @@ -166,13 +178,15 @@ private CheckBox createCheckbox(T item) { } private CheckboxSetItemDataSource createDataSource(T item) { - return new CheckboxSetItemDataSource<>(item, v -> getInternalValue().contains(v), (c, v) -> { - Set internalValue = getInternalValue(); + return new CheckboxSetItemDataSource<>(item, v -> getSafeInternalValue().contains(v), (c, v) -> { + Set internalValue = getSafeInternalValue(); if (c) { internalValue.add(v); } else { internalValue.remove(v); } + + setInternalValue(internalValue); }); } @@ -192,6 +206,11 @@ protected void setInternalValue(Set newValue) { } } + protected Set getSafeInternalValue() { + Set internalValue = getInternalValue(); + return internalValue != null ? new HashSet<>(internalValue) : new HashSet<>(); + } + public Registration addCheckboxValueChangeListener(CheckboxValueChangeListener listener) { return addListener(CheckboxValueChangeEvent.class, listener, CheckboxValueChangeListener.CHECKBOX_CHANGE_METHOD); } @@ -228,19 +247,21 @@ private final class CheckboxRow extends HorizontalLayout { private final List checkBoxes; - public CheckboxRow(T leftItem, T rightItem) { - checkBoxes = new ArrayList<>(2); + public CheckboxRow(List items, int columnCount) { + int itemCount = items.size(); + checkBoxes = new ArrayList<>(itemCount); setWidthFull(); setMargin(false); - CheckBox cb1 = createCheckbox(leftItem); - checkBoxes.add(cb1); - addComponent(cb1); + items.forEach(i -> { + CheckBox cb = createCheckbox(i); + addComponent(cb); + checkBoxes.add(cb); + }); - if (rightItem != null) { - CheckBox cb2 = createCheckbox(rightItem); - addComponent(cb2); - checkBoxes.add(cb2); + if (columnCount > itemCount) { + // add empty columns to fill the row + addComponent(new HorizontalLayout()); } } diff --git a/sormas-ui/src/test/java/de/symeda/sormas/backend/TestDataCreator.java b/sormas-ui/src/test/java/de/symeda/sormas/backend/TestDataCreator.java index 4ea4d286f1d..804ab6c1d9e 100644 --- a/sormas-ui/src/test/java/de/symeda/sormas/backend/TestDataCreator.java +++ b/sormas-ui/src/test/java/de/symeda/sormas/backend/TestDataCreator.java @@ -17,6 +17,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -318,7 +319,9 @@ private UserDto createUser( user.setLastName(lastName); user.setUserName(firstName + lastName); user.setUserRoles(new HashSet<>(Arrays.asList(roles))); - user.setLimitedDisease(limitedDisease); + if (limitedDisease != null) { + user.setLimitedDiseases(Collections.singleton(limitedDisease)); + } user.setRegion(beanTest.getRegionFacade().getReferenceByUuid(regionUuid)); user.setDistrict(beanTest.getDistrictFacade().getReferenceByUuid(districtUuid)); user.setCommunity(beanTest.getCommunityFacade().getReferenceByUuid(communityUuid)); From d086bd9d41dbf54b527a351ed9101f763000a6db Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Tue, 7 Nov 2023 07:51:57 +0100 Subject: [PATCH 10/65] HSP-6365 Stabilize "Add contact person details to facilities case person)" - added new methods that handling changed selector --- .../pages/application/cases/CreateNewCasePage.java | 2 ++ .../pages/application/configuration/FacilitiesTabPage.java | 2 ++ .../steps/web/application/cases/CreateNewCaseSteps.java | 7 ++++++- .../steps/web/application/configuration/FacilitySteps.java | 7 ++++++- 4 files changed, 16 insertions(+), 2 deletions(-) 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 ce514886508..dc1f8dfedcc 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 @@ -34,6 +34,8 @@ public class CreateNewCasePage { By.cssSelector(".v-window #responsibleCommunity div"); public static final By FACILITY_CATEGORY_COMBOBOX = By.cssSelector("#typeGroup div"); public static final By FACILITY_TYPE_COMBOBOX = By.cssSelector("#type div"); + public static final By NEW_CASE_FACILITY_TYPE_COMBOBOX = + By.cssSelector(".v-window #facilityType div"); public static final By FACILITY_COMBOBOX = By.cssSelector("#healthFacility div"); public static final By FACILITY_NAME_COMBOBOX = By.cssSelector("#facility div"); public static final By PLACE_OF_STAY_HOME = diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/configuration/FacilitiesTabPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/configuration/FacilitiesTabPage.java index 727916938a8..ddc9c8ac46b 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/configuration/FacilitiesTabPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/configuration/FacilitiesTabPage.java @@ -60,6 +60,8 @@ public class FacilitiesTabPage { By.cssSelector(".v-window [location='district'] [role='combobox'] div"); public static final By FACILITY_CATEGORY_COMBOBOX = By.cssSelector(".v-window #typeGroup div"); public static final By FACILITY_TYPE_COMBOBOX = By.cssSelector(".v-window #type div"); + public static final By NEW_CASE_FACILITY_TYPE_COMBOBOX = + By.cssSelector(".v-window #facilityType div"); public static final By FACILITY_EXPOSURE_TYPE_COMBOBOX = By.cssSelector(".v-window #facilityType div"); public static final By FACILITY_CONTACT_PERSON_FIRST_NAME_INPUT = 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 9d0cbd77b54..548aff1c26e 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 @@ -70,6 +70,7 @@ import static org.sormas.e2etests.pages.application.cases.CreateNewCasePage.LINE_LISTING_DISEASE_COMBOBOX; import static org.sormas.e2etests.pages.application.cases.CreateNewCasePage.NAME_UUID_EXTERNAL_ID_TOKEN_LIKE; import static org.sormas.e2etests.pages.application.cases.CreateNewCasePage.NATIONAL_HEALTH_ID_ATTRIBUTE; +import static org.sormas.e2etests.pages.application.cases.CreateNewCasePage.NEW_CASE_FACILITY_TYPE_COMBOBOX; import static org.sormas.e2etests.pages.application.cases.CreateNewCasePage.NEW_DOCUMENT_BUTTON; import static org.sormas.e2etests.pages.application.cases.CreateNewCasePage.NICKNAME_ATTRIBUTE; import static org.sormas.e2etests.pages.application.cases.CreateNewCasePage.PASSPORT_NUMBER_ATTRIBUTE; @@ -1594,7 +1595,7 @@ public CreateNewCaseSteps( selectResponsibleDistrict(survnetCase.getResponsibleDistrict()); selectPlaceOfStay(survnetCase.getPlaceOfStay()); selectFacilityCategory(survnetCase.getFacilityCategory()); - selectFacilityType(survnetCase.getFacilityType()); + selectNewCaseFacilityType(survnetCase.getFacilityType()); selectFacility(survnetCase.getFacility()); fillFirstName(survnetCase.getFirstName()); fillLastName(survnetCase.getLastName()); @@ -1750,6 +1751,10 @@ private void selectFacilityType(String selectFacilityType) { webDriverHelpers.selectFromCombobox(FACILITY_TYPE_COMBOBOX, selectFacilityType); } + private void selectNewCaseFacilityType(String facilityType) { + webDriverHelpers.selectFromCombobox(NEW_CASE_FACILITY_TYPE_COMBOBOX, facilityType); + } + private void selectFacility(String selectFacility) { webDriverHelpers.selectFromCombobox(FACILITY_COMBOBOX, selectFacility); } diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/configuration/FacilitySteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/configuration/FacilitySteps.java index c23cd92310e..9be12c199c0 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/configuration/FacilitySteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/configuration/FacilitySteps.java @@ -48,6 +48,7 @@ import static org.sormas.e2etests.pages.application.configuration.FacilitiesTabPage.FACILITY_NAME_INPUT; import static org.sormas.e2etests.pages.application.configuration.FacilitiesTabPage.FACILITY_TYPE_COMBOBOX; import static org.sormas.e2etests.pages.application.configuration.FacilitiesTabPage.FACILITY_TYPE_COMBOBOX_FACILITIES_CONFIGURATION; +import static org.sormas.e2etests.pages.application.configuration.FacilitiesTabPage.NEW_CASE_FACILITY_TYPE_COMBOBOX; import static org.sormas.e2etests.pages.application.configuration.FacilitiesTabPage.REGION_COMBOBOX; import static org.sormas.e2etests.pages.application.configuration.FacilitiesTabPage.REGION_COMBOBOX_FACILITIES_CONFIGURATION; import static org.sormas.e2etests.pages.application.configuration.FacilitiesTabPage.RELEVANCE_STATUS_COMBOBOX_FACILITIES_CONFIGURATION; @@ -170,7 +171,7 @@ public FacilitySteps( selectResponsibleDistrict(caze.getResponsibleDistrict()); selectPlaceOfStay(caze.getPlaceOfStay()); selectFacilityCategory(caze.getFacilityCategory()); - selectFacilityType(caze.getFacilityType()); + selectNewCaseFacilityType(caze.getFacilityType()); selectFacility(caze.getFacility()); fillFirstName(caze.getFirstName()); fillLastName(caze.getLastName()); @@ -394,6 +395,10 @@ private void selectFacilityType(String facilityType) { webDriverHelpers.selectFromCombobox(FACILITY_TYPE_COMBOBOX, facilityType); } + private void selectNewCaseFacilityType(String facilityType) { + webDriverHelpers.selectFromCombobox(NEW_CASE_FACILITY_TYPE_COMBOBOX, facilityType); + } + private void selectFacilityTypeEvent(String facilityType) { webDriverHelpers.selectFromCombobox(FACILITY_EXPOSURE_TYPE_COMBOBOX, facilityType); } From c6d450cfc2857b80ea2435c1c6c8cd437474c5b5 Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Fri, 10 Nov 2023 10:50:49 +0100 Subject: [PATCH 11/65] HSP-6365 Stabilize "Add contact person details to facilities case person - updated handling facility type selector in test scenario --- .../steps/web/application/cases/CreateNewCaseSteps.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/CreateNewCaseSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/cases/CreateNewCaseSteps.java index 548aff1c26e..8b8b9957109 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 @@ -685,7 +685,7 @@ public CreateNewCaseSteps( (String placeOfStay, String facilityCategory, String facilityType) -> { selectPlaceOfStay(placeOfStay); selectFacilityCategory(facilityCategory); - selectFacilityType(facilityType); + selectNewCaseFacilityType(facilityType); selectFacility("Other facility"); fillPlaceDescription(caze.getPlaceDescription()); }); From fee8826f030e7ae151b00a4549574ebc76162493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9=20Strysewske?= Date: Fri, 10 Nov 2023 12:05:46 +0100 Subject: [PATCH 12/65] #11435 - Fix broken SQL script formatting --- .../src/main/resources/sql/sormas_schema.sql | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/sormas-backend/src/main/resources/sql/sormas_schema.sql b/sormas-backend/src/main/resources/sql/sormas_schema.sql index d14d05516ae..37206aee0e5 100644 --- a/sormas-backend/src/main/resources/sql/sormas_schema.sql +++ b/sormas-backend/src/main/resources/sql/sormas_schema.sql @@ -12747,18 +12747,12 @@ ALTER TABLE diseaseconfiguration_history ADD COLUMN automaticsampleassignmentthr INSERT INTO schema_version (version_number, comment) VALUES (530, 'Add an automatic processing logic to external messages #12573'); - -- 2023-10-27 Assign multiple limited diseases to users #11435 -ALTER TABLE users - RENAME COLUMN limiteddisease TO limiteddiseases; -ALTER TABLE users - ALTER COLUMN limiteddiseases TYPE text; -ALTER TABLE users_history - RENAME COLUMN limiteddisease TO limiteddiseases; -ALTER TABLE users_history - ALTER COLUMN limiteddiseases TYPE text; - -INSERT INTO schema_version (version_number, comment) -VALUES (531, 'Assign multiple limited diseases to users #11435'); +ALTER TABLE users RENAME COLUMN limiteddisease TO limiteddiseases; +ALTER TABLE users ALTER COLUMN limiteddiseases TYPE text; +ALTER TABLE users_history RENAME COLUMN limiteddisease TO limiteddiseases; +ALTER TABLE users_history ALTER COLUMN limiteddiseases TYPE text; + +INSERT INTO schema_version (version_number, comment) VALUES (531, 'Assign multiple limited diseases to users #11435'); -- *** Insert new sql commands BEFORE this line. Remember to always consider _history tables. *** \ No newline at end of file From d80383c522ade0b1bdcb444427ee43bb4102da8e Mon Sep 17 00:00:00 2001 From: sormas-vitagroup Date: Fri, 10 Nov 2023 11:09:28 +0000 Subject: [PATCH 13/65] [GitHub Actions] Update openAPI spec files --- sormas-rest/swagger.json | 20 ++- sormas-rest/swagger.yaml | 262 ++++++++++++++++++++------------------- 2 files changed, 148 insertions(+), 134 deletions(-) diff --git a/sormas-rest/swagger.json b/sormas-rest/swagger.json index 01df2b3e9b6..09e3f0998f9 100644 --- a/sormas-rest/swagger.json +++ b/sormas-rest/swagger.json @@ -19529,9 +19529,13 @@ "type" : "string", "format" : "date-time" }, - "disease" : { - "type" : "string", - "enum" : [ "AFP", "CHOLERA", "CONGENITAL_RUBELLA", "CSM", "DENGUE", "EVD", "GUINEA_WORM", "LASSA", "MEASLES", "MONKEYPOX", "NEW_INFLUENZA", "PLAGUE", "POLIO", "UNSPECIFIED_VHF", "WEST_NILE_FEVER", "YELLOW_FEVER", "RABIES", "ANTHRAX", "CORONAVIRUS", "PNEUMONIA", "MALARIA", "TYPHOID_FEVER", "ACUTE_VIRAL_HEPATITIS", "NON_NEONATAL_TETANUS", "HIV", "SCHISTOSOMIASIS", "SOIL_TRANSMITTED_HELMINTHS", "TRYPANOSOMIASIS", "DIARRHEA_DEHYDRATION", "DIARRHEA_BLOOD", "SNAKE_BITE", "RUBELLA", "TUBERCULOSIS", "LEPROSY", "LYMPHATIC_FILARIASIS", "BURULI_ULCER", "PERTUSSIS", "NEONATAL_TETANUS", "ONCHOCERCIASIS", "DIPHTERIA", "TRACHOMA", "YAWS_ENDEMIC_SYPHILIS", "MATERNAL_DEATHS", "PERINATAL_DEATHS", "INFLUENZA_A", "INFLUENZA_B", "H_METAPNEUMOVIRUS", "RESPIRATORY_SYNCYTIAL_VIRUS", "PARAINFLUENZA_1_4", "ADENOVIRUS", "RHINOVIRUS", "ENTEROVIRUS", "M_PNEUMONIAE", "C_PNEUMONIAE", "ARI", "CHIKUNGUNYA", "POST_IMMUNIZATION_ADVERSE_EVENTS_MILD", "POST_IMMUNIZATION_ADVERSE_EVENTS_SEVERE", "FHA", "OTHER", "UNDEFINED" ] + "diseases" : { + "type" : "array", + "items" : { + "type" : "string", + "enum" : [ "AFP", "CHOLERA", "CONGENITAL_RUBELLA", "CSM", "DENGUE", "EVD", "GUINEA_WORM", "LASSA", "MEASLES", "MONKEYPOX", "NEW_INFLUENZA", "PLAGUE", "POLIO", "UNSPECIFIED_VHF", "WEST_NILE_FEVER", "YELLOW_FEVER", "RABIES", "ANTHRAX", "CORONAVIRUS", "PNEUMONIA", "MALARIA", "TYPHOID_FEVER", "ACUTE_VIRAL_HEPATITIS", "NON_NEONATAL_TETANUS", "HIV", "SCHISTOSOMIASIS", "SOIL_TRANSMITTED_HELMINTHS", "TRYPANOSOMIASIS", "DIARRHEA_DEHYDRATION", "DIARRHEA_BLOOD", "SNAKE_BITE", "RUBELLA", "TUBERCULOSIS", "LEPROSY", "LYMPHATIC_FILARIASIS", "BURULI_ULCER", "PERTUSSIS", "NEONATAL_TETANUS", "ONCHOCERCIASIS", "DIPHTERIA", "TRACHOMA", "YAWS_ENDEMIC_SYPHILIS", "MATERNAL_DEATHS", "PERINATAL_DEATHS", "INFLUENZA_A", "INFLUENZA_B", "H_METAPNEUMOVIRUS", "RESPIRATORY_SYNCYTIAL_VIRUS", "PARAINFLUENZA_1_4", "ADENOVIRUS", "RHINOVIRUS", "ENTEROVIRUS", "M_PNEUMONIAE", "C_PNEUMONIAE", "ARI", "CHIKUNGUNYA", "POST_IMMUNIZATION_ADVERSE_EVENTS_MILD", "POST_IMMUNIZATION_ADVERSE_EVENTS_SEVERE", "FHA", "OTHER", "UNDEFINED" ] + }, + "uniqueItems" : true }, "district" : { "$ref" : "#/components/schemas/DistrictReferenceDto" @@ -25012,9 +25016,13 @@ "maxLength" : 512, "minLength" : 0 }, - "limitedDisease" : { - "type" : "string", - "enum" : [ "AFP", "CHOLERA", "CONGENITAL_RUBELLA", "CSM", "DENGUE", "EVD", "GUINEA_WORM", "LASSA", "MEASLES", "MONKEYPOX", "NEW_INFLUENZA", "PLAGUE", "POLIO", "UNSPECIFIED_VHF", "WEST_NILE_FEVER", "YELLOW_FEVER", "RABIES", "ANTHRAX", "CORONAVIRUS", "PNEUMONIA", "MALARIA", "TYPHOID_FEVER", "ACUTE_VIRAL_HEPATITIS", "NON_NEONATAL_TETANUS", "HIV", "SCHISTOSOMIASIS", "SOIL_TRANSMITTED_HELMINTHS", "TRYPANOSOMIASIS", "DIARRHEA_DEHYDRATION", "DIARRHEA_BLOOD", "SNAKE_BITE", "RUBELLA", "TUBERCULOSIS", "LEPROSY", "LYMPHATIC_FILARIASIS", "BURULI_ULCER", "PERTUSSIS", "NEONATAL_TETANUS", "ONCHOCERCIASIS", "DIPHTERIA", "TRACHOMA", "YAWS_ENDEMIC_SYPHILIS", "MATERNAL_DEATHS", "PERINATAL_DEATHS", "INFLUENZA_A", "INFLUENZA_B", "H_METAPNEUMOVIRUS", "RESPIRATORY_SYNCYTIAL_VIRUS", "PARAINFLUENZA_1_4", "ADENOVIRUS", "RHINOVIRUS", "ENTEROVIRUS", "M_PNEUMONIAE", "C_PNEUMONIAE", "ARI", "CHIKUNGUNYA", "POST_IMMUNIZATION_ADVERSE_EVENTS_MILD", "POST_IMMUNIZATION_ADVERSE_EVENTS_SEVERE", "FHA", "OTHER", "UNDEFINED" ] + "limitedDiseases" : { + "type" : "array", + "items" : { + "type" : "string", + "enum" : [ "AFP", "CHOLERA", "CONGENITAL_RUBELLA", "CSM", "DENGUE", "EVD", "GUINEA_WORM", "LASSA", "MEASLES", "MONKEYPOX", "NEW_INFLUENZA", "PLAGUE", "POLIO", "UNSPECIFIED_VHF", "WEST_NILE_FEVER", "YELLOW_FEVER", "RABIES", "ANTHRAX", "CORONAVIRUS", "PNEUMONIA", "MALARIA", "TYPHOID_FEVER", "ACUTE_VIRAL_HEPATITIS", "NON_NEONATAL_TETANUS", "HIV", "SCHISTOSOMIASIS", "SOIL_TRANSMITTED_HELMINTHS", "TRYPANOSOMIASIS", "DIARRHEA_DEHYDRATION", "DIARRHEA_BLOOD", "SNAKE_BITE", "RUBELLA", "TUBERCULOSIS", "LEPROSY", "LYMPHATIC_FILARIASIS", "BURULI_ULCER", "PERTUSSIS", "NEONATAL_TETANUS", "ONCHOCERCIASIS", "DIPHTERIA", "TRACHOMA", "YAWS_ENDEMIC_SYPHILIS", "MATERNAL_DEATHS", "PERINATAL_DEATHS", "INFLUENZA_A", "INFLUENZA_B", "H_METAPNEUMOVIRUS", "RESPIRATORY_SYNCYTIAL_VIRUS", "PARAINFLUENZA_1_4", "ADENOVIRUS", "RHINOVIRUS", "ENTEROVIRUS", "M_PNEUMONIAE", "C_PNEUMONIAE", "ARI", "CHIKUNGUNYA", "POST_IMMUNIZATION_ADVERSE_EVENTS_MILD", "POST_IMMUNIZATION_ADVERSE_EVENTS_SEVERE", "FHA", "OTHER", "UNDEFINED" ] + }, + "uniqueItems" : true }, "name" : { "type" : "string" diff --git a/sormas-rest/swagger.yaml b/sormas-rest/swagger.yaml index b73de56b797..5c8ff814746 100644 --- a/sormas-rest/swagger.yaml +++ b/sormas-rest/swagger.yaml @@ -18912,70 +18912,73 @@ components: changeDateAfter: type: string format: date-time - disease: - type: string - enum: - - AFP - - CHOLERA - - CONGENITAL_RUBELLA - - CSM - - DENGUE - - EVD - - GUINEA_WORM - - LASSA - - MEASLES - - MONKEYPOX - - NEW_INFLUENZA - - PLAGUE - - POLIO - - UNSPECIFIED_VHF - - WEST_NILE_FEVER - - YELLOW_FEVER - - RABIES - - ANTHRAX - - CORONAVIRUS - - PNEUMONIA - - MALARIA - - TYPHOID_FEVER - - ACUTE_VIRAL_HEPATITIS - - NON_NEONATAL_TETANUS - - HIV - - SCHISTOSOMIASIS - - SOIL_TRANSMITTED_HELMINTHS - - TRYPANOSOMIASIS - - DIARRHEA_DEHYDRATION - - DIARRHEA_BLOOD - - SNAKE_BITE - - RUBELLA - - TUBERCULOSIS - - LEPROSY - - LYMPHATIC_FILARIASIS - - BURULI_ULCER - - PERTUSSIS - - NEONATAL_TETANUS - - ONCHOCERCIASIS - - DIPHTERIA - - TRACHOMA - - YAWS_ENDEMIC_SYPHILIS - - MATERNAL_DEATHS - - PERINATAL_DEATHS - - INFLUENZA_A - - INFLUENZA_B - - H_METAPNEUMOVIRUS - - RESPIRATORY_SYNCYTIAL_VIRUS - - PARAINFLUENZA_1_4 - - ADENOVIRUS - - RHINOVIRUS - - ENTEROVIRUS - - M_PNEUMONIAE - - C_PNEUMONIAE - - ARI - - CHIKUNGUNYA - - POST_IMMUNIZATION_ADVERSE_EVENTS_MILD - - POST_IMMUNIZATION_ADVERSE_EVENTS_SEVERE - - FHA - - OTHER - - UNDEFINED + diseases: + type: array + items: + type: string + enum: + - AFP + - CHOLERA + - CONGENITAL_RUBELLA + - CSM + - DENGUE + - EVD + - GUINEA_WORM + - LASSA + - MEASLES + - MONKEYPOX + - NEW_INFLUENZA + - PLAGUE + - POLIO + - UNSPECIFIED_VHF + - WEST_NILE_FEVER + - YELLOW_FEVER + - RABIES + - ANTHRAX + - CORONAVIRUS + - PNEUMONIA + - MALARIA + - TYPHOID_FEVER + - ACUTE_VIRAL_HEPATITIS + - NON_NEONATAL_TETANUS + - HIV + - SCHISTOSOMIASIS + - SOIL_TRANSMITTED_HELMINTHS + - TRYPANOSOMIASIS + - DIARRHEA_DEHYDRATION + - DIARRHEA_BLOOD + - SNAKE_BITE + - RUBELLA + - TUBERCULOSIS + - LEPROSY + - LYMPHATIC_FILARIASIS + - BURULI_ULCER + - PERTUSSIS + - NEONATAL_TETANUS + - ONCHOCERCIASIS + - DIPHTERIA + - TRACHOMA + - YAWS_ENDEMIC_SYPHILIS + - MATERNAL_DEATHS + - PERINATAL_DEATHS + - INFLUENZA_A + - INFLUENZA_B + - H_METAPNEUMOVIRUS + - RESPIRATORY_SYNCYTIAL_VIRUS + - PARAINFLUENZA_1_4 + - ADENOVIRUS + - RHINOVIRUS + - ENTEROVIRUS + - M_PNEUMONIAE + - C_PNEUMONIAE + - ARI + - CHIKUNGUNYA + - POST_IMMUNIZATION_ADVERSE_EVENTS_MILD + - POST_IMMUNIZATION_ADVERSE_EVENTS_SEVERE + - FHA + - OTHER + - UNDEFINED + uniqueItems: true district: $ref: '#/components/schemas/DistrictReferenceDto' region: @@ -25022,70 +25025,73 @@ components: type: string maxLength: 512 minLength: 0 - limitedDisease: - type: string - enum: - - AFP - - CHOLERA - - CONGENITAL_RUBELLA - - CSM - - DENGUE - - EVD - - GUINEA_WORM - - LASSA - - MEASLES - - MONKEYPOX - - NEW_INFLUENZA - - PLAGUE - - POLIO - - UNSPECIFIED_VHF - - WEST_NILE_FEVER - - YELLOW_FEVER - - RABIES - - ANTHRAX - - CORONAVIRUS - - PNEUMONIA - - MALARIA - - TYPHOID_FEVER - - ACUTE_VIRAL_HEPATITIS - - NON_NEONATAL_TETANUS - - HIV - - SCHISTOSOMIASIS - - SOIL_TRANSMITTED_HELMINTHS - - TRYPANOSOMIASIS - - DIARRHEA_DEHYDRATION - - DIARRHEA_BLOOD - - SNAKE_BITE - - RUBELLA - - TUBERCULOSIS - - LEPROSY - - LYMPHATIC_FILARIASIS - - BURULI_ULCER - - PERTUSSIS - - NEONATAL_TETANUS - - ONCHOCERCIASIS - - DIPHTERIA - - TRACHOMA - - YAWS_ENDEMIC_SYPHILIS - - MATERNAL_DEATHS - - PERINATAL_DEATHS - - INFLUENZA_A - - INFLUENZA_B - - H_METAPNEUMOVIRUS - - RESPIRATORY_SYNCYTIAL_VIRUS - - PARAINFLUENZA_1_4 - - ADENOVIRUS - - RHINOVIRUS - - ENTEROVIRUS - - M_PNEUMONIAE - - C_PNEUMONIAE - - ARI - - CHIKUNGUNYA - - POST_IMMUNIZATION_ADVERSE_EVENTS_MILD - - POST_IMMUNIZATION_ADVERSE_EVENTS_SEVERE - - FHA - - OTHER - - UNDEFINED + limitedDiseases: + type: array + items: + type: string + enum: + - AFP + - CHOLERA + - CONGENITAL_RUBELLA + - CSM + - DENGUE + - EVD + - GUINEA_WORM + - LASSA + - MEASLES + - MONKEYPOX + - NEW_INFLUENZA + - PLAGUE + - POLIO + - UNSPECIFIED_VHF + - WEST_NILE_FEVER + - YELLOW_FEVER + - RABIES + - ANTHRAX + - CORONAVIRUS + - PNEUMONIA + - MALARIA + - TYPHOID_FEVER + - ACUTE_VIRAL_HEPATITIS + - NON_NEONATAL_TETANUS + - HIV + - SCHISTOSOMIASIS + - SOIL_TRANSMITTED_HELMINTHS + - TRYPANOSOMIASIS + - DIARRHEA_DEHYDRATION + - DIARRHEA_BLOOD + - SNAKE_BITE + - RUBELLA + - TUBERCULOSIS + - LEPROSY + - LYMPHATIC_FILARIASIS + - BURULI_ULCER + - PERTUSSIS + - NEONATAL_TETANUS + - ONCHOCERCIASIS + - DIPHTERIA + - TRACHOMA + - YAWS_ENDEMIC_SYPHILIS + - MATERNAL_DEATHS + - PERINATAL_DEATHS + - INFLUENZA_A + - INFLUENZA_B + - H_METAPNEUMOVIRUS + - RESPIRATORY_SYNCYTIAL_VIRUS + - PARAINFLUENZA_1_4 + - ADENOVIRUS + - RHINOVIRUS + - ENTEROVIRUS + - M_PNEUMONIAE + - C_PNEUMONIAE + - ARI + - CHIKUNGUNYA + - POST_IMMUNIZATION_ADVERSE_EVENTS_MILD + - POST_IMMUNIZATION_ADVERSE_EVENTS_SEVERE + - FHA + - OTHER + - UNDEFINED + uniqueItems: true name: type: string phone: From 25605425c9df26537b06f12f610b71c5b69fdfa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9=20Strysewske?= Date: Fri, 10 Nov 2023 13:57:43 +0100 Subject: [PATCH 14/65] #12750 - Remove matchMissingInfo property --- .../sormas/api/person/PersonSimilarityCriteria.java | 9 --------- .../de/symeda/sormas/backend/person/PersonService.java | 10 ++++------ .../symeda/sormas/ui/person/PersonSelectionGrid.java | 1 - 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonSimilarityCriteria.java b/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonSimilarityCriteria.java index 5d283ea8664..fd0ca37565c 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonSimilarityCriteria.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/person/PersonSimilarityCriteria.java @@ -20,7 +20,6 @@ public class PersonSimilarityCriteria extends BaseCriteria implements Cloneable private String passportNumber; private String nationalHealthId; private String nameUuidExternalIdExternalTokenLike; - private Boolean matchMissingInfo = Boolean.FALSE; /** * If true, compare the name of the person only to the first and last name fields of the database; if false, compare the * name of the person to other fields like UUID and external ID as well. @@ -119,14 +118,6 @@ public void setName(PersonDto person) { this.nameUuidExternalIdExternalTokenLike = person.getFirstName() + " " + person.getLastName(); } - public Boolean getMatchMissingInfo() { - return matchMissingInfo; - } - - public void setMatchMissingInfo(Boolean matchMissingInfo) { - this.matchMissingInfo = matchMissingInfo; - } - public Boolean getStrictNameComparison() { return strictNameComparison; } 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 6ecea94fdbc..689377134b0 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 @@ -844,8 +844,6 @@ public Predicate buildSimilarityCriteriaFilter(PersonSimilarityCriteria criteria Predicate filter = null; - Boolean matchMissingInfo = criteria.getMatchMissingInfo(); - if (!StringUtils.isBlank(criteria.getFirstName()) && !StringUtils.isBlank(criteria.getLastName())) { Expression nameExpr = cb.concat(personFrom.get(Person.FIRST_NAME), " "); nameExpr = cb.concat(nameExpr, personFrom.get(Person.LAST_NAME)); @@ -876,19 +874,19 @@ public Predicate buildSimilarityCriteriaFilter(PersonSimilarityCriteria criteria } if (criteria.getBirthdateYYYY() != null) { final Predicate yearEquals = cb.equal(personFrom.get(Person.BIRTHDATE_YYYY), criteria.getBirthdateYYYY()); - filter = and(cb, filter, matchMissingInfo ? yearEquals : cb.or(cb.isNull(personFrom.get(Person.BIRTHDATE_YYYY)), yearEquals)); + filter = and(cb, filter, cb.or(cb.isNull(personFrom.get(Person.BIRTHDATE_YYYY)), yearEquals)); } if (criteria.getBirthdateMM() != null) { final Predicate monthEquals = cb.equal(personFrom.get(Person.BIRTHDATE_MM), criteria.getBirthdateMM()); - filter = and(cb, filter, matchMissingInfo ? monthEquals : cb.or(cb.isNull(personFrom.get(Person.BIRTHDATE_MM)), monthEquals)); + filter = and(cb, filter, cb.or(cb.isNull(personFrom.get(Person.BIRTHDATE_MM)), monthEquals)); } if (criteria.getBirthdateDD() != null) { final Predicate dayEquals = cb.equal(personFrom.get(Person.BIRTHDATE_DD), criteria.getBirthdateDD()); - filter = and(cb, filter, matchMissingInfo ? dayEquals : cb.or(cb.isNull(personFrom.get(Person.BIRTHDATE_DD)), dayEquals)); + filter = and(cb, filter, cb.or(cb.isNull(personFrom.get(Person.BIRTHDATE_DD)), dayEquals)); } if (!StringUtils.isBlank(criteria.getNationalHealthId())) { final Predicate nationalEqual = cb.equal(personFrom.get(Person.NATIONAL_HEALTH_ID), criteria.getNationalHealthId()); - filter = and(cb, filter, matchMissingInfo ? nationalEqual : cb.or(cb.isNull(personFrom.get(Person.NATIONAL_HEALTH_ID)), nationalEqual)); + filter = and(cb, filter, cb.or(cb.isNull(personFrom.get(Person.NATIONAL_HEALTH_ID)), nationalEqual)); } if (!StringUtils.isBlank(criteria.getPassportNumber())) { filter = CriteriaBuilderHelper.or(cb, filter, cb.equal(personFrom.get(Person.PASSPORT_NUMBER), criteria.getPassportNumber())); 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 c41ab6aa3da..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 @@ -91,7 +91,6 @@ private BeanItemContainer getContainer() { * The person criteria. */ public void loadData(PersonSimilarityCriteria criteria) { - criteria.setMatchMissingInfo(true); List similarPersons = FacadeProvider.getPersonFacade().getSimilarPersonDtos(criteria); getContainer().removeAllItems(); From 320acc5e980ada5308348d5348b23cf60fb00ffa Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Fri, 10 Nov 2023 13:30:29 +0100 Subject: [PATCH 15/65] HSP-6369 Stabilize "Display date and time for pathogen test result on sample card" - updated selector for ADD_PATHOGEN_TEST_BUTTON --- .../pages/application/samples/CreateNewSamplePage.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) 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 03d49c26c71..debcb2cc33d 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 @@ -94,9 +94,7 @@ public class CreateNewSamplePage { By.xpath("//label[text()='PCR / RT-PCR']"); public static final By FINAL_LABORATORY_RESULT_COMBOBOX = By.cssSelector("[id='pathogenTestResult'] [class='v-filterselect-button']"); - public static final By ADD_PATHOGEN_TEST_BUTTON = - By.xpath( - "(//div[@class='v-window-contents']//div[@class='v-expand']//div[@tabindex='0'])[1]"); + public static final By ADD_PATHOGEN_TEST_BUTTON = By.xpath("//div[@class='v-button v-widget']"); public static final By HAEMOGLOBIN_IN_URINE_COMBOBOX = By.cssSelector("[id='haemoglobinuria'] [class='v-filterselect-button']"); public static final By HAEMOGLOBIN_IN_URINE_INPUT = @@ -141,8 +139,7 @@ public class CreateNewSamplePage { "//div[@class='v-slot v-slot-side-component']//div[@class='v-label v-widget bold v-label-bold uppercase v-label-uppercase critical v-label-critical v-label-undef-w']"); public static final By NEW_TEST_RESULTS_BUTTON_FOR_PATHOGEN_TESTS = By.cssSelector("[id='New test result']"); - public static final By ADD_PATHOGEN_TEST = - By.cssSelector(".v-window-contents .v-slot:nth-of-type(1) .v-button"); + public static final By ADD_PATHOGEN_TEST = By.xpath("//div[@class='v-button v-widget']"); public static final By DATE_AND_TIME_OF_RESULTS = By.xpath("//div[contains(text(),'Date and time of result:')]"); public static final By UPDATE_CASE_DISEASE_VARIANT = From 6b2c8ea58d537d46b1872a4bbafdfeb4461e1969 Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Fri, 10 Nov 2023 13:34:41 +0100 Subject: [PATCH 16/65] HSP-6369 Stabilize "Display date and time for pathogen test result on sample card" - removed duplicated PATHOGEN TEST button --- .../steps/web/application/samples/CreateNewSampleSteps.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 ec07bfdb193..a9114b41c8f 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 @@ -265,7 +265,7 @@ public CreateNewSampleSteps( selectReasonForSample(sample.getReasonForSample()); fillSampleID(sample.getSampleID()); fillCommentsOnSample(sample.getCommentsOnSample()); - webDriverHelpers.clickOnWebElementBySelector(ADD_PATHOGEN_TEST); + webDriverHelpers.clickOnWebElementBySelector(ADD_PATHOGEN_TEST_BUTTON); selectTestedDisease(sample.getTestedDisease()); selectTypeOfTest(sample.getTypeOfTest()); selectTestResult(sample.getSampleTestResults()); @@ -313,7 +313,7 @@ public CreateNewSampleSteps( selectPurposeOfSample(sample.getPurposeOfTheSample(), SAMPLE_PURPOSE_OPTIONS); fillDateOfCollection(sample.getDateOfCollection()); selectSampleType(sample.getSampleType()); - webDriverHelpers.clickOnWebElementBySelector(ADD_PATHOGEN_TEST); + webDriverHelpers.clickOnWebElementBySelector(ADD_PATHOGEN_TEST_BUTTON); selectTestedDisease(sample.getTestedDisease()); selectTypeOfTest(sample.getTypeOfTest()); selectTestResult(sample.getSampleTestResults()); From 8746b64525e34c36bff10f8e6ba334ead240853f Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Fri, 10 Nov 2023 13:36:29 +0100 Subject: [PATCH 17/65] HSP-6369 Stabilize "Display date and time for pathogen test result on sample card" - removed and resolved duplicated PATHOGEN TEST button --- .../e2etests/pages/application/samples/CreateNewSamplePage.java | 1 - 1 file changed, 1 deletion(-) 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 debcb2cc33d..34e249bc734 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 @@ -139,7 +139,6 @@ public class CreateNewSamplePage { "//div[@class='v-slot v-slot-side-component']//div[@class='v-label v-widget bold v-label-bold uppercase v-label-uppercase critical v-label-critical v-label-undef-w']"); public static final By NEW_TEST_RESULTS_BUTTON_FOR_PATHOGEN_TESTS = By.cssSelector("[id='New test result']"); - public static final By ADD_PATHOGEN_TEST = By.xpath("//div[@class='v-button v-widget']"); public static final By DATE_AND_TIME_OF_RESULTS = By.xpath("//div[contains(text(),'Date and time of result:')]"); public static final By UPDATE_CASE_DISEASE_VARIANT = From 025106487c53a174348c1cb02f4881ec4d40c990 Mon Sep 17 00:00:00 2001 From: sergiupacurariu <62688603+sergiupacurariu@users.noreply.github.com> Date: Fri, 10 Nov 2023 15:36:37 +0200 Subject: [PATCH 18/65] #12704 - Cases can be created for Contacts, Event participants and Travel entries when the CASE SURVEILLANCE is disabled --- .../sormas/ui/contact/ContactDataView.java | 3 ++- .../ui/events/EventParticipantsGrid.java | 24 +++++++++++++++---- .../ui/travelentry/TravelEntryDataView.java | 6 ++--- 3 files changed, 23 insertions(+), 10 deletions(-) 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 7b50645ade8..dc68f9bb18d 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 @@ -46,6 +46,7 @@ import de.symeda.sormas.api.vaccination.VaccinationAssociationType; import de.symeda.sormas.api.vaccination.VaccinationCriteria; import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.UserProvider; import de.symeda.sormas.ui.caze.CaseInfoLayout; import de.symeda.sormas.ui.docgeneration.QuarantineOrderDocumentsComponent; @@ -99,7 +100,7 @@ protected void initView(String params) { editComponent = ControllerProvider.getContactController() .getContactDataEditComponent(getContactRef().getUuid(), ViewMode.NORMAL, contactDto.isPseudonymized()); - if (FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.CASE_SURVEILANCE)) { + if (UiUtil.permitted(FeatureType.CASE_SURVEILANCE, UserRight.CASE_CREATE)) { addCreateFromCaseButtonLogic(); } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsGrid.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsGrid.java index 8edfaf1715f..94662bf6dc8 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsGrid.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/events/EventParticipantsGrid.java @@ -17,6 +17,8 @@ import java.util.Date; +import org.apache.commons.lang3.ArrayUtils; + import com.vaadin.ui.renderers.DateRenderer; import de.symeda.sormas.api.FacadeProvider; @@ -32,6 +34,7 @@ import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.UserProvider; import de.symeda.sormas.ui.ViewModelProviders; import de.symeda.sormas.ui.utils.CaseUuidRenderer; @@ -81,7 +84,7 @@ public EventParticipantsGrid(EventParticipantCriteria criteria) { caseIdColumn.setRenderer(new CaseUuidRenderer(uuid -> { // '!=' check is ok because the converter returns the constant when no case creation is allowed - return NO_CASE_CREATE != uuid && FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.CASE_SURVEILANCE); + return NO_CASE_CREATE != uuid && UiUtil.permitted(FeatureType.CASE_SURVEILANCE, UserRight.CASE_CREATE); })); Column deleteColumn = addColumn(entry -> { @@ -96,20 +99,31 @@ public EventParticipantsGrid(EventParticipantCriteria criteria) { deleteColumn.setCaption(I18nProperties.getCaption(Captions.deletionReason)); Language userLanguage = I18nProperties.getUserLanguage(); - setColumns( + String[] columns = new String[] {}; + columns = ArrayUtils.addAll( + columns, EventParticipantIndexDto.UUID, EventParticipantIndexDto.PERSON_UUID, EventParticipantIndexDto.FIRST_NAME, EventParticipantIndexDto.LAST_NAME, EventParticipantIndexDto.SEX, EventParticipantIndexDto.APPROXIMATE_AGE, - EventParticipantIndexDto.INVOLVEMENT_DESCRIPTION, - CASE_ID, + EventParticipantIndexDto.INVOLVEMENT_DESCRIPTION); + + if (UiUtil.permitted(FeatureType.CASE_SURVEILANCE, UserRight.CASE_VIEW)) { + columns = ArrayUtils.add(columns, CASE_ID); + } + + columns = ArrayUtils.addAll( + columns, EventParticipantIndexDto.CONTACT_COUNT, SampleIndexDto.PATHOGEN_TEST_RESULT, SampleIndexDto.SAMPLE_DATE_TIME, EventParticipantIndexDto.VACCINATION_STATUS, DELETE_REASON_COLUMN); + + setColumns(columns); + ((Column) getColumn(SampleIndexDto.SAMPLE_DATE_TIME)) .setRenderer(new DateRenderer(DateHelper.getLocalDateTimeFormat(userLanguage))); ((Column) getColumn(EventParticipantIndexDto.UUID)).setRenderer(new UuidRenderer()); @@ -131,7 +145,7 @@ public EventParticipantsGrid(EventParticipantCriteria criteria) { getColumn(EventParticipantIndexDto.CONTACT_COUNT).setSortable(false); - if (FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.CASE_SURVEILANCE)) { + if (UiUtil.permitted(FeatureType.CASE_SURVEILANCE, UserRight.CASE_VIEW)) { addItemClickListener(new ShowDetailsListener<>(CASE_ID, false, e -> { if (e.getCaseUuid() != null) { ControllerProvider.getCaseController().navigateToCase(e.getCaseUuid()); 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 3fb81e0f626..976a4035c46 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 @@ -14,6 +14,7 @@ import de.symeda.sormas.api.travelentry.TravelEntryDto; import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.UiUtil; import de.symeda.sormas.ui.UserProvider; import de.symeda.sormas.ui.caze.CaseInfoLayout; import de.symeda.sormas.ui.docgeneration.QuarantineOrderDocumentsComponent; @@ -65,10 +66,7 @@ protected void initView(String params) { container.addComponent(layout); UserProvider currentUser = UserProvider.getCurrent(); - boolean caseButtonVisible = currentUser != null - && currentUser.hasUserRight(UserRight.CASE_CREATE) - && FacadeProvider.getFeatureConfigurationFacade().isFeatureEnabled(FeatureType.CASE_SURVEILANCE); - + boolean caseButtonVisible = currentUser != null && UiUtil.permitted(FeatureType.CASE_SURVEILANCE, UserRight.CASE_CREATE); CaseReferenceDto resultingCase = travelEntryDto.getResultingCase(); if (resultingCase == null && caseButtonVisible) { Button createCaseButton = ButtonHelper.createButton(Captions.travelEntryCreateCase, e -> showUnsavedChangesPopup(() -> { From 89cb4e6cda2155a74a3fc8fe8f102a2d88efb257 Mon Sep 17 00:00:00 2001 From: Michal Kozakiewicz Date: Fri, 10 Nov 2023 14:47:12 +0100 Subject: [PATCH 19/65] HSP-6368 Stabilize "Validate Statistics directory database export tab layout" - adjusted test field to Statistic UI --- .../pages/application/statistics/StatisticsPage.java | 4 ++-- .../steps/web/application/statistics/StatisticsSteps.java | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/statistics/StatisticsPage.java b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/statistics/StatisticsPage.java index 54c34232cd8..3e6d6f6a002 100644 --- a/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/statistics/StatisticsPage.java +++ b/sormas-e2e-tests/src/main/java/org/sormas/e2etests/pages/application/statistics/StatisticsPage.java @@ -92,8 +92,8 @@ public class StatisticsPage { public static final By EVENTS_CHECKBOX = By.xpath("//label[text()='Events']/preceding-sibling::input"); public static final By EVENT_GROUPS_CHECKBOX = By.xpath("//label[text()='Event groups']"); - public static final By PERSONS_INVOLVED_CHECKBOX = - By.xpath("//label[text()='Persons involved']/preceding-sibling::input"); + public static final By PERSONS_LOCATIONS_CHECKBOX = + By.xpath("//label[text()='Person locations']/preceding-sibling::input"); public static final By ACTIONS_CHECKBOX = By.xpath("//label[text()='Actions']/preceding-sibling::input"); public static final By IMMUNIZATIONS_CHECKBOX = diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/statistics/StatisticsSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/statistics/StatisticsSteps.java index 0f90a8d57d1..d5277e8a0c6 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/statistics/StatisticsSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/statistics/StatisticsSteps.java @@ -240,8 +240,8 @@ public StatisticsSteps(WebDriverHelpers webDriverHelpers, SoftAssert softly) { webDriverHelpers.isElementChecked(EVENTS_CHECKBOX), "Events Checkbox is not checked in the database export page"); softly.assertTrue( - webDriverHelpers.isElementChecked(PERSONS_INVOLVED_CHECKBOX), - "Persons involved Checkbox is not checked in the database export page"); + webDriverHelpers.isElementChecked(PERSONS_LOCATIONS_CHECKBOX), + "Person locations Checkbox is not checked in the database export page"); softly.assertTrue( webDriverHelpers.isElementChecked(ACTIONS_CHECKBOX), "Actions Checkbox is not checked in the database export page"); @@ -400,8 +400,8 @@ public StatisticsSteps(WebDriverHelpers webDriverHelpers, SoftAssert softly) { webDriverHelpers.isElementChecked(EVENTS_CHECKBOX), "Events Checkbox is not checked in the database export page"); softly.assertFalse( - webDriverHelpers.isElementChecked(PERSONS_INVOLVED_CHECKBOX), - "Persons involved Checkbox is not checked in the database export page"); + webDriverHelpers.isElementChecked(PERSONS_LOCATIONS_CHECKBOX), + "Person locations Checkbox is not checked in the database export page"); softly.assertFalse( webDriverHelpers.isElementChecked(ACTIONS_CHECKBOX), "Actions Checkbox is not checked in the database export page"); From 4b7db4de855665cb6b015a82174c4938fd38fae7 Mon Sep 17 00:00:00 2001 From: sormas-vitagroup Date: Mon, 13 Nov 2023 09:56:08 +0000 Subject: [PATCH 20/65] [GitHub Actions] Update openAPI spec files --- sormas-rest/swagger.json | 3 --- sormas-rest/swagger.yaml | 2 -- 2 files changed, 5 deletions(-) diff --git a/sormas-rest/swagger.json b/sormas-rest/swagger.json index 09e3f0998f9..3de0afe7544 100644 --- a/sormas-rest/swagger.json +++ b/sormas-rest/swagger.json @@ -21168,9 +21168,6 @@ "lastName" : { "type" : "string" }, - "matchMissingInfo" : { - "type" : "boolean" - }, "name" : { "$ref" : "#/components/schemas/PersonDto" }, diff --git a/sormas-rest/swagger.yaml b/sormas-rest/swagger.yaml index 5c8ff814746..12a6a0c14d5 100644 --- a/sormas-rest/swagger.yaml +++ b/sormas-rest/swagger.yaml @@ -20487,8 +20487,6 @@ components: type: string lastName: type: string - matchMissingInfo: - type: boolean name: $ref: '#/components/schemas/PersonDto' nameUuidExternalIdExternalTokenLike: From e661fd8067cd7a9183485f1f1194e8d06530f6c3 Mon Sep 17 00:00:00 2001 From: mk-sgent <97879405+mk-sgent@users.noreply.github.com> Date: Mon, 13 Nov 2023 14:16:09 +0100 Subject: [PATCH 21/65] =?UTF-8?q?HSP-6377=20Stabilize=20-=20selectors=20ad?= =?UTF-8?q?justment=20and=20refactoring=20methods=20for=E2=80=A6=20(#12754?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * HSP-6377 Stabilize - selectors adjustment and refactoring methods for Restricted Disease field in CreateNewUser process and refactoring methods for Restricted Disease field in CreateNewUser process * HSP-6377 Stabilize - selectors adjustment and refactoring methods for Restricted Disease field in CreateNewUser process and refactoring methods for Restricted Disease field in CreateNewUser process - removed test Tags --- .../application/users/CreateNewUserPage.java | 5 +++- .../pages/application/users/EditUserPage.java | 3 ++- .../application/users/CreateNewUserSteps.java | 24 ++++++++++++------- .../web/application/users/EditUserSteps.java | 4 ++-- 4 files changed, 24 insertions(+), 12 deletions(-) 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 381d21b3cb1..9f981d538e5 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 @@ -53,7 +53,10 @@ public class CreateNewUserPage { public static final By ACTIVE_CHECKBOX = By.cssSelector(".v-window #active label"); public static final By USER_NAME_INPUT = By.id("userName"); public static final By USER_ROLE_CHECKBOX = By.cssSelector("#userRoles label"); - public static final By LIMITED_DISEASE_COMBOBOX = By.cssSelector("#limitedDisease > div"); + public static final By RESTRICT_DISEASES_CHECKBOX = + By.cssSelector("#restrictDiseasesCheckboxLoc label"); + public static final By LIMITED_DISEASE_CHECKBOX = By.cssSelector("#limitedDiseases label"); + public static final By DISCARD_BUTTON = By.id("discard"); public static final By SAVE_BUTTON = By.id("commit"); public static final By PASSWORD_FIELD = 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 872a975ca31..8575e4fe482 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 @@ -55,7 +55,8 @@ public class EditUserPage { public static final By ACTIVE_LABEL = By.cssSelector(".v-window #active label"); public static final By USER_NAME_INPUT = By.id("userName"); public static final By USER_ROLE_CHECKBOX_TEXT = By.cssSelector("#userRoles [checked] + label"); - public static final By LIMITED_DISEASE_COMBOBOX_INPUT = By.cssSelector("#limitedDisease > input"); + public static final By LIMITED_DISEASE_CHECKBOX_TEXT = + By.cssSelector("#limitedDiseases [checked] + label"); public static final By DISCARD_BUTTON = By.id("discard"); public static final By SAVE_BUTTON_EDIT_USER = By.id("commit"); public static final By NOTIFICATION_CAPTION_EDIT_USER = 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 f05b6910680..b3534e3f2ba 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 @@ -155,7 +155,7 @@ public CreateNewUserSteps( selectActive(user.getActive()); fillUserName(user.getUserName()); selectUserRole(role); - selectLimitedDisease(user.getLimitedDisease()); + selectRestrictDiseases(user.getLimitedDisease()); userName = user.getUserName(); webDriverHelpers.scrollToElement(SAVE_BUTTON); webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON); @@ -256,7 +256,7 @@ public CreateNewUserSteps( selectActive(user.getActive()); fillUserName(user.getUserName()); selectUserRole(role); - selectLimitedDisease(user.getLimitedDisease()); + selectRestrictDiseases(user.getLimitedDisease()); webDriverHelpers.scrollToElement(SAVE_BUTTON); webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON); webDriverHelpers.waitForPageLoadingSpinnerToDisappear(20); @@ -297,7 +297,7 @@ public CreateNewUserSteps( selectActive(user.getActive()); fillUserName(user.getUserName()); selectUserRole("National User"); - selectLimitedDisease(user.getLimitedDisease()); + selectRestrictDiseases(user.getLimitedDisease()); webDriverHelpers.scrollToElement(SAVE_BUTTON); webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON); webDriverHelpers.waitForPageLoadingSpinnerToDisappear(20); @@ -335,7 +335,7 @@ public CreateNewUserSteps( fillGpsAccuracy(user.getGpsAccuracy()); fillUserName(user.getUserName()); selectUserRole("National User"); - selectLimitedDisease(user.getLimitedDisease()); + selectRestrictDiseases(user.getLimitedDisease()); webDriverHelpers.scrollToElement(SAVE_BUTTON); webDriverHelpers.clickOnWebElementBySelector(SAVE_BUTTON); webDriverHelpers.waitForPageLoadingSpinnerToDisappear(20); @@ -372,7 +372,7 @@ public CreateNewUserSteps( selectActive(user.getActive()); selectActiveUserRole(); selectUserRole(editUser.getUserRole()); - selectLimitedDisease(editUser.getLimitedDisease()); + changeRestrictDiseases(user.getLimitedDisease(), editUser.getLimitedDisease()); webDriverHelpers.scrollToElement(CreateNewUserPage.SAVE_BUTTON); webDriverHelpers.clickOnWebElementBySelector(CreateNewUserPage.SAVE_BUTTON); }); @@ -762,9 +762,17 @@ private void closeNewPasswordPopUp() { TimeUnit.SECONDS.sleep(1); } - private void selectLimitedDisease(String limitedDisease) { - webDriverHelpers.scrollToElement(LIMITED_DISEASE_COMBOBOX); - webDriverHelpers.selectFromCombobox(LIMITED_DISEASE_COMBOBOX, limitedDisease); + private void selectRestrictDiseases(String limitedDisease) { + webDriverHelpers.scrollToElement(RESTRICT_DISEASES_CHECKBOX); + webDriverHelpers.clickOnWebElementBySelector(RESTRICT_DISEASES_CHECKBOX); + webDriverHelpers.clickWebElementByText(LIMITED_DISEASE_CHECKBOX, limitedDisease); + } + + private void changeRestrictDiseases(String previousLimitedDisease, String limitedDisease) { + webDriverHelpers.scrollToElement(RESTRICT_DISEASES_CHECKBOX); + webDriverHelpers.doubleClickOnWebElementBySelector(RESTRICT_DISEASES_CHECKBOX); + webDriverHelpers.clickWebElementByText(LIMITED_DISEASE_CHECKBOX, previousLimitedDisease); + webDriverHelpers.clickWebElementByText(LIMITED_DISEASE_CHECKBOX, limitedDisease); } private List> getTableRowsData() { diff --git a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/users/EditUserSteps.java b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/users/EditUserSteps.java index 82d106c5daf..2720d39f177 100644 --- a/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/users/EditUserSteps.java +++ b/sormas-e2e-tests/src/test/java/org/sormas/e2etests/steps/web/application/users/EditUserSteps.java @@ -158,7 +158,7 @@ private User collectEditUserData() { .gpsAccuracy(webDriverHelpers.getValueFromWebElement(LAT_LON_ACCURACY_INPUT)) .active(webDriverHelpers.getWebElement(ACTIVE_CHECKBOX).isSelected()) .userName(webDriverHelpers.getValueFromWebElement(USER_NAME_INPUT)) - .limitedDisease(webDriverHelpers.getValueFromWebElement(LIMITED_DISEASE_COMBOBOX_INPUT)) + .limitedDisease(webDriverHelpers.getTextFromWebElement(LIMITED_DISEASE_CHECKBOX_TEXT)) .userRole(webDriverHelpers.getTextFromWebElement(USER_ROLE_CHECKBOX_TEXT)) .build(); } @@ -191,7 +191,7 @@ private User collectUserData() { .gpsAccuracy(webDriverHelpers.getValueFromWebElement(LAT_LON_ACCURACY_INPUT)) .userName(webDriverHelpers.getValueFromWebElement(USER_NAME_INPUT)) .active(webDriverHelpers.getWebElement(ACTIVE_CHECKBOX).isSelected()) - .limitedDisease(webDriverHelpers.getValueFromWebElement(LIMITED_DISEASE_COMBOBOX_INPUT)) + .limitedDisease(webDriverHelpers.getTextFromWebElement(LIMITED_DISEASE_CHECKBOX_TEXT)) .userRole(webDriverHelpers.getTextFromWebElement(USER_ROLE_CHECKBOX_TEXT)) .build(); } From 4ab94a65f7adcb39d908660b3785848f8362ea60 Mon Sep 17 00:00:00 2001 From: Carina Paul <47103965+carina29@users.noreply.github.com> Date: Tue, 14 Nov 2023 10:41:02 +0200 Subject: [PATCH 22/65] #4837 - Only show cases in the users jurisdiction by default (#12720) * #4837 - Only show cases in the users jurisdiction by default * #4837 - Fixes and styling * #4837 - Delete CaseUserFilterCriteria.java * #4837 - Add contactIncludeFromOtherJurisdictions * #4837 - fixes * #4837 - fixes for Contact filtering * #4837 - fixes * #4837 - delete comments * #4837 - changes after review, part 1 * #4837 - changes after review * #4837 - changes after review * #4837 - delete comment * #4837 - change the styling --- .../de/symeda/sormas/api/i18n/Captions.java | 4 +- .../src/main/resources/captions.properties | 4 +- .../symeda/sormas/app/backend/caze/Case.java | 6 + .../sormas/app/backend/caze/CaseCriteria.java | 10 ++ .../sormas/app/backend/caze/CaseDao.java | 118 ++++++++++--- .../sormas/app/backend/contact/Contact.java | 14 +- .../app/backend/contact/ContactCriteria.java | 10 ++ .../app/backend/contact/ContactDao.java | 155 +++++++++++++++--- .../app/caze/list/CaseListActivity.java | 5 +- .../app/caze/list/CaseListViewModel.java | 1 + .../controls/FilterCheckBoxField.java | 63 +++++++ .../app/contact/list/ContactListActivity.java | 3 +- .../res/layout/filter_case_list_layout.xml | 9 +- .../layout/filter_checkbox_field_layout.xml | 53 ++++++ .../res/layout/filter_contact_list_layout.xml | 9 +- sormas-app/app/src/main/res/values/colors.xml | 1 + sormas-app/app/src/main/res/values/dimens.xml | 2 + sormas-app/app/src/main/res/values/styles.xml | 33 +++- .../symeda/sormas/ui/caze/CaseFilterForm.java | 2 +- .../sormas/ui/contact/ContactsFilterForm.java | 2 +- 20 files changed, 436 insertions(+), 68 deletions(-) create mode 100644 sormas-app/app/src/main/java/de/symeda/sormas/app/component/controls/FilterCheckBoxField.java create mode 100644 sormas-app/app/src/main/res/layout/filter_checkbox_field_layout.xml 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 eebfff17d66..c8232f2e240 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 @@ -514,7 +514,7 @@ public interface Captions { String caseFilterCasesWithCaseManagementData = "caseFilterCasesWithCaseManagementData"; String caseFilterCasesWithReinfection = "caseFilterCasesWithReinfection"; String caseFilterExcludeSharedCases = "caseFilterExcludeSharedCases"; - String caseFilterInludeCasesFromOtherJurisdictions = "caseFilterInludeCasesFromOtherJurisdictions"; + String caseFilterIncludeCasesFromOtherJurisdictions = "caseFilterIncludeCasesFromOtherJurisdictions"; String caseFilterOnlyCasesChangedSinceLastSharedWithExternalSurvTool = "caseFilterOnlyCasesChangedSinceLastSharedWithExternalSurvTool"; String caseFilterOnlyCasesNotSharedWithExternalSurvTool = "caseFilterOnlyCasesNotSharedWithExternalSurvTool"; String caseFilterOnlyCasesSharedWithExternalSurvToo = "caseFilterOnlyCasesSharedWithExternalSurvToo"; @@ -765,7 +765,7 @@ public interface Captions { String contactFilterWithDifferentRegion = "contactFilterWithDifferentRegion"; String contactFollowUpDay = "contactFollowUpDay"; String contactFollowUpVisitsOverview = "contactFollowUpVisitsOverview"; - String contactInludeContactsFromOtherJurisdictions = "contactInludeContactsFromOtherJurisdictions"; + String contactIncludeContactsFromOtherJurisdictions = "contactIncludeContactsFromOtherJurisdictions"; String contactLostToFollowUp = "contactLostToFollowUp"; String contactMergeDuplicates = "contactMergeDuplicates"; String contactMinusDays = "contactMinusDays"; diff --git a/sormas-api/src/main/resources/captions.properties b/sormas-api/src/main/resources/captions.properties index 0b2c659b276..7617c2206f6 100644 --- a/sormas-api/src/main/resources/captions.properties +++ b/sormas-api/src/main/resources/captions.properties @@ -362,7 +362,7 @@ caseFilterWithoutResponsibleUser=Only cases without responsible user caseFilterWithExtendedQuarantine=Only cases with extended quarantine caseFilterWithReducedQuarantine=Only cases with reduced quarantine caseFilterOnlyQuarantineHelpNeeded=Help needed in quarantine -caseFilterInludeCasesFromOtherJurisdictions=Include cases from other jurisdictions +caseFilterIncludeCasesFromOtherJurisdictions=Include cases from other jurisdictions caseFilterOnlyCasesWithFulfilledReferenceDefinition=Only cases with fulfilled reference definition caseFilterRelatedToEvent=Only cases with events caseFilterOnlyFromOtherInstances=Only cases from other instances @@ -717,7 +717,7 @@ contactChooseSourceCase=Choose Source Case contactOnlyQuarantineHelpNeeded=Help needed in quarantine contactOnlyWithExtendedQuarantine=Only contacts with extended quarantine contactOnlyWithReducedQuarantine=Only contacts with reduced quarantine -contactInludeContactsFromOtherJurisdictions=Include contacts from other jurisdictions +contactIncludeContactsFromOtherJurisdictions=Include contacts from other jurisdictions contactOnlyWithSharedEventWithSourceCase=Only contacts with source case linked to the specified event contactOnlyWithSourceCaseInGivenEvent=Only contacts whose source case is linked to this event contactFollowUpDay=Day 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 6f44008fcfe..dc613da641d 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 @@ -104,6 +104,12 @@ public class Case extends PseudonymizableAdo { public static final String VACCINATION_STATUS = "vaccinationStatus"; public static final String HEALTH_CONDITIONS = "healthConditions"; + public static final String DISTRICT = "district_id"; + public static final String RESPONSIBLE_DISTRICT = "responsibleDistrict_id"; + public static final String COMMUNITY = "community_id"; + public static final String RESPONSIBLE_COMMUNITY = "responsibleCommunity_id"; + public static final String POINT_OF_ENTRY = "pointOfEntry_id"; + @DatabaseField(foreign = true, foreignAutoRefresh = true, canBeNull = false, maxForeignAutoRefreshLevel = 3) private Person person; diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseCriteria.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseCriteria.java index 8d0ea3a97cd..161fc6c1b00 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseCriteria.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseCriteria.java @@ -40,6 +40,8 @@ public class CaseCriteria implements Serializable { private Region region; private Person person; + private Boolean includeCasesFromOtherJurisdictions = Boolean.FALSE; + public CaseCriteria setTextFilter(String textFilter) { this.textFilter = textFilter; return this; @@ -137,4 +139,12 @@ public Person getPerson() { public void setPerson(Person person) { this.person = person; } + + public Boolean getIncludeCasesFromOtherJurisdictions() { + return includeCasesFromOtherJurisdictions; + } + + public void setIncludeCasesFromOtherJurisdictions(Boolean includeCasesFromOtherJurisdictions) { + this.includeCasesFromOtherJurisdictions = includeCasesFromOtherJurisdictions; + } } 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 f7b7a6fdbc0..3262ac9a99f 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 @@ -39,9 +39,7 @@ import android.os.Build; import android.text.Html; import android.util.Log; - import androidx.core.app.NotificationCompat; - import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.caze.CaseClassification; import de.symeda.sormas.api.caze.CaseOrigin; @@ -76,7 +74,9 @@ import de.symeda.sormas.app.backend.event.EventEditAuthorization; import de.symeda.sormas.app.backend.event.EventParticipant; import de.symeda.sormas.app.backend.exposure.Exposure; +import de.symeda.sormas.app.backend.facility.Facility; import de.symeda.sormas.app.backend.person.Person; +import de.symeda.sormas.app.backend.pointofentry.PointOfEntry; import de.symeda.sormas.app.backend.region.Community; import de.symeda.sormas.app.backend.region.District; import de.symeda.sormas.app.backend.region.Region; @@ -754,54 +754,122 @@ public List queryByCriteria(CaseCriteria criteria, long offset, long limit private QueryBuilder buildQueryBuilder(CaseCriteria criteria) throws SQLException { QueryBuilder queryBuilder = queryBuilder(); QueryBuilder personQueryBuilder = DatabaseHelper.getPersonDao().queryBuilder(); + Where where = queryBuilder.where().eq(AbstractDomainObject.SNAPSHOT, false); + + if (criteria != null) { + if (criteria.getIncludeCasesFromOtherJurisdictions().equals(false)) { + where.and(); + createJurisdictionFilter(where); + } + createCriteriaFilter(where, criteria); + queryBuilder.setWhere(where); + } + + queryBuilder = queryBuilder.leftJoin(personQueryBuilder); + return queryBuilder; + } - List> whereStatements = new ArrayList<>(); - Where where = queryBuilder.where(); - whereStatements.add(where.eq(AbstractDomainObject.SNAPSHOT, false)); + public Where createJurisdictionFilter(Where where) throws SQLException { + List whereUserFilterStatements = new ArrayList<>(); + + User currentUser = ConfigProvider.getUser(); + if (currentUser == null) { + return null; + } + + final JurisdictionLevel jurisdictionLevel = currentUser.getJurisdictionLevel(); + + switch (jurisdictionLevel) { + case DISTRICT: + District district = currentUser.getDistrict(); + if (district != null) { + whereUserFilterStatements.add(where.or(where.eq((Case.DISTRICT), district), where.eq(Case.RESPONSIBLE_DISTRICT, district.getId()))); + } + break; + + case HEALTH_FACILITY: + Facility healthFacility = currentUser.getHealthFacility(); + if (healthFacility != null) { + whereUserFilterStatements.add(where.eq(Case.HEALTH_FACILITY, healthFacility.getId())); + } + break; + case COMMUNITY: + Community community = currentUser.getCommunity(); + if (community != null) { + whereUserFilterStatements + .add(where.or(where.eq((Case.COMMUNITY), community), where.eq(Case.RESPONSIBLE_COMMUNITY, community.getId()))); + } + break; + case POINT_OF_ENTRY: + PointOfEntry pointOfEntry = currentUser.getPointOfEntry(); + if (pointOfEntry != null) { + whereUserFilterStatements.add(where.eq(Case.POINT_OF_ENTRY, pointOfEntry.getId())); + } + break; + default: + } + + if (!whereUserFilterStatements.isEmpty()) { + where.or(whereUserFilterStatements.size()); + } + + return where; + } + + public Where createCriteriaFilter(Where where, CaseCriteria criteria) throws SQLException { if (criteria.getInvestigationStatus() != null) { - whereStatements.add(where.eq(Case.INVESTIGATION_STATUS, criteria.getInvestigationStatus())); + where.and(); + where.eq(Case.INVESTIGATION_STATUS, criteria.getInvestigationStatus()); } + if (criteria.getDisease() != null) { - whereStatements.add(where.eq(Case.DISEASE, criteria.getDisease())); + where.and(); + where.eq(Case.DISEASE, criteria.getDisease()); } + if (criteria.getCaseClassification() != null) { - whereStatements.add(where.eq(Case.CASE_CLASSIFICATION, criteria.getCaseClassification())); + where.and(); + where.eq(Case.CASE_CLASSIFICATION, criteria.getCaseClassification()); } + if (criteria.getOutcome() != null) { - whereStatements.add(where.eq(Case.OUTCOME, criteria.getOutcome())); + where.and(); + where.eq(Case.OUTCOME, criteria.getOutcome()); } + if (criteria.getEpiWeekFrom() != null) { - whereStatements.add(where.ge(Case.REPORT_DATE, DateHelper.getEpiWeekStart(criteria.getEpiWeekFrom()))); + where.and(); + where.ge(Case.REPORT_DATE, DateHelper.getEpiWeekStart(criteria.getEpiWeekFrom())); } + if (criteria.getEpiWeekTo() != null) { - whereStatements.add(where.le(Case.REPORT_DATE, DateHelper.getEpiWeekEnd(criteria.getEpiWeekTo()))); + where.and(); + where.le(Case.REPORT_DATE, DateHelper.getEpiWeekEnd(criteria.getEpiWeekTo())); } + if (criteria.getCaseOrigin() != null) { - whereStatements.add(where.eq(Case.CASE_ORIGIN, criteria.getCaseOrigin())); + where.and(); + where.eq(Case.CASE_ORIGIN, criteria.getCaseOrigin()); } + if (!StringUtils.isEmpty(criteria.getTextFilter())) { String[] textFilters = criteria.getTextFilter().split("\\s+"); for (String filter : textFilters) { String textFilter = "%" + filter.toLowerCase() + "%"; if (!StringUtils.isEmpty(textFilter)) { - whereStatements.add( - where.or( - where.raw(Case.TABLE_NAME + "." + Case.UUID + " LIKE '" + textFilter.replaceAll("'", "''") + "'"), - where.raw(Case.TABLE_NAME + "." + Case.EPID_NUMBER + " LIKE '" + textFilter.replaceAll("'", "''") + "'"), - where.raw(Case.TABLE_NAME + "." + Case.EXTERNAL_ID + " LIKE '" + textFilter.replaceAll("'", "''") + "'"), - where.raw(Person.TABLE_NAME + "." + Person.FIRST_NAME + " LIKE '" + textFilter.replaceAll("'", "''") + "'"), - where.raw(Person.TABLE_NAME + "." + Person.LAST_NAME + " LIKE '" + textFilter.replaceAll("'", "''") + "'"))); + where.and(); + where.or( + where.raw(Case.TABLE_NAME + "." + Case.UUID + " LIKE '" + textFilter.replaceAll("'", "''") + "'"), + where.raw(Case.TABLE_NAME + "." + Case.EPID_NUMBER + " LIKE '" + textFilter.replaceAll("'", "''") + "'"), + where.raw(Case.TABLE_NAME + "." + Case.EXTERNAL_ID + " LIKE '" + textFilter.replaceAll("'", "''") + "'"), + where.raw(Person.TABLE_NAME + "." + Person.FIRST_NAME + " LIKE '" + textFilter.replaceAll("'", "''") + "'"), + where.raw(Person.TABLE_NAME + "." + Person.LAST_NAME + " LIKE '" + textFilter.replaceAll("'", "''") + "'")); } } } - if (!whereStatements.isEmpty()) { - Where whereStatement = where.and(whereStatements.size()); - queryBuilder.setWhere(whereStatement); - } - queryBuilder = queryBuilder.leftJoin(personQueryBuilder); - return queryBuilder; + return where; } public static Region getRegionWithFallback(Case caze) { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/Contact.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/Contact.java index a28196d66b1..9102367b19f 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/Contact.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/Contact.java @@ -18,10 +18,6 @@ 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 java.util.Date; import javax.persistence.Column; @@ -29,6 +25,10 @@ import javax.persistence.EnumType; import javax.persistence.Enumerated; +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.VaccinationStatus; import de.symeda.sormas.api.contact.ContactCategory; @@ -92,6 +92,12 @@ public class Contact extends PseudonymizableAdo { public static final String HEALTH_CONDITIONS = "healthConditions"; public static final String VACCINATION_STATUS = "vaccinationStatus"; + public static final String REGION = "region_id"; + + public static final String DISTRICT = "district_id"; + + public static final String COMMUNITY = "community_id"; + @DatabaseField(dataType = DataType.DATE_LONG, canBeNull = true) private Date reportDateTime; @DatabaseField(foreign = true, foreignAutoRefresh = true) diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/ContactCriteria.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/ContactCriteria.java index f06b849b7b7..6d8b1c2dd5a 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/ContactCriteria.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/ContactCriteria.java @@ -33,6 +33,8 @@ public class ContactCriteria implements Serializable { private Date reportDateTo; private Case caze; + private Boolean includeContactsFromOtherJurisdictions = Boolean.FALSE; + public String getTextFilter() { return textFilter; } @@ -87,6 +89,14 @@ public ContactCriteria setReportDateTo(Date reportDateTo) { return this; } + public Boolean getIncludeContactsFromOtherJurisdictions() { + return includeContactsFromOtherJurisdictions; + } + + public void setIncludeContactsFromOtherJurisdictions(Boolean includeContactsFromOtherJurisdictions) { + this.includeContactsFromOtherJurisdictions = includeContactsFromOtherJurisdictions; + } + public Case getCaze() { return caze; } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/ContactDao.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/ContactDao.java index 4e799032db6..b8ed03626db 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/ContactDao.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/ContactDao.java @@ -34,6 +34,7 @@ import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.contact.ContactProximity; import de.symeda.sormas.api.contact.FollowUpStatus; +import de.symeda.sormas.api.user.JurisdictionLevel; import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.app.backend.caze.Case; import de.symeda.sormas.app.backend.clinicalcourse.HealthConditions; @@ -44,7 +45,11 @@ import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.backend.epidata.EpiData; import de.symeda.sormas.app.backend.exposure.Exposure; +import de.symeda.sormas.app.backend.facility.Facility; import de.symeda.sormas.app.backend.person.Person; +import de.symeda.sormas.app.backend.pointofentry.PointOfEntry; +import de.symeda.sormas.app.backend.region.Community; +import de.symeda.sormas.app.backend.region.District; import de.symeda.sormas.app.backend.task.Task; import de.symeda.sormas.app.backend.user.User; import de.symeda.sormas.app.backend.visit.Visit; @@ -191,53 +196,159 @@ public List queryByCriteria(ContactCriteria criteria, long offset, long } } - private QueryBuilder buildQueryBuilder(ContactCriteria criteria) throws SQLException { + private QueryBuilder buildQueryBuilder(ContactCriteria contactCriteria) throws SQLException { QueryBuilder queryBuilder = queryBuilder(); - QueryBuilder personQueryBuilder = DatabaseHelper.getPersonDao().queryBuilder(); - List> whereStatements = new ArrayList<>(); - Where where = queryBuilder.where(); - whereStatements.add(where.eq(AbstractDomainObject.SNAPSHOT, false)); + QueryBuilder caseQueryBuilder = DatabaseHelper.getCaseDao().queryBuilder(); + queryBuilder.join(Contact.CASE_UUID, Case.UUID, caseQueryBuilder, QueryBuilder.JoinType.LEFT, QueryBuilder.JoinWhereOperation.AND); + + Where where = queryBuilder.where().eq(AbstractDomainObject.SNAPSHOT, false); + + // Only use user filter if no restricting case is specified + if (contactCriteria.getIncludeContactsFromOtherJurisdictions().equals(false)) { + where.and(); + createJurisdictionFilterForCase(where); + where.or(); + createJurisdictionFilter(where); + } + + if (contactCriteria != null) { + createCriteriaFilter(where, contactCriteria); + } + + queryBuilder.setWhere(where); + return queryBuilder; + } + + public Where createJurisdictionFilterForCase(Where where) { + List> whereJurisdictionFilterStatements = new ArrayList<>(); + + User currentUser = ConfigProvider.getUser(); + if (currentUser == null) { + return null; + } + + final JurisdictionLevel jurisdictionLevel = currentUser.getJurisdictionLevel(); + + switch (jurisdictionLevel) { + case DISTRICT: + District district = currentUser.getDistrict(); + if (district != null) { + whereJurisdictionFilterStatements.add( + where.or( + where.raw(Case.TABLE_NAME + "." + Case.DISTRICT + "= '" + district + "'"), + where.raw(Case.TABLE_NAME + "." + Case.RESPONSIBLE_DISTRICT + "= '" + district.getId() + "'"))); + } + break; + + case HEALTH_FACILITY: + Facility healthFacility = currentUser.getHealthFacility(); + if (healthFacility != null) { + whereJurisdictionFilterStatements.add(where.raw(Case.TABLE_NAME + "." + Case.HEALTH_FACILITY + "= '" + healthFacility + "'")); + } + break; + + case COMMUNITY: + Community community = currentUser.getCommunity(); + if (community != null) { + whereJurisdictionFilterStatements.add( + where.or( + where.raw(Case.TABLE_NAME + "." + Case.COMMUNITY + "= '" + community + "'"), + where.raw(Case.TABLE_NAME + "." + Case.RESPONSIBLE_COMMUNITY + "= '" + community.getId() + "'"))); + } + break; + + case POINT_OF_ENTRY: + PointOfEntry pointOfEntry = currentUser.getPointOfEntry(); + if (pointOfEntry != null) { + whereJurisdictionFilterStatements.add(where.raw(Case.TABLE_NAME + "." + Case.POINT_OF_ENTRY + "= '" + pointOfEntry.getId() + "'")); + } + break; + default: + } + + if (!whereJurisdictionFilterStatements.isEmpty()) { + where.or(whereJurisdictionFilterStatements.size()); + } + return where; + } + + public Where createJurisdictionFilter(Where where) throws SQLException { + List> whereUserFilterStatements = new ArrayList<>(); + + User currentUser = ConfigProvider.getUser(); + if (currentUser == null) { + return null; + } + + final JurisdictionLevel jurisdictionLevel = currentUser.getJurisdictionLevel(); + + switch (jurisdictionLevel) { + case DISTRICT: + District district = currentUser.getDistrict(); + if (district != null) { + whereUserFilterStatements.add(where.eq(Contact.DISTRICT, currentUser.getDistrict().getId())); + } + break; + + case COMMUNITY: + Community community = currentUser.getCommunity(); + if (community != null) { + whereUserFilterStatements.add(where.eq(Contact.COMMUNITY, currentUser.getCommunity().getId())); + } + break; + default: + } + + if (!whereUserFilterStatements.isEmpty()) { + where.or(whereUserFilterStatements.size()); + } + + return where; + } + + public Where createCriteriaFilter(Where where, ContactCriteria criteria) throws SQLException { if (criteria.getCaze() != null) { - whereStatements.add(where.eq(Contact.CASE_UUID, criteria.getCaze().getUuid())); + where.and(); + where.eq(Contact.CASE_UUID, criteria.getCaze().getUuid()); } else { if (criteria.getFollowUpStatus() != null) { - whereStatements.add(where.eq(Contact.FOLLOW_UP_STATUS, criteria.getFollowUpStatus())); + where.and(); + where.eq(Contact.FOLLOW_UP_STATUS, criteria.getFollowUpStatus()); } if (criteria.getContactClassification() != null) { - whereStatements.add(where.eq(Contact.CONTACT_CLASSIFICATION, criteria.getContactClassification())); + where.and(); + where.eq(Contact.CONTACT_CLASSIFICATION, criteria.getContactClassification()); } if (criteria.getDisease() != null) { - whereStatements.add(where.eq("caseDisease", criteria.getDisease())); + where.and(); + where.eq("caseDisease", criteria.getDisease()); } if (criteria.getReportDateFrom() != null) { - whereStatements.add(where.ge(Contact.REPORT_DATE_TIME, DateHelper.getStartOfDay(criteria.getReportDateFrom()))); + where.and(); + where.ge(Contact.REPORT_DATE_TIME, DateHelper.getStartOfDay(criteria.getReportDateFrom())); } if (criteria.getReportDateTo() != null) { - whereStatements.add(where.le(Contact.REPORT_DATE_TIME, DateHelper.getEndOfDay(criteria.getReportDateTo()))); + where.and(); + where.le(Contact.REPORT_DATE_TIME, DateHelper.getEndOfDay(criteria.getReportDateTo())); } if (!StringUtils.isEmpty(criteria.getTextFilter())) { String[] textFilters = criteria.getTextFilter().split("\\s+"); for (String filter : textFilters) { String textFilter = "%" + filter.toLowerCase() + "%"; if (!StringUtils.isEmpty(textFilter)) { - whereStatements.add( - where.or( - where.raw(Contact.TABLE_NAME + "." + Contact.UUID + " LIKE '" + textFilter.replaceAll("'", "''") + "'"), - where.raw(Person.TABLE_NAME + "." + Person.FIRST_NAME + " LIKE '" + textFilter.replaceAll("'", "''") + "'"), - where.raw(Person.TABLE_NAME + "." + Person.LAST_NAME + " LIKE '" + textFilter.replaceAll("'", "''") + "'"))); + where.and(); + where.or( + where.raw(Contact.TABLE_NAME + "." + Contact.UUID + " LIKE '" + textFilter.replaceAll("'", "''") + "'"), + where.raw(Person.TABLE_NAME + "." + Person.FIRST_NAME + " LIKE '" + textFilter.replaceAll("'", "''") + "'"), + where.raw(Person.TABLE_NAME + "." + Person.LAST_NAME + " LIKE '" + textFilter.replaceAll("'", "''") + "'")); } } } } - if (!whereStatements.isEmpty()) { - Where whereStatement = where.and(whereStatements.size()); - queryBuilder.setWhere(whereStatement); - } - queryBuilder = queryBuilder.leftJoin(personQueryBuilder); - return queryBuilder; + return where; } public void deleteContactAndAllDependingEntities(String contactUuid) throws SQLException { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/list/CaseListActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/list/CaseListActivity.java index bb138466203..b10beb4958c 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/list/CaseListActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/list/CaseListActivity.java @@ -20,18 +20,14 @@ import java.util.Calendar; import java.util.Date; import java.util.List; -import java.util.Random; import android.content.Context; import android.os.Bundle; import android.view.Menu; import android.view.View; -import android.widget.AdapterView; - import androidx.databinding.DataBindingUtil; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.RecyclerView; - import de.symeda.sormas.api.caze.CaseClassification; import de.symeda.sormas.api.caze.CaseOrigin; import de.symeda.sormas.api.caze.CaseOutcome; @@ -213,6 +209,7 @@ public void addFiltersToPageMenu() { model.getCaseCriteria().setEpiWeekFrom(null); model.getCaseCriteria().setEpiWeekTo(null); model.getCaseCriteria().setCaseOrigin(null); + model.getCaseCriteria().setIncludeCasesFromOtherJurisdictions(false); filterBinding.invalidateAll(); filterBinding.executePendingBindings(); model.notifyCriteriaUpdated(); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/list/CaseListViewModel.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/list/CaseListViewModel.java index be3f864a19c..b8cac4d1ff8 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/list/CaseListViewModel.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/list/CaseListViewModel.java @@ -88,6 +88,7 @@ public void loadRange(@NonNull LoadRangeParams params, @NonNull LoadRangeCallbac List cases = DatabaseHelper.getCaseDao().queryByCriteria(caseCriteria, params.startPosition, params.loadSize); callback.onResult(cases); } + } public static class CaseDataFactory extends DataSource.Factory { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/component/controls/FilterCheckBoxField.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/component/controls/FilterCheckBoxField.java new file mode 100644 index 00000000000..f46810847a4 --- /dev/null +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/component/controls/FilterCheckBoxField.java @@ -0,0 +1,63 @@ +package de.symeda.sormas.app.component.controls; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; + +import de.symeda.sormas.app.R; + +public class FilterCheckBoxField extends ControlCheckBoxField { + + public FilterCheckBoxField(Context context) { + super(context); + } + + public FilterCheckBoxField(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public FilterCheckBoxField(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + protected void inflateView(Context context, AttributeSet attrs, int defStyle) { + LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + if (inflater != null) { + inflater.inflate(R.layout.filter_checkbox_field_layout, this); + } else { + throw new RuntimeException("Unable to inflate layout in " + getClass().getName()); + } + } + + @Override + public void enableErrorState(String errorMessage) { + //Do nothing + } + + @Override + public void enableErrorState(int messageResourceId) { + //Do nothing + } + + @Override + public void disableErrorState() { + //Do nothing + } + + @Override + public void enableWarningState(int messageResourceId) { + //Do nothing + } + + @Override + public void enableWarningState(String message) { + //Do nothing + } + + @Override + public void disableWarningState() { + //Do nothing + } +} diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/list/ContactListActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/list/ContactListActivity.java index 8c87d5f4ce3..b7e035cded1 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/list/ContactListActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/list/ContactListActivity.java @@ -16,13 +16,11 @@ package de.symeda.sormas.app.contact.list; import java.util.List; -import java.util.Random; import android.content.Context; import android.os.Bundle; import android.view.Menu; import android.view.View; -import android.widget.AdapterView; import androidx.databinding.DataBindingUtil; import androidx.lifecycle.ViewModelProvider; @@ -195,6 +193,7 @@ public void addFiltersToPageMenu() { model.getContactCriteria().setDisease(null); model.getContactCriteria().setReportDateFrom(null); model.getContactCriteria().setReportDateTo(null); + model.getContactCriteria().setIncludeContactsFromOtherJurisdictions(false); filterBinding.invalidateAll(); filterBinding.executePendingBindings(); model.notifyCriteriaUpdated(); diff --git a/sormas-app/app/src/main/res/layout/filter_case_list_layout.xml b/sormas-app/app/src/main/res/layout/filter_case_list_layout.xml index 40235787cd5..4eb0dc483e1 100644 --- a/sormas-app/app/src/main/res/layout/filter_case_list_layout.xml +++ b/sormas-app/app/src/main/res/layout/filter_case_list_layout.xml @@ -25,6 +25,7 @@ + @@ -91,6 +92,12 @@ app:value="@={criteria.epiWeekTo}" style="@style/ControlSingleColumnStyle" /> + + - \ No newline at end of file + diff --git a/sormas-app/app/src/main/res/layout/filter_checkbox_field_layout.xml b/sormas-app/app/src/main/res/layout/filter_checkbox_field_layout.xml new file mode 100644 index 00000000000..fe5e8d1741c --- /dev/null +++ b/sormas-app/app/src/main/res/layout/filter_checkbox_field_layout.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + diff --git a/sormas-app/app/src/main/res/layout/filter_contact_list_layout.xml b/sormas-app/app/src/main/res/layout/filter_contact_list_layout.xml index 4dffc5a23e0..5672556649f 100644 --- a/sormas-app/app/src/main/res/layout/filter_contact_list_layout.xml +++ b/sormas-app/app/src/main/res/layout/filter_contact_list_layout.xml @@ -24,6 +24,7 @@ + @@ -76,6 +77,12 @@ app:value="@={criteria.reportDateTo}" style="@style/ControlSingleColumnStyle" /> + + - \ No newline at end of file + diff --git a/sormas-app/app/src/main/res/values/colors.xml b/sormas-app/app/src/main/res/values/colors.xml index aaee36479ef..a7e246d9bba 100644 --- a/sormas-app/app/src/main/res/values/colors.xml +++ b/sormas-app/app/src/main/res/values/colors.xml @@ -55,6 +55,7 @@ #ff6691c4 #1A6691c4 #806691c4 + #CDD8EC #ffcdd8ec #66cdd8ec #FF374b5a diff --git a/sormas-app/app/src/main/res/values/dimens.xml b/sormas-app/app/src/main/res/values/dimens.xml index bf32d343269..f015359ef87 100644 --- a/sormas-app/app/src/main/res/values/dimens.xml +++ b/sormas-app/app/src/main/res/values/dimens.xml @@ -401,6 +401,8 @@ 54dp 54dp + 30dp + 30dp @dimen/slimControlHeight diff --git a/sormas-app/app/src/main/res/values/styles.xml b/sormas-app/app/src/main/res/values/styles.xml index 55e7e4327dc..82bd6125add 100644 --- a/sormas-app/app/src/main/res/values/styles.xml +++ b/sormas-app/app/src/main/res/values/styles.xml @@ -99,7 +99,6 @@ - + + + @@ -346,6 +358,21 @@ ?android:attr/listChoiceIndicatorMultiple + + + +