Refactoring epics API
parent
890c668e7e
commit
32267af4f4
|
@ -134,6 +134,25 @@ class ViewSetMixin(object):
|
||||||
return super().check_permissions(request, action=action, obj=obj)
|
return super().check_permissions(request, action=action, obj=obj)
|
||||||
|
|
||||||
|
|
||||||
|
class NestedViewSetMixin(object):
|
||||||
|
def get_queryset(self):
|
||||||
|
return self._filter_queryset_by_parents_lookups(super().get_queryset())
|
||||||
|
|
||||||
|
def _filter_queryset_by_parents_lookups(self, queryset):
|
||||||
|
parents_query_dict = self._get_parents_query_dict()
|
||||||
|
if parents_query_dict:
|
||||||
|
return queryset.filter(**parents_query_dict)
|
||||||
|
else:
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
def _get_parents_query_dict(self):
|
||||||
|
result = {}
|
||||||
|
for kwarg_name in self.kwargs:
|
||||||
|
query_value = self.kwargs.get(kwarg_name)
|
||||||
|
result[kwarg_name] = query_value
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
class ViewSet(ViewSetMixin, views.APIView):
|
class ViewSet(ViewSetMixin, views.APIView):
|
||||||
"""
|
"""
|
||||||
The base ViewSet class does not provide any actions by default.
|
The base ViewSet class does not provide any actions by default.
|
||||||
|
|
|
@ -318,7 +318,58 @@ class DRFDefaultRouter(SimpleRouter):
|
||||||
return urls
|
return urls
|
||||||
|
|
||||||
|
|
||||||
class DefaultRouter(DRFDefaultRouter):
|
class NestedRegistryItem(object):
|
||||||
|
def __init__(self, router, parent_prefix, parent_item=None):
|
||||||
|
self.router = router
|
||||||
|
self.parent_prefix = parent_prefix
|
||||||
|
self.parent_item = parent_item
|
||||||
|
|
||||||
|
def register(self, prefix, viewset, base_name, parents_query_lookups):
|
||||||
|
self.router._register(
|
||||||
|
prefix=self.get_prefix(current_prefix=prefix, parents_query_lookups=parents_query_lookups),
|
||||||
|
viewset=viewset,
|
||||||
|
base_name=base_name,
|
||||||
|
)
|
||||||
|
return NestedRegistryItem(
|
||||||
|
router=self.router,
|
||||||
|
parent_prefix=prefix,
|
||||||
|
parent_item=self
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_prefix(self, current_prefix, parents_query_lookups):
|
||||||
|
return "{0}/{1}".format(
|
||||||
|
self.get_parent_prefix(parents_query_lookups),
|
||||||
|
current_prefix
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_parent_prefix(self, parents_query_lookups):
|
||||||
|
prefix = "/"
|
||||||
|
current_item = self
|
||||||
|
i = len(parents_query_lookups) - 1
|
||||||
|
while current_item:
|
||||||
|
prefix = "{parent_prefix}/(?P<{parent_pk_kwarg_name}>[^/.]+)/{prefix}".format(
|
||||||
|
parent_prefix=current_item.parent_prefix,
|
||||||
|
parent_pk_kwarg_name=parents_query_lookups[i],
|
||||||
|
prefix=prefix
|
||||||
|
)
|
||||||
|
i -= 1
|
||||||
|
current_item = current_item.parent_item
|
||||||
|
return prefix.strip("/")
|
||||||
|
|
||||||
|
|
||||||
|
class NestedRouterMixin:
|
||||||
|
def _register(self, *args, **kwargs):
|
||||||
|
return super().register(*args, **kwargs)
|
||||||
|
|
||||||
|
def register(self, *args, **kwargs):
|
||||||
|
self._register(*args, **kwargs)
|
||||||
|
return NestedRegistryItem(
|
||||||
|
router=self,
|
||||||
|
parent_prefix=self.registry[-1][0]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultRouter(NestedRouterMixin, DRFDefaultRouter):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
__all__ = ["DefaultRouter"]
|
__all__ = ["DefaultRouter"]
|
||||||
|
|
|
@ -24,10 +24,17 @@ from taiga.projects.votes.admin import VoteInline
|
||||||
from . import models
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
|
class RelatedUserStoriesInline(admin.TabularInline):
|
||||||
|
model = models.RelatedUserStory
|
||||||
|
sortable_field_name = "order"
|
||||||
|
raw_id_fields = ["user_story", ]
|
||||||
|
extra = 0
|
||||||
|
|
||||||
|
|
||||||
class EpicAdmin(admin.ModelAdmin):
|
class EpicAdmin(admin.ModelAdmin):
|
||||||
list_display = ["project", "ref", "subject"]
|
list_display = ["project", "ref", "subject"]
|
||||||
list_display_links = ["ref", "subject"]
|
list_display_links = ["ref", "subject"]
|
||||||
inlines = [WatchedInline, VoteInline]
|
inlines = [WatchedInline, VoteInline, RelatedUserStoriesInline]
|
||||||
raw_id_fields = ["project"]
|
raw_id_fields = ["project"]
|
||||||
search_fields = ["subject", "description", "id", "ref"]
|
search_fields = ["subject", "description", "id", "ref"]
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ from taiga.base import exceptions as exc
|
||||||
from taiga.base.decorators import list_route, detail_route
|
from taiga.base.decorators import list_route, detail_route
|
||||||
from taiga.base.api import ModelCrudViewSet, ModelListViewSet
|
from taiga.base.api import ModelCrudViewSet, ModelListViewSet
|
||||||
from taiga.base.api.mixins import BlockedByProjectMixin
|
from taiga.base.api.mixins import BlockedByProjectMixin
|
||||||
|
from taiga.base.api.viewsets import NestedViewSetMixin
|
||||||
from taiga.base.utils import json
|
from taiga.base.utils import json
|
||||||
|
|
||||||
from taiga.projects.history.mixins import HistoryResourceMixin
|
from taiga.projects.history.mixins import HistoryResourceMixin
|
||||||
|
@ -108,17 +109,16 @@ class EpicViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixin,
|
||||||
|
|
||||||
super().pre_save(obj)
|
super().pre_save(obj)
|
||||||
|
|
||||||
def _reorder_if_needed(self, obj, old_order_key, order_key, order_attr, project):
|
def _reorder_if_needed(self, obj, old_order_key, order_key):
|
||||||
# Executes the extra ordering if there is a difference in the ordering keys
|
# Executes the extra ordering if there is a difference in the ordering keys
|
||||||
if old_order_key != order_key:
|
if old_order_key != order_key:
|
||||||
extra_orders = json.loads(self.request.META.get("HTTP_SET_ORDERS", "{}"))
|
extra_orders = json.loads(self.request.META.get("HTTP_SET_ORDERS", "{}"))
|
||||||
data = [{"epic_id": obj.id, "order": getattr(obj, order_attr)}]
|
data = [{"epic_id": obj.id, "order": getattr(obj, "epics_order")}]
|
||||||
for id, order in extra_orders.items():
|
for id, order in extra_orders.items():
|
||||||
data.append({"epic_id": int(id), "order": order})
|
data.append({"epic_id": int(id), "order": order})
|
||||||
|
|
||||||
return services.update_epics_order_in_bulk(data,
|
return services.update_epics_order_in_bulk(data,
|
||||||
field=order_attr,
|
project=obj.project)
|
||||||
project=project)
|
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def post_save(self, obj, created=False):
|
def post_save(self, obj, created=False):
|
||||||
|
@ -126,9 +126,7 @@ class EpicViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixin,
|
||||||
# Let's reorder the related stuff after edit the element
|
# Let's reorder the related stuff after edit the element
|
||||||
orders_updated = self._reorder_if_needed(obj,
|
orders_updated = self._reorder_if_needed(obj,
|
||||||
self._old_epics_order_key,
|
self._old_epics_order_key,
|
||||||
self._epics_order_key(obj),
|
self._epics_order_key(obj))
|
||||||
"epics_order",
|
|
||||||
obj.project)
|
|
||||||
self.headers["Taiga-Info-Order-Updated"] = json.dumps(orders_updated)
|
self.headers["Taiga-Info-Order-Updated"] = json.dumps(orders_updated)
|
||||||
|
|
||||||
super().post_save(obj, created)
|
super().post_save(obj, created)
|
||||||
|
@ -227,77 +225,78 @@ class EpicViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixin,
|
||||||
|
|
||||||
return response.BadRequest(validator.errors)
|
return response.BadRequest(validator.errors)
|
||||||
|
|
||||||
@detail_route(methods=["POST"])
|
|
||||||
def bulk_create_related_userstories(self, request, **kwargs):
|
class EpicRelatedUserStoryViewSet(NestedViewSetMixin, BlockedByProjectMixin, ModelCrudViewSet):
|
||||||
|
queryset = models.RelatedUserStory.objects.all()
|
||||||
|
serializer_class = serializers.EpicRelatedUserStorySerializer
|
||||||
|
validator_class = validators.EpicRelatedUserStoryValidator
|
||||||
|
model = models.RelatedUserStory
|
||||||
|
permission_classes = (permissions.EpicRelatedUserStoryPermission,)
|
||||||
|
|
||||||
|
"""
|
||||||
|
Updating the order attribute can affect the ordering of another userstories in the epic
|
||||||
|
This method generate a key for the userstory and can be used to be compared before and after
|
||||||
|
saving
|
||||||
|
If there is any difference it means an extra ordering update must be done
|
||||||
|
"""
|
||||||
|
def _order_key(self, obj):
|
||||||
|
return "{}-{}".format(obj.user_story.project_id, obj.order)
|
||||||
|
|
||||||
|
def pre_save(self, obj):
|
||||||
|
if not obj.id:
|
||||||
|
obj.epic_id = self.kwargs["epic"]
|
||||||
|
else:
|
||||||
|
self._old_order_key = self._order_key(self.get_object())
|
||||||
|
|
||||||
|
super().pre_save(obj)
|
||||||
|
|
||||||
|
def _reorder_if_needed(self, obj, old_order_key, order_key):
|
||||||
|
# Executes the extra ordering if there is a difference in the ordering keys
|
||||||
|
if old_order_key != order_key:
|
||||||
|
extra_orders = json.loads(self.request.META.get("HTTP_SET_ORDERS", "{}"))
|
||||||
|
data = [{"us_id": obj.id, "order": getattr(obj, "order")}]
|
||||||
|
for id, order in extra_orders.items():
|
||||||
|
data.append({"epic_id": int(id), "order": order})
|
||||||
|
|
||||||
|
return services.update_epic_related_userstories_order_in_bulk(
|
||||||
|
data,
|
||||||
|
epic=obj.epic
|
||||||
|
)
|
||||||
|
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def post_save(self, obj, created=False):
|
||||||
|
if not created:
|
||||||
|
# Let's reorder the related stuff after edit the element
|
||||||
|
orders_updated = self._reorder_if_needed(obj,
|
||||||
|
self._old_epics_order_key,
|
||||||
|
self._epics_order_key(obj))
|
||||||
|
self.headers["Taiga-Info-Order-Updated"] = json.dumps(orders_updated)
|
||||||
|
|
||||||
|
super().post_save(obj, created)
|
||||||
|
|
||||||
|
@list_route(methods=["POST"])
|
||||||
|
def bulk_create(self, request, **kwargs):
|
||||||
validator = validators.CrateRelatedUserStoriesBulkValidator(data=request.DATA)
|
validator = validators.CrateRelatedUserStoriesBulkValidator(data=request.DATA)
|
||||||
if validator.is_valid():
|
if validator.is_valid():
|
||||||
data = validator.data
|
data = validator.data
|
||||||
obj = self.get_object()
|
|
||||||
project = obj.project
|
epic = get_object_or_404(models.Epic, id=kwargs["epic"])
|
||||||
self.check_permissions(request, 'bulk_create_userstories', project)
|
project = epic.project
|
||||||
|
|
||||||
|
self.check_permissions(request, 'bulk_create', project)
|
||||||
if project.blocked_code is not None:
|
if project.blocked_code is not None:
|
||||||
raise exc.Blocked(_("Blocked element"))
|
raise exc.Blocked(_("Blocked element"))
|
||||||
|
|
||||||
services.create_related_userstories_in_bulk(
|
services.create_related_userstories_in_bulk(
|
||||||
data["userstories"],
|
data["userstories"],
|
||||||
obj,
|
epic,
|
||||||
project=project,
|
project=project,
|
||||||
owner=request.user
|
owner=request.user
|
||||||
)
|
)
|
||||||
obj = self.get_queryset().get(id=obj.id)
|
|
||||||
epic_serialized = self.get_serializer_class()(obj)
|
|
||||||
return response.Ok(epic_serialized.data)
|
|
||||||
|
|
||||||
return response.BadRequest(validator.errors)
|
related_uss_serialized = self.get_serializer_class()(epic.relateduserstory_set.all(), many=True)
|
||||||
|
return response.Ok(related_uss_serialized.data)
|
||||||
@detail_route(methods=["POST"])
|
|
||||||
def set_related_userstory(self, request, **kwargs):
|
|
||||||
validator = validators.SetRelatedUserStoryValidator(data=request.DATA)
|
|
||||||
if validator.is_valid():
|
|
||||||
data = validator.data
|
|
||||||
epic = self.get_object()
|
|
||||||
project = epic.project
|
|
||||||
user_story = UserStory.objects.get(id=data["us_id"])
|
|
||||||
self.check_permissions(request, "update", epic)
|
|
||||||
self.check_permissions(request, "select_related_userstory", user_story.project)
|
|
||||||
|
|
||||||
if project.blocked_code is not None:
|
|
||||||
raise exc.Blocked(_("Blocked element"))
|
|
||||||
|
|
||||||
obj, created = models.RelatedUserStory.objects.update_or_create(
|
|
||||||
epic=epic,
|
|
||||||
user_story=user_story,
|
|
||||||
defaults={
|
|
||||||
"order": data["order"]
|
|
||||||
})
|
|
||||||
epic = self.get_queryset().get(id=epic.id)
|
|
||||||
epic_serialized = self.get_serializer_class()(epic)
|
|
||||||
return response.Ok(epic_serialized.data)
|
|
||||||
|
|
||||||
return response.BadRequest(validator.errors)
|
|
||||||
|
|
||||||
@detail_route(methods=["POST"])
|
|
||||||
def unset_related_userstory(self, request, **kwargs):
|
|
||||||
validator = validators.UnsetRelatedUserStoryValidator(data=request.DATA)
|
|
||||||
if validator.is_valid():
|
|
||||||
data = validator.data
|
|
||||||
epic = self.get_object()
|
|
||||||
project = epic.project
|
|
||||||
user_story = UserStory.objects.get(id=data["us_id"])
|
|
||||||
self.check_permissions(request, "update", epic)
|
|
||||||
|
|
||||||
if project.blocked_code is not None:
|
|
||||||
raise exc.Blocked(_("Blocked element"))
|
|
||||||
|
|
||||||
related_us = get_object_or_404(
|
|
||||||
models.RelatedUserStory,
|
|
||||||
epic=epic,
|
|
||||||
user_story=user_story
|
|
||||||
)
|
|
||||||
related_us.delete()
|
|
||||||
epic = self.get_queryset().get(id=epic.id)
|
|
||||||
epic_serialized = self.get_serializer_class()(epic)
|
|
||||||
return response.Ok(epic_serialized.data)
|
|
||||||
|
|
||||||
return response.BadRequest(validator.errors)
|
return response.BadRequest(validator.errors)
|
||||||
|
|
||||||
|
|
|
@ -105,4 +105,4 @@ class RelatedUserStory(models.Model):
|
||||||
ordering = ["user_story", "order", "id"]
|
ordering = ["user_story", "order", "id"]
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "{0} - {1}".format(self.epic, self.user_story)
|
return "{0} - {1}".format(self.epic_id, self.user_story_id)
|
||||||
|
|
|
@ -34,14 +34,24 @@ class EpicPermission(TaigaResourcePermission):
|
||||||
filters_data_perms = AllowAny()
|
filters_data_perms = AllowAny()
|
||||||
csv_perms = AllowAny()
|
csv_perms = AllowAny()
|
||||||
bulk_create_perms = HasProjectPerm('add_epic')
|
bulk_create_perms = HasProjectPerm('add_epic')
|
||||||
bulk_create_userstories_perms = HasProjectPerm('modify_epic') & (HasProjectPerm('add_us_to_project') | HasProjectPerm('add_us'))
|
|
||||||
select_related_userstory_perms = HasProjectPerm('view_us')
|
|
||||||
upvote_perms = IsAuthenticated() & HasProjectPerm('view_epics')
|
upvote_perms = IsAuthenticated() & HasProjectPerm('view_epics')
|
||||||
downvote_perms = IsAuthenticated() & HasProjectPerm('view_epics')
|
downvote_perms = IsAuthenticated() & HasProjectPerm('view_epics')
|
||||||
watch_perms = IsAuthenticated() & HasProjectPerm('view_epics')
|
watch_perms = IsAuthenticated() & HasProjectPerm('view_epics')
|
||||||
unwatch_perms = IsAuthenticated() & HasProjectPerm('view_epics')
|
unwatch_perms = IsAuthenticated() & HasProjectPerm('view_epics')
|
||||||
|
|
||||||
|
|
||||||
|
class EpicRelatedUserStoryPermission(TaigaResourcePermission):
|
||||||
|
enought_perms = IsProjectAdmin() | IsSuperUser()
|
||||||
|
global_perms = None
|
||||||
|
retrieve_perms = HasProjectPerm('view_epics')
|
||||||
|
create_perms = HasProjectPerm('modify_epic')
|
||||||
|
update_perms = HasProjectPerm('modify_epic')
|
||||||
|
partial_update_perms = HasProjectPerm('modify_epic')
|
||||||
|
destroy_perms = HasProjectPerm('modify_epic')
|
||||||
|
list_perms = AllowAny()
|
||||||
|
bulk_create_perms = HasProjectPerm('modify_epic')
|
||||||
|
|
||||||
|
|
||||||
class EpicVotersPermission(TaigaResourcePermission):
|
class EpicVotersPermission(TaigaResourcePermission):
|
||||||
enought_perms = IsProjectAdmin() | IsSuperUser()
|
enought_perms = IsProjectAdmin() | IsSuperUser()
|
||||||
global_perms = None
|
global_perms = None
|
||||||
|
|
|
@ -78,3 +78,8 @@ class EpicSerializer(EpicListSerializer):
|
||||||
|
|
||||||
class EpicNeighborsSerializer(NeighborsSerializerMixin, EpicSerializer):
|
class EpicNeighborsSerializer(NeighborsSerializerMixin, EpicSerializer):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class EpicRelatedUserStorySerializer(serializers.LightSerializer):
|
||||||
|
user_story = Field(attr="user_story_id")
|
||||||
|
order = Field()
|
||||||
|
|
|
@ -60,10 +60,7 @@ class CrateRelatedUserStoriesBulkValidator(ProjectExistsValidator, EpicExistsVal
|
||||||
userstories = serializers.CharField()
|
userstories = serializers.CharField()
|
||||||
|
|
||||||
|
|
||||||
class SetRelatedUserStoryValidator(UserStoryExistsValidator, validators.Validator):
|
class EpicRelatedUserStoryValidator(validators.ModelValidator):
|
||||||
us_id = serializers.IntegerField()
|
class Meta:
|
||||||
order = serializers.IntegerField(required=False, default=10000)
|
model = models.RelatedUserStory
|
||||||
|
read_only_fields = ('id', 'epic', 'user_story')
|
||||||
|
|
||||||
class UnsetRelatedUserStoryValidator(UserStoryExistsValidator, validators.Validator):
|
|
||||||
us_id = serializers.IntegerField()
|
|
||||||
|
|
|
@ -146,6 +146,7 @@ from taiga.projects.milestones.api import MilestoneViewSet
|
||||||
from taiga.projects.milestones.api import MilestoneWatchersViewSet
|
from taiga.projects.milestones.api import MilestoneWatchersViewSet
|
||||||
|
|
||||||
from taiga.projects.epics.api import EpicViewSet
|
from taiga.projects.epics.api import EpicViewSet
|
||||||
|
from taiga.projects.epics.api import EpicRelatedUserStoryViewSet
|
||||||
from taiga.projects.epics.api import EpicVotersViewSet
|
from taiga.projects.epics.api import EpicVotersViewSet
|
||||||
from taiga.projects.epics.api import EpicWatchersViewSet
|
from taiga.projects.epics.api import EpicWatchersViewSet
|
||||||
|
|
||||||
|
@ -170,8 +171,11 @@ router.register(r"milestones", MilestoneViewSet,
|
||||||
router.register(r"milestones/(?P<resource_id>\d+)/watchers", MilestoneWatchersViewSet,
|
router.register(r"milestones/(?P<resource_id>\d+)/watchers", MilestoneWatchersViewSet,
|
||||||
base_name="milestone-watchers")
|
base_name="milestone-watchers")
|
||||||
|
|
||||||
router.register(r"epics", EpicViewSet,
|
router.register(r"epics", EpicViewSet, base_name="epics")\
|
||||||
base_name="epics")
|
.register(r"related_userstories", EpicRelatedUserStoryViewSet,
|
||||||
|
base_name="epics-related-userstories",
|
||||||
|
parents_query_lookups=["epic"])
|
||||||
|
|
||||||
router.register(r"epics/(?P<resource_id>\d+)/voters", EpicVotersViewSet,
|
router.register(r"epics/(?P<resource_id>\d+)/voters", EpicVotersViewSet,
|
||||||
base_name="epic-voters")
|
base_name="epic-voters")
|
||||||
router.register(r"epics/(?P<resource_id>\d+)/watchers", EpicWatchersViewSet,
|
router.register(r"epics/(?P<resource_id>\d+)/watchers", EpicWatchersViewSet,
|
||||||
|
|
|
@ -676,10 +676,10 @@ def test_epic_action_bulk_create(client, data):
|
||||||
|
|
||||||
|
|
||||||
def test_bulk_create_related_userstories(client, data):
|
def test_bulk_create_related_userstories(client, data):
|
||||||
public_url = reverse('epics-bulk-create-related-userstories', kwargs={"pk": data.public_epic.pk})
|
public_url = reverse('epics-related-userstories-bulk-create', args=[data.public_epic.pk])
|
||||||
private_url1 = reverse('epics-bulk-create-related-userstories', kwargs={"pk": data.private_epic1.pk})
|
private_url1 = reverse('epics-related-userstories-bulk-create', args=[data.private_epic1.pk])
|
||||||
private_url2 = reverse('epics-bulk-create-related-userstories', kwargs={"pk": data.private_epic2.pk})
|
private_url2 = reverse('epics-related-userstories-bulk-create', args=[data.private_epic2.pk])
|
||||||
blocked_url = reverse('epics-bulk-create-related-userstories', kwargs={"pk": data.blocked_epic.pk})
|
blocked_url = reverse('epics-related-userstories-bulk-create', args=[data.blocked_epic.pk])
|
||||||
|
|
||||||
users = [
|
users = [
|
||||||
None,
|
None,
|
||||||
|
@ -698,9 +698,9 @@ def test_bulk_create_related_userstories(client, data):
|
||||||
results = helper_test_http_method(client, 'post', private_url1, bulk_data, users)
|
results = helper_test_http_method(client, 'post', private_url1, bulk_data, users)
|
||||||
assert results == [401, 403, 403, 200, 200]
|
assert results == [401, 403, 403, 200, 200]
|
||||||
results = helper_test_http_method(client, 'post', private_url2, bulk_data, users)
|
results = helper_test_http_method(client, 'post', private_url2, bulk_data, users)
|
||||||
assert results == [404, 404, 404, 200, 200]
|
assert results == [401, 403, 403, 200, 200]
|
||||||
results = helper_test_http_method(client, 'post', blocked_url, bulk_data, users)
|
results = helper_test_http_method(client, 'post', blocked_url, bulk_data, users)
|
||||||
assert results == [404, 404, 404, 451, 451]
|
assert results == [401, 403, 403, 451, 451]
|
||||||
|
|
||||||
|
|
||||||
def test_set_related_user_story(client, data):
|
def test_set_related_user_story(client, data):
|
||||||
|
|
|
@ -98,7 +98,7 @@ def test_bulk_create_related_userstories(client):
|
||||||
epic = f.EpicFactory.create(project=project)
|
epic = f.EpicFactory.create(project=project)
|
||||||
f.MembershipFactory.create(project=project, user=user, is_admin=True)
|
f.MembershipFactory.create(project=project, user=user, is_admin=True)
|
||||||
|
|
||||||
url = reverse('epics-bulk-create-related-userstories', kwargs={"pk": epic.pk})
|
url = reverse('epics-related-userstories-bulk-create', args=[epic.pk])
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"userstories": "test1\ntest2"
|
"userstories": "test1\ntest2"
|
||||||
|
@ -106,7 +106,7 @@ def test_bulk_create_related_userstories(client):
|
||||||
client.login(user)
|
client.login(user)
|
||||||
response = client.json.post(url, json.dumps(data))
|
response = client.json.post(url, json.dumps(data))
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.data['user_stories_counts'] == {'opened': 2, 'closed': 0}
|
assert len(response.data) == 2
|
||||||
|
|
||||||
|
|
||||||
def test_set_related_userstory(client):
|
def test_set_related_userstory(client):
|
||||||
|
@ -116,13 +116,14 @@ def test_set_related_userstory(client):
|
||||||
f.MembershipFactory.create(project=epic.project, user=user, is_admin=True)
|
f.MembershipFactory.create(project=epic.project, user=user, is_admin=True)
|
||||||
f.MembershipFactory.create(project=us.project, user=user, is_admin=True)
|
f.MembershipFactory.create(project=us.project, user=user, is_admin=True)
|
||||||
|
|
||||||
url = reverse('epics-set-related-userstory', kwargs={"pk": epic.pk})
|
url = reverse('epics-related-userstories-list', args=[epic.pk])
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"us_id": us.id
|
"user_story": us.id
|
||||||
}
|
}
|
||||||
client.login(user)
|
client.login(user)
|
||||||
response = client.json.post(url, json.dumps(data))
|
response = client.json.post(url, json.dumps(data))
|
||||||
|
print(response.data)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.data['user_stories_counts'] == {'opened': 1, 'closed': 0}
|
assert response.data['user_stories_counts'] == {'opened': 1, 'closed': 0}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue