From eb672a8166fdb2a612ccd4a726cc4373b5c85a2f Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Mon, 15 Dec 2025 06:37:01 -0800 Subject: [PATCH 1/6] Use WorkflowJob permission to check for ability to move a job --- api/src/org/labkey/api/data/ContainerManager.java | 8 ++++++-- .../src/org/labkey/query/controllers/QueryController.java | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/api/src/org/labkey/api/data/ContainerManager.java b/api/src/org/labkey/api/data/ContainerManager.java index d3afeddd020..3800ef6f4d4 100644 --- a/api/src/org/labkey/api/data/ContainerManager.java +++ b/api/src/org/labkey/api/data/ContainerManager.java @@ -77,6 +77,7 @@ import org.labkey.api.security.permissions.InsertPermission; import org.labkey.api.security.permissions.Permission; import org.labkey.api.security.permissions.ReadPermission; +import org.labkey.api.security.permissions.SampleWorkflowJobPermission; import org.labkey.api.security.roles.AuthorRole; import org.labkey.api.security.roles.ReaderRole; import org.labkey.api.security.roles.Role; @@ -2605,7 +2606,7 @@ private static Container getForPathAlias(String path) return ret.length == 0 ? null : ret[0]; } - public static Container getMoveTargetContainer(@Nullable String queryName, @NotNull Container sourceContainer, User user, @Nullable String targetIdOrPath, Errors errors) + public static Container getMoveTargetContainer(String schemaName, @Nullable String queryName, @NotNull Container sourceContainer, User user, @Nullable String targetIdOrPath, Errors errors) { if (targetIdOrPath == null) { @@ -2620,7 +2621,10 @@ public static Container getMoveTargetContainer(@Nullable String queryName, @NotN return null; } - if (!_targetContainer.hasPermission(user, InsertPermission.class)) + Class permClass = InsertPermission.class; + if (schemaName != null && schemaName.equalsIgnoreCase("workflow") && queryName != null && queryName.equalsIgnoreCase("job")) + permClass = SampleWorkflowJobPermission.class; + if (!_targetContainer.hasPermission(user, permClass)) { String _queryName = queryName == null ? "this table" : "'" + queryName + "'"; errors.reject(ERROR_GENERIC, "You do not have permission to move rows from " + _queryName + " to the target container: " + targetIdOrPath + "."); diff --git a/query/src/org/labkey/query/controllers/QueryController.java b/query/src/org/labkey/query/controllers/QueryController.java index da1f6703863..a25d7f875f7 100644 --- a/query/src/org/labkey/query/controllers/QueryController.java +++ b/query/src/org/labkey/query/controllers/QueryController.java @@ -4968,7 +4968,8 @@ public void validateForm(MoveRowsForm form, Errors errors) else { String queryName = json.optString(PROP_QUERY_NAME, null); - _targetContainer = ContainerManager.getMoveTargetContainer(queryName, getContainer(), getUser(), getTargetContainerProp(), errors); + String schemaName = json.optString(PROP_SCHEMA_NAME, null); + _targetContainer = ContainerManager.getMoveTargetContainer(schemaName, queryName, getContainer(), getUser(), getTargetContainerProp(), errors); } } } From 8512ec25b4d4ce584764e2b3d0565b335efc1e94 Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Tue, 16 Dec 2025 11:06:02 -0800 Subject: [PATCH 2/6] Throw UnauthorizedException instead of a generic error when the user doesn't have permission in the target container --- api/src/org/labkey/api/data/ContainerManager.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/api/src/org/labkey/api/data/ContainerManager.java b/api/src/org/labkey/api/data/ContainerManager.java index 3800ef6f4d4..8ad9432e469 100644 --- a/api/src/org/labkey/api/data/ContainerManager.java +++ b/api/src/org/labkey/api/data/ContainerManager.java @@ -2627,8 +2627,7 @@ public static Container getMoveTargetContainer(String schemaName, @Nullable Stri if (!_targetContainer.hasPermission(user, permClass)) { String _queryName = queryName == null ? "this table" : "'" + queryName + "'"; - errors.reject(ERROR_GENERIC, "You do not have permission to move rows from " + _queryName + " to the target container: " + targetIdOrPath + "."); - return null; + throw new UnauthorizedException("You do not have permission to move rows from " + _queryName + " to the target container: " + targetIdOrPath + "."); } if (!isValidTargetContainer(sourceContainer, _targetContainer)) From 4c688222a19394fa807dc43c3ddfb59fc953ef37 Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Wed, 17 Dec 2025 20:01:45 -0800 Subject: [PATCH 3/6] Add updateConatiner for list of identifiers --- api/src/org/labkey/api/exp/OntologyManager.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/api/src/org/labkey/api/exp/OntologyManager.java b/api/src/org/labkey/api/exp/OntologyManager.java index b30147543c8..4a5dae595da 100644 --- a/api/src/org/labkey/api/exp/OntologyManager.java +++ b/api/src/org/labkey/api/exp/OntologyManager.java @@ -928,7 +928,12 @@ public static void updateObjectPropertyOrder(User user, Container container, Str */ public static int updateContainer(Container targetContainer, User user, @NotNull String objectLSID) { - return Table.updateContainer(getTinfoObject(), "objectURI", List.of(objectLSID), targetContainer, user, false); + return updateContainer(targetContainer, user, List.of(objectLSID)); + } + + public static int updateContainer(Container targetContainer, User user, @NotNull List objectLSIDs) + { + return Table.updateContainer(getTinfoObject(), "objectURI", objectLSIDs, targetContainer, user, false); } /** From 3330bb9e3a10adc7862182016c6416cb9341afaa Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Wed, 17 Dec 2025 20:15:54 -0800 Subject: [PATCH 4/6] When moving comments also move their attachments --- .../announcements/api/AnnouncementServiceImpl.java | 3 ++- .../labkey/announcements/model/AnnouncementManager.java | 9 +++++++-- .../api/announcements/api/AnnouncementService.java | 5 +++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/announcements/src/org/labkey/announcements/api/AnnouncementServiceImpl.java b/announcements/src/org/labkey/announcements/api/AnnouncementServiceImpl.java index 4196d1f0002..588c21f0639 100644 --- a/announcements/src/org/labkey/announcements/api/AnnouncementServiceImpl.java +++ b/announcements/src/org/labkey/announcements/api/AnnouncementServiceImpl.java @@ -32,6 +32,7 @@ import org.labkey.api.data.Container; import org.labkey.api.security.User; import org.labkey.api.security.UserPrincipal; +import org.labkey.api.util.Pair; import org.labkey.api.view.HttpView; import org.labkey.api.view.NotFoundException; import org.labkey.api.view.UnauthorizedException; @@ -213,7 +214,7 @@ public Announcement updateAnnouncement(int RowId, Container c, User u, String ti } @Override - public int updateContainer(List discussionSrcIds, Container targetContainer, User u) + public Pair updateContainer(List discussionSrcIds, Container targetContainer, User u) { return AnnouncementManager.updateContainer(discussionSrcIds, targetContainer, u); } diff --git a/announcements/src/org/labkey/announcements/model/AnnouncementManager.java b/announcements/src/org/labkey/announcements/model/AnnouncementManager.java index 28b20cb1b58..587ce882718 100644 --- a/announcements/src/org/labkey/announcements/model/AnnouncementManager.java +++ b/announcements/src/org/labkey/announcements/model/AnnouncementManager.java @@ -685,9 +685,14 @@ public static AnnouncementModel updateAnnouncement(User user, AnnouncementModel return result; } - public static int updateContainer(List discussionSrcIds, Container targetContainer, User user) + public static Pair updateContainer(List discussionSrcIds, Container targetContainer, User user) { - return Table.updateContainer(_comm.getTableInfoAnnouncements(), "discussionSrcIdentifier", discussionSrcIds, targetContainer, user, false); + // move the attachments associated with the comments + SimpleFilter filter = new SimpleFilter(FieldKey.fromParts("discussionSrcIdentifier"), discussionSrcIds, CompareType.IN); + TableSelector selector = new TableSelector(_comm.getTableInfoAnnouncements(), Collections.singleton("entityId"), filter, null); + int numAttachments = Table.updateContainer(_core.getTableInfoDocuments(), "parent", selector.getArrayList(String.class), targetContainer, user, false); + int announcementsCount = Table.updateContainer(_comm.getTableInfoAnnouncements(), "discussionSrcIdentifier", discussionSrcIds, targetContainer, user, false); + return Pair.of(announcementsCount, numAttachments); } diff --git a/api/src/org/labkey/api/announcements/api/AnnouncementService.java b/api/src/org/labkey/api/announcements/api/AnnouncementService.java index 7d517322389..98284886a02 100644 --- a/api/src/org/labkey/api/announcements/api/AnnouncementService.java +++ b/api/src/org/labkey/api/announcements/api/AnnouncementService.java @@ -19,6 +19,7 @@ import org.labkey.api.data.Container; import org.labkey.api.security.User; import org.labkey.api.services.ServiceRegistry; +import org.labkey.api.util.Pair; import java.util.Collection; import java.util.List; @@ -61,8 +62,8 @@ Announcement insertAnnouncement(Container container, User u, String title, Strin // Update Announcement updateAnnouncement(int RowId, Container c, User u, String title, String body); - // move announcements to the given target container - int updateContainer(List discussionSrcIds, Container targetContainer, User u); + // move announcements and their attachments to the given target container + Pair updateContainer(List discussionSrcIds, Container targetContainer, User u); // Delete void deleteAnnouncement(Announcement announcement); From 366b23bed9166952f2123c4ba78613398ef5c47c Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Wed, 17 Dec 2025 20:23:51 -0800 Subject: [PATCH 5/6] Use a map, not a pair --- .../announcements/api/AnnouncementServiceImpl.java | 2 +- .../labkey/announcements/model/AnnouncementManager.java | 9 +++++---- .../api/announcements/api/AnnouncementService.java | 3 ++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/announcements/src/org/labkey/announcements/api/AnnouncementServiceImpl.java b/announcements/src/org/labkey/announcements/api/AnnouncementServiceImpl.java index 588c21f0639..3fe8d7f479b 100644 --- a/announcements/src/org/labkey/announcements/api/AnnouncementServiceImpl.java +++ b/announcements/src/org/labkey/announcements/api/AnnouncementServiceImpl.java @@ -214,7 +214,7 @@ public Announcement updateAnnouncement(int RowId, Container c, User u, String ti } @Override - public Pair updateContainer(List discussionSrcIds, Container targetContainer, User u) + public Map updateContainer(List discussionSrcIds, Container targetContainer, User u) { return AnnouncementManager.updateContainer(discussionSrcIds, targetContainer, u); } diff --git a/announcements/src/org/labkey/announcements/model/AnnouncementManager.java b/announcements/src/org/labkey/announcements/model/AnnouncementManager.java index 587ce882718..1d5e146c090 100644 --- a/announcements/src/org/labkey/announcements/model/AnnouncementManager.java +++ b/announcements/src/org/labkey/announcements/model/AnnouncementManager.java @@ -685,14 +685,15 @@ public static AnnouncementModel updateAnnouncement(User user, AnnouncementModel return result; } - public static Pair updateContainer(List discussionSrcIds, Container targetContainer, User user) + public static Map updateContainer(List discussionSrcIds, Container targetContainer, User user) { // move the attachments associated with the comments SimpleFilter filter = new SimpleFilter(FieldKey.fromParts("discussionSrcIdentifier"), discussionSrcIds, CompareType.IN); TableSelector selector = new TableSelector(_comm.getTableInfoAnnouncements(), Collections.singleton("entityId"), filter, null); - int numAttachments = Table.updateContainer(_core.getTableInfoDocuments(), "parent", selector.getArrayList(String.class), targetContainer, user, false); - int announcementsCount = Table.updateContainer(_comm.getTableInfoAnnouncements(), "discussionSrcIdentifier", discussionSrcIds, targetContainer, user, false); - return Pair.of(announcementsCount, numAttachments); + Map updateCounts = new HashMap<>(); + updateCounts.put("attachments", Table.updateContainer(_core.getTableInfoDocuments(), "parent", selector.getArrayList(String.class), targetContainer, user, false)); + updateCounts.put("announcements", Table.updateContainer(_comm.getTableInfoAnnouncements(), "discussionSrcIdentifier", discussionSrcIds, targetContainer, user, false)); + return updateCounts; } diff --git a/api/src/org/labkey/api/announcements/api/AnnouncementService.java b/api/src/org/labkey/api/announcements/api/AnnouncementService.java index 98284886a02..a79136ada54 100644 --- a/api/src/org/labkey/api/announcements/api/AnnouncementService.java +++ b/api/src/org/labkey/api/announcements/api/AnnouncementService.java @@ -23,6 +23,7 @@ import java.util.Collection; import java.util.List; +import java.util.Map; public interface AnnouncementService { @@ -63,7 +64,7 @@ Announcement insertAnnouncement(Container container, User u, String title, Strin Announcement updateAnnouncement(int RowId, Container c, User u, String title, String body); // move announcements and their attachments to the given target container - Pair updateContainer(List discussionSrcIds, Container targetContainer, User u); + Map updateContainer(List discussionSrcIds, Container targetContainer, User u); // Delete void deleteAnnouncement(Announcement announcement); From f709e93964355a7ce073e83a73879812ae25e1b5 Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Wed, 17 Dec 2025 20:28:22 -0800 Subject: [PATCH 6/6] Unused imports --- .../org/labkey/announcements/api/AnnouncementServiceImpl.java | 1 - .../org/labkey/api/announcements/api/AnnouncementService.java | 1 - 2 files changed, 2 deletions(-) diff --git a/announcements/src/org/labkey/announcements/api/AnnouncementServiceImpl.java b/announcements/src/org/labkey/announcements/api/AnnouncementServiceImpl.java index 3fe8d7f479b..07b5e5ebad9 100644 --- a/announcements/src/org/labkey/announcements/api/AnnouncementServiceImpl.java +++ b/announcements/src/org/labkey/announcements/api/AnnouncementServiceImpl.java @@ -32,7 +32,6 @@ import org.labkey.api.data.Container; import org.labkey.api.security.User; import org.labkey.api.security.UserPrincipal; -import org.labkey.api.util.Pair; import org.labkey.api.view.HttpView; import org.labkey.api.view.NotFoundException; import org.labkey.api.view.UnauthorizedException; diff --git a/api/src/org/labkey/api/announcements/api/AnnouncementService.java b/api/src/org/labkey/api/announcements/api/AnnouncementService.java index a79136ada54..039fdad7e46 100644 --- a/api/src/org/labkey/api/announcements/api/AnnouncementService.java +++ b/api/src/org/labkey/api/announcements/api/AnnouncementService.java @@ -19,7 +19,6 @@ import org.labkey.api.data.Container; import org.labkey.api.security.User; import org.labkey.api.services.ServiceRegistry; -import org.labkey.api.util.Pair; import java.util.Collection; import java.util.List;