From 688e047ff8c2c43c402e24635a0b10f73607f0bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Thu, 11 Sep 2014 17:55:53 +0200 Subject: [PATCH] Delete comments functionality --- taiga/base/api/permissions.py | 5 +++ taiga/export_import/serializers.py | 1 + taiga/projects/history/api.py | 41 +++++++++++++++++++ .../migrations/0002_auto_20140916_0936.py | 28 +++++++++++++ taiga/projects/history/models.py | 5 +++ taiga/projects/history/permissions.py | 16 +++++++- taiga/projects/issues/permissions.py | 1 + 7 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 taiga/projects/history/migrations/0002_auto_20140916_0936.py diff --git a/taiga/base/api/permissions.py b/taiga/base/api/permissions.py index 28954745..d00a089c 100644 --- a/taiga/base/api/permissions.py +++ b/taiga/base/api/permissions.py @@ -207,6 +207,11 @@ class IsProjectOwner(PermissionComponent): return is_project_owner(request.user, obj) +class IsObjectOwner(PermissionComponent): + def check_permissions(self, request, view, obj=None): + return obj.owner == request.user + + ###################################################################### # Generic permissions. ###################################################################### diff --git a/taiga/export_import/serializers.py b/taiga/export_import/serializers.py index 9bade4f5..977da9d7 100644 --- a/taiga/export_import/serializers.py +++ b/taiga/export_import/serializers.py @@ -186,6 +186,7 @@ class HistoryExportSerializer(serializers.ModelSerializer): snapshot = JsonField(required=False) values = HistoryValuesField(required=False) comment = CommentField(required=False) + delete_comment_user = HistoryUserField(required=False) class Meta: model = history_models.HistoryEntry diff --git a/taiga/projects/history/api.py b/taiga/projects/history/api.py index b606fb28..622946ae 100644 --- a/taiga/projects/history/api.py +++ b/taiga/projects/history/api.py @@ -16,9 +16,12 @@ from django.contrib.contenttypes.models import ContentType from django.shortcuts import get_object_or_404 +from django.utils import timezone from rest_framework.response import Response +from rest_framework import status +from taiga.base.decorators import detail_route from taiga.base.api import ReadOnlyListViewSet from . import permissions @@ -53,6 +56,44 @@ class HistoryViewSet(ReadOnlyListViewSet): return Response(serializer.data) + @detail_route(methods=['post']) + def delete_comment(self, request, pk): + obj = self.get_object() + self.check_permissions(request, 'delete_comment', obj) + + comment_id = request.QUERY_PARAMS.get('id', None) + comment = services.get_history_queryset_by_model_instance(obj).filter(id=comment_id).first() + + if comment is None: + return Response(status=status.HTTP_404_NOT_FOUND) + + if comment.delete_comment_date or comment.delete_comment_user: + return Response({"error": "Comment already deleted"}, status=status.HTTP_400_BAD_REQUEST) + + comment.delete_comment_date = timezone.now() + comment.delete_comment_user = request.user + comment.save() + return Response(status=status.HTTP_200_OK) + + @detail_route(methods=['post']) + def undelete_comment(self, request, pk): + obj = self.get_object() + self.check_permissions(request, 'undelete_comment', obj) + + comment_id = request.QUERY_PARAMS.get('id', None) + comment = services.get_history_queryset_by_model_instance(obj).filter(id=comment_id).first() + + if comment is None: + return Response(status=status.HTTP_404_NOT_FOUND) + + if not comment.delete_comment_date and not comment.delete_comment_user: + return Response({"error": "Comment not deleted"}, status=status.HTTP_400_BAD_REQUEST) + + comment.delete_comment_date = None + comment.delete_comment_user = None + comment.save() + return Response(status=status.HTTP_200_OK) + # Just for restframework! Because it raises # 404 on main api root if this method not exists. def list(self, request): diff --git a/taiga/projects/history/migrations/0002_auto_20140916_0936.py b/taiga/projects/history/migrations/0002_auto_20140916_0936.py new file mode 100644 index 00000000..b78c6da4 --- /dev/null +++ b/taiga/projects/history/migrations/0002_auto_20140916_0936.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +from django.conf import settings + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('history', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='historyentry', + name='delete_comment_date', + field=models.DateTimeField(default=None, null=True, blank=True), + preserve_default=True, + ), + migrations.AddField( + model_name='historyentry', + name='delete_comment_user', + field=models.ForeignKey(null=True, default=None, related_name='deleted_comments', to=settings.AUTH_USER_MODEL, blank=True), + preserve_default=True, + ), + ] diff --git a/taiga/projects/history/models.py b/taiga/projects/history/models.py index 051eb98b..a6ae8b15 100644 --- a/taiga/projects/history/models.py +++ b/taiga/projects/history/models.py @@ -19,6 +19,7 @@ from django.utils import timezone from django.db import models from django.db.models.loading import get_model from django.utils.functional import cached_property +from django.conf import settings from django_pgjson.fields import JsonField from taiga.mdrender.service import get_diff_of_htmls @@ -64,6 +65,10 @@ class HistoryEntry(models.Model): comment = models.TextField(blank=True) comment_html = models.TextField(blank=True) + delete_comment_date = models.DateTimeField(null=True, blank=True, default=None) + delete_comment_user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, default=None, + related_name="deleted_comments") + @cached_property def is_comment(self): return self.type == HistoryType.comment diff --git a/taiga/projects/history/permissions.py b/taiga/projects/history/permissions.py index 64b219d1..d81cbbe8 100644 --- a/taiga/projects/history/permissions.py +++ b/taiga/projects/history/permissions.py @@ -15,20 +15,34 @@ # along with this program. If not, see . from taiga.base.api.permissions import (TaigaResourcePermission, HasProjectPerm, - IsProjectOwner, AllowAny) + IsProjectOwner, AllowAny, + IsObjectOwner, PermissionComponent) + + +class IsCommentDeleter(PermissionComponent): + def check_permissions(self, request, view, obj=None): + return obj.delete_comment_user == request.user class UserStoryHistoryPermission(TaigaResourcePermission): retrieve_perms = HasProjectPerm('view_project') + delete_comment_perms = IsProjectOwner() | IsObjectOwner() + undelete_comment_perms = IsProjectOwner() | IsCommentDeleter() class TaskHistoryPermission(TaigaResourcePermission): retrieve_perms = HasProjectPerm('view_project') + delete_comment_perms = IsProjectOwner() | IsObjectOwner() + undelete_comment_perms = IsProjectOwner() | IsCommentDeleter() class IssueHistoryPermission(TaigaResourcePermission): retrieve_perms = HasProjectPerm('view_project') + delete_comment_perms = IsProjectOwner() | IsObjectOwner() + undelete_comment_perms = IsProjectOwner() | IsCommentDeleter() class WikiHistoryPermission(TaigaResourcePermission): retrieve_perms = HasProjectPerm('view_project') + delete_comment_perms = IsProjectOwner() | IsObjectOwner() + undelete_comment_perms = IsProjectOwner() | IsCommentDeleter() diff --git a/taiga/projects/issues/permissions.py b/taiga/projects/issues/permissions.py index 5700387d..b5689a7e 100644 --- a/taiga/projects/issues/permissions.py +++ b/taiga/projects/issues/permissions.py @@ -31,6 +31,7 @@ class IssuePermission(TaigaResourcePermission): upvote_perms = IsAuthenticated() & HasProjectPerm('vote_issues') downvote_perms = IsAuthenticated() & HasProjectPerm('vote_issues') bulk_create_perms = HasProjectPerm('add_issue') + delete_comment_perms= HasProjectPerm('modify_issue') class HasIssueIdUrlParam(PermissionComponent):