From dc4c85d77bde917c0067deb1539e1745a99fce18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9=20Strysewske?= Date: Thu, 8 Dec 2022 15:25:20 +0100 Subject: [PATCH] #4060 - Manual archiving of tasks --- .../de/symeda/sormas/api/task/TaskFacade.java | 4 ++ .../de/symeda/sormas/api/user/UserRight.java | 2 + .../src/main/resources/strings.properties | 6 ++- .../sormas/backend/task/TaskFacadeEjb.java | 13 ++++- .../sormas/backend/task/TaskService.java | 13 +++++ .../src/main/resources/sql/sormas_schema.sql | 13 +++++ .../symeda/sormas/ui/task/TaskController.java | 52 +++++++++++++++++++ 7 files changed, 100 insertions(+), 3 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskFacade.java index f1be4cd70f1..6d2d5f60ea0 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskFacade.java @@ -76,6 +76,10 @@ public interface TaskFacade { void updateArchived(List taskUuids, boolean archived); + void updateArchived(String taskUuid, boolean archived); + + boolean isArchived(String taskUuid); + List getArchivedUuidsSince(Date since); List getObsoleteUuidsSince(Date since); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRight.java b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRight.java index 95eaa41f5fc..fb0eceefd08 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRight.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRight.java @@ -110,6 +110,7 @@ public enum UserRight { TASK_DELETE(UserRightGroup.TASK, UserRight._TASK_VIEW), TASK_EXPORT(UserRightGroup.TASK, UserRight._TASK_VIEW), TASK_ASSIGN(UserRightGroup.TASK, UserRight._TASK_EDIT), + TASK_ARCHIVE(UserRightGroup.TASK, UserRight._TASK_VIEW), ACTION_CREATE(UserRightGroup.EVENT, UserRight._EVENT_VIEW), ACTION_DELETE(UserRightGroup.EVENT, UserRight._EVENT_VIEW, UserRight._DOCUMENT_DELETE), @@ -317,6 +318,7 @@ public enum UserRight { public static final String _TASK_ASSIGN = "TASK_ASSIGN"; public static final String _TASK_DELETE = "TASK_DELETE"; public static final String _TASK_EXPORT = "TASK_EXPORT"; + public static final String _TASK_ARCHIVE = "TASK_ARCHIVE"; public static final String _ACTION_CREATE = "ACTION_CREATE"; public static final String _ACTION_DELETE = "ACTION_DELETE"; public static final String _ACTION_EDIT = "ACTION_EDIT"; diff --git a/sormas-api/src/main/resources/strings.properties b/sormas-api/src/main/resources/strings.properties index f0601a705f9..0013c413d63 100644 --- a/sormas-api/src/main/resources/strings.properties +++ b/sormas-api/src/main/resources/strings.properties @@ -130,8 +130,8 @@ confirmationArchiveEvent = Are you sure you want to archive this event? This wil confirmationArchiveEvents = Are you sure you want to archive all %d selected events? confirmationArchiveEventParticipant = Are you sure you want to archive this event participant? This will not remove it from the system or any statistics, but only hide it from the list of event participants. confirmationArchiveImmunization = Are you sure you want to archive this immunization? This will not remove it from the system or any statistics, but only hide it from the normal immunization directory. -confirmationArchiveTask = Are you sure you want to archive all %d selected tasks? -confirmationArchiveTasks = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. +confirmationArchiveTask = Are you sure you want to archive this task? This will not remove it from the system or any statistics, but only hide it from the normal task management. +confirmationArchiveTasks = Are you sure you want to archive all %d selected tasks? confirmationArchiveTravelEntry = Are you sure you want to archive this travel entry? This will not remove it from the system or any statistics, but only hide it from the normal travel entry directory. confirmationArchiveEventGroup = Are you sure you want to archive this event group? This will not remove it from the system or any statistics, but only hide it from the normal event group directory. confirmationCancelFollowUp = Are you sure you want to cancel the follow-up of all %d selected contacts? @@ -1128,8 +1128,10 @@ messageSpecifyRowAttribute = Please specify the row attribute you have chosen fo messageSymptomsHint = Please tick an answer for ALL symptoms indicating if they occurred at any point in time during this illness: messageSymptomsVisitHint = Please tick an answer for ALL symptoms indicating if they were present at the time of this visit: messageTasksArchived = All selected tasks have been archived +messageTaskArchived = The task has been archived messageTasksEdited = All tasks have been edited messageTasksDearchived = All selected tasks have been de-archived +messageTaskDearchived = The task has been de-archived messageTasksDeleted = All selected tasks have been deleted messageTemplateNotAvailable = The template file is not available. Please contact an admin and tell them about this issue. messageTravelEntrySaved = Travel entry data saved diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/task/TaskFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/task/TaskFacadeEjb.java index b2dac4cc3f7..27703e92557 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/task/TaskFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/task/TaskFacadeEjb.java @@ -997,11 +997,22 @@ private void validate(TaskDto task) throws ValidationRuntimeException { } @Override - @RightsAllowed(UserRight._TASK_EDIT) + @RightsAllowed(UserRight._TASK_ARCHIVE) public void updateArchived(List taskUuids, boolean archived) { IterableHelper.executeBatched(taskUuids, ARCHIVE_BATCH_SIZE, e -> taskService.updateArchived(e, archived)); } + @Override + @RightsAllowed(UserRight._TASK_ARCHIVE) + public void updateArchived(String taskUuid, boolean archived) { + taskService.updateArchived(Collections.singletonList(taskUuid), archived); + } + + @Override + public boolean isArchived(String taskUuid) { + return taskService.isArchived(taskUuid); + } + @Override public List getArchivedUuidsSince(Date since) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/task/TaskService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/task/TaskService.java index d2e726bfafd..f93749799d1 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/task/TaskService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/task/TaskService.java @@ -63,6 +63,7 @@ import de.symeda.sormas.backend.caze.CaseQueryContext; import de.symeda.sormas.backend.caze.CaseService; import de.symeda.sormas.backend.caze.CaseUserFilterCriteria; +import de.symeda.sormas.backend.common.AbstractDomainObject; import de.symeda.sormas.backend.common.AdoServiceWithUserFilterAndJurisdiction; import de.symeda.sormas.backend.common.CriteriaBuilderHelper; import de.symeda.sormas.backend.common.JurisdictionFlagsService; @@ -725,6 +726,18 @@ public void updateArchived(List taskUuids, boolean archived) { em.createQuery(cu).executeUpdate(); } + public boolean isArchived(String taskUuid) { + + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(Long.class); + Root from = cq.from(getElementClass()); + + cq.where(cb.and(cb.equal(from.get(Task.ARCHIVED), true), cb.equal(from.get(AbstractDomainObject.UUID), taskUuid))); + cq.select(cb.count(from)); + long count = em.createQuery(cq).getSingleResult(); + return count > 0; + } + @Override public TaskJurisdictionFlagsDto getJurisdictionFlags(Task entity) { diff --git a/sormas-backend/src/main/resources/sql/sormas_schema.sql b/sormas-backend/src/main/resources/sql/sormas_schema.sql index e267770fe87..fea9bca0898 100644 --- a/sormas-backend/src/main/resources/sql/sormas_schema.sql +++ b/sormas-backend/src/main/resources/sql/sormas_schema.sql @@ -12243,4 +12243,17 @@ ALTER TABLE externalmessage_history ADD COLUMN reportmessageid varchar(255); INSERT INTO schema_version (version_number, comment) VALUES (503, '[DEMIS2SORMAS] Add a Field for the NotificationBundleId to the External Message and map it when processing #10826'); +-- 2022-12-08 Add task archive user right #4060 +INSERT INTO userroles_userrights (userrole_id, userright) SELECT id, 'TASK_ARCHIVE' FROM public.userroles WHERE userroles.linkeddefaultuserrole = 'ADMIN'; +INSERT INTO userroles_userrights (userrole_id, userright) SELECT id, 'TASK_ARCHIVE' FROM public.userroles WHERE userroles.linkeddefaultuserrole = 'NATIONAL_USER'; +INSERT INTO userroles_userrights (userrole_id, userright) SELECT id, 'TASK_ARCHIVE' FROM public.userroles WHERE userroles.linkeddefaultuserrole = 'ADMIN_SUPERVISOR'; +INSERT INTO userroles_userrights (userrole_id, userright) SELECT id, 'TASK_ARCHIVE' FROM public.userroles WHERE userroles.linkeddefaultuserrole = 'SURVEILLANCE_SUPERVISOR'; +INSERT INTO userroles_userrights (userrole_id, userright) SELECT id, 'TASK_ARCHIVE' FROM public.userroles WHERE userroles.linkeddefaultuserrole = 'CONTACT_SUPERVISOR'; +INSERT INTO userroles_userrights (userrole_id, userright) SELECT id, 'TASK_ARCHIVE' FROM public.userroles WHERE userroles.linkeddefaultuserrole = 'CASE_SUPERVISOR'; +INSERT INTO userroles_userrights (userrole_id, userright) SELECT id, 'TASK_ARCHIVE' FROM public.userroles WHERE userroles.linkeddefaultuserrole = 'NATIONAL_CLINICIAN'; +INSERT INTO userroles_userrights (userrole_id, userright) SELECT id, 'TASK_ARCHIVE' FROM public.userroles WHERE userroles.linkeddefaultuserrole = 'POE_SUPERVISOR'; +INSERT INTO userroles_userrights (userrole_id, userright) SELECT id, 'TASK_ARCHIVE' FROM public.userroles WHERE userroles.linkeddefaultuserrole = 'POE_NATIONAL_USER'; + +INSERT INTO schema_version (version_number, comment) VALUES (504, 'Add task archive user right #4060'); + -- *** Insert new sql commands BEFORE this line. Remember to always consider _history tables. *** diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/task/TaskController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/task/TaskController.java index 14d8106187c..acaefe4eef5 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/task/TaskController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/task/TaskController.java @@ -22,15 +22,19 @@ import java.util.stream.Collectors; import com.vaadin.server.Page; +import com.vaadin.ui.Alignment; +import com.vaadin.ui.Button; import com.vaadin.ui.Label; import com.vaadin.ui.Notification; import com.vaadin.ui.Notification.Type; import com.vaadin.ui.UI; import com.vaadin.ui.Window; +import com.vaadin.ui.themes.ValoTheme; import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.ReferenceDto; +import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Strings; import de.symeda.sormas.api.sample.SampleDto; @@ -41,7 +45,10 @@ import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.ui.ControllerProvider; import de.symeda.sormas.ui.UserProvider; +import de.symeda.sormas.ui.utils.ArchivingController; +import de.symeda.sormas.ui.utils.ButtonHelper; import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent; +import de.symeda.sormas.ui.utils.DirtyCheckPopup; import de.symeda.sormas.ui.utils.VaadinUiUtil; public class TaskController { @@ -136,6 +143,31 @@ public void edit(TaskIndexDto dto, Runnable callback, boolean editedFromTaskGrid callback.run(); }, I18nProperties.getString(Strings.entityTask)); } + + // Initialize 'Archive' button + if (UserProvider.getCurrent().hasUserRight(UserRight.TASK_ARCHIVE)) { + boolean archived = FacadeProvider.getTaskFacade().isArchived(dto.getUuid()); + Button archiveButton = ButtonHelper.createButton( + ArchivingController.ARCHIVE_DEARCHIVE_BUTTON_ID, + I18nProperties.getCaption(archived ? Captions.actionDearchiveCoreEntity : Captions.actionArchiveCoreEntity), + e -> { + if (editView.isDirty()) { + DirtyCheckPopup.show(editView, () -> archiveOrDearchive(newDto, !archived, () -> { + popupWindow.close(); + callback.run(); + })); + } else { + archiveOrDearchive(newDto, !archived, () -> { + popupWindow.close(); + callback.run(); + }); + } + }, + ValoTheme.BUTTON_LINK); + + editView.getButtonsPanel().addComponentAsFirst(archiveButton); + editView.getButtonsPanel().setComponentAlignment(archiveButton, Alignment.BOTTOM_LEFT); + } } private TaskDto createNewTask(TaskContext context, ReferenceDto entityRef) { @@ -211,6 +243,26 @@ public void showBulkTaskDataEditComponent(Collection sel editView.addDiscardListener(popupWindow::close); } + private void archiveOrDearchive(TaskDto task, boolean archive, Runnable callback) { + + VaadinUiUtil.showConfirmationPopup( + archive ? I18nProperties.getString(Strings.headingConfirmArchiving) : I18nProperties.getString(Strings.headingConfirmDearchiving), + new Label( + archive ? I18nProperties.getString(Strings.confirmationArchiveTask) : I18nProperties.getString(Strings.confirmationDearchiveTask)), + I18nProperties.getString(Strings.yes), + I18nProperties.getString(Strings.no), + null, + e -> { + if (Boolean.TRUE.equals(e)) { + FacadeProvider.getTaskFacade().updateArchived(task.getUuid(), archive); + callback.run(); + Notification.show(I18nProperties.getString(Strings.messageTasksArchived), Type.ASSISTIVE_NOTIFICATION); + } + + callback.run(); + }); + } + public void archiveAllSelectedItems(Collection selectedRows, Runnable callback) { if (selectedRows.size() == 0) {