Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 9 additions & 12 deletions hypha/apply/funds/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,9 @@ def view_comments(role, user, submission) -> bool:
if submission_view:
return True

project = getattr(submission, "project", None)
if project:
# Users such as contracting staff and project form approvers reach a
# submission's comments through its project rather than the submission.
for project in submission.projects.all():
can_access, _ = can_access_project(user, project)
if can_access:
return True
Expand Down Expand Up @@ -251,12 +252,10 @@ def can_view_submission_screening(user, submission):
def can_invite_co_applicants(user, submission):
if submission.is_archive:
return False, _("Co-applicant can't be added to archived submission")
project = getattr(submission, "project", None)
if project:
from hypha.apply.projects.models.project import COMPLETE
from hypha.apply.projects.models.project import COMPLETE

if project.status == COMPLETE:
return False, _("Co-applicants can't be invited to completed projects")
if submission.projects.filter(status=COMPLETE).exists():
return False, _("Co-applicants can't be invited to completed projects")
if (
submission.co_applicant_invites.count()
>= settings.SUBMISSIONS_COAPPLICANT_INVITES_LIMIT
Expand All @@ -280,12 +279,10 @@ def can_view_co_applicants(user, submission):
def can_update_co_applicant(user, invite):
if invite.submission.is_archive:
return False, _("Co-applicant can't be updated to archived submission")
project = getattr(invite.submission, "project", None)
if project:
from hypha.apply.projects.models.project import COMPLETE
from hypha.apply.projects.models.project import COMPLETE

if project.status == COMPLETE:
return False, _("Co-applicants can't be updated to completed projects")
if invite.submission.projects.filter(status=COMPLETE).exists():
return False, _("Co-applicants can't be updated to completed projects")
if invite.invited_by == user:
return True, _("Same user who invited can delete the co-applicant")
if invite.submission.user == user:
Expand Down
72 changes: 72 additions & 0 deletions hypha/apply/funds/tests/test_permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
from hypha.apply.users.tests.factories import (
AdminFactory,
ApplicantFactory,
ContractingFactory,
FinanceFactory,
ReviewerFactory,
StaffFactory,
UserFactory,
Expand Down Expand Up @@ -310,6 +312,23 @@ def test_limit_reached_blocks_invite(self):
result, _ = can_invite_co_applicants(applicant, submission)
self.assertFalse(result)

def test_complete_project_blocks_invite(self):
"""The submission owner could otherwise invite, so this isolates status"""
from hypha.apply.projects.models.project import COMPLETE
from hypha.apply.projects.tests.factories import ProjectFactory

submission = ProjectFactory(status=COMPLETE).submission
result, _ = can_invite_co_applicants(submission.user, submission)
self.assertFalse(result)

def test_incomplete_project_does_not_block_invite(self):
from hypha.apply.projects.models.project import INVOICING_AND_REPORTING
from hypha.apply.projects.tests.factories import ProjectFactory

submission = ProjectFactory(status=INVOICING_AND_REPORTING).submission
result, _ = can_invite_co_applicants(submission.user, submission)
self.assertTrue(result)


class TestGetArchiveGroups(TestCase):
@override_settings(
Expand Down Expand Up @@ -457,6 +476,15 @@ def test_archived_submission_blocks_update(self):
result, _ = can_update_co_applicant(self.inviter, invite)
self.assertFalse(result)

def test_complete_project_blocks_update(self):
from hypha.apply.projects.models.project import COMPLETE
from hypha.apply.projects.tests.factories import ProjectFactory

project = ProjectFactory(status=COMPLETE, user=self.inviter)
invite = self._make_invite(project.submission, invited_by=self.inviter)
result, _ = can_update_co_applicant(self.inviter, invite)
self.assertFalse(result)


# ---------------------------------------------------------------------------
# user_can_view_post_comment_form — co-applicant VIEW vs EDIT/COMMENT role
Expand Down Expand Up @@ -504,3 +532,47 @@ def test_staff_can_post_comment(self):
self.assertTrue(
user_can_view_post_comment_form(StaffFactory(), self.submission)
)


class TestViewComments(TestCase):
"""`view_comments` reaches a submission's project via `submission.projects`"""

def setUp(self):
from hypha.apply.projects.models.project import INVOICING_AND_REPORTING
from hypha.apply.projects.tests.factories import ProjectFactory

self.vendor = ApplicantFactory()
self.project = ProjectFactory(status=INVOICING_AND_REPORTING, user=self.vendor)
self.submission = self.project.submission

def check(self, user):
return has_object_permission("view_comments", user, self.submission)

def test_staff_can(self):
self.assertTrue(self.check(StaffFactory()))

def test_admin_can(self):
self.assertTrue(self.check(AdminFactory()))

def test_project_vendor_can(self):
self.assertTrue(self.check(self.vendor))

def test_finance_and_contracting_can_via_the_project(self):
"""These roles have no submission access, only project access"""
for user in [FinanceFactory(), ContractingFactory()]:
with self.subTest(user.roles):
self.assertFalse(can_view_submission(user, self.submission)[0])
self.assertTrue(self.check(user))

def test_unrelated_applicant_cannot(self):
self.assertFalse(self.check(ApplicantFactory()))

def test_submission_without_a_project_falls_back_to_submission_access(self):
submission = ApplicationSubmissionFactory()
self.assertFalse(submission.projects.exists())
self.assertTrue(
has_object_permission("view_comments", StaffFactory(), submission)
)
self.assertFalse(
has_object_permission("view_comments", ContractingFactory(), submission)
)