From 344dc8dc3fee7a83b9a243ed93467a6bdc46a9a0 Mon Sep 17 00:00:00 2001 From: Katharina Kaiser Date: Mon, 15 Dec 2025 15:40:38 +0100 Subject: [PATCH] Fix: Determine workflow configuration by checking group assignment The `isWorkflowConfigured` method previously relied on comparing the workflow group object's name against expected string values. This caused issues with migrated data where workflow group names did not follow the naming conventions of the new DSpace version, leading to incorrect workflow configuration detection. This commit updates the implementation to be independent of group names entirely. It now directly checks for the existence of a configured workflow group object that is assigned to a specific collection's workflow step. This ensures correct workflow status determination for both newly created and migrated collections. A new test class with integration tests is added to test the `XmlWorkflowItemService.isWorkflowConfigured` method. fixes #534 Signed-off-by: Katharina Kaiser --- .../dspace/workflow/WorkflowItemService.java | 4 +- .../XmlWorkflowItemServiceImpl.java | 16 ++- .../xmlworkflow/XmlWorkflowItemServiceIT.java | 118 ++++++++++++++++++ 3 files changed, 130 insertions(+), 8 deletions(-) create mode 100644 dspace-api/src/test/java/org/dspace/xmlworkflow/XmlWorkflowItemServiceIT.java diff --git a/dspace-api/src/main/java/org/dspace/workflow/WorkflowItemService.java b/dspace-api/src/main/java/org/dspace/workflow/WorkflowItemService.java index 7c30a58c89bc..51764782296b 100644 --- a/dspace-api/src/main/java/org/dspace/workflow/WorkflowItemService.java +++ b/dspace-api/src/main/java/org/dspace/workflow/WorkflowItemService.java @@ -123,9 +123,7 @@ public void deleteByCollection(Context context, Collection collection) * @param collection the collection to check * @return true if the given collection has a workflow configured, * false otherwise - * @throws SQLException An exception that provides information on a database - * access error or other errors. */ - public boolean isWorkflowConfigured(Context context, Collection collection) throws SQLException; + boolean isWorkflowConfigured(Context context, Collection collection); } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/XmlWorkflowItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/XmlWorkflowItemServiceImpl.java index 848842e3b5e8..4b3fe9f97b1f 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/XmlWorkflowItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/XmlWorkflowItemServiceImpl.java @@ -16,6 +16,7 @@ import org.dspace.authorize.AuthorizeException; import org.dspace.content.Collection; import org.dspace.content.Item; +import org.dspace.content.service.CollectionService; import org.dspace.content.service.ItemService; import org.dspace.core.Context; import org.dspace.core.LogHelper; @@ -55,6 +56,8 @@ public class XmlWorkflowItemServiceImpl implements XmlWorkflowItemService { protected WorkflowItemRoleService workflowItemRoleService; @Autowired(required = true) protected GroupService groupService; + @Autowired(required = true) + protected CollectionService collectionService; /* * The current step in the workflow system in which this workflow item is present @@ -218,16 +221,19 @@ public void move(Context context, XmlWorkflowItem inProgressSubmission, Collecti * Check if a WORKFLOW_ROLE group related to the given collection exists. */ @Override - public boolean isWorkflowConfigured(Context context, Collection collection) throws SQLException { + public boolean isWorkflowConfigured(Context context, Collection collection) { if (collection == null) { return false; } - String groupName = "COLLECTION_" + collection.getID() + "_WORKFLOW_ROLE"; - Group workflowRoleGroup = groupService.findByNamePrefix(context, groupName); - - return workflowRoleGroup != null && !groupService.isEmpty(workflowRoleGroup); + for (int i = 1; i <= 3; i++) { + Group workflowGroup = collectionService.getWorkflowGroup(context, collection, i); + if (workflowGroup != null) { + return !groupService.isEmpty(workflowGroup); + } + } + return false; } } diff --git a/dspace-api/src/test/java/org/dspace/xmlworkflow/XmlWorkflowItemServiceIT.java b/dspace-api/src/test/java/org/dspace/xmlworkflow/XmlWorkflowItemServiceIT.java new file mode 100644 index 000000000000..7007dc60553f --- /dev/null +++ b/dspace-api/src/test/java/org/dspace/xmlworkflow/XmlWorkflowItemServiceIT.java @@ -0,0 +1,118 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.xmlworkflow; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.dspace.AbstractIntegrationTestWithDatabase; +import org.dspace.authorize.factory.AuthorizeServiceFactory; +import org.dspace.authorize.service.AuthorizeService; +import org.dspace.builder.CollectionBuilder; +import org.dspace.builder.CommunityBuilder; +import org.dspace.builder.EPersonBuilder; +import org.dspace.builder.GroupBuilder; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.eperson.EPerson; +import org.dspace.eperson.Group; +import org.dspace.eperson.factory.EPersonServiceFactory; +import org.dspace.eperson.service.GroupService; +import org.dspace.services.ConfigurationService; +import org.dspace.services.factory.DSpaceServicesFactory; +import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory; +import org.dspace.xmlworkflow.storedcomponents.service.XmlWorkflowItemService; +import org.junit.Test; + +/** + * IT for {@link org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItemServiceImpl} + * + * @author K.Kaiser (TU Wien) + */ +public class XmlWorkflowItemServiceIT extends AbstractIntegrationTestWithDatabase { + + protected XmlWorkflowItemService xmlWorkflowItemService = XmlWorkflowServiceFactory.getInstance() + .getXmlWorkflowItemService(); + protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); + protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); + protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); + + + @Test + public void isCollectionWithWorkflowConfiguredWithNewGroupName() throws Exception { + context.turnOffAuthorisationSystem(); + EPerson submitter = EPersonBuilder.createEPerson(context).withEmail("submitter@example.org").build(); + context.setCurrentUser(submitter); + Community community = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Collection colWithWorkflow = CollectionBuilder.createCollection(context, community) + .withName("Collection WITH workflow") + .withWorkflowGroup("editor", submitter) + .build(); + context.restoreAuthSystemState(); + String expectedGroupName = "COLLECTION_" + colWithWorkflow.getID() + "_WORKFLOW_ROLE_editor"; + assertEquals("Expecting automatic group name", expectedGroupName, + colWithWorkflow.getWorkflowStep2(context).getName()); + assertTrue("Workflow is configured with automatic group name and with a member", + xmlWorkflowItemService.isWorkflowConfigured(context, colWithWorkflow)); + } + + @Test + public void isCollectionWithWorkflowConfiguredWithOldGroupName() throws Exception { + context.turnOffAuthorisationSystem(); + EPerson submitter = EPersonBuilder.createEPerson(context).withEmail("submitter@example.org").build(); + context.setCurrentUser(submitter); + Group reviewer = GroupBuilder.createGroup(context).withName("Reviewers").addMember(submitter).build(); + Community community = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Collection colWithWorkflow = CollectionBuilder.createCollection(context, community) + .withName("Collection WITH workflow") + .build(); + colWithWorkflow.setWorkflowGroup(context, 1, reviewer); + context.restoreAuthSystemState(); + assertEquals("Group name of Workflow Step 1 must be 'Reviewers'", "Reviewers", + colWithWorkflow.getWorkflowStep1(context).getName()); + assertTrue("Workflow with group members must be considered a workflow", + xmlWorkflowItemService.isWorkflowConfigured(context, colWithWorkflow)); + } + + @Test + public void isCollectionWithoutWorkflowConfiguredWithEmptyGroup() throws Exception { + context.turnOffAuthorisationSystem(); + Group editor = GroupBuilder.createGroup(context).withName("Editors").build(); + Community community = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Collection colWithWorkflow = CollectionBuilder.createCollection(context, community) + .withName("Collection WITH workflow, but empty group") + .build(); + colWithWorkflow.setWorkflowGroup(context, 2, editor); + context.restoreAuthSystemState(); + assertEquals("Group name of Workflow Step 2 must be 'Editors'", "Editors", + colWithWorkflow.getWorkflowStep2(context).getName()); + assertFalse("Workflow without group members must not be considered a workflow", + xmlWorkflowItemService.isWorkflowConfigured(context, colWithWorkflow)); + } + + @Test + public void isCollectionWithoutWorkflowConfigured() { + context.turnOffAuthorisationSystem(); + Community community = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Collection colWithoutWorkflow = CollectionBuilder.createCollection(context, community) + .withName("Collection WITHOUT workflow") + .build(); + context.restoreAuthSystemState(); + assertFalse("Collection without a workflow configured", + xmlWorkflowItemService.isWorkflowConfigured(context, colWithoutWorkflow)); + } +}