diff --git a/taiga/projects/history/permissions.py b/taiga/projects/history/permissions.py index 6b97d078..c0adf8d6 100644 --- a/taiga/projects/history/permissions.py +++ b/taiga/projects/history/permissions.py @@ -18,35 +18,46 @@ from taiga.base.api.permissions import (TaigaResourcePermission, HasProjectPerm, IsProjectOwner, AllowAny, IsObjectOwner, PermissionComponent) +from taiga.permissions.service import is_project_owner +from taiga.projects.history.services import get_model_from_key, get_pk_from_key + class IsCommentDeleter(PermissionComponent): def check_permissions(self, request, view, obj=None): return obj.delete_comment_user and obj.delete_comment_user.get("pk", "not-pk") == request.user.pk + class IsCommentOwner(PermissionComponent): def check_permissions(self, request, view, obj=None): return obj.user and obj.user.get("pk", "not-pk") == request.user.pk +class IsCommentProjectOwner(PermissionComponent): + def check_permissions(self, request, view, obj=None): + model = get_model_from_key(obj.key) + pk = get_pk_from_key(obj.key) + project = model.objects.get(pk=pk) + return is_project_owner(request.user, project) + class UserStoryHistoryPermission(TaigaResourcePermission): retrieve_perms = HasProjectPerm('view_project') - delete_comment_perms = IsProjectOwner() | IsCommentOwner() - undelete_comment_perms = IsProjectOwner() | IsCommentDeleter() + delete_comment_perms = IsCommentProjectOwner() | IsCommentOwner() + undelete_comment_perms = IsCommentProjectOwner() | IsCommentDeleter() class TaskHistoryPermission(TaigaResourcePermission): retrieve_perms = HasProjectPerm('view_project') - delete_comment_perms = IsProjectOwner() | IsCommentOwner() - undelete_comment_perms = IsProjectOwner() | IsCommentDeleter() + delete_comment_perms = IsCommentProjectOwner() | IsCommentOwner() + undelete_comment_perms = IsCommentProjectOwner() | IsCommentDeleter() class IssueHistoryPermission(TaigaResourcePermission): retrieve_perms = HasProjectPerm('view_project') - delete_comment_perms = IsProjectOwner() | IsCommentOwner() - undelete_comment_perms = IsProjectOwner() | IsCommentDeleter() + delete_comment_perms = IsCommentProjectOwner() | IsCommentOwner() + undelete_comment_perms = IsCommentProjectOwner() | IsCommentDeleter() class WikiHistoryPermission(TaigaResourcePermission): retrieve_perms = HasProjectPerm('view_project') - delete_comment_perms = IsProjectOwner() | IsCommentOwner() - undelete_comment_perms = IsProjectOwner() | IsCommentDeleter() + delete_comment_perms = IsCommentProjectOwner() | IsCommentOwner() + undelete_comment_perms = IsCommentProjectOwner() | IsCommentDeleter() diff --git a/taiga/projects/history/services.py b/taiga/projects/history/services.py index 31e56f99..c79c7eec 100644 --- a/taiga/projects/history/services.py +++ b/taiga/projects/history/services.py @@ -81,6 +81,14 @@ def get_model_from_key(key:str) -> object: return apps.get_model(class_name) +def get_pk_from_key(key:str) -> object: + """ + Get pk from key + """ + class_name, pk = key.split(":", 1) + return pk + + def register_values_implementation(typename:str, fn=None): """ Register values implementation for specified typename. diff --git a/tests/factories.py b/tests/factories.py index bc2dddc8..f49e4d49 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -400,6 +400,13 @@ class AttachmentFactory(Factory): attached_file = factory.django.FileField(data=b"File contents") +class HistoryEntryFactory(Factory): + class Meta: + model = "history.HistoryEntry" + strategy = factory.CREATE_STRATEGY + + type = 1 + def create_issue(**kwargs): "Create an issue and along with its dependencies." owner = kwargs.pop("owner", None) diff --git a/tests/integration/test_history.py b/tests/integration/test_history.py index 73334d7d..690b724e 100644 --- a/tests/integration/test_history.py +++ b/tests/integration/test_history.py @@ -26,7 +26,7 @@ from .. import factories as f from taiga.projects.history import services from taiga.projects.history.models import HistoryEntry from taiga.projects.history.choices import HistoryType - +from taiga.projects.history.services import make_key_from_model_object pytestmark = pytest.mark.django_db @@ -216,3 +216,19 @@ def test_history_with_only_comment_shouldnot_be_hidden(client): assert response.status_code == 200, response.content assert qs_all.count() == 1 assert qs_hidden.count() == 0 + + +def test_delete_comment_by_project_owner(client): + project = f.create_project() + us = f.create_userstory(project=project) + membership = f.MembershipFactory.create(project=project, user=project.owner, is_owner=True) + key = make_key_from_model_object(us) + history_entry = f.HistoryEntryFactory.create(type=HistoryType.change, + comment="testing", + key=key) + + client.login(project.owner) + url = reverse("userstory-history-delete-comment", args=(us.id,)) + url = "%s?id=%s"%(url, history_entry.id) + response = client.post(url, content_type="application/json") + assert 200 == response.status_code, response.status_code