diff --git a/onprc_ehr/src/org/labkey/onprc_ehr/issues/RestrictedIssueProviderImpl.java b/onprc_ehr/src/org/labkey/onprc_ehr/issues/RestrictedIssueProviderImpl.java index fdc119b09..be3ade1ec 100644 --- a/onprc_ehr/src/org/labkey/onprc_ehr/issues/RestrictedIssueProviderImpl.java +++ b/onprc_ehr/src/org/labkey/onprc_ehr/issues/RestrictedIssueProviderImpl.java @@ -96,21 +96,6 @@ public boolean hasPermission(User user, @NotNull Issue issue, List relate return false; } } - - // the user must also have access to all related issues - for (Issue related : relatedIssues) - { - Container relatedContainer = ContainerManager.getForId(related.getContainerId()); - if (relatedContainer != null && isRestrictedIssueTracker(relatedContainer, related.getIssueDefName())) - { - Group relatedGroup = getRestrictedIssueListGroup(relatedContainer, related.getIssueDefName()); - if (!checkAccess(user, related, relatedGroup)) - { - errors.add(new SimpleValidationError(String.format("A related issue : %d is in a restricted issue list. You do not have access to that issue", related.getIssueId()))); - return false; - } - } - } return true; } diff --git a/onprc_ehr/test/src/org/labkey/test/tests/onprc_ehr/ONPRC_RestrictedIssueTest.java b/onprc_ehr/test/src/org/labkey/test/tests/onprc_ehr/ONPRC_RestrictedIssueTest.java new file mode 100644 index 000000000..7e54dae2c --- /dev/null +++ b/onprc_ehr/test/src/org/labkey/test/tests/onprc_ehr/ONPRC_RestrictedIssueTest.java @@ -0,0 +1,268 @@ +package org.labkey.test.tests.onprc_ehr; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.labkey.test.BaseWebDriverTest; +import org.labkey.test.Locator; +import org.labkey.test.TestTimeoutException; +import org.labkey.test.categories.EHR; +import org.labkey.test.categories.ONPRC; +import org.labkey.test.pages.issues.DetailsPage; +import org.labkey.test.pages.issues.InsertPage; +import org.labkey.test.pages.issues.UpdatePage; +import org.labkey.test.util.IssuesHelper; +import org.labkey.test.util.SqlserverOnlyTest; +import org.labkey.test.util.TestUser; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +@Category({EHR.class, ONPRC.class}) +public class ONPRC_RestrictedIssueTest extends BaseWebDriverTest implements SqlserverOnlyTest +{ + private final IssuesHelper _issuesHelper; + + // constants + private static final TestUser USER1 = new TestUser("user1_issuetest@issues.test"); + private static final TestUser USER2 = new TestUser("user2_issuetest@issues.test"); + private static final TestUser ISSUE_CREATOR = new TestUser("issue_creator_issuetest@issues.test"); + private static final TestUser FOLDER_ADMIN = new TestUser("folder_admin_issuetest@issues.test"); + + private static final String RESTRICTED_ISSUES_LIST = "restricted-issues"; + private static final String UNRESTRICTED_ISSUES_LIST = "unrestricted-issues"; + private static final String ACCESS_ERROR_MSG = "This issue is in a restricted issue list. You do not have access to this issue"; + + public ONPRC_RestrictedIssueTest() + { + _issuesHelper = new IssuesHelper(this); + } + + @BeforeClass + public static void doSetup() + { + ONPRC_RestrictedIssueTest initTest = getCurrentTest(); + initTest.doInit(); + } + + public void doInit() + { + _containerHelper.createProject(getProjectName(), null); + + // Create test users + USER1.create(this).addPermission("Editor", getProjectName()); + USER2.create(this).addPermission("Editor", getProjectName()); + ISSUE_CREATOR.create(this).addPermission("Editor", getProjectName()); + FOLDER_ADMIN.create(this).addPermission("Folder Administrator", getProjectName()); + + // Add issue list definitions + _issuesHelper.createNewIssuesList(RESTRICTED_ISSUES_LIST, _containerHelper, true, false, false); + waitAndClickAndWait(Locator.linkContainingText(RESTRICTED_ISSUES_LIST)); + _issuesHelper.goToAdmin(); + _issuesHelper.setRestrictedIssueList(true); + _issuesHelper.setIssueAssignmentList("Site: Users"); + clickButton("Save"); + + goToProjectHome(); + _issuesHelper.createNewIssuesList(UNRESTRICTED_ISSUES_LIST, _containerHelper, false, false, false); + waitAndClickAndWait(Locator.linkContainingText(UNRESTRICTED_ISSUES_LIST)); + _issuesHelper.goToAdmin(); + _issuesHelper.setIssueAssignmentList("Site: Users"); + clickButton("Save"); + } + + @Override + protected void doCleanup(boolean afterTest) throws TestTimeoutException + { + _userHelper.deleteUsers(false, USER1, USER2, ISSUE_CREATOR, FOLDER_ADMIN); + _containerHelper.deleteProject(getProjectName(), afterTest); + } + + @Override + public List getAssociatedModules() + { + return Arrays.asList("ehr", "onprc_ehr"); + } + + @Override + protected String getProjectName() + { + return "RestrictedIssuesVerifyProject"; + } + + @Test + public void restrictedIssueTest() + { + goToProjectHome(); + + // create a few issues in the restricted list + impersonate(ISSUE_CREATOR.getEmail()); + clickAndWait(Locator.linkContainingText(RESTRICTED_ISSUES_LIST)); + DetailsPage detailsPage = _issuesHelper.addIssue(String.format("Restricted issue assigned to (%s)", USER1.getUserDisplayName()), USER1.getUserDisplayName()); + final String ISSUE_1 = detailsPage.getIssueId(); + InsertPage insertPage = detailsPage.clickCreateNewIssue(); + insertPage.title().set(String.format("Restricted issue assigned to (%s)", USER2.getUserDisplayName())); + insertPage.assignedTo().set(USER2.getUserDisplayName()); + insertPage.save(); + final String ISSUE_2 = insertPage.getIssueId(); + stopImpersonating(); + + // verify site admins can see both issues (but not folder admins) + goToProjectHome(); + clickAndWait(Locator.linkContainingText(RESTRICTED_ISSUES_LIST)); + verifyIssueAccess(ISSUE_1, true); + verifyIssueAccess(ISSUE_2, true); + + impersonate(FOLDER_ADMIN.getEmail()); + goToProjectHome(); + clickAndWait(Locator.linkContainingText(RESTRICTED_ISSUES_LIST)); + verifyIssueAccess(ISSUE_1, false); + verifyIssueAccess(ISSUE_2, false); + stopImpersonating(); + + // creators can see all of the issues they opened + impersonate(ISSUE_CREATOR.getEmail()); + goToProjectHome(); + clickAndWait(Locator.linkContainingText(RESTRICTED_ISSUES_LIST)); + verifyIssueAccess(ISSUE_1, true); + verifyIssueAccess(ISSUE_2, true); + stopImpersonating(); + + // users can view issues assigned to them + impersonate(USER1.getEmail()); + goToProjectHome(); + clickAndWait(Locator.linkContainingText(RESTRICTED_ISSUES_LIST)); + verifyIssueAccess(ISSUE_1, true); + verifyIssueAccess(ISSUE_2, false); + stopImpersonating(); + + // verify notify list grants access + UpdatePage page = UpdatePage.beginAt(this, ISSUE_2); + page.notifyList().set(USER1.getEmail()); + page.save(); + impersonate(USER1.getEmail()); + goToProjectHome(); + clickAndWait(Locator.linkContainingText(RESTRICTED_ISSUES_LIST)); + verifyIssueAccess(ISSUE_1, true); + verifyIssueAccess(ISSUE_2, true); + stopImpersonating(); + } + + private void verifyIssueAccess(String issueID, boolean shouldHaveAccess) + { + Locator issueLink = getIssueLinkLocator(issueID); + waitForElement(issueLink, defaultWaitForPage); + pushLocation(); + waitAndClickAndWait(issueLink); + if (shouldHaveAccess) + assertTextNotPresent(ACCESS_ERROR_MSG); + else + assertTextPresent(ACCESS_ERROR_MSG); + popLocation(); + } + + @Test + public void relatedIssueTest() + { + goToProjectHome(); + + // create 2 issues related to each other + impersonate(ISSUE_CREATOR.getEmail()); + clickAndWait(Locator.linkContainingText(RESTRICTED_ISSUES_LIST)); + DetailsPage detailsPage = _issuesHelper.addIssue(String.format("Restricted issue assigned to (%s)", USER1.getUserDisplayName()), USER1.getUserDisplayName()); + final String ISSUE_1 = detailsPage.getIssueId(); + InsertPage insertPage = detailsPage.clickCreateNewIssue(); + insertPage.title().set(String.format("Restricted issue assigned to (%s)", USER2.getUserDisplayName())); + insertPage.assignedTo().set(USER2.getUserDisplayName()); + insertPage.related().set(ISSUE_1); + insertPage.save(); + final String ISSUE_2 = insertPage.getIssueId(); + stopImpersonating(); + + // verify creator sees both all issues and their relationships + impersonate(ISSUE_CREATOR.getEmail()); + goToProjectHome(); + clickAndWait(Locator.linkContainingText(RESTRICTED_ISSUES_LIST)); + verifyRelatedIssueAccess(ISSUE_1, ISSUE_2, true); + verifyRelatedIssueAccess(ISSUE_2, ISSUE_1, true); + stopImpersonating(); + + // verify users can open issue assigned to them but not see the related issue + impersonate(USER1.getEmail()); + goToProjectHome(); + clickAndWait(Locator.linkContainingText(RESTRICTED_ISSUES_LIST)); + verifyRelatedIssueAccess(ISSUE_1, ISSUE_2, false); + // shouldn't be able to access the other issue at all + verifyIssueAccess(ISSUE_2, false); + stopImpersonating(); + + impersonate(USER2.getEmail()); + goToProjectHome(); + clickAndWait(Locator.linkContainingText(RESTRICTED_ISSUES_LIST)); + verifyRelatedIssueAccess(ISSUE_2, ISSUE_1, false); + verifyIssueAccess(ISSUE_1, false); + stopImpersonating(); + + // create issues in the unrestricted issue list and relate them to issues in the other list + impersonate(ISSUE_CREATOR.getEmail()); + goToProjectHome(); + clickAndWait(Locator.linkContainingText(UNRESTRICTED_ISSUES_LIST)); + // issue related to both restricted issues + detailsPage = _issuesHelper.addIssue(String.format("UnRestricted issue assigned to (%s)", USER1.getUserDisplayName()), + USER1.getUserDisplayName(), Collections.singletonMap("related", String.join(",", List.of(ISSUE_1, ISSUE_2)))); + final String ISSUE_3 = detailsPage.getIssueId(); + stopImpersonating(); + + // any user with read access to the unrestricted list can see details but no links to the linked restricted issues + impersonate(FOLDER_ADMIN.getEmail()); + goToProjectHome(); + clickAndWait(Locator.linkContainingText(UNRESTRICTED_ISSUES_LIST)); + verifyRelatedIssueAccess(ISSUE_3, ISSUE_1, false); + verifyRelatedIssueAccess(ISSUE_3, ISSUE_2, false); + stopImpersonating(); + + // users can link to the restricted issues they have access to + impersonate(USER1.getEmail()); + goToProjectHome(); + clickAndWait(Locator.linkContainingText(UNRESTRICTED_ISSUES_LIST)); + verifyRelatedIssueAccess(ISSUE_3, ISSUE_1, true); + verifyRelatedIssueAccess(ISSUE_3, ISSUE_2, false); + stopImpersonating(); + + impersonate(USER2.getEmail()); + goToProjectHome(); + clickAndWait(Locator.linkContainingText(UNRESTRICTED_ISSUES_LIST)); + verifyRelatedIssueAccess(ISSUE_3, ISSUE_1, false); + verifyRelatedIssueAccess(ISSUE_3, ISSUE_2, true); + stopImpersonating(); + } + + private void verifyRelatedIssueAccess(String issueID, String relatedIssueID, boolean shouldHaveRelatedAccess) + { + Locator issueLink = getIssueLinkLocator(issueID); + waitForElement(issueLink, defaultWaitForPage); + pushLocation(); + clickAndWait(issueLink); + Locator relatedIssueLink = getIssueLinkLocator(relatedIssueID); + if (shouldHaveRelatedAccess) + { + assertElementPresent(relatedIssueLink); + // related link should also navigate properly + clickAndWait(relatedIssueLink); + assertTextNotPresent(ACCESS_ERROR_MSG); + } + else + { + // no link but the related ID should render as text + assertElementNotPresent(relatedIssueLink); + assertTextPresent(relatedIssueID); + } + popLocation(); + } + + private Locator getIssueLinkLocator(String issueID) + { + return Locator.tagWithAttributeContaining("a", "href", String.format("issues-details.view?issueId=%s", issueID)); + } +}