Task #3538: Add tribe_gig PickledObjectField attribute to UserStory model
parent
3ba759e5d1
commit
fd12f84969
|
@ -11,6 +11,7 @@
|
||||||
- Improve login and forgot password: allow username or email case-insensitive if the query only
|
- Improve login and forgot password: allow username or email case-insensitive if the query only
|
||||||
match with one user.
|
match with one user.
|
||||||
- Improve the django admin panel, now it is more usable and all the selector fields works properly.
|
- Improve the django admin panel, now it is more usable and all the selector fields works properly.
|
||||||
|
- [API] Add tribe_gig field to user stories (improve integration between Taiga and Taiga Tribe).
|
||||||
- [API] Performance improvements for project stats.
|
- [API] Performance improvements for project stats.
|
||||||
- Lots of small and not so small bugfixes.
|
- Lots of small and not so small bugfixes.
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,19 @@ class PgArrayField(serializers.WritableField):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
class PickledObjectField(serializers.WritableField):
|
||||||
|
"""
|
||||||
|
PickledObjectField objects serializer.
|
||||||
|
"""
|
||||||
|
widget = widgets.Textarea
|
||||||
|
|
||||||
|
def to_native(self, obj):
|
||||||
|
return obj
|
||||||
|
|
||||||
|
def from_native(self, data):
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
class TagsField(serializers.WritableField):
|
class TagsField(serializers.WritableField):
|
||||||
"""
|
"""
|
||||||
Pickle objects serializer.
|
Pickle objects serializer.
|
||||||
|
|
|
@ -76,6 +76,23 @@ class ProjectViewSet(LikedResourceMixin, HistoryResourceMixin, ModelCrudViewSet)
|
||||||
|
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
|
def get_serializer_class(self):
|
||||||
|
if self.action == "list":
|
||||||
|
return self.list_serializer_class
|
||||||
|
elif self.action == "create":
|
||||||
|
return self.serializer_class
|
||||||
|
|
||||||
|
if self.action == "by_slug":
|
||||||
|
slug = self.request.QUERY_PARAMS.get("slug", None)
|
||||||
|
project = get_object_or_404(models.Project, slug=slug)
|
||||||
|
else:
|
||||||
|
project = self.get_object()
|
||||||
|
|
||||||
|
if permissions_service.is_project_owner(self.request.user, project):
|
||||||
|
return self.admin_serializer_class
|
||||||
|
|
||||||
|
return self.serializer_class
|
||||||
|
|
||||||
@detail_route(methods=["POST"])
|
@detail_route(methods=["POST"])
|
||||||
def watch(self, request, pk=None):
|
def watch(self, request, pk=None):
|
||||||
project = self.get_object()
|
project = self.get_object()
|
||||||
|
@ -105,23 +122,6 @@ class ProjectViewSet(LikedResourceMixin, HistoryResourceMixin, ModelCrudViewSet)
|
||||||
services.update_projects_order_in_bulk(data, "user_order", request.user)
|
services.update_projects_order_in_bulk(data, "user_order", request.user)
|
||||||
return response.NoContent(data=None)
|
return response.NoContent(data=None)
|
||||||
|
|
||||||
def get_serializer_class(self):
|
|
||||||
if self.action == "list":
|
|
||||||
return self.list_serializer_class
|
|
||||||
elif self.action == "create":
|
|
||||||
return self.serializer_class
|
|
||||||
|
|
||||||
if self.action == "by_slug":
|
|
||||||
slug = self.request.QUERY_PARAMS.get("slug", None)
|
|
||||||
project = get_object_or_404(models.Project, slug=slug)
|
|
||||||
else:
|
|
||||||
project = self.get_object()
|
|
||||||
|
|
||||||
if permissions_service.is_project_owner(self.request.user, project):
|
|
||||||
return self.admin_serializer_class
|
|
||||||
|
|
||||||
return self.serializer_class
|
|
||||||
|
|
||||||
@list_route(methods=["GET"])
|
@list_route(methods=["GET"])
|
||||||
def by_slug(self, request):
|
def by_slug(self, request):
|
||||||
slug = request.QUERY_PARAMS.get("slug", None)
|
slug = request.QUERY_PARAMS.get("slug", None)
|
||||||
|
|
|
@ -286,6 +286,7 @@ def userstory_freezer(us) -> dict:
|
||||||
"blocked_note": us.blocked_note,
|
"blocked_note": us.blocked_note,
|
||||||
"blocked_note_html": mdrender(us.project, us.blocked_note),
|
"blocked_note_html": mdrender(us.project, us.blocked_note),
|
||||||
"custom_attributes": extract_user_story_custom_attributes(us),
|
"custom_attributes": extract_user_story_custom_attributes(us),
|
||||||
|
"tribe_gig": us.tribe_gig,
|
||||||
}
|
}
|
||||||
|
|
||||||
return snapshot
|
return snapshot
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
"kanban_order",
|
"kanban_order",
|
||||||
"taskboard_order",
|
"taskboard_order",
|
||||||
"us_order",
|
"us_order",
|
||||||
"custom_attributes"
|
"custom_attributes",
|
||||||
|
"tribe_gig",
|
||||||
] %}
|
] %}
|
||||||
|
|
||||||
{% for field_name, values in changed_fields.items() %}
|
{% for field_name, values in changed_fields.items() %}
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
"us_order",
|
"us_order",
|
||||||
"blocked_note_diff",
|
"blocked_note_diff",
|
||||||
"blocked_note_html",
|
"blocked_note_html",
|
||||||
"custom_attributes"
|
"custom_attributes",
|
||||||
|
"tribe_gig",
|
||||||
] %}
|
] %}
|
||||||
{% for field_name, values in changed_fields.items() %}
|
{% for field_name, values in changed_fields.items() %}
|
||||||
{% if field_name not in excluded_fields %}
|
{% if field_name not in excluded_fields %}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import picklefield.fields
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('userstories', '0010_remove_userstory_watchers'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='userstory',
|
||||||
|
name='tribe_gig',
|
||||||
|
field=picklefield.fields.PickledObjectField(editable=False, null=True, default=None, verbose_name='taiga tribe gig', blank=True),
|
||||||
|
),
|
||||||
|
]
|
|
@ -21,6 +21,7 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from djorm_pgarray.fields import TextArrayField
|
from djorm_pgarray.fields import TextArrayField
|
||||||
|
from picklefield.fields import PickledObjectField
|
||||||
|
|
||||||
from taiga.base.tags import TaggedMixin
|
from taiga.base.tags import TaggedMixin
|
||||||
from taiga.projects.occ import OCCModelMixin
|
from taiga.projects.occ import OCCModelMixin
|
||||||
|
@ -101,6 +102,10 @@ class UserStory(OCCModelMixin, WatchedModelMixin, BlockedMixin, TaggedMixin, mod
|
||||||
related_name="generated_user_stories",
|
related_name="generated_user_stories",
|
||||||
verbose_name=_("generated from issue"))
|
verbose_name=_("generated from issue"))
|
||||||
external_reference = TextArrayField(default=None, verbose_name=_("external reference"))
|
external_reference = TextArrayField(default=None, verbose_name=_("external reference"))
|
||||||
|
|
||||||
|
tribe_gig = PickledObjectField(null=True, blank=True, default=None,
|
||||||
|
verbose_name="taiga tribe gig")
|
||||||
|
|
||||||
_importing = None
|
_importing = None
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from taiga.base.api import serializers
|
from taiga.base.api import serializers
|
||||||
from taiga.base.fields import TagsField
|
from taiga.base.fields import TagsField
|
||||||
|
from taiga.base.fields import PickledObjectField
|
||||||
from taiga.base.fields import PgArrayField
|
from taiga.base.fields import PgArrayField
|
||||||
from taiga.base.neighbors import NeighborsSerializerMixin
|
from taiga.base.neighbors import NeighborsSerializerMixin
|
||||||
from taiga.base.utils import json
|
from taiga.base.utils import json
|
||||||
|
@ -45,7 +46,8 @@ class RolePointsField(serializers.WritableField):
|
||||||
return json.loads(obj)
|
return json.loads(obj)
|
||||||
|
|
||||||
|
|
||||||
class UserStorySerializer(WatchersValidator, VoteResourceSerializerMixin, EditableWatchedResourceModelSerializer, serializers.ModelSerializer):
|
class UserStorySerializer(WatchersValidator, VoteResourceSerializerMixin, EditableWatchedResourceModelSerializer,
|
||||||
|
serializers.ModelSerializer):
|
||||||
tags = TagsField(default=[], required=False)
|
tags = TagsField(default=[], required=False)
|
||||||
external_reference = PgArrayField(required=False)
|
external_reference = PgArrayField(required=False)
|
||||||
points = RolePointsField(source="role_points", required=False)
|
points = RolePointsField(source="role_points", required=False)
|
||||||
|
@ -59,6 +61,7 @@ class UserStorySerializer(WatchersValidator, VoteResourceSerializerMixin, Editab
|
||||||
status_extra_info = BasicUserStoryStatusSerializer(source="status", required=False, read_only=True)
|
status_extra_info = BasicUserStoryStatusSerializer(source="status", required=False, read_only=True)
|
||||||
assigned_to_extra_info = UserBasicInfoSerializer(source="assigned_to", required=False, read_only=True)
|
assigned_to_extra_info = UserBasicInfoSerializer(source="assigned_to", required=False, read_only=True)
|
||||||
owner_extra_info = UserBasicInfoSerializer(source="owner", required=False, read_only=True)
|
owner_extra_info = UserBasicInfoSerializer(source="owner", required=False, read_only=True)
|
||||||
|
tribe_gig = PickledObjectField(required=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.UserStory
|
model = models.UserStory
|
||||||
|
|
|
@ -514,3 +514,24 @@ def test_update_userstory_remove_watchers(client):
|
||||||
assert response.data["watchers"] == []
|
assert response.data["watchers"] == []
|
||||||
watcher_ids = list(us.get_watchers().values_list("id", flat=True))
|
watcher_ids = list(us.get_watchers().values_list("id", flat=True))
|
||||||
assert watcher_ids == []
|
assert watcher_ids == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_update_userstory_update_tribe_gig(client):
|
||||||
|
project = f.ProjectFactory.create()
|
||||||
|
us = f.UserStoryFactory.create(project=project, status__project=project, milestone__project=project)
|
||||||
|
f.MembershipFactory.create(project=us.project, user=us.owner, is_owner=True)
|
||||||
|
|
||||||
|
url = reverse("userstories-detail", kwargs={"pk": us.pk})
|
||||||
|
data = {
|
||||||
|
"tribe_gig": {
|
||||||
|
"id": 2,
|
||||||
|
"title": "This is a gig test title"
|
||||||
|
},
|
||||||
|
"version":1
|
||||||
|
}
|
||||||
|
|
||||||
|
client.login(user=us.owner)
|
||||||
|
response = client.json.patch(url, json.dumps(data))
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.data["tribe_gig"] == data["tribe_gig"]
|
||||||
|
|
Loading…
Reference in New Issue