Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hide contracting category documents from restricted users #4136

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 4.2.15 on 2024-09-17 04:02

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("auth", "0012_alter_user_first_name_max_length"),
("application_projects", "0087_alter_pafreviewersrole_user_roles"),
]

operations = [
migrations.AddField(
model_name="contractdocumentcategory",
name="restrict_document_access_view",
field=models.ManyToManyField(
blank=True,
help_text="Only selected group's users will be restricted from document access",
related_name="contract_document_category",
to="auth.group",
verbose_name="Restrict document access for groups",
),
),
]
12 changes: 12 additions & 0 deletions hypha/apply/projects/models/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,15 @@ class Meta:
class ContractDocumentCategory(models.Model):
name = models.CharField(max_length=254)
recommended_minimum = models.PositiveIntegerField(null=True, blank=True)
restrict_document_access_view = models.ManyToManyField(
Group,
verbose_name=_("Restrict document access for groups"),
help_text=_(
"Only selected group's users will be restricted from document access"
),
related_name="contract_document_category",
blank=True,
)
required = models.BooleanField(default=True)
template = models.FileField(
upload_to=contract_document_template_path,
Expand All @@ -759,6 +768,9 @@ class Meta:
panels = [
FieldPanel("name"),
FieldPanel("required"),
FieldPanel(
"restrict_document_access_view", widget=forms.CheckboxSelectMultiple
),
FieldPanel("template"),
]

Expand Down
21 changes: 21 additions & 0 deletions hypha/apply/projects/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,26 @@ def can_access_project(user, project):
return False, "Forbidden Error"


def can_view_contract_category_documents(user, project, **kwargs):
from hypha.apply.activity.adapters.utils import get_users_for_groups

contract_category = kwargs.get("contract_category")
if not contract_category:
return False, "Contract Category is required"
restricted_group_users = get_users_for_groups(
list(contract_category.restrict_document_access_view.all())
)
if restricted_group_users and user in restricted_group_users:
return False, "Forbidden Error"
if user.is_apply_staff or user.is_contracting:
return True, "Access allowed"

if user == project.user:
return True, "Access allowed"

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"
Expand Down Expand Up @@ -396,4 +416,5 @@ def can_edit_vendor_details(user, project):
"project_access": can_access_project,
"paf_edit": can_edit_paf,
"vendor_edit": can_edit_vendor_details,
"view_contract_documents": can_view_contract_category_documents,
}
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,8 @@ <h5> {% trans "Are you sure you want to submit contracting documents?" %}</h5>
</div>
{% else %}
{% contract_category_latest_file project document_category as latest_file %}
{% if latest_file %}
{% can_access_category_document project user document_category as have_view_access %}
{% if latest_file and have_view_access %}
<div class="docs-block__row-inner">
<a class="docs-block__icon-link" href="{% url 'apply:projects:contract_document' pk=object.pk file_pk=latest_file.pk %}" target="_blank">
{% heroicon_micro "eye" class="inline me-1 w-4 h-4" aria_hidden=true %}
Expand Down
12 changes: 12 additions & 0 deletions hypha/apply/projects/templatetags/contract_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,15 @@ def can_update_contracting_documents(project, user):
if user == project.user and not user.is_apply_staff and not user.is_contracting:
return True
return False


@register.simple_tag
def can_access_category_document(project, user, category):
permission, _ = has_permission(
"view_contract_documents",
user,
object=project,
contract_category=category,
raise_exception=False,
)
return permission
24 changes: 11 additions & 13 deletions hypha/apply/projects/views/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -1545,28 +1545,26 @@ def test_func(self):


@method_decorator(login_required, name="dispatch")
class ContractDocumentPrivateMediaView(UserPassesTestMixin, PrivateMediaView):
class ContractDocumentPrivateMediaView(PrivateMediaView):
raise_exception = True

def dispatch(self, *args, **kwargs):
project_pk = self.kwargs["pk"]
self.project = get_object_or_404(Project, pk=project_pk)
self.document = ContractPacketFile.objects.get(pk=kwargs["file_pk"])
permission, _ = has_permission(
"view_contract_documents",
self.request.user,
object=self.project,
contract_category=self.document.category,
raise_exception=True,
)
return super().dispatch(*args, **kwargs)

def get_media(self, *args, **kwargs):
document = ContractPacketFile.objects.get(pk=kwargs["file_pk"])
if document.project != self.project:
if self.document.project != self.project:
raise Http404
return document.document

def test_func(self):
if self.request.user.is_apply_staff or self.request.user.is_contracting:
return True

if self.request.user == self.project.user:
return True

return False
return self.document.document


# PROJECT FORM VIEWS
Expand Down
Loading