diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0b5f288a..eca3114a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
# Changelog #
+## 2.2.0 ??? (unreleased)
+### Features
+- [API] edit comment endpoint: comment owners and project admins can edit existing comments
+
## 2.1.0 Ursus Americanus (2016-05-03)
diff --git a/taiga/projects/history/api.py b/taiga/projects/history/api.py
index d10194ce..3f1ca240 100644
--- a/taiga/projects/history/api.py
+++ b/taiga/projects/history/api.py
@@ -23,6 +23,7 @@ from taiga.base import response
from taiga.base.decorators import detail_route
from taiga.base.api import ReadOnlyListViewSet
from taiga.base.api.utils import get_object_or_404
+from taiga.mdrender.service import render as mdrender
from . import permissions
from . import serializers
@@ -56,42 +57,93 @@ class HistoryViewSet(ReadOnlyListViewSet):
return response.Ok(serializer.data)
+ @detail_route(methods=['get'])
+ def comment_versions(self, request, pk):
+ obj = self.get_object()
+ history_entry_id = request.QUERY_PARAMS.get('id', None)
+ history_entry = services.get_history_queryset_by_model_instance(obj).filter(id=history_entry_id).first()
+
+ self.check_permissions(request, 'comment_versions', history_entry)
+
+ if history_entry is None:
+ return response.NotFound()
+
+ history_entry.attach_user_info_to_comment_versions()
+ return response.Ok(history_entry.comment_versions)
+
+ @detail_route(methods=['post'])
+ def edit_comment(self, request, pk):
+ obj = self.get_object()
+ history_entry_id = request.QUERY_PARAMS.get('id', None)
+ history_entry = services.get_history_queryset_by_model_instance(obj).filter(id=history_entry_id).first()
+ obj = services.get_instance_from_key(history_entry.key)
+ comment = request.DATA.get("comment", None)
+
+ self.check_permissions(request, 'edit_comment', history_entry)
+
+ if history_entry is None:
+ return response.NotFound()
+
+ if comment is None:
+ return response.BadRequest({"error": _("comment is required")})
+
+ if history_entry.delete_comment_date or history_entry.delete_comment_user:
+ return response.BadRequest({"error": _("deleted comments can't be edited")})
+
+ # comment_versions can be None if there are no historic versions of the comment
+ comment_versions = history_entry.comment_versions or []
+ comment_versions.append({
+ "date": history_entry.created_at,
+ "comment": history_entry.comment,
+ "comment_html": history_entry.comment_html,
+ "user": {
+ "id": request.user.pk,
+ }
+ })
+
+ history_entry.edit_comment_date = timezone.now()
+ history_entry.comment = comment
+ history_entry.comment_html = mdrender(obj.project, comment)
+ history_entry.comment_versions = comment_versions
+ history_entry.save()
+ return response.Ok()
+
@detail_route(methods=['post'])
def delete_comment(self, request, pk):
obj = self.get_object()
- comment_id = request.QUERY_PARAMS.get('id', None)
- comment = services.get_history_queryset_by_model_instance(obj).filter(id=comment_id).first()
+ history_entry_id = request.QUERY_PARAMS.get('id', None)
+ history_entry = services.get_history_queryset_by_model_instance(obj).filter(id=history_entry_id).first()
- self.check_permissions(request, 'delete_comment', comment)
+ self.check_permissions(request, 'delete_comment', history_entry)
- if comment is None:
+ if history_entry is None:
return response.NotFound()
- if comment.delete_comment_date or comment.delete_comment_user:
+ if history_entry.delete_comment_date or history_entry.delete_comment_user:
return response.BadRequest({"error": _("Comment already deleted")})
- comment.delete_comment_date = timezone.now()
- comment.delete_comment_user = {"pk": request.user.pk, "name": request.user.get_full_name()}
- comment.save()
+ history_entry.delete_comment_date = timezone.now()
+ history_entry.delete_comment_user = {"pk": request.user.pk, "name": request.user.get_full_name()}
+ history_entry.save()
return response.Ok()
@detail_route(methods=['post'])
def undelete_comment(self, request, pk):
obj = self.get_object()
- comment_id = request.QUERY_PARAMS.get('id', None)
- comment = services.get_history_queryset_by_model_instance(obj).filter(id=comment_id).first()
+ history_entry_id = request.QUERY_PARAMS.get('id', None)
+ history_entry = services.get_history_queryset_by_model_instance(obj).filter(id=history_entry_id).first()
- self.check_permissions(request, 'undelete_comment', comment)
+ self.check_permissions(request, 'undelete_comment', history_entry)
- if comment is None:
+ if history_entry is None:
return response.NotFound()
- if not comment.delete_comment_date and not comment.delete_comment_user:
+ if not history_entry.delete_comment_date and not history_entry.delete_comment_user:
return response.BadRequest({"error": _("Comment not deleted")})
- comment.delete_comment_date = None
- comment.delete_comment_user = None
- comment.save()
+ history_entry.delete_comment_date = None
+ history_entry.delete_comment_user = None
+ history_entry.save()
return response.Ok()
# Just for restframework! Because it raises
diff --git a/taiga/projects/history/migrations/0009_auto_20160512_1110.py b/taiga/projects/history/migrations/0009_auto_20160512_1110.py
new file mode 100644
index 00000000..0cf39023
--- /dev/null
+++ b/taiga/projects/history/migrations/0009_auto_20160512_1110.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.2 on 2016-05-12 11:10
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django_pgjson.fields
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('history', '0008_auto_20150508_1028'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='historyentry',
+ name='comment_versions',
+ field=django_pgjson.fields.JsonField(blank=True, default=None, null=True),
+ ),
+ migrations.AddField(
+ model_name='historyentry',
+ name='edit_comment_date',
+ field=models.DateTimeField(blank=True, default=None, null=True),
+ ),
+ ]
diff --git a/taiga/projects/history/models.py b/taiga/projects/history/models.py
index e947c6fe..39012f60 100644
--- a/taiga/projects/history/models.py
+++ b/taiga/projects/history/models.py
@@ -67,6 +67,10 @@ class HistoryEntry(models.Model):
delete_comment_date = models.DateTimeField(null=True, blank=True, default=None)
delete_comment_user = JsonField(null=True, blank=True, default=None)
+ # Historic version of comments
+ comment_versions = JsonField(null=True, blank=True, default=None)
+ edit_comment_date = models.DateTimeField(null=True, blank=True, default=None)
+
# Flag for mark some history entries as
# hidden. Hidden history entries are important
# for save but not important to preview.
@@ -111,6 +115,20 @@ class HistoryEntry(models.Model):
self._owner = owner
self._prefetched_owner = True
+ def attach_user_info_to_comment_versions(self):
+ if not self.comment_versions:
+ return
+
+ from taiga.users.serializers import UserSerializer
+
+ user_ids = [v["user"]["id"] for v in self.comment_versions if "user" in v and "id" in v["user"]]
+ users_by_id = {u.id: u for u in get_user_model().objects.filter(id__in=user_ids)}
+
+ for version in self.comment_versions:
+ user = users_by_id.get(version["user"]["id"], None)
+ if user:
+ version["user"] = UserSerializer(user).data
+
@cached_property
def values_diff(self):
result = {}
diff --git a/taiga/projects/history/permissions.py b/taiga/projects/history/permissions.py
index 015ac22c..fdce68cd 100644
--- a/taiga/projects/history/permissions.py
+++ b/taiga/projects/history/permissions.py
@@ -33,32 +33,41 @@ class IsCommentOwner(PermissionComponent):
return obj.user and obj.user.get("pk", "not-pk") == request.user.pk
-class IsCommentProjectOwner(PermissionComponent):
+class IsCommentProjectAdmin(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_admin(request.user, project)
+
class UserStoryHistoryPermission(TaigaResourcePermission):
retrieve_perms = HasProjectPerm('view_project')
- delete_comment_perms = IsCommentProjectOwner() | IsCommentOwner()
- undelete_comment_perms = IsCommentProjectOwner() | IsCommentDeleter()
+ edit_comment_perms = IsCommentProjectAdmin() | IsCommentOwner()
+ delete_comment_perms = IsCommentProjectAdmin() | IsCommentOwner()
+ undelete_comment_perms = IsCommentProjectAdmin() | IsCommentDeleter()
+ comment_versions_perms = IsCommentProjectAdmin() | IsCommentOwner()
class TaskHistoryPermission(TaigaResourcePermission):
retrieve_perms = HasProjectPerm('view_project')
- delete_comment_perms = IsCommentProjectOwner() | IsCommentOwner()
- undelete_comment_perms = IsCommentProjectOwner() | IsCommentDeleter()
+ edit_comment_perms = IsCommentProjectAdmin() | IsCommentOwner()
+ delete_comment_perms = IsCommentProjectAdmin() | IsCommentOwner()
+ undelete_comment_perms = IsCommentProjectAdmin() | IsCommentDeleter()
+ comment_versions_perms = IsCommentProjectAdmin() | IsCommentOwner()
class IssueHistoryPermission(TaigaResourcePermission):
retrieve_perms = HasProjectPerm('view_project')
- delete_comment_perms = IsCommentProjectOwner() | IsCommentOwner()
- undelete_comment_perms = IsCommentProjectOwner() | IsCommentDeleter()
+ edit_comment_perms = IsCommentProjectAdmin() | IsCommentOwner()
+ delete_comment_perms = IsCommentProjectAdmin() | IsCommentOwner()
+ undelete_comment_perms = IsCommentProjectAdmin() | IsCommentDeleter()
+ comment_versions_perms = IsCommentProjectAdmin() | IsCommentOwner()
class WikiHistoryPermission(TaigaResourcePermission):
retrieve_perms = HasProjectPerm('view_project')
- delete_comment_perms = IsCommentProjectOwner() | IsCommentOwner()
- undelete_comment_perms = IsCommentProjectOwner() | IsCommentDeleter()
+ edit_comment_perms = IsCommentProjectAdmin() | IsCommentOwner()
+ delete_comment_perms = IsCommentProjectAdmin() | IsCommentOwner()
+ undelete_comment_perms = IsCommentProjectAdmin() | IsCommentDeleter()
+ comment_versions_perms = IsCommentProjectAdmin() | IsCommentOwner()
diff --git a/taiga/projects/history/serializers.py b/taiga/projects/history/serializers.py
index 72b3c763..f231f29c 100644
--- a/taiga/projects/history/serializers.py
+++ b/taiga/projects/history/serializers.py
@@ -33,9 +33,11 @@ class HistoryEntrySerializer(serializers.ModelSerializer):
values_diff = I18NJsonField(i18n_fields=HISTORY_ENTRY_I18N_FIELDS)
user = serializers.SerializerMethodField("get_user")
delete_comment_user = JsonField()
+ comment_versions = JsonField()
class Meta:
model = models.HistoryEntry
+ exclude = ("comment_versions",)
def get_user(self, entry):
user = {"pk": None, "username": None, "name": None, "photo": None, "is_active": False}
diff --git a/taiga/projects/history/services.py b/taiga/projects/history/services.py
index 22839ec8..61004471 100644
--- a/taiga/projects/history/services.py
+++ b/taiga/projects/history/services.py
@@ -91,6 +91,20 @@ def get_pk_from_key(key:str) -> object:
return pk
+def get_instance_from_key(key:str) -> object:
+ """
+ Get instance from key
+ """
+ model = get_model_from_key(key)
+ pk = get_pk_from_key(key)
+ try:
+ obj = model.objects.get(pk=pk)
+ return obj
+ except model.DoesNotExist:
+ # Catch simultaneous DELETE request
+ return None
+
+
def register_values_implementation(typename:str, fn=None):
"""
Register values implementation for specified typename.
diff --git a/taiga/timeline/signals.py b/taiga/timeline/signals.py
index eda08031..c0f1dffa 100644
--- a/taiga/timeline/signals.py
+++ b/taiga/timeline/signals.py
@@ -44,7 +44,6 @@ def _clean_description_fields(values_diff):
def on_new_history_entry(sender, instance, created, **kwargs):
-
if instance._importing:
return
@@ -81,6 +80,10 @@ def on_new_history_entry(sender, instance, created, **kwargs):
if instance.delete_comment_date:
extra_data["comment_deleted"] = True
+ # Detect edited comment
+ if instance.comment_versions is not None and len(instance.comment_versions)>0:
+ extra_data["comment_edited"] = True
+
created_datetime = instance.created_at
_push_to_timelines(project, user, obj, event_type, created_datetime, extra_data=extra_data)
diff --git a/tests/integration/resources_permissions/test_history_resources.py b/tests/integration/resources_permissions/test_history_resources.py
index b0991080..be17510c 100644
--- a/tests/integration/resources_permissions/test_history_resources.py
+++ b/tests/integration/resources_permissions/test_history_resources.py
@@ -1,6 +1,11 @@
from django.core.urlresolvers import reverse
+from django.utils import timezone
+from taiga.base.utils import json
from taiga.permissions.permissions import MEMBERS_PERMISSIONS, ANON_PERMISSIONS, USER_PERMISSIONS
+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
from tests import factories as f
from tests.utils import helper_test_http_method, disconnect_signals, reconnect_signals
@@ -21,11 +26,11 @@ def teardown_module(module):
def data():
m = type("Models", (object,), {})
- m.registered_user = f.UserFactory.create()
- m.project_member_with_perms = f.UserFactory.create()
- m.project_member_without_perms = f.UserFactory.create()
- m.project_owner = f.UserFactory.create()
- m.other_user = f.UserFactory.create()
+ m.registered_user = f.UserFactory.create(full_name="registered_user")
+ m.project_member_with_perms = f.UserFactory.create(full_name="project_member_with_perms")
+ m.project_member_without_perms = f.UserFactory.create(full_name="project_member_without_perms")
+ m.project_owner = f.UserFactory.create(full_name="project_owner")
+ m.other_user = f.UserFactory.create(full_name="other_user")
m.public_project = f.ProjectFactory(is_private=False,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
@@ -76,39 +81,33 @@ def data():
return m
+#########################################################
+## User stories
+#########################################################
+
+
@pytest.fixture
def data_us(data):
m = type("Models", (object,), {})
m.public_user_story = f.UserStoryFactory(project=data.public_project, ref=1)
+ m.public_history_entry = f.HistoryEntryFactory.create(type=HistoryType.change,
+ comment="testing public",
+ key=make_key_from_model_object(m.public_user_story),
+ diff={},
+ user={"pk": data.project_member_with_perms.pk})
+
m.private_user_story1 = f.UserStoryFactory(project=data.private_project1, ref=5)
+ m.private_history_entry1 = f.HistoryEntryFactory.create(type=HistoryType.change,
+ comment="testing 1",
+ key=make_key_from_model_object(m.private_user_story1),
+ diff={},
+ user={"pk": data.project_member_with_perms.pk})
m.private_user_story2 = f.UserStoryFactory(project=data.private_project2, ref=9)
- return m
-
-
-@pytest.fixture
-def data_task(data):
- m = type("Models", (object,), {})
- m.public_task = f.TaskFactory(project=data.public_project, ref=2)
- m.private_task1 = f.TaskFactory(project=data.private_project1, ref=6)
- m.private_task2 = f.TaskFactory(project=data.private_project2, ref=10)
- return m
-
-
-@pytest.fixture
-def data_issue(data):
- m = type("Models", (object,), {})
- m.public_issue = f.IssueFactory(project=data.public_project, ref=3)
- m.private_issue1 = f.IssueFactory(project=data.private_project1, ref=7)
- m.private_issue2 = f.IssueFactory(project=data.private_project2, ref=11)
- return m
-
-
-@pytest.fixture
-def data_wiki(data):
- m = type("Models", (object,), {})
- m.public_wiki = f.WikiPageFactory(project=data.public_project, slug=4)
- m.private_wiki1 = f.WikiPageFactory(project=data.private_project1, slug=8)
- m.private_wiki2 = f.WikiPageFactory(project=data.private_project2, slug=12)
+ m.private_history_entry2 = f.HistoryEntryFactory.create(type=HistoryType.change,
+ comment="testing 2",
+ key=make_key_from_model_object(m.private_user_story2),
+ diff={},
+ user={"pk": data.project_member_with_perms.pk})
return m
@@ -133,6 +132,222 @@ def test_user_story_history_retrieve(client, data, data_us):
assert results == [401, 403, 403, 200, 200]
+def test_user_story_action_edit_comment(client, data, data_us):
+ public_url = "{}?id={}".format(
+ reverse('userstory-history-edit-comment', kwargs={"pk": data_us.public_user_story.pk}),
+ data_us.public_history_entry.id
+ )
+ private_url1 = "{}?id={}".format(
+ reverse('userstory-history-edit-comment', kwargs={"pk": data_us.private_user_story1.pk}),
+ data_us.private_history_entry1.id
+ )
+ private_url2 = "{}?id={}".format(
+ reverse('userstory-history-edit-comment', kwargs={"pk": data_us.private_user_story2.pk}),
+ data_us.private_history_entry2.id
+ )
+
+ users = [
+ None,
+ data.registered_user,
+ data.project_member_without_perms,
+ data.project_member_with_perms,
+ data.project_owner
+ ]
+
+ data = json.dumps({"comment": "testing update comment"})
+
+ results = helper_test_http_method(client, 'post', public_url, data, users)
+ assert results == [401, 403, 403, 200, 200]
+ results = helper_test_http_method(client, 'post', private_url1, data, users)
+ assert results == [401, 403, 403, 200, 200]
+ results = helper_test_http_method(client, 'post', private_url2, data, users)
+ assert results == [401, 403, 403, 200, 200]
+
+
+def test_user_story_action_delete_comment(client, data, data_us):
+ public_url = "{}?id={}".format(
+ reverse('userstory-history-delete-comment', kwargs={"pk": data_us.public_user_story.pk}),
+ data_us.public_history_entry.id
+ )
+ private_url1 = "{}?id={}".format(
+ reverse('userstory-history-delete-comment', kwargs={"pk": data_us.private_user_story1.pk}),
+ data_us.private_history_entry1.id
+ )
+ private_url2 = "{}?id={}".format(
+ reverse('userstory-history-delete-comment', kwargs={"pk": data_us.private_user_story2.pk}),
+ data_us.private_history_entry2.id
+ )
+
+ users_and_statuses = [
+ (None, 401),
+ (data.registered_user, 403),
+ (data.project_member_without_perms, 403),
+ (data.project_member_with_perms, 200),
+ (data.project_owner, 200),
+ ]
+
+ for user, status_code in users_and_statuses:
+ data_us.public_history_entry.delete_comment_date = None
+ data_us.public_history_entry.delete_comment_user = None
+ data_us.public_history_entry.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(public_url)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+ for user, status_code in users_and_statuses:
+ data_us.private_history_entry1.delete_comment_date = None
+ data_us.private_history_entry1.delete_comment_user = None
+ data_us.private_history_entry1.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(private_url1)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+ for user, status_code in users_and_statuses:
+ data_us.private_history_entry2.delete_comment_date = None
+ data_us.private_history_entry2.delete_comment_user = None
+ data_us.private_history_entry2.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(private_url2)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+
+def test_user_story_action_undelete_comment(client, data, data_us):
+ public_url = "{}?id={}".format(
+ reverse('userstory-history-undelete-comment', kwargs={"pk": data_us.public_user_story.pk}),
+ data_us.public_history_entry.id
+ )
+ private_url1 = "{}?id={}".format(
+ reverse('userstory-history-undelete-comment', kwargs={"pk": data_us.private_user_story1.pk}),
+ data_us.private_history_entry1.id
+ )
+ private_url2 = "{}?id={}".format(
+ reverse('userstory-history-undelete-comment', kwargs={"pk": data_us.private_user_story2.pk}),
+ data_us.private_history_entry2.id
+ )
+
+ users_and_statuses = [
+ (None, 401),
+ (data.registered_user, 403),
+ (data.project_member_without_perms, 403),
+ (data.project_member_with_perms, 200),
+ (data.project_owner, 200),
+ ]
+
+ for user, status_code in users_and_statuses:
+ data_us.public_history_entry.delete_comment_date = timezone.now()
+ data_us.public_history_entry.delete_comment_user = {"pk": data.project_member_with_perms.pk}
+ data_us.public_history_entry.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(public_url)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+ for user, status_code in users_and_statuses:
+ data_us.private_history_entry1.delete_comment_date = timezone.now()
+ data_us.private_history_entry1.delete_comment_user = {"pk": data.project_member_with_perms.pk}
+ data_us.private_history_entry1.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(private_url1)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+ for user, status_code in users_and_statuses:
+ data_us.private_history_entry2.delete_comment_date = timezone.now()
+ data_us.private_history_entry2.delete_comment_user = {"pk": data.project_member_with_perms.pk}
+ data_us.private_history_entry2.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(private_url2)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+
+def test_user_story_action_comment_versions(client, data, data_us):
+ public_url = "{}?id={}".format(
+ reverse('userstory-history-comment-versions', kwargs={"pk": data_us.public_user_story.pk}),
+ data_us.public_history_entry.id
+ )
+ private_url1 = "{}?id={}".format(
+ reverse('userstory-history-comment-versions', kwargs={"pk": data_us.private_user_story1.pk}),
+ data_us.private_history_entry1.id
+ )
+ private_url2 = "{}?id={}".format(
+ reverse('userstory-history-comment-versions', kwargs={"pk": data_us.private_user_story2.pk}),
+ data_us.private_history_entry2.id
+ )
+
+ users = [
+ None,
+ data.registered_user,
+ data.project_member_without_perms,
+ data.project_member_with_perms,
+ data.project_owner,
+ ]
+
+ results = helper_test_http_method(client, 'get', public_url, None, users)
+ assert results == [401, 403, 403, 200, 200]
+ results = helper_test_http_method(client, 'get', private_url1, None, users)
+ assert results == [401, 403, 403, 200, 200]
+ results = helper_test_http_method(client, 'get', private_url2, None, users)
+ assert results == [401, 403, 403, 200, 200]
+
+
+#########################################################
+## Tasks
+#########################################################
+
+
+@pytest.fixture
+def data_task(data):
+ m = type("Models", (object,), {})
+ m.public_task = f.TaskFactory(project=data.public_project, ref=2)
+ m.public_history_entry = f.HistoryEntryFactory.create(type=HistoryType.change,
+ comment="testing public",
+ key=make_key_from_model_object(m.public_task),
+ diff={},
+ user={"pk": data.project_member_with_perms.pk})
+
+ m.private_task1 = f.TaskFactory(project=data.private_project1, ref=6)
+ m.private_history_entry1 = f.HistoryEntryFactory.create(type=HistoryType.change,
+ comment="testing 1",
+ key=make_key_from_model_object(m.private_task1),
+ diff={},
+ user={"pk": data.project_member_with_perms.pk})
+ m.private_task2 = f.TaskFactory(project=data.private_project2, ref=10)
+ m.private_history_entry2 = f.HistoryEntryFactory.create(type=HistoryType.change,
+ comment="testing 2",
+ key=make_key_from_model_object(m.private_task2),
+ diff={},
+ user={"pk": data.project_member_with_perms.pk})
+ return m
+
+
def test_task_history_retrieve(client, data, data_task):
public_url = reverse('task-history-detail', kwargs={"pk": data_task.public_task.pk})
private_url1 = reverse('task-history-detail', kwargs={"pk": data_task.private_task1.pk})
@@ -154,6 +369,222 @@ def test_task_history_retrieve(client, data, data_task):
assert results == [401, 403, 403, 200, 200]
+def test_task_action_edit_comment(client, data, data_task):
+ public_url = "{}?id={}".format(
+ reverse('task-history-edit-comment', kwargs={"pk": data_task.public_task.pk}),
+ data_task.public_history_entry.id
+ )
+ private_url1 = "{}?id={}".format(
+ reverse('task-history-edit-comment', kwargs={"pk": data_task.private_task1.pk}),
+ data_task.private_history_entry1.id
+ )
+ private_url2 = "{}?id={}".format(
+ reverse('task-history-edit-comment', kwargs={"pk": data_task.private_task2.pk}),
+ data_task.private_history_entry2.id
+ )
+
+ users = [
+ None,
+ data.registered_user,
+ data.project_member_without_perms,
+ data.project_member_with_perms,
+ data.project_owner
+ ]
+
+ data = json.dumps({"comment": "testing update comment"})
+
+ results = helper_test_http_method(client, 'post', public_url, data, users)
+ assert results == [401, 403, 403, 200, 200]
+ results = helper_test_http_method(client, 'post', private_url1, data, users)
+ assert results == [401, 403, 403, 200, 200]
+ results = helper_test_http_method(client, 'post', private_url2, data, users)
+ assert results == [401, 403, 403, 200, 200]
+
+
+def test_task_action_delete_comment(client, data, data_task):
+ public_url = "{}?id={}".format(
+ reverse('task-history-delete-comment', kwargs={"pk": data_task.public_task.pk}),
+ data_task.public_history_entry.id
+ )
+ private_url1 = "{}?id={}".format(
+ reverse('task-history-delete-comment', kwargs={"pk": data_task.private_task1.pk}),
+ data_task.private_history_entry1.id
+ )
+ private_url2 = "{}?id={}".format(
+ reverse('task-history-delete-comment', kwargs={"pk": data_task.private_task2.pk}),
+ data_task.private_history_entry2.id
+ )
+
+ users_and_statuses = [
+ (None, 401),
+ (data.registered_user, 403),
+ (data.project_member_without_perms, 403),
+ (data.project_member_with_perms, 200),
+ (data.project_owner, 200),
+ ]
+
+ for user, status_code in users_and_statuses:
+ data_task.public_history_entry.delete_comment_date = None
+ data_task.public_history_entry.delete_comment_user = None
+ data_task.public_history_entry.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(public_url)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+ for user, status_code in users_and_statuses:
+ data_task.private_history_entry1.delete_comment_date = None
+ data_task.private_history_entry1.delete_comment_user = None
+ data_task.private_history_entry1.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(private_url1)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+ for user, status_code in users_and_statuses:
+ data_task.private_history_entry2.delete_comment_date = None
+ data_task.private_history_entry2.delete_comment_user = None
+ data_task.private_history_entry2.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(private_url2)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+
+def test_task_action_undelete_comment(client, data, data_task):
+ public_url = "{}?id={}".format(
+ reverse('task-history-undelete-comment', kwargs={"pk": data_task.public_task.pk}),
+ data_task.public_history_entry.id
+ )
+ private_url1 = "{}?id={}".format(
+ reverse('task-history-undelete-comment', kwargs={"pk": data_task.private_task1.pk}),
+ data_task.private_history_entry1.id
+ )
+ private_url2 = "{}?id={}".format(
+ reverse('task-history-undelete-comment', kwargs={"pk": data_task.private_task2.pk}),
+ data_task.private_history_entry2.id
+ )
+
+ users_and_statuses = [
+ (None, 401),
+ (data.registered_user, 403),
+ (data.project_member_without_perms, 403),
+ (data.project_member_with_perms, 200),
+ (data.project_owner, 200),
+ ]
+
+ for user, status_code in users_and_statuses:
+ data_task.public_history_entry.delete_comment_date = timezone.now()
+ data_task.public_history_entry.delete_comment_user = {"pk": data.project_member_with_perms.pk}
+ data_task.public_history_entry.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(public_url)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+ for user, status_code in users_and_statuses:
+ data_task.private_history_entry1.delete_comment_date = timezone.now()
+ data_task.private_history_entry1.delete_comment_user = {"pk": data.project_member_with_perms.pk}
+ data_task.private_history_entry1.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(private_url1)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+ for user, status_code in users_and_statuses:
+ data_task.private_history_entry2.delete_comment_date = timezone.now()
+ data_task.private_history_entry2.delete_comment_user = {"pk": data.project_member_with_perms.pk}
+ data_task.private_history_entry2.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(private_url2)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+
+def test_task_action_comment_versions(client, data, data_task):
+ public_url = "{}?id={}".format(
+ reverse('task-history-comment-versions', kwargs={"pk": data_task.public_task.pk}),
+ data_task.public_history_entry.id
+ )
+ private_url1 = "{}?id={}".format(
+ reverse('task-history-comment-versions', kwargs={"pk": data_task.private_task1.pk}),
+ data_task.private_history_entry1.id
+ )
+ private_url2 = "{}?id={}".format(
+ reverse('task-history-comment-versions', kwargs={"pk": data_task.private_task2.pk}),
+ data_task.private_history_entry2.id
+ )
+
+ users = [
+ None,
+ data.registered_user,
+ data.project_member_without_perms,
+ data.project_member_with_perms,
+ data.project_owner,
+ ]
+
+ results = helper_test_http_method(client, 'get', public_url, None, users)
+ assert results == [401, 403, 403, 200, 200]
+ results = helper_test_http_method(client, 'get', private_url1, None, users)
+ assert results == [401, 403, 403, 200, 200]
+ results = helper_test_http_method(client, 'get', private_url2, None, users)
+ assert results == [401, 403, 403, 200, 200]
+
+
+#########################################################
+## Issues
+#########################################################
+
+
+@pytest.fixture
+def data_issue(data):
+ m = type("Models", (object,), {})
+ m.public_issue = f.IssueFactory(project=data.public_project, ref=3)
+ m.public_history_entry = f.HistoryEntryFactory.create(type=HistoryType.change,
+ comment="testing public",
+ key=make_key_from_model_object(m.public_issue),
+ diff={},
+ user={"pk": data.project_member_with_perms.pk})
+
+ m.private_issue1 = f.IssueFactory(project=data.private_project1, ref=7)
+ m.private_history_entry1 = f.HistoryEntryFactory.create(type=HistoryType.change,
+ comment="testing 1",
+ key=make_key_from_model_object(m.private_issue1),
+ diff={},
+ user={"pk": data.project_member_with_perms.pk})
+ m.private_issue2 = f.IssueFactory(project=data.private_project2, ref=11)
+ m.private_history_entry2 = f.HistoryEntryFactory.create(type=HistoryType.change,
+ comment="testing 2",
+ key=make_key_from_model_object(m.private_issue2),
+ diff={},
+ user={"pk": data.project_member_with_perms.pk})
+ return m
+
+
def test_issue_history_retrieve(client, data, data_issue):
public_url = reverse('issue-history-detail', kwargs={"pk": data_issue.public_issue.pk})
private_url1 = reverse('issue-history-detail', kwargs={"pk": data_issue.private_issue1.pk})
@@ -175,6 +606,222 @@ def test_issue_history_retrieve(client, data, data_issue):
assert results == [401, 403, 403, 200, 200]
+def test_issue_action_edit_comment(client, data, data_issue):
+ public_url = "{}?id={}".format(
+ reverse('issue-history-edit-comment', kwargs={"pk": data_issue.public_issue.pk}),
+ data_issue.public_history_entry.id
+ )
+ private_url1 = "{}?id={}".format(
+ reverse('issue-history-edit-comment', kwargs={"pk": data_issue.private_issue1.pk}),
+ data_issue.private_history_entry1.id
+ )
+ private_url2 = "{}?id={}".format(
+ reverse('issue-history-edit-comment', kwargs={"pk": data_issue.private_issue2.pk}),
+ data_issue.private_history_entry2.id
+ )
+
+ users = [
+ None,
+ data.registered_user,
+ data.project_member_without_perms,
+ data.project_member_with_perms,
+ data.project_owner
+ ]
+
+ data = json.dumps({"comment": "testing update comment"})
+
+ results = helper_test_http_method(client, 'post', public_url, data, users)
+ assert results == [401, 403, 403, 200, 200]
+ results = helper_test_http_method(client, 'post', private_url1, data, users)
+ assert results == [401, 403, 403, 200, 200]
+ results = helper_test_http_method(client, 'post', private_url2, data, users)
+ assert results == [401, 403, 403, 200, 200]
+
+
+def test_issue_action_delete_comment(client, data, data_issue):
+ public_url = "{}?id={}".format(
+ reverse('issue-history-delete-comment', kwargs={"pk": data_issue.public_issue.pk}),
+ data_issue.public_history_entry.id
+ )
+ private_url1 = "{}?id={}".format(
+ reverse('issue-history-delete-comment', kwargs={"pk": data_issue.private_issue1.pk}),
+ data_issue.private_history_entry1.id
+ )
+ private_url2 = "{}?id={}".format(
+ reverse('issue-history-delete-comment', kwargs={"pk": data_issue.private_issue2.pk}),
+ data_issue.private_history_entry2.id
+ )
+
+ users_and_statuses = [
+ (None, 401),
+ (data.registered_user, 403),
+ (data.project_member_without_perms, 403),
+ (data.project_member_with_perms, 200),
+ (data.project_owner, 200),
+ ]
+
+ for user, status_code in users_and_statuses:
+ data_issue.public_history_entry.delete_comment_date = None
+ data_issue.public_history_entry.delete_comment_user = None
+ data_issue.public_history_entry.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(public_url)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+ for user, status_code in users_and_statuses:
+ data_issue.private_history_entry1.delete_comment_date = None
+ data_issue.private_history_entry1.delete_comment_user = None
+ data_issue.private_history_entry1.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(private_url1)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+ for user, status_code in users_and_statuses:
+ data_issue.private_history_entry2.delete_comment_date = None
+ data_issue.private_history_entry2.delete_comment_user = None
+ data_issue.private_history_entry2.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(private_url2)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+
+def test_issue_action_undelete_comment(client, data, data_issue):
+ public_url = "{}?id={}".format(
+ reverse('issue-history-undelete-comment', kwargs={"pk": data_issue.public_issue.pk}),
+ data_issue.public_history_entry.id
+ )
+ private_url1 = "{}?id={}".format(
+ reverse('issue-history-undelete-comment', kwargs={"pk": data_issue.private_issue1.pk}),
+ data_issue.private_history_entry1.id
+ )
+ private_url2 = "{}?id={}".format(
+ reverse('issue-history-undelete-comment', kwargs={"pk": data_issue.private_issue2.pk}),
+ data_issue.private_history_entry2.id
+ )
+
+ users_and_statuses = [
+ (None, 401),
+ (data.registered_user, 403),
+ (data.project_member_without_perms, 403),
+ (data.project_member_with_perms, 200),
+ (data.project_owner, 200),
+ ]
+
+ for user, status_code in users_and_statuses:
+ data_issue.public_history_entry.delete_comment_date = timezone.now()
+ data_issue.public_history_entry.delete_comment_user = {"pk": data.project_member_with_perms.pk}
+ data_issue.public_history_entry.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(public_url)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+ for user, status_code in users_and_statuses:
+ data_issue.private_history_entry1.delete_comment_date = timezone.now()
+ data_issue.private_history_entry1.delete_comment_user = {"pk": data.project_member_with_perms.pk}
+ data_issue.private_history_entry1.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(private_url1)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+ for user, status_code in users_and_statuses:
+ data_issue.private_history_entry2.delete_comment_date = timezone.now()
+ data_issue.private_history_entry2.delete_comment_user = {"pk": data.project_member_with_perms.pk}
+ data_issue.private_history_entry2.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(private_url2)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+
+def test_issue_action_comment_versions(client, data, data_issue):
+ public_url = "{}?id={}".format(
+ reverse('issue-history-comment-versions', kwargs={"pk": data_issue.public_issue.pk}),
+ data_issue.public_history_entry.id
+ )
+ private_url1 = "{}?id={}".format(
+ reverse('issue-history-comment-versions', kwargs={"pk": data_issue.private_issue1.pk}),
+ data_issue.private_history_entry1.id
+ )
+ private_url2 = "{}?id={}".format(
+ reverse('issue-history-comment-versions', kwargs={"pk": data_issue.private_issue2.pk}),
+ data_issue.private_history_entry2.id
+ )
+
+ users = [
+ None,
+ data.registered_user,
+ data.project_member_without_perms,
+ data.project_member_with_perms,
+ data.project_owner,
+ ]
+
+ results = helper_test_http_method(client, 'get', public_url, None, users)
+ assert results == [401, 403, 403, 200, 200]
+ results = helper_test_http_method(client, 'get', private_url1, None, users)
+ assert results == [401, 403, 403, 200, 200]
+ results = helper_test_http_method(client, 'get', private_url2, None, users)
+ assert results == [401, 403, 403, 200, 200]
+
+
+#########################################################
+## Wiki pages
+#########################################################
+
+
+@pytest.fixture
+def data_wiki(data):
+ m = type("Models", (object,), {})
+ m.public_wiki = f.WikiPageFactory(project=data.public_project, slug=4)
+ m.public_history_entry = f.HistoryEntryFactory.create(type=HistoryType.change,
+ comment="testing public",
+ key=make_key_from_model_object(m.public_wiki),
+ diff={},
+ user={"pk": data.project_member_with_perms.pk})
+
+ m.private_wiki1 = f.WikiPageFactory(project=data.private_project1, slug=8)
+ m.private_history_entry1 = f.HistoryEntryFactory.create(type=HistoryType.change,
+ comment="testing 1",
+ key=make_key_from_model_object(m.private_wiki1),
+ diff={},
+ user={"pk": data.project_member_with_perms.pk})
+ m.private_wiki2 = f.WikiPageFactory(project=data.private_project2, slug=12)
+ m.private_history_entry2 = f.HistoryEntryFactory.create(type=HistoryType.change,
+ comment="testing 2",
+ key=make_key_from_model_object(m.private_wiki2),
+ diff={},
+ user={"pk": data.project_member_with_perms.pk})
+ return m
+
+
def test_wiki_history_retrieve(client, data, data_wiki):
public_url = reverse('wiki-history-detail', kwargs={"pk": data_wiki.public_wiki.pk})
private_url1 = reverse('wiki-history-detail', kwargs={"pk": data_wiki.private_wiki1.pk})
@@ -194,3 +841,189 @@ def test_wiki_history_retrieve(client, data, data_wiki):
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', private_url2, None, users)
assert results == [401, 403, 403, 200, 200]
+
+
+def test_wiki_action_edit_comment(client, data, data_wiki):
+ public_url = "{}?id={}".format(
+ reverse('wiki-history-edit-comment', kwargs={"pk": data_wiki.public_wiki.pk}),
+ data_wiki.public_history_entry.id
+ )
+ private_url1 = "{}?id={}".format(
+ reverse('wiki-history-edit-comment', kwargs={"pk": data_wiki.private_wiki1.pk}),
+ data_wiki.private_history_entry1.id
+ )
+ private_url2 = "{}?id={}".format(
+ reverse('wiki-history-edit-comment', kwargs={"pk": data_wiki.private_wiki2.pk}),
+ data_wiki.private_history_entry2.id
+ )
+
+ users = [
+ None,
+ data.registered_user,
+ data.project_member_without_perms,
+ data.project_member_with_perms,
+ data.project_owner
+ ]
+
+ data = json.dumps({"comment": "testing update comment"})
+
+ results = helper_test_http_method(client, 'post', public_url, data, users)
+ assert results == [401, 403, 403, 200, 200]
+ results = helper_test_http_method(client, 'post', private_url1, data, users)
+ assert results == [401, 403, 403, 200, 200]
+ results = helper_test_http_method(client, 'post', private_url2, data, users)
+ assert results == [401, 403, 403, 200, 200]
+
+
+def test_wiki_action_delete_comment(client, data, data_wiki):
+ public_url = "{}?id={}".format(
+ reverse('wiki-history-delete-comment', kwargs={"pk": data_wiki.public_wiki.pk}),
+ data_wiki.public_history_entry.id
+ )
+ private_url1 = "{}?id={}".format(
+ reverse('wiki-history-delete-comment', kwargs={"pk": data_wiki.private_wiki1.pk}),
+ data_wiki.private_history_entry1.id
+ )
+ private_url2 = "{}?id={}".format(
+ reverse('wiki-history-delete-comment', kwargs={"pk": data_wiki.private_wiki2.pk}),
+ data_wiki.private_history_entry2.id
+ )
+
+ users_and_statuses = [
+ (None, 401),
+ (data.registered_user, 403),
+ (data.project_member_without_perms, 403),
+ (data.project_member_with_perms, 200),
+ (data.project_owner, 200),
+ ]
+
+ for user, status_code in users_and_statuses:
+ data_wiki.public_history_entry.delete_comment_date = None
+ data_wiki.public_history_entry.delete_comment_user = None
+ data_wiki.public_history_entry.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(public_url)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+ for user, status_code in users_and_statuses:
+ data_wiki.private_history_entry1.delete_comment_date = None
+ data_wiki.private_history_entry1.delete_comment_user = None
+ data_wiki.private_history_entry1.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(private_url1)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+ for user, status_code in users_and_statuses:
+ data_wiki.private_history_entry2.delete_comment_date = None
+ data_wiki.private_history_entry2.delete_comment_user = None
+ data_wiki.private_history_entry2.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(private_url2)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+
+def test_wiki_action_undelete_comment(client, data, data_wiki):
+ public_url = "{}?id={}".format(
+ reverse('wiki-history-undelete-comment', kwargs={"pk": data_wiki.public_wiki.pk}),
+ data_wiki.public_history_entry.id
+ )
+ private_url1 = "{}?id={}".format(
+ reverse('wiki-history-undelete-comment', kwargs={"pk": data_wiki.private_wiki1.pk}),
+ data_wiki.private_history_entry1.id
+ )
+ private_url2 = "{}?id={}".format(
+ reverse('wiki-history-undelete-comment', kwargs={"pk": data_wiki.private_wiki2.pk}),
+ data_wiki.private_history_entry2.id
+ )
+
+ users_and_statuses = [
+ (None, 401),
+ (data.registered_user, 403),
+ (data.project_member_without_perms, 403),
+ (data.project_member_with_perms, 200),
+ (data.project_owner, 200),
+ ]
+
+ for user, status_code in users_and_statuses:
+ data_wiki.public_history_entry.delete_comment_date = timezone.now()
+ data_wiki.public_history_entry.delete_comment_user = {"pk": data.project_member_with_perms.pk}
+ data_wiki.public_history_entry.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(public_url)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+ for user, status_code in users_and_statuses:
+ data_wiki.private_history_entry1.delete_comment_date = timezone.now()
+ data_wiki.private_history_entry1.delete_comment_user = {"pk": data.project_member_with_perms.pk}
+ data_wiki.private_history_entry1.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(private_url1)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+ for user, status_code in users_and_statuses:
+ data_wiki.private_history_entry2.delete_comment_date = timezone.now()
+ data_wiki.private_history_entry2.delete_comment_user = {"pk": data.project_member_with_perms.pk}
+ data_wiki.private_history_entry2.save()
+
+ if user:
+ client.login(user)
+ else:
+ client.logout()
+ response = client.json.post(private_url2)
+ error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
+ assert response.status_code == status_code, error_mesage
+
+
+def test_wiki_action_comment_versions(client, data, data_wiki):
+ public_url = "{}?id={}".format(
+ reverse('wiki-history-comment-versions', kwargs={"pk": data_wiki.public_wiki.pk}),
+ data_wiki.public_history_entry.id
+ )
+ private_url1 = "{}?id={}".format(
+ reverse('wiki-history-comment-versions', kwargs={"pk": data_wiki.private_wiki1.pk}),
+ data_wiki.private_history_entry1.id
+ )
+ private_url2 = "{}?id={}".format(
+ reverse('wiki-history-comment-versions', kwargs={"pk": data_wiki.private_wiki2.pk}),
+ data_wiki.private_history_entry2.id
+ )
+
+ users = [
+ None,
+ data.registered_user,
+ data.project_member_without_perms,
+ data.project_member_with_perms,
+ data.project_owner,
+ ]
+
+ results = helper_test_http_method(client, 'get', public_url, None, users)
+ assert results == [401, 403, 403, 200, 200]
+ results = helper_test_http_method(client, 'get', private_url1, None, users)
+ assert results == [401, 403, 403, 200, 200]
+ results = helper_test_http_method(client, 'get', private_url2, None, users)
+ assert results == [401, 403, 403, 200, 200]
diff --git a/tests/integration/test_history.py b/tests/integration/test_history.py
index 01469c0a..5d936c0d 100644
--- a/tests/integration/test_history.py
+++ b/tests/integration/test_history.py
@@ -17,6 +17,8 @@
# along with this program. If not, see
test
", + "date": "2016-05-09T09:34:27.221Z", + "comment": "test", + "user": { + "id": project.owner.id, + }}]) + + client.login(project.owner) + url = reverse("userstory-history-comment-versions", args=(us.id,)) + url = "%s?id=%s" % (url, history_entry.id) + + response = client.get(url, content_type="application/json") + assert 200 == response.status_code, response.status_code + assert response.data[0]["user"]["username"] == project.owner.username + + +def test_get_comment_versions_from_history_entry_without_comment(client): + project = f.create_project() + us = f.create_userstory(project=project) + f.MembershipFactory.create(project=project, user=project.owner, is_admin=True) + key = make_key_from_model_object(us) + history_entry = f.HistoryEntryFactory.create( + type=HistoryType.change, + key=key, + diff={}, + user={"pk": project.owner.id}) + + client.login(project.owner) + url = reverse("userstory-history-comment-versions", args=(us.id,)) + url = "%s?id=%s" % (url, history_entry.id) + + response = client.get(url, content_type="application/json") + assert 200 == response.status_code, response.status_code + assert response.data == None