From dcb467c060014516710a3838cd862301e5193855 Mon Sep 17 00:00:00 2001
From: Sandeep Chauhan <sandeepsajan0@gmail.com>
Date: Tue, 18 Apr 2023 14:12:15 +0530
Subject: [PATCH] Fix Permissions for Project access(detail view) (#3220)

Fixes #3205
Fixes #3216

1. Staff can access the project in every status.
2. Contracting can access projects only in `WAITING_FOR_APPROVAL` and
`CONTRACTING` statuses.
3. Finance can access projects only in the `WAITING_FOR_APPROVAL` and
`IN_PROGRESS` statuses.
4. Applicant(only project user) can access the project in every status
to keep track.
5. Unauthorised users and any other role can not access the project.
---
 hypha/apply/projects/permissions.py      | 20 ++++++++++++++++++++
 hypha/apply/projects/tests/test_views.py |  5 +++--
 hypha/apply/projects/views/project.py    |  8 ++++++--
 3 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/hypha/apply/projects/permissions.py b/hypha/apply/projects/permissions.py
index 400cb9781..ad5e6973b 100644
--- a/hypha/apply/projects/permissions.py
+++ b/hypha/apply/projects/permissions.py
@@ -153,6 +153,25 @@ def can_view_report(user, report, **kwargs):
     return False, 'Forbidden Error'
 
 
+def can_access_project(user, project):
+    if not user.is_authenticated:
+        return False, 'Login Required'
+
+    if user.is_contracting and project.status in [CONTRACTING, WAITING_FOR_APPROVAL]:
+        return True, 'Contracting can view project only in Waiting for approval and contracting status'
+
+    if user.is_finance and project.status in [WAITING_FOR_APPROVAL, IN_PROGRESS]:
+        return True, 'Finance can view project only  in Waiting for approval and in progress status'
+
+    if user.is_apply_staff:
+        return True, 'Staff can view project in all statuses'
+
+    if user.is_applicant and user == project.user:
+        return True, 'Applicant(project user) can view project in all statuses'
+
+    return False, 'Forbidden Error'
+
+
 permissions_map = {
     'contract_approve': can_approve_contract,
     'contract_upload': can_upload_contract,
@@ -163,4 +182,5 @@ permissions_map = {
     'report_config_update': can_update_report_config,
     'report_view': can_view_report,
     'submit_contract_documents': can_submit_contract_documents,
+    'project_access': can_access_project,
 }
diff --git a/hypha/apply/projects/tests/test_views.py b/hypha/apply/projects/tests/test_views.py
index c011290ca..373397909 100644
--- a/hypha/apply/projects/tests/test_views.py
+++ b/hypha/apply/projects/tests/test_views.py
@@ -231,12 +231,13 @@ class TestFinanceProjectDetailView(BaseProjectDetailTestCase):
     user_factory = FinanceFactory
 
     def test_has_access(self):
-        project = ProjectFactory()
+        project = ProjectFactory(status=WAITING_FOR_APPROVAL)
         response = self.get_page(project)
         self.assertEqual(response.status_code, 200)
 
+
     def test_lab_project_renders(self):
-        project = ProjectFactory(submission=LabSubmissionFactory())
+        project = ProjectFactory(submission=LabSubmissionFactory(), status=WAITING_FOR_APPROVAL)
         response = self.get_page(project)
         self.assertEqual(response.status_code, 200)
 
diff --git a/hypha/apply/projects/views/project.py b/hypha/apply/projects/views/project.py
index 9fa762881..9cdace426 100644
--- a/hypha/apply/projects/views/project.py
+++ b/hypha/apply/projects/views/project.py
@@ -670,6 +670,11 @@ class AdminProjectDetailView(
     model = Project
     template_name_suffix = '_admin_detail'
 
+    def dispatch(self, *args, **kwargs):
+        project = self.get_object()
+        permission, _ = has_permission('project_access', self.request.user, object=project, raise_exception=True)
+        return super().dispatch(*args, **kwargs)
+
     def get_context_data(self, **kwargs):
         context = super().get_context_data(**kwargs)
         project_settings = ProjectSettings.for_request(self.request)
@@ -716,8 +721,7 @@ class ApplicantProjectDetailView(
 
     def dispatch(self, request, *args, **kwargs):
         project = self.get_object()
-        if project.user != request.user:
-            raise PermissionDenied
+        permission, _ = has_permission('project_access', request.user, object=project, raise_exception=True)
         return super().dispatch(request, *args, **kwargs)
 
     def get_context_data(self, **kwargs):
-- 
GitLab