diff --git a/hypha/apply/projects/permissions.py b/hypha/apply/projects/permissions.py index 7dd2a9e8dfdf410f043aee7bf4400001b3b1320d..b0ee9a4d858a5768d0b38b24185663470222fc69 100644 --- a/hypha/apply/projects/permissions.py +++ b/hypha/apply/projects/permissions.py @@ -364,6 +364,22 @@ def can_access_project(user, project): return False, "Forbidden Error" +def can_edit_paf(user, project): + if no_pafreviewer_role() and project.status != COMPLETE: + return True, "Paf is editable for active projects if no reviewer roles" + if project.editable_by(user): + return True, "PAF is editable in Draft by this user" + return False, "You are not allowed to edit the project at this time" + + +def can_edit_vendor_details(user, project): + if project.status == COMPLETE: + return False, "Only active project's details can be edited" + if user.is_apply_staff or user == project.lead: + return True, "Lead and staff can edit vendor details for any active project" + return False, "Forbidden Error" + + permissions_map = { "contract_approve": can_approve_contract, "contract_upload": can_upload_contract, @@ -378,4 +394,6 @@ permissions_map = { "report_view": can_view_report, "submit_contract_documents": can_submit_contract_documents, "project_access": can_access_project, + "paf_edit": can_edit_paf, + "vendor_edit": can_edit_vendor_details, } diff --git a/hypha/apply/projects/templates/application_projects/includes/supporting_documents.html b/hypha/apply/projects/templates/application_projects/includes/supporting_documents.html index 57ec81692318d500d22f8cc2281c6a0dde98f783..6a789f4b4b52c531e8b9a1d6bd7cb92afae1897c 100644 --- a/hypha/apply/projects/templates/application_projects/includes/supporting_documents.html +++ b/hypha/apply/projects/templates/application_projects/includes/supporting_documents.html @@ -1,5 +1,5 @@ {% load i18n approval_tools project_tags heroicons %} -{% user_can_edit_project object request.user as editable %} +{% user_can_edit_vendor_details object request.user as can_edit_vendor_details %} {% allow_collapsible_header object header_type='project_documents' as collapsible_header %} <div class="docs-block wrapper--outer-space-large" {% if collapsible_header %} x-data="{ collapsed: true }" {% endif %}> @@ -96,7 +96,7 @@ <p class="docs-block__title">{% trans "Contracting Information" %}</p> </div> <div class="docs-block__row-inner"> - {% if editable %} + {% if can_edit_vendor_details %} <a class="{% if not project.vendor.user_has_updated_details %}button button--project-action{% else %}docs-block__icon-link{% endif %}" href="{% url 'apply:projects:vendor' pk=project.pk %}"> {% if project.vendor.user_has_updated_details %} {% heroicon_micro "pencil-square" class="inline me-1 w-4 h-4" aria_hidden=true %} @@ -126,7 +126,8 @@ <p class="docs-block__title">{% trans "Project Form" %}</p> </div> <div class="docs-block__row-inner"> - {% if editable and not user.is_applicant %} + {% user_can_edit_paf object user as can_edit_paf %} + {% if can_edit_paf %} <a class="{% if not object.user_has_updated_details %}button button--project-action{% else %}docs-block__icon-link{% endif %}" href="{% url 'apply:projects:edit' pk=object.pk %}"> {% if object.user_has_updated_details %} {% heroicon_micro "pencil-square" class="inline me-1 w-4 h-4" aria_hidden=true %} diff --git a/hypha/apply/projects/templates/application_projects/project_approval_detail.html b/hypha/apply/projects/templates/application_projects/project_approval_detail.html index a0bff7233307b6e3632857a719f349da282d1dcb..42d4abbe81babeadb73ccfb576c1518325bf5355 100644 --- a/hypha/apply/projects/templates/application_projects/project_approval_detail.html +++ b/hypha/apply/projects/templates/application_projects/project_approval_detail.html @@ -101,8 +101,8 @@ <aside class="sidebar sidebar__project"> <div class="js-actions-sidebar sidebar__inner sidebar__inner--light-blue sidebar__inner--actions {% if mobile %}sidebar__inner--mobile{% endif %}"> <h5>{% trans "Actions to take" %}</h5> - {% user_can_edit_project object user as can_edit_project %} - {% if can_edit_project %} + {% user_can_edit_paf object user as can_edit_paf %} + {% if can_edit_paf %} <a class="button button--bottom-space button--primary button--full-width {% if user_can_approve %} is-disabled {% endif %}" href="{% url 'apply:projects:edit' pk=object.pk %}">{% trans "Edit PAF" %}</a> {% endif %} <div x-data="{ show: false }" class="dropdown"> diff --git a/hypha/apply/projects/templates/application_projects/vendor_detail.html b/hypha/apply/projects/templates/application_projects/vendor_detail.html index a7aebf2548414d4709805660382b425f771e8d80..e531e868c758f72f4c616a65472513cce597e31d 100644 --- a/hypha/apply/projects/templates/application_projects/vendor_detail.html +++ b/hypha/apply/projects/templates/application_projects/vendor_detail.html @@ -1,6 +1,6 @@ {% extends "base-apply.html" %} {% load nh3_tags i18n approval_tools heroicons %} -{% user_can_edit_project object request.user as editable %} +{% user_can_edit_vendor_details object request.user as can_edit_vendor_details %} {% block title %}{% trans "Contracting Information for" %} {{ project.title }} {% endblock %} {% block content %} @@ -18,7 +18,7 @@ <div> <h5 class="vendor-info">{% trans "Last Updated" %}: {{ vendor.updated_at|date:'DATE_FORMAT' }}</h5> </div> - {% if editable %} + {% if can_edit_vendor_details %} <div> <a class="link link--edit-vendor is-active" href="{% url 'apply:projects:vendor' pk=project.pk %}"> {% heroicon_micro "pencil-square" class="inline me-1" aria_hidden=true %} diff --git a/hypha/apply/projects/templatetags/approval_tools.py b/hypha/apply/projects/templatetags/approval_tools.py index 00db39432012fa111708080e5603117efe38ef81..09313f730e3e160ce82ae97f854629d8bddf41b4 100644 --- a/hypha/apply/projects/templatetags/approval_tools.py +++ b/hypha/apply/projects/templatetags/approval_tools.py @@ -67,8 +67,15 @@ def user_can_update_paf_status(project, user, **kwargs): @register.simple_tag -def user_can_edit_project(project, user): - return project.editable_by(user) +def user_can_edit_vendor_details(project, user): + permission, _ = has_permission("vendor_edit", user, project, raise_exception=False) + return permission + + +@register.simple_tag +def user_can_edit_paf(project, user): + permission, _ = has_permission("paf_edit", user, project, raise_exception=False) + return permission @register.simple_tag diff --git a/hypha/apply/projects/views/project.py b/hypha/apply/projects/views/project.py index 50efccccc989112e842572ecd8204aa388966224..e3535bb13360980f4765b4e1de44d9b3d27c6e99 100644 --- a/hypha/apply/projects/views/project.py +++ b/hypha/apply/projects/views/project.py @@ -1794,11 +1794,12 @@ class ProjectFormEditView(BaseStreamForm, UpdateView): def dispatch(self, request, *args, **kwargs): self.object = self.get_object() - if not self.object.editable_by(request.user): - messages.info( - self.request, _("You are not allowed to edit the project at this time") - ) - return redirect(self.object) + + permission, msg = has_permission( + "paf_edit", self.request.user, self.object, raise_exception=True + ) + if not permission: + messages.info(self.request, msg) return super().dispatch(request, *args, **kwargs) @cached_property diff --git a/hypha/apply/projects/views/vendor.py b/hypha/apply/projects/views/vendor.py index 133627465cea63e311662056b964d4c4f1622a0f..ce6c4e40aff27df979fbda114ac25ee74c232fba 100644 --- a/hypha/apply/projects/views/vendor.py +++ b/hypha/apply/projects/views/vendor.py @@ -33,6 +33,7 @@ from ..models import ( ProjectSettings, Vendor, ) +from ..permissions import has_permission def show_extra_info_form(wizard): @@ -47,15 +48,13 @@ class CreateVendorAccessMixin: project_settings = ProjectSettings.for_request(request) if not project_settings.vendor_setup_required: raise PermissionDenied - is_admin = request.user.is_apply_staff project = self.get_project() - is_owner = request.user == project.user - if not (is_owner or is_admin): - raise PermissionDenied - if not project.editable_by(request.user): - raise PermissionDenied + # is_owner = request.user == project.user :todo: confirm it if not project.vendor: raise Http404 + permission, _ = has_permission( + "vendor_edit", request.user, project, raise_exception=True + ) return super().dispatch(request, *args, **kwargs)