US #55: Custom fields - Create model to save the custom attributes values and update the history
parent
ebc3388d03
commit
2893213932
|
@ -14,9 +14,17 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from taiga.base.api import ModelCrudViewSet
|
||||
from taiga.base.api.viewsets import ModelViewSet
|
||||
from taiga.base import exceptions as exc
|
||||
from taiga.base import filters
|
||||
from taiga.base import response
|
||||
|
||||
from taiga.projects.mixins.ordering import BulkUpdateOrderMixin
|
||||
from taiga.projects.history.mixins import HistoryResourceMixin
|
||||
from taiga.projects.occ.mixins import OCCResourceMixin
|
||||
|
||||
from . import models
|
||||
from . import serializers
|
||||
|
@ -24,6 +32,10 @@ from . import permissions
|
|||
from . import services
|
||||
|
||||
|
||||
######################################################
|
||||
# Custom Attribute ViewSets
|
||||
#######################################################
|
||||
|
||||
class UserStoryCustomAttributeViewSet(ModelCrudViewSet, BulkUpdateOrderMixin):
|
||||
model = models.UserStoryCustomAttribute
|
||||
serializer_class = serializers.UserStoryCustomAttributeSerializer
|
||||
|
@ -55,3 +67,45 @@ class IssueCustomAttributeViewSet(ModelCrudViewSet, BulkUpdateOrderMixin):
|
|||
bulk_update_param = "bulk_issue_custom_attributes"
|
||||
bulk_update_perm = "change_issue_custom_attributes"
|
||||
bulk_update_order_action = services.bulk_update_issue_custom_attribute_order
|
||||
|
||||
|
||||
######################################################
|
||||
# Custom Attributes Values ViewSets
|
||||
#######################################################
|
||||
|
||||
class BaseCustomAttributesValuesViewSet(OCCResourceMixin, HistoryResourceMixin, ModelViewSet):
|
||||
def list(self, request, *args, **kwargs):
|
||||
return response.NotFound()
|
||||
|
||||
def post_delete(self, obj):
|
||||
# NOTE: When destroy a custom attributes values object, the
|
||||
# content_object change after and not before
|
||||
self.persist_history_snapshot(obj, delete=True)
|
||||
super().pre_delete(obj)
|
||||
|
||||
def get_object_for_snapshot(self, obj):
|
||||
return getattr(obj, self.content_object)
|
||||
|
||||
|
||||
class UserStoryCustomAttributesValuesViewSet(BaseCustomAttributesValuesViewSet):
|
||||
model = models.UserStoryCustomAttributesValues
|
||||
serializer_class = serializers.UserStoryCustomAttributesValuesSerializer
|
||||
permission_classes = (permissions.UserStoryCustomAttributesValuesPermission,)
|
||||
lookup_field = "user_story_id"
|
||||
content_object = "user_story"
|
||||
|
||||
|
||||
class TaskCustomAttributesValuesViewSet(BaseCustomAttributesValuesViewSet):
|
||||
model = models.TaskCustomAttributesValues
|
||||
serializer_class = serializers.TaskCustomAttributesValuesSerializer
|
||||
permission_classes = (permissions.TaskCustomAttributesValuesPermission,)
|
||||
lockup_fields = "task_id"
|
||||
content_object = "task"
|
||||
|
||||
|
||||
class IssueCustomAttributesValuesViewSet(BaseCustomAttributesValuesViewSet):
|
||||
model = models.IssueCustomAttributesValues
|
||||
serializer_class = serializers.IssueCustomAttributesValuesSerializer
|
||||
permission_classes = (permissions.IssueCustomAttributesValuesPermission,)
|
||||
lockup_fields = "issue_id"
|
||||
content_object = "issue"
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import django_pgjson.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('tasks', '0005_auto_20150114_0954'),
|
||||
('userstories', '0009_remove_userstory_is_archived'),
|
||||
('issues', '0004_auto_20150114_0954'),
|
||||
('custom_attributes', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='IssueCustomAttributesValues',
|
||||
fields=[
|
||||
('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)),
|
||||
('version', models.IntegerField(default=1, verbose_name='version')),
|
||||
('values', django_pgjson.fields.JsonField(default={}, verbose_name='values')),
|
||||
('issue', models.OneToOneField(related_name='custom_attributes_values', to='issues.Issue', verbose_name='issue')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['id'],
|
||||
'verbose_name_plural': 'issue custom attributes values',
|
||||
'verbose_name': 'issue ustom attributes values',
|
||||
'abstract': False,
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TaskCustomAttributesValues',
|
||||
fields=[
|
||||
('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)),
|
||||
('version', models.IntegerField(default=1, verbose_name='version')),
|
||||
('values', django_pgjson.fields.JsonField(default={}, verbose_name='values')),
|
||||
('task', models.OneToOneField(related_name='custom_attributes_values', to='tasks.Task', verbose_name='task')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['id'],
|
||||
'verbose_name_plural': 'task custom attributes values',
|
||||
'verbose_name': 'task ustom attributes values',
|
||||
'abstract': False,
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserStoryCustomAttributesValues',
|
||||
fields=[
|
||||
('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)),
|
||||
('version', models.IntegerField(default=1, verbose_name='version')),
|
||||
('values', django_pgjson.fields.JsonField(default={}, verbose_name='values')),
|
||||
('user_story', models.OneToOneField(related_name='custom_attributes_values', to='userstories.UserStory', verbose_name='user story')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['id'],
|
||||
'verbose_name_plural': 'user story custom attributes values',
|
||||
'verbose_name': 'user story ustom attributes values',
|
||||
'abstract': False,
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
]
|
|
@ -18,9 +18,13 @@ from django.db import models
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils import timezone
|
||||
|
||||
from django_pgjson.fields import JsonField
|
||||
|
||||
from taiga.projects.occ.mixins import OCCModelMixin
|
||||
|
||||
|
||||
######################################################
|
||||
# Base Model Class
|
||||
# Custom Attribute Models
|
||||
#######################################################
|
||||
|
||||
class AbstractCustomAttribute(models.Model):
|
||||
|
@ -51,11 +55,6 @@ class AbstractCustomAttribute(models.Model):
|
|||
return super().save(*args, **kwargs)
|
||||
|
||||
|
||||
|
||||
######################################################
|
||||
# Custom Field Models
|
||||
#######################################################
|
||||
|
||||
class UserStoryCustomAttribute(AbstractCustomAttribute):
|
||||
class Meta(AbstractCustomAttribute.Meta):
|
||||
verbose_name = "user story custom attribute"
|
||||
|
@ -72,3 +71,60 @@ class IssueCustomAttribute(AbstractCustomAttribute):
|
|||
class Meta(AbstractCustomAttribute.Meta):
|
||||
verbose_name = "issue custom attribute"
|
||||
verbose_name_plural = "issue custom attributes"
|
||||
|
||||
|
||||
######################################################
|
||||
# Custom Attributes Values Models
|
||||
#######################################################
|
||||
|
||||
class AbstractCustomAttributesValues(OCCModelMixin, models.Model):
|
||||
values = JsonField(null=False, blank=False, default={}, verbose_name=_("values"))
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
ordering = ["id"]
|
||||
|
||||
|
||||
class UserStoryCustomAttributesValues(AbstractCustomAttributesValues):
|
||||
user_story = models.OneToOneField("userstories.UserStory",
|
||||
null=False, blank=False, related_name="custom_attributes_values",
|
||||
verbose_name=_("user story"))
|
||||
|
||||
class Meta(AbstractCustomAttributesValues.Meta):
|
||||
verbose_name = "user story ustom attributes values"
|
||||
verbose_name_plural = "user story custom attributes values"
|
||||
|
||||
@property
|
||||
def project(self):
|
||||
# NOTE: This property simplifies checking permissions
|
||||
return self.user_story.project
|
||||
|
||||
|
||||
class TaskCustomAttributesValues(AbstractCustomAttributesValues):
|
||||
task = models.OneToOneField("tasks.Task",
|
||||
null=False, blank=False, related_name="custom_attributes_values",
|
||||
verbose_name=_("task"))
|
||||
|
||||
class Meta(AbstractCustomAttributesValues.Meta):
|
||||
verbose_name = "task ustom attributes values"
|
||||
verbose_name_plural = "task custom attributes values"
|
||||
|
||||
@property
|
||||
def project(self):
|
||||
# NOTE: This property simplifies checking permissions
|
||||
return self.task.project
|
||||
|
||||
|
||||
class IssueCustomAttributesValues(AbstractCustomAttributesValues):
|
||||
issue = models.OneToOneField("issues.Issue",
|
||||
null=False, blank=False, related_name="custom_attributes_values",
|
||||
verbose_name=_("issue"))
|
||||
|
||||
class Meta(AbstractCustomAttributesValues.Meta):
|
||||
verbose_name = "issue ustom attributes values"
|
||||
verbose_name_plural = "issue custom attributes values"
|
||||
|
||||
@property
|
||||
def project(self):
|
||||
# NOTE: This property simplifies checking permissions
|
||||
return self.issue.project
|
||||
|
|
|
@ -18,9 +18,16 @@ from taiga.base.api.permissions import TaigaResourcePermission
|
|||
from taiga.base.api.permissions import HasProjectPerm
|
||||
from taiga.base.api.permissions import IsProjectOwner
|
||||
from taiga.base.api.permissions import AllowAny
|
||||
from taiga.base.api.permissions import IsSuperUser
|
||||
|
||||
|
||||
######################################################
|
||||
# Custom Attribute Permissions
|
||||
#######################################################
|
||||
|
||||
class UserStoryCustomAttributePermission(TaigaResourcePermission):
|
||||
enought_perms = IsProjectOwner() | IsSuperUser()
|
||||
global_perms = None
|
||||
retrieve_perms = HasProjectPerm('view_project')
|
||||
create_perms = IsProjectOwner()
|
||||
update_perms = IsProjectOwner()
|
||||
|
@ -30,6 +37,8 @@ class UserStoryCustomAttributePermission(TaigaResourcePermission):
|
|||
|
||||
|
||||
class TaskCustomAttributePermission(TaigaResourcePermission):
|
||||
enought_perms = IsProjectOwner() | IsSuperUser()
|
||||
global_perms = None
|
||||
retrieve_perms = HasProjectPerm('view_project')
|
||||
create_perms = IsProjectOwner()
|
||||
update_perms = IsProjectOwner()
|
||||
|
@ -39,9 +48,42 @@ class TaskCustomAttributePermission(TaigaResourcePermission):
|
|||
|
||||
|
||||
class IssueCustomAttributePermission(TaigaResourcePermission):
|
||||
enought_perms = IsProjectOwner() | IsSuperUser()
|
||||
global_perms = None
|
||||
retrieve_perms = HasProjectPerm('view_project')
|
||||
create_perms = IsProjectOwner()
|
||||
update_perms = IsProjectOwner()
|
||||
destroy_perms = IsProjectOwner()
|
||||
list_perms = AllowAny()
|
||||
bulk_update_order_perms = IsProjectOwner()
|
||||
|
||||
|
||||
######################################################
|
||||
# Custom Attributes Values Permissions
|
||||
#######################################################
|
||||
|
||||
class UserStoryCustomAttributesValuesPermission(TaigaResourcePermission):
|
||||
enought_perms = IsProjectOwner() | IsSuperUser()
|
||||
global_perms = None
|
||||
retrieve_perms = HasProjectPerm('view_us')
|
||||
create_perms = HasProjectPerm('add_us')
|
||||
update_perms = HasProjectPerm('modify_us')
|
||||
destroy_perms = HasProjectPerm('delete_us')
|
||||
|
||||
|
||||
class TaskCustomAttributesValuesPermission(TaigaResourcePermission):
|
||||
enought_perms = IsProjectOwner() | IsSuperUser()
|
||||
global_perms = None
|
||||
retrieve_perms = HasProjectPerm('view_tasks')
|
||||
create_perms = HasProjectPerm('add_task')
|
||||
update_perms = HasProjectPerm('modify_task')
|
||||
destroy_perms = HasProjectPerm('delete_task')
|
||||
|
||||
|
||||
class IssueCustomAttributesValuesPermission(TaigaResourcePermission):
|
||||
enought_perms = IsProjectOwner() | IsSuperUser()
|
||||
global_perms = None
|
||||
retrieve_perms = HasProjectPerm('view_issues')
|
||||
create_perms = HasProjectPerm('add_issue')
|
||||
update_perms = HasProjectPerm('modify_issue')
|
||||
destroy_perms = HasProjectPerm('delete_issue')
|
||||
|
|
|
@ -14,20 +14,26 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
from django.apps import apps
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from rest_framework.serializers import ValidationError
|
||||
|
||||
from taiga.base.serializers import ModelSerializer
|
||||
from taiga.base.serializers import JsonField
|
||||
|
||||
from . import models
|
||||
|
||||
|
||||
######################################################
|
||||
# Base Serializer Class
|
||||
# Custom Attribute Serializer
|
||||
#######################################################
|
||||
|
||||
class BaseCustomAttributeSerializer(ModelSerializer):
|
||||
class Meta:
|
||||
read_only_fields = ('id', 'created_date', 'modified_date')
|
||||
|
||||
def validate(self, data):
|
||||
"""
|
||||
Check the name is not duplicated in the project. Check when:
|
||||
|
@ -49,20 +55,78 @@ class BaseCustomAttributeSerializer(ModelSerializer):
|
|||
return data
|
||||
|
||||
|
||||
######################################################
|
||||
# Custom Field Serializers
|
||||
#######################################################
|
||||
|
||||
class UserStoryCustomAttributeSerializer(BaseCustomAttributeSerializer):
|
||||
class Meta:
|
||||
class Meta(BaseCustomAttributeSerializer.Meta):
|
||||
model = models.UserStoryCustomAttribute
|
||||
|
||||
|
||||
class TaskCustomAttributeSerializer(BaseCustomAttributeSerializer):
|
||||
class Meta:
|
||||
class Meta(BaseCustomAttributeSerializer.Meta):
|
||||
model = models.TaskCustomAttribute
|
||||
|
||||
|
||||
class IssueCustomAttributeSerializer(BaseCustomAttributeSerializer):
|
||||
class Meta:
|
||||
class Meta(BaseCustomAttributeSerializer.Meta):
|
||||
model = models.IssueCustomAttribute
|
||||
|
||||
|
||||
######################################################
|
||||
# Custom Attribute Serializer
|
||||
#######################################################
|
||||
|
||||
|
||||
class BaseCustomAttributesValuesSerializer:
|
||||
values = JsonField(source="values", label="values", required=True)
|
||||
_custom_attribute_model = None
|
||||
_container_field = None
|
||||
|
||||
def validate_values(self, attrs, source):
|
||||
# values must be a dict
|
||||
data_values = attrs.get("values", None)
|
||||
if self.object:
|
||||
data_values = (data_values or self.object.values)
|
||||
|
||||
if type(data_values) is not dict:
|
||||
raise ValidationError(_("Invalid content. It must be {\"key\": \"value\",...}"))
|
||||
|
||||
# Values keys must be in the container object project
|
||||
data_container = attrs.get(self._container_field, None)
|
||||
if data_container:
|
||||
project_id = data_container.project_id
|
||||
elif self.object:
|
||||
project_id = getattr(self.object, self._container_field).project_id
|
||||
else:
|
||||
project_id = None
|
||||
|
||||
values_ids = list(data_values.keys())
|
||||
qs = self._custom_attribute_model.objects.filter(project=project_id,
|
||||
id__in=values_ids)
|
||||
if qs.count() != len(values_ids):
|
||||
raise ValidationError(_("It contain invalid custom fields."))
|
||||
|
||||
return attrs
|
||||
|
||||
|
||||
class UserStoryCustomAttributesValuesSerializer(BaseCustomAttributesValuesSerializer, ModelSerializer):
|
||||
_custom_attribute_model = models.UserStoryCustomAttribute
|
||||
_container_model = "userstories.UserStory"
|
||||
_container_field = "user_story"
|
||||
|
||||
class Meta:
|
||||
model = models.UserStoryCustomAttributesValues
|
||||
|
||||
|
||||
class TaskCustomAttributesValuesSerializer(BaseCustomAttributesValuesSerializer, ModelSerializer):
|
||||
_custom_attribute_model = models.TaskCustomAttribute
|
||||
_container_field = "task"
|
||||
|
||||
class Meta:
|
||||
model = models.TaskCustomAttributesValues
|
||||
|
||||
|
||||
class IssueCustomAttributesValuesSerializer(BaseCustomAttributesValuesSerializer, ModelSerializer):
|
||||
_custom_attribute_model = models.IssueCustomAttribute
|
||||
_container_field = "issue"
|
||||
|
||||
class Meta:
|
||||
model = models.IssueCustomAttributesValues
|
||||
|
|
|
@ -14,9 +14,13 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from contextlib import suppress
|
||||
|
||||
from functools import partial
|
||||
from django.apps import apps
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
|
||||
from taiga.base.utils.iterators import as_tuple
|
||||
from taiga.base.utils.iterators import as_dict
|
||||
from taiga.mdrender.service import render as mdrender
|
||||
|
@ -181,6 +185,42 @@ def extract_attachments(obj) -> list:
|
|||
"order": attach.order}
|
||||
|
||||
|
||||
@as_tuple
|
||||
def extract_user_story_custom_attributes(obj) -> list:
|
||||
with suppress(ObjectDoesNotExist):
|
||||
custom_attributes_values = obj.custom_attributes_values.values
|
||||
for attr in obj.project.userstorycustomattributes.all():
|
||||
with suppress(KeyError):
|
||||
value = custom_attributes_values[str(attr.id)]
|
||||
yield {"id": attr.id,
|
||||
"name": attr.name,
|
||||
"values": value}
|
||||
|
||||
|
||||
@as_tuple
|
||||
def extract_task_custom_attributes(obj) -> list:
|
||||
with suppress(ObjectDoesNotExist):
|
||||
custom_attributes_values = obj.custom_attributes_values.values
|
||||
for attr in obj.project.taskcustomattributes.all():
|
||||
with suppress(KeyError):
|
||||
value = custom_attributes_values[str(attr.id)]
|
||||
yield {"id": attr.id,
|
||||
"name": attr.name,
|
||||
"values": value}
|
||||
|
||||
|
||||
@as_tuple
|
||||
def extract_issue_custom_attributes(obj) -> list:
|
||||
with suppress(ObjectDoesNotExist):
|
||||
custom_attributes_values = obj.custom_attributes_values.values
|
||||
for attr in obj.project.issuecustomattributes.all():
|
||||
with suppress(KeyError):
|
||||
value = custom_attributes_values[str(attr.id)]
|
||||
yield {"id": attr.id,
|
||||
"name": attr.name,
|
||||
"values": value}
|
||||
|
||||
|
||||
def project_freezer(project) -> dict:
|
||||
fields = ("name",
|
||||
"slug",
|
||||
|
@ -243,6 +283,7 @@ def userstory_freezer(us) -> dict:
|
|||
"is_blocked": us.is_blocked,
|
||||
"blocked_note": us.blocked_note,
|
||||
"blocked_note_html": mdrender(us.project, us.blocked_note),
|
||||
"custom_attributes": extract_user_story_custom_attributes(us),
|
||||
}
|
||||
|
||||
return snapshot
|
||||
|
@ -267,6 +308,7 @@ def issue_freezer(issue) -> dict:
|
|||
"is_blocked": issue.is_blocked,
|
||||
"blocked_note": issue.blocked_note,
|
||||
"blocked_note_html": mdrender(issue.project, issue.blocked_note),
|
||||
"custom_attributes": extract_issue_custom_attributes(issue),
|
||||
}
|
||||
|
||||
return snapshot
|
||||
|
@ -292,6 +334,7 @@ def task_freezer(task) -> dict:
|
|||
"is_blocked": task.is_blocked,
|
||||
"blocked_note": task.blocked_note,
|
||||
"blocked_note_html": mdrender(task.project, task.blocked_note),
|
||||
"custom_attributes": extract_task_custom_attributes(task),
|
||||
}
|
||||
|
||||
return snapshot
|
||||
|
|
|
@ -197,6 +197,35 @@ class HistoryEntry(models.Model):
|
|||
if attachments["new"] or attachments["changed"] or attachments["deleted"]:
|
||||
value = attachments
|
||||
|
||||
elif key == "custom_attributes":
|
||||
custom_attributes = {
|
||||
"new": [],
|
||||
"changed": [],
|
||||
"deleted": [],
|
||||
}
|
||||
|
||||
oldcustattrs = {x["id"]:x for x in self.diff["custom_attributes"][0]}
|
||||
newcustattrs = {x["id"]:x for x in self.diff["custom_attributes"][1]}
|
||||
|
||||
for aid in set(tuple(oldcustattrs.keys()) + tuple(newcustattrs.keys())):
|
||||
if aid in oldcustattrs and aid in newcustattrs:
|
||||
changes = make_diff_from_dicts(oldcustattrs[aid], newcustattrs[aid],
|
||||
excluded_keys=("name"))
|
||||
|
||||
if changes:
|
||||
change = {
|
||||
"name": newcustattrs.get(aid, {}).get("name", ""),
|
||||
"changes": changes
|
||||
}
|
||||
custom_attributes["changed"].append(change)
|
||||
elif aid in oldcustattrs and aid not in newcustattrs:
|
||||
custom_attributes["deleted"].append(oldcustattrs[aid])
|
||||
elif aid not in oldcustattrs and aid in newcustattrs:
|
||||
custom_attributes["new"].append(newcustattrs[aid])
|
||||
|
||||
if custom_attributes["new"] or custom_attributes["changed"] or custom_attributes["deleted"]:
|
||||
value = custom_attributes
|
||||
|
||||
elif key in self.values:
|
||||
value = [resolve_value(key, x) for x in self.diff[key]]
|
||||
else:
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
"backlog_order",
|
||||
"kanban_order",
|
||||
"taskboard_order",
|
||||
"us_order"
|
||||
"us_order",
|
||||
"custom_attributes"
|
||||
] %}
|
||||
|
||||
{% for field_name, values in changed_fields.items() %}
|
||||
|
@ -80,9 +81,7 @@
|
|||
<tr>
|
||||
<td colspan="2">
|
||||
<h3>{{ _("Deleted attachment") }}</h3>
|
||||
{% if att.changes.description %}
|
||||
<p>{{ att.filename|linebreaksbr }}</p>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -155,7 +154,6 @@
|
|||
</tr>
|
||||
{# * #}
|
||||
{% else %}
|
||||
|
||||
<tr>
|
||||
<td valign="middle" rowspan="2" class="update-row-name">
|
||||
<h3>{{ verbose_name(obj_class, field_name) }}</h3>
|
||||
|
@ -172,5 +170,52 @@
|
|||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
{% elif field_name == "custom_attributes" %}
|
||||
{# CUSTOM ATTRIBUTES #}
|
||||
{% if values.new %}
|
||||
{% for attr in values['new']%}
|
||||
<tr>
|
||||
<td valign="middle" rowspan="2" class="update-row-name">
|
||||
<h3>{{ attr.name }}</h3>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<span>{{ _("to") }}</span><br>
|
||||
<strong>{{ attr.value|linebreaksbr }}</strong>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if values.changed %}
|
||||
{% for attr in values['changed'] %}
|
||||
<tr>
|
||||
<td valign="middle" rowspan="2" class="update-row-name">
|
||||
<h3>{{ attr.name }}</h3>
|
||||
</td>
|
||||
<td valign="top" class="update-row-from">
|
||||
<span>{{ _("from") }}</span><br>
|
||||
<strong>{{ attr.changes.value.0|linebreaksbr }}</strong>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<span>{{ _("to") }}</span><br>
|
||||
<strong>{{ attr.changes.value.1|linebreaksbr }}</strong>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if values.deleted %}
|
||||
{% for attr in values['deleted']%}
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<h3>{{ attr.name }}</h3>
|
||||
<p>{{ _("-deleted-") }}</p>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
"taskboard_order",
|
||||
"us_order",
|
||||
"blocked_note_diff",
|
||||
"blocked_note_html"
|
||||
"blocked_note_html",
|
||||
"custom_attributes"
|
||||
] %}
|
||||
{% for field_name, values in changed_fields.items() %}
|
||||
{% if field_name not in excluded_fields %}
|
||||
|
@ -18,6 +19,7 @@
|
|||
{% for role, points in values.items() %}
|
||||
* {{ role }} {{ _("to:") }} {{ points.1 }} {{ _("from:") }} {{ points.0 }}
|
||||
{% endfor %}
|
||||
|
||||
{# ATTACHMENTS #}
|
||||
{% elif field_name == "attachments" %}
|
||||
{% if values.new %}
|
||||
|
@ -40,6 +42,7 @@
|
|||
- {{ att.filename }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{# TAGS AND WATCHERS #}
|
||||
{% elif field_name in ["tags", "watchers"] %}
|
||||
{% set values_from = values.0 or [] %}
|
||||
|
@ -53,6 +56,36 @@
|
|||
{% if values_removed %}
|
||||
* {{ _("removed:") }} {{ ', '.join(values_removed) }}
|
||||
{% endif %}
|
||||
|
||||
{# * #}
|
||||
{% else %}
|
||||
* {{ _("From:") }} {{ values.0 }}
|
||||
* {{ _("To:") }} {{ values.1 }}
|
||||
{% endif %}
|
||||
|
||||
{% elif field_name == "custom_attributes" %}
|
||||
{# CUSTOM ATTRIBUTES #}
|
||||
{% elif field_name == "attachments" %}
|
||||
{% if values.new %}
|
||||
{% for attr in values['new']%}
|
||||
- {{ attr.name }}:
|
||||
* {{ attr.value }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if values.changed %}
|
||||
{% for attr in values['changed'] %}
|
||||
- {{ attr.name }}:
|
||||
* {{ _("From:") }} {{ attr.changes.value.0 }}
|
||||
* {{ _("To:") }} {{ attr.changes.value.1 }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if values.deleted %}
|
||||
{% for attr in values['deleted']%}
|
||||
- {{ attr.name }}: {{ _("-deleted-") }}
|
||||
* {{ attr.value }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
from rest_framework import serializers
|
||||
|
||||
from taiga.base.serializers import (Serializer, TagsField, NeighborsSerializerMixin,
|
||||
from taiga.base.serializers import (Serializer, TagsField, NeighborsSerializerMixin,
|
||||
PgArrayField, ModelSerializer)
|
||||
|
||||
from taiga.mdrender.service import render as mdrender
|
||||
|
|
|
@ -18,7 +18,7 @@ from rest_framework import serializers
|
|||
|
||||
from taiga.base.serializers import (Serializer, TagsField, NeighborsSerializerMixin,
|
||||
PgArrayField, ModelSerializer)
|
||||
|
||||
|
||||
from taiga.mdrender.service import render as mdrender
|
||||
from taiga.projects.validators import ProjectExistsValidator
|
||||
from taiga.projects.milestones.validators import SprintExistsValidator
|
||||
|
|
|
@ -22,10 +22,10 @@ from django.utils import timezone
|
|||
|
||||
from djorm_pgarray.fields import TextArrayField
|
||||
|
||||
from taiga.base.tags import TaggedMixin
|
||||
from taiga.projects.occ import OCCModelMixin
|
||||
from taiga.projects.notifications.mixins import WatchedModelMixin
|
||||
from taiga.projects.mixins.blocked import BlockedMixin
|
||||
from taiga.base.tags import TaggedMixin
|
||||
|
||||
|
||||
class RolePoints(models.Model):
|
||||
|
|
|
@ -14,15 +14,19 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import json
|
||||
from django.apps import apps
|
||||
from rest_framework import serializers
|
||||
|
||||
from taiga.base.serializers import (Serializer, TagsField, NeighborsSerializerMixin,
|
||||
PgArrayField, ModelSerializer)
|
||||
from taiga.base.serializers import Serializer
|
||||
from taiga.base.serializers import TagsField
|
||||
from taiga.base.serializers import NeighborsSerializerMixin
|
||||
from taiga.base.serializers import PgArrayField
|
||||
from taiga.base.serializers import ModelSerializer
|
||||
from taiga.base.utils import json
|
||||
|
||||
from taiga.mdrender.service import render as mdrender
|
||||
from taiga.projects.validators import ProjectExistsValidator, UserStoryStatusExistsValidator
|
||||
from taiga.projects.validators import ProjectExistsValidator
|
||||
from taiga.projects.validators import UserStoryStatusExistsValidator
|
||||
from taiga.projects.userstories.validators import UserStoryExistsValidator
|
||||
from taiga.projects.notifications.validators import WatchersValidator
|
||||
|
||||
|
@ -92,7 +96,6 @@ class UserStorySerializer(WatchersValidator, ModelSerializer):
|
|||
|
||||
|
||||
class UserStoryNeighborsSerializer(NeighborsSerializerMixin, UserStorySerializer):
|
||||
|
||||
def serialize_neighbor(self, neighbor):
|
||||
return NeighborUserStorySerializer(neighbor).data
|
||||
|
||||
|
@ -104,8 +107,7 @@ class NeighborUserStorySerializer(ModelSerializer):
|
|||
depth = 0
|
||||
|
||||
|
||||
class UserStoriesBulkSerializer(ProjectExistsValidator, UserStoryStatusExistsValidator,
|
||||
Serializer):
|
||||
class UserStoriesBulkSerializer(ProjectExistsValidator, UserStoryStatusExistsValidator, Serializer):
|
||||
project_id = serializers.IntegerField()
|
||||
status_id = serializers.IntegerField(required=False)
|
||||
bulk_stories = serializers.CharField()
|
||||
|
@ -118,8 +120,6 @@ class _UserStoryOrderBulkSerializer(UserStoryExistsValidator, Serializer):
|
|||
order = serializers.IntegerField()
|
||||
|
||||
|
||||
class UpdateUserStoriesOrderBulkSerializer(ProjectExistsValidator,
|
||||
UserStoryStatusExistsValidator,
|
||||
Serializer):
|
||||
class UpdateUserStoriesOrderBulkSerializer(ProjectExistsValidator, UserStoryStatusExistsValidator, Serializer):
|
||||
project_id = serializers.IntegerField()
|
||||
bulk_stories = _UserStoryOrderBulkSerializer(many=True)
|
||||
|
|
|
@ -71,6 +71,9 @@ router.register(r"severities",SeverityViewSet , base_name="severities")
|
|||
from taiga.projects.custom_attributes.api import UserStoryCustomAttributeViewSet
|
||||
from taiga.projects.custom_attributes.api import TaskCustomAttributeViewSet
|
||||
from taiga.projects.custom_attributes.api import IssueCustomAttributeViewSet
|
||||
from taiga.projects.custom_attributes.api import UserStoryCustomAttributesValuesViewSet
|
||||
from taiga.projects.custom_attributes.api import TaskCustomAttributesValuesViewSet
|
||||
from taiga.projects.custom_attributes.api import IssueCustomAttributesValuesViewSet
|
||||
|
||||
router.register(r"userstory-custom-attributes", UserStoryCustomAttributeViewSet,
|
||||
base_name="userstory-custom-attributes")
|
||||
|
@ -79,6 +82,13 @@ router.register(r"task-custom-attributes", TaskCustomAttributeViewSet,
|
|||
router.register(r"issue-custom-attributes", IssueCustomAttributeViewSet,
|
||||
base_name="issue-custom-attributes")
|
||||
|
||||
router.register(r"userstories/custom-attributes-values", UserStoryCustomAttributesValuesViewSet,
|
||||
base_name="userstory-custom-attributes-values")
|
||||
router.register(r"tasks/custom-attributes-values", TaskCustomAttributesValuesViewSet,
|
||||
base_name="task-custom-attributes-values")
|
||||
router.register(r"issues/custom-attributes-values", IssueCustomAttributesValuesViewSet,
|
||||
base_name="issue-custom-attributes-values")
|
||||
|
||||
|
||||
# Search
|
||||
from taiga.searches.api import SearchViewSet
|
||||
|
|
|
@ -384,6 +384,33 @@ class IssueCustomAttributeFactory(Factory):
|
|||
project = factory.SubFactory("tests.factories.ProjectFactory")
|
||||
|
||||
|
||||
class UserStoryCustomAttributesValuesFactory(Factory):
|
||||
class Meta:
|
||||
model = "custom_attributes.UserStoryCustomAttributesValues"
|
||||
strategy = factory.CREATE_STRATEGY
|
||||
|
||||
values = {}
|
||||
user_story = factory.SubFactory("tests.factories.UserStoryFactory")
|
||||
|
||||
|
||||
class TaskCustomAttributesValuesFactory(Factory):
|
||||
class Meta:
|
||||
model = "custom_attributes.TaskCustomAttributesValues"
|
||||
strategy = factory.CREATE_STRATEGY
|
||||
|
||||
values = {}
|
||||
task = factory.SubFactory("tests.factories.TaskFactory")
|
||||
|
||||
|
||||
class IssueCustomAttributesValuesFactory(Factory):
|
||||
class Meta:
|
||||
model = "custom_attributes.IssueCustomAttributesValues"
|
||||
strategy = factory.CREATE_STRATEGY
|
||||
|
||||
values = {}
|
||||
issue = factory.SubFactory("tests.factories.IssueFactory")
|
||||
|
||||
|
||||
# class FanFactory(Factory):
|
||||
# project = factory.SubFactory("tests.factories.ProjectFactory")
|
||||
# user = factory.SubFactory("tests.factories.UserFactory")
|
||||
|
|
|
@ -1,586 +0,0 @@
|
|||
# Copyright (C) 2015 Andrey Antukh <niwi@niwi.be>
|
||||
# Copyright (C) 2015 Jesús Espino <jespinog@gmail.com>
|
||||
# Copyright (C) 2015 David Barragán <bameda@dbarragan.com>
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from taiga.base.utils import json
|
||||
from taiga.projects.custom_attributes import serializers
|
||||
from taiga.permissions.permissions import MEMBERS_PERMISSIONS
|
||||
|
||||
from tests import factories as f
|
||||
from tests.utils import helper_test_http_method
|
||||
|
||||
import pytest
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
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.superuser = f.UserFactory.create(is_superuser=True)
|
||||
|
||||
m.public_project = f.ProjectFactory(is_private=False,
|
||||
anon_permissions=['view_project'],
|
||||
public_permissions=['view_project'],
|
||||
owner=m.project_owner)
|
||||
m.private_project1 = f.ProjectFactory(is_private=True,
|
||||
anon_permissions=['view_project'],
|
||||
public_permissions=['view_project'],
|
||||
owner=m.project_owner)
|
||||
m.private_project2 = f.ProjectFactory(is_private=True,
|
||||
anon_permissions=[],
|
||||
public_permissions=[],
|
||||
owner=m.project_owner)
|
||||
|
||||
m.public_membership = f.MembershipFactory(project=m.public_project,
|
||||
user=m.project_member_with_perms,
|
||||
email=m.project_member_with_perms.email,
|
||||
role__project=m.public_project,
|
||||
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
|
||||
m.private_membership1 = f.MembershipFactory(project=m.private_project1,
|
||||
user=m.project_member_with_perms,
|
||||
email=m.project_member_with_perms.email,
|
||||
role__project=m.private_project1,
|
||||
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
|
||||
|
||||
f.MembershipFactory(project=m.private_project1,
|
||||
user=m.project_member_without_perms,
|
||||
email=m.project_member_without_perms.email,
|
||||
role__project=m.private_project1,
|
||||
role__permissions=[])
|
||||
|
||||
m.private_membership2 = f.MembershipFactory(project=m.private_project2,
|
||||
user=m.project_member_with_perms,
|
||||
email=m.project_member_with_perms.email,
|
||||
role__project=m.private_project2,
|
||||
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
|
||||
f.MembershipFactory(project=m.private_project2,
|
||||
user=m.project_member_without_perms,
|
||||
email=m.project_member_without_perms.email,
|
||||
role__project=m.private_project2,
|
||||
role__permissions=[])
|
||||
|
||||
f.MembershipFactory(project=m.public_project,
|
||||
user=m.project_owner,
|
||||
is_owner=True)
|
||||
|
||||
f.MembershipFactory(project=m.private_project1,
|
||||
user=m.project_owner,
|
||||
is_owner=True)
|
||||
|
||||
f.MembershipFactory(project=m.private_project2,
|
||||
user=m.project_owner,
|
||||
is_owner=True)
|
||||
|
||||
m.public_userstory_ca = f.UserStoryCustomAttributeFactory(project=m.public_project)
|
||||
m.private_userstory_ca1 = f.UserStoryCustomAttributeFactory(project=m.private_project1)
|
||||
m.private_userstory_ca2 = f.UserStoryCustomAttributeFactory(project=m.private_project2)
|
||||
|
||||
m.public_task_ca = f.TaskCustomAttributeFactory(project=m.public_project)
|
||||
m.private_task_ca1 = f.TaskCustomAttributeFactory(project=m.private_project1)
|
||||
m.private_task_ca2 = f.TaskCustomAttributeFactory(project=m.private_project2)
|
||||
|
||||
m.public_issue_ca = f.IssueCustomAttributeFactory(project=m.public_project)
|
||||
m.private_issue_ca1 = f.IssueCustomAttributeFactory(project=m.private_project1)
|
||||
m.private_issue_ca2 = f.IssueCustomAttributeFactory(project=m.private_project2)
|
||||
|
||||
return m
|
||||
|
||||
|
||||
#########################################################
|
||||
# User Story Custom Fields
|
||||
#########################################################
|
||||
|
||||
def test_userstory_status_retrieve(client, data):
|
||||
public_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.public_userstory_ca.pk})
|
||||
private1_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.private_userstory_ca1.pk})
|
||||
private2_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.private_userstory_ca2.pk})
|
||||
|
||||
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 == [200, 200, 200, 200, 200]
|
||||
results = helper_test_http_method(client, 'get', private1_url, None, users)
|
||||
assert results == [200, 200, 200, 200, 200]
|
||||
results = helper_test_http_method(client, 'get', private2_url, None, users)
|
||||
assert results == [401, 403, 403, 200, 200]
|
||||
|
||||
|
||||
def test_userstory_status_update(client, data):
|
||||
public_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.public_userstory_ca.pk})
|
||||
private1_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.private_userstory_ca1.pk})
|
||||
private2_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.private_userstory_ca2.pk})
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
userstory_ca_data = serializers.UserStoryCustomAttributeSerializer(data.public_userstory_ca).data
|
||||
userstory_ca_data["name"] = "test"
|
||||
userstory_ca_data = json.dumps(userstory_ca_data)
|
||||
results = helper_test_http_method(client, 'put', public_url, userstory_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
userstory_ca_data = serializers.UserStoryCustomAttributeSerializer(data.private_userstory_ca1).data
|
||||
userstory_ca_data["name"] = "test"
|
||||
userstory_ca_data = json.dumps(userstory_ca_data)
|
||||
results = helper_test_http_method(client, 'put', private1_url, userstory_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
userstory_ca_data = serializers.UserStoryCustomAttributeSerializer(data.private_userstory_ca2).data
|
||||
userstory_ca_data["name"] = "test"
|
||||
userstory_ca_data = json.dumps(userstory_ca_data)
|
||||
results = helper_test_http_method(client, 'put', private2_url, userstory_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
|
||||
def test_userstory_status_delete(client, data):
|
||||
public_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.public_userstory_ca.pk})
|
||||
private1_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.private_userstory_ca1.pk})
|
||||
private2_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.private_userstory_ca2.pk})
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
results = helper_test_http_method(client, 'delete', public_url, None, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
results = helper_test_http_method(client, 'delete', private1_url, None, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
results = helper_test_http_method(client, 'delete', private2_url, None, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
|
||||
|
||||
def test_userstory_status_list(client, data):
|
||||
url = reverse('userstory-custom-attributes-list')
|
||||
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 2
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.registered_user)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 2
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.project_member_without_perms)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 2
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.project_member_with_perms)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 3
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.project_owner)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 3
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
def test_userstory_status_patch(client, data):
|
||||
public_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.public_userstory_ca.pk})
|
||||
private1_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.private_userstory_ca1.pk})
|
||||
private2_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.private_userstory_ca2.pk})
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
results = helper_test_http_method(client, 'patch', public_url, '{"name": "Test"}', users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
results = helper_test_http_method(client, 'patch', private1_url, '{"name": "Test"}', users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
results = helper_test_http_method(client, 'patch', private2_url, '{"name": "Test"}', users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
|
||||
def test_userstory_status_action_bulk_update_order(client, data):
|
||||
url = reverse('userstory-custom-attributes-bulk-update-order')
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
post_data = json.dumps({
|
||||
"bulk_userstory_custom_attributes": [(1,2)],
|
||||
"project": data.public_project.pk
|
||||
})
|
||||
results = helper_test_http_method(client, 'post', url, post_data, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
|
||||
post_data = json.dumps({
|
||||
"bulk_userstory_custom_attributes": [(1,2)],
|
||||
"project": data.private_project1.pk
|
||||
})
|
||||
results = helper_test_http_method(client, 'post', url, post_data, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
|
||||
post_data = json.dumps({
|
||||
"bulk_userstory_custom_attributes": [(1,2)],
|
||||
"project": data.private_project2.pk
|
||||
})
|
||||
results = helper_test_http_method(client, 'post', url, post_data, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
|
||||
|
||||
#########################################################
|
||||
# Task Custom Fields
|
||||
#########################################################
|
||||
|
||||
def test_task_status_retrieve(client, data):
|
||||
public_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.public_task_ca.pk})
|
||||
private1_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.private_task_ca1.pk})
|
||||
private2_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.private_task_ca2.pk})
|
||||
|
||||
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 == [200, 200, 200, 200, 200]
|
||||
results = helper_test_http_method(client, 'get', private1_url, None, users)
|
||||
assert results == [200, 200, 200, 200, 200]
|
||||
results = helper_test_http_method(client, 'get', private2_url, None, users)
|
||||
assert results == [401, 403, 403, 200, 200]
|
||||
|
||||
|
||||
def test_task_status_update(client, data):
|
||||
public_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.public_task_ca.pk})
|
||||
private1_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.private_task_ca1.pk})
|
||||
private2_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.private_task_ca2.pk})
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
task_ca_data = serializers.TaskCustomAttributeSerializer(data.public_task_ca).data
|
||||
task_ca_data["name"] = "test"
|
||||
task_ca_data = json.dumps(task_ca_data)
|
||||
results = helper_test_http_method(client, 'put', public_url, task_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
task_ca_data = serializers.TaskCustomAttributeSerializer(data.private_task_ca1).data
|
||||
task_ca_data["name"] = "test"
|
||||
task_ca_data = json.dumps(task_ca_data)
|
||||
results = helper_test_http_method(client, 'put', private1_url, task_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
task_ca_data = serializers.TaskCustomAttributeSerializer(data.private_task_ca2).data
|
||||
task_ca_data["name"] = "test"
|
||||
task_ca_data = json.dumps(task_ca_data)
|
||||
results = helper_test_http_method(client, 'put', private2_url, task_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
|
||||
def test_task_status_delete(client, data):
|
||||
public_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.public_task_ca.pk})
|
||||
private1_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.private_task_ca1.pk})
|
||||
private2_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.private_task_ca2.pk})
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
results = helper_test_http_method(client, 'delete', public_url, None, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
results = helper_test_http_method(client, 'delete', private1_url, None, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
results = helper_test_http_method(client, 'delete', private2_url, None, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
|
||||
|
||||
def test_task_status_list(client, data):
|
||||
url = reverse('task-custom-attributes-list')
|
||||
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 2
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.registered_user)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 2
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.project_member_without_perms)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 2
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.project_member_with_perms)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 3
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.project_owner)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 3
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
def test_task_status_patch(client, data):
|
||||
public_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.public_task_ca.pk})
|
||||
private1_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.private_task_ca1.pk})
|
||||
private2_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.private_task_ca2.pk})
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
results = helper_test_http_method(client, 'patch', public_url, '{"name": "Test"}', users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
results = helper_test_http_method(client, 'patch', private1_url, '{"name": "Test"}', users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
results = helper_test_http_method(client, 'patch', private2_url, '{"name": "Test"}', users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
|
||||
def test_task_status_action_bulk_update_order(client, data):
|
||||
url = reverse('task-custom-attributes-bulk-update-order')
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
post_data = json.dumps({
|
||||
"bulk_task_custom_attributes": [(1,2)],
|
||||
"project": data.public_project.pk
|
||||
})
|
||||
results = helper_test_http_method(client, 'post', url, post_data, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
|
||||
post_data = json.dumps({
|
||||
"bulk_task_custom_attributes": [(1,2)],
|
||||
"project": data.private_project1.pk
|
||||
})
|
||||
results = helper_test_http_method(client, 'post', url, post_data, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
|
||||
post_data = json.dumps({
|
||||
"bulk_task_custom_attributes": [(1,2)],
|
||||
"project": data.private_project2.pk
|
||||
})
|
||||
results = helper_test_http_method(client, 'post', url, post_data, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
|
||||
|
||||
#########################################################
|
||||
# Issue Custom Fields
|
||||
#########################################################
|
||||
|
||||
def test_issue_status_retrieve(client, data):
|
||||
public_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.public_issue_ca.pk})
|
||||
private1_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.private_issue_ca1.pk})
|
||||
private2_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.private_issue_ca2.pk})
|
||||
|
||||
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 == [200, 200, 200, 200, 200]
|
||||
results = helper_test_http_method(client, 'get', private1_url, None, users)
|
||||
assert results == [200, 200, 200, 200, 200]
|
||||
results = helper_test_http_method(client, 'get', private2_url, None, users)
|
||||
assert results == [401, 403, 403, 200, 200]
|
||||
|
||||
|
||||
def test_issue_status_update(client, data):
|
||||
public_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.public_issue_ca.pk})
|
||||
private1_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.private_issue_ca1.pk})
|
||||
private2_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.private_issue_ca2.pk})
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
issue_ca_data = serializers.IssueCustomAttributeSerializer(data.public_issue_ca).data
|
||||
issue_ca_data["name"] = "test"
|
||||
issue_ca_data = json.dumps(issue_ca_data)
|
||||
results = helper_test_http_method(client, 'put', public_url, issue_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
issue_ca_data = serializers.IssueCustomAttributeSerializer(data.private_issue_ca1).data
|
||||
issue_ca_data["name"] = "test"
|
||||
issue_ca_data = json.dumps(issue_ca_data)
|
||||
results = helper_test_http_method(client, 'put', private1_url, issue_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
issue_ca_data = serializers.IssueCustomAttributeSerializer(data.private_issue_ca2).data
|
||||
issue_ca_data["name"] = "test"
|
||||
issue_ca_data = json.dumps(issue_ca_data)
|
||||
results = helper_test_http_method(client, 'put', private2_url, issue_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
|
||||
def test_issue_status_delete(client, data):
|
||||
public_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.public_issue_ca.pk})
|
||||
private1_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.private_issue_ca1.pk})
|
||||
private2_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.private_issue_ca2.pk})
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
results = helper_test_http_method(client, 'delete', public_url, None, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
results = helper_test_http_method(client, 'delete', private1_url, None, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
results = helper_test_http_method(client, 'delete', private2_url, None, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
|
||||
|
||||
def test_issue_status_list(client, data):
|
||||
url = reverse('issue-custom-attributes-list')
|
||||
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 2
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.registered_user)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 2
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.project_member_without_perms)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 2
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.project_member_with_perms)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 3
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.project_owner)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 3
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
def test_issue_status_patch(client, data):
|
||||
public_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.public_issue_ca.pk})
|
||||
private1_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.private_issue_ca1.pk})
|
||||
private2_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.private_issue_ca2.pk})
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
results = helper_test_http_method(client, 'patch', public_url, '{"name": "Test"}', users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
results = helper_test_http_method(client, 'patch', private1_url, '{"name": "Test"}', users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
results = helper_test_http_method(client, 'patch', private2_url, '{"name": "Test"}', users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
|
||||
def test_issue_status_action_bulk_update_order(client, data):
|
||||
url = reverse('issue-custom-attributes-bulk-update-order')
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
post_data = json.dumps({
|
||||
"bulk_issue_custom_attributes": [(1,2)],
|
||||
"project": data.public_project.pk
|
||||
})
|
||||
results = helper_test_http_method(client, 'post', url, post_data, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
|
||||
post_data = json.dumps({
|
||||
"bulk_issue_custom_attributes": [(1,2)],
|
||||
"project": data.private_project1.pk
|
||||
})
|
||||
results = helper_test_http_method(client, 'post', url, post_data, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
|
||||
post_data = json.dumps({
|
||||
"bulk_issue_custom_attributes": [(1,2)],
|
||||
"project": data.private_project2.pk
|
||||
})
|
||||
results = helper_test_http_method(client, 'post', url, post_data, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
|
@ -0,0 +1,428 @@
|
|||
# Copyright (C) 2015 Andrey Antukh <niwi@niwi.be>
|
||||
# Copyright (C) 2015 Jesús Espino <jespinog@gmail.com>
|
||||
# Copyright (C) 2015 David Barragán <bameda@dbarragan.com>
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from taiga.base.utils import json
|
||||
from taiga.projects.custom_attributes import serializers
|
||||
from taiga.permissions.permissions import MEMBERS_PERMISSIONS
|
||||
|
||||
from tests import factories as f
|
||||
from tests.utils import helper_test_http_method
|
||||
|
||||
import pytest
|
||||
pytestmark = pytest.mark.django_db(transaction=True)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
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.superuser = f.UserFactory.create(is_superuser=True)
|
||||
|
||||
m.public_project = f.ProjectFactory(is_private=False,
|
||||
anon_permissions=['view_project'],
|
||||
public_permissions=['view_project'],
|
||||
owner=m.project_owner)
|
||||
m.private_project1 = f.ProjectFactory(is_private=True,
|
||||
anon_permissions=['view_project'],
|
||||
public_permissions=['view_project'],
|
||||
owner=m.project_owner)
|
||||
m.private_project2 = f.ProjectFactory(is_private=True,
|
||||
anon_permissions=[],
|
||||
public_permissions=[],
|
||||
owner=m.project_owner)
|
||||
|
||||
m.public_membership = f.MembershipFactory(project=m.public_project,
|
||||
user=m.project_member_with_perms,
|
||||
email=m.project_member_with_perms.email,
|
||||
role__project=m.public_project,
|
||||
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
|
||||
m.private_membership1 = f.MembershipFactory(project=m.private_project1,
|
||||
user=m.project_member_with_perms,
|
||||
email=m.project_member_with_perms.email,
|
||||
role__project=m.private_project1,
|
||||
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
|
||||
|
||||
f.MembershipFactory(project=m.private_project1,
|
||||
user=m.project_member_without_perms,
|
||||
email=m.project_member_without_perms.email,
|
||||
role__project=m.private_project1,
|
||||
role__permissions=[])
|
||||
|
||||
m.private_membership2 = f.MembershipFactory(project=m.private_project2,
|
||||
user=m.project_member_with_perms,
|
||||
email=m.project_member_with_perms.email,
|
||||
role__project=m.private_project2,
|
||||
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
|
||||
f.MembershipFactory(project=m.private_project2,
|
||||
user=m.project_member_without_perms,
|
||||
email=m.project_member_without_perms.email,
|
||||
role__project=m.private_project2,
|
||||
role__permissions=[])
|
||||
|
||||
f.MembershipFactory(project=m.public_project,
|
||||
user=m.project_owner,
|
||||
is_owner=True)
|
||||
|
||||
f.MembershipFactory(project=m.private_project1,
|
||||
user=m.project_owner,
|
||||
is_owner=True)
|
||||
|
||||
f.MembershipFactory(project=m.private_project2,
|
||||
user=m.project_owner,
|
||||
is_owner=True)
|
||||
|
||||
m.public_issue_ca = f.IssueCustomAttributeFactory(project=m.public_project)
|
||||
m.private_issue_ca1 = f.IssueCustomAttributeFactory(project=m.private_project1)
|
||||
m.private_issue_ca2 = f.IssueCustomAttributeFactory(project=m.private_project2)
|
||||
|
||||
#m.public_issue = f.IssueFactory(project=m.public_project, owner=m.project_owner)
|
||||
#m.private_issue1 = f.IssueFactory(project=m.private_project1, owner=m.project_owner)
|
||||
#m.private_issue2 = f.IssueFactory(project=m.private_project2, owner=m.project_owner)
|
||||
|
||||
#m.public_issue_cav = f.IssueCustomAttributesValuesFactory(project=m.public_project,
|
||||
# issue=f.IssueFactory(project=m.public_project,
|
||||
# owner=m.project_owner),
|
||||
# values={str(m.public_issue_ca.id):"test"})
|
||||
#m.private_issue_cav1 = f.IssueCustomAttributesValuesFactory(project=m.private_project1,
|
||||
# issue=f.IssueFactory(project=m.private_project1,
|
||||
# owner=m.project_owner),
|
||||
# values={str(m.private_issue_ca1.id):"test"})
|
||||
#m.private_issue_cav2 = f.IssueCustomAttributesValuesFactory(project=m.private_project2,
|
||||
# issue=f.IssueFactory(project=m.private_project2,
|
||||
# owner=m.project_owner),
|
||||
# values={str(m.private_issue_ca2.id):"test"})
|
||||
|
||||
return m
|
||||
|
||||
|
||||
#########################################################
|
||||
# Issue Custom Attribute
|
||||
#########################################################
|
||||
|
||||
def test_issue_custom_attribute_retrieve(client, data):
|
||||
public_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.public_issue_ca.pk})
|
||||
private1_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.private_issue_ca1.pk})
|
||||
private2_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.private_issue_ca2.pk})
|
||||
|
||||
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 == [200, 200, 200, 200, 200]
|
||||
results = helper_test_http_method(client, 'get', private1_url, None, users)
|
||||
assert results == [200, 200, 200, 200, 200]
|
||||
results = helper_test_http_method(client, 'get', private2_url, None, users)
|
||||
assert results == [401, 403, 403, 200, 200]
|
||||
|
||||
|
||||
def test_issue_custom_attribute_create(client, data):
|
||||
public_url = reverse('issue-custom-attributes-list')
|
||||
private1_url = reverse('issue-custom-attributes-list')
|
||||
private2_url = reverse('issue-custom-attributes-list')
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
issue_ca_data = {"name": "test-new", "project": data.public_project.id}
|
||||
issue_ca_data = json.dumps(issue_ca_data)
|
||||
results = helper_test_http_method(client, 'post', public_url, issue_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 201]
|
||||
|
||||
issue_ca_data = {"name": "test-new", "project": data.private_project1.id}
|
||||
issue_ca_data = json.dumps(issue_ca_data)
|
||||
results = helper_test_http_method(client, 'post', private1_url, issue_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 201]
|
||||
|
||||
issue_ca_data = {"name": "test-new", "project": data.private_project2.id}
|
||||
issue_ca_data = json.dumps(issue_ca_data)
|
||||
results = helper_test_http_method(client, 'post', private2_url, issue_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 201]
|
||||
|
||||
|
||||
def test_issue_custom_attribute_update(client, data):
|
||||
public_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.public_issue_ca.pk})
|
||||
private1_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.private_issue_ca1.pk})
|
||||
private2_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.private_issue_ca2.pk})
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
issue_ca_data = serializers.IssueCustomAttributeSerializer(data.public_issue_ca).data
|
||||
issue_ca_data["name"] = "test"
|
||||
issue_ca_data = json.dumps(issue_ca_data)
|
||||
results = helper_test_http_method(client, 'put', public_url, issue_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
issue_ca_data = serializers.IssueCustomAttributeSerializer(data.private_issue_ca1).data
|
||||
issue_ca_data["name"] = "test"
|
||||
issue_ca_data = json.dumps(issue_ca_data)
|
||||
results = helper_test_http_method(client, 'put', private1_url, issue_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
issue_ca_data = serializers.IssueCustomAttributeSerializer(data.private_issue_ca2).data
|
||||
issue_ca_data["name"] = "test"
|
||||
issue_ca_data = json.dumps(issue_ca_data)
|
||||
results = helper_test_http_method(client, 'put', private2_url, issue_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
|
||||
def test_issue_custom_attribute_delete(client, data):
|
||||
public_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.public_issue_ca.pk})
|
||||
private1_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.private_issue_ca1.pk})
|
||||
private2_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.private_issue_ca2.pk})
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
results = helper_test_http_method(client, 'delete', public_url, None, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
results = helper_test_http_method(client, 'delete', private1_url, None, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
results = helper_test_http_method(client, 'delete', private2_url, None, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
|
||||
|
||||
def test_issue_custom_attribute_list(client, data):
|
||||
url = reverse('issue-custom-attributes-list')
|
||||
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 2
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.registered_user)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 2
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.project_member_without_perms)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 2
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.project_member_with_perms)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 3
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.project_owner)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 3
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
def test_issue_custom_attribute_patch(client, data):
|
||||
public_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.public_issue_ca.pk})
|
||||
private1_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.private_issue_ca1.pk})
|
||||
private2_url = reverse('issue-custom-attributes-detail', kwargs={"pk": data.private_issue_ca2.pk})
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
results = helper_test_http_method(client, 'patch', public_url, '{"name": "Test"}', users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
results = helper_test_http_method(client, 'patch', private1_url, '{"name": "Test"}', users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
results = helper_test_http_method(client, 'patch', private2_url, '{"name": "Test"}', users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
|
||||
def test_issue_custom_attribute_action_bulk_update_order(client, data):
|
||||
url = reverse('issue-custom-attributes-bulk-update-order')
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
post_data = json.dumps({
|
||||
"bulk_issue_custom_attributes": [(1,2)],
|
||||
"project": data.public_project.pk
|
||||
})
|
||||
results = helper_test_http_method(client, 'post', url, post_data, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
|
||||
post_data = json.dumps({
|
||||
"bulk_issue_custom_attributes": [(1,2)],
|
||||
"project": data.private_project1.pk
|
||||
})
|
||||
results = helper_test_http_method(client, 'post', url, post_data, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
|
||||
post_data = json.dumps({
|
||||
"bulk_issue_custom_attributes": [(1,2)],
|
||||
"project": data.private_project2.pk
|
||||
})
|
||||
results = helper_test_http_method(client, 'post', url, post_data, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
|
||||
|
||||
#########################################################
|
||||
# Issue Custom Attributes Values
|
||||
#########################################################
|
||||
|
||||
#def test_issue_custom_attributes_values_retrieve(client, data):
|
||||
# public_url = reverse('issue-custom-attributes-values-detail', args=[data.public_issue_cav.issue.id])
|
||||
# private1_url = reverse('issue-custom-attributes-values-detail', args=[data.private_issue_cav1.issue.id])
|
||||
# private2_url = reverse('issue-custom-attributes-values-detail', args=[data.private_issue_cav2.issue.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 == [200, 200, 200, 200, 200]
|
||||
# results = helper_test_http_method(client, 'get', private1_url, None, users)
|
||||
# assert results == [200, 200, 200, 200, 200]
|
||||
# results = helper_test_http_method(client, 'get', private2_url, None, users)
|
||||
# assert results == [401, 403, 403, 200, 200]
|
||||
#
|
||||
#
|
||||
#def test_issue_custom_attributes_values_update(client, data):
|
||||
# public_url = reverse('issue-custom-attributes-values-detail', args=[data.public_issue_cav.issue.id])
|
||||
# private1_url = reverse('issue-custom-attributes-values-detail', args=[data.private_issue_cav1.issue.id])
|
||||
# private2_url = reverse('issue-custom-attributes-values-detail', args=[data.private_issue_cav2.issue.id])
|
||||
#
|
||||
# users = [
|
||||
# None,
|
||||
# data.registered_user,
|
||||
# data.project_member_without_perms,
|
||||
# data.project_member_with_perms,
|
||||
# data.project_owner
|
||||
# ]
|
||||
#
|
||||
# issue_cav_data = serializers.IssueCustomAttributesValuesSerializer(data.public_issue_cav).data
|
||||
# issue_cav_data["values"] = '{{"{}":"test-update"}}'.format(data.public_issue_ca.id)
|
||||
# issue_cav_data = json.dumps(issue_cav_data)
|
||||
# results = helper_test_http_method(client, 'put', public_url, issue_cav_data, users)
|
||||
# assert results == [401, 403, 403, 403, 200]
|
||||
#
|
||||
# issue_cav_data = serializers.IssueCustomAttributesValuesSerializer(data.private_issue_cav1).data
|
||||
# issue_cav_data["values"] = '{{"{}":"test-update"}}'.format(data.private_issue_ca1.id)
|
||||
# issue_cav_data = json.dumps(issue_cav_data)
|
||||
# results = helper_test_http_method(client, 'put', private1_url, issue_cav_data, users)
|
||||
# assert results == [401, 403, 403, 403, 200]
|
||||
#
|
||||
# issue_cav_data = serializers.IssueCustomAttributesValuesSerializer(data.private_issue_cav2).data
|
||||
# issue_cav_data["values"] = '{{"{}":"test-update"}}'.format(data.private_issue_ca2.id)
|
||||
# issue_cav_data = json.dumps(issue_cav_data)
|
||||
# results = helper_test_http_method(client, 'put', private2_url, issue_cav_data, users)
|
||||
# assert results == [401, 403, 403, 403, 200]
|
||||
#
|
||||
#
|
||||
#def test_issue_custom_attributes_values_delete(client, data):
|
||||
# public_url = reverse('issue-custom-attributes-values-detail', args=[data.public_issue_cav.issue.id])
|
||||
# private1_url = reverse('issue-custom-attributes-values-detail', args=[data.private_issue_cav1.issue.id])
|
||||
# private2_url = reverse('issue-custom-attributes-values-detail', args=[data.private_issue_cav2.issue.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, 'delete', public_url, None, users)
|
||||
# assert results == [401, 403, 403, 403, 204]
|
||||
# results = helper_test_http_method(client, 'delete', private1_url, None, users)
|
||||
# assert results == [401, 403, 403, 403, 204]
|
||||
# results = helper_test_http_method(client, 'delete', private2_url, None, users)
|
||||
# assert results == [401, 403, 403, 403, 204]
|
||||
#
|
||||
#
|
||||
#def test_issue_custom_attributes_values_list(client, data):
|
||||
# url = reverse('issue-custom-attributes-values-list')
|
||||
#
|
||||
# response = client.json.get(url)
|
||||
# assert response.status_code == 404
|
||||
#
|
||||
# client.login(data.registered_user)
|
||||
# response = client.json.get(url)
|
||||
# assert response.status_code == 404
|
||||
#
|
||||
# client.login(data.project_member_without_perms)
|
||||
# response = client.json.get(url)
|
||||
# assert response.status_code == 404
|
||||
#
|
||||
# client.login(data.project_member_with_perms)
|
||||
# response = client.json.get(url)
|
||||
# assert response.status_code == 404
|
||||
#
|
||||
# client.login(data.project_owner)
|
||||
# response = client.json.get(url)
|
||||
# assert response.status_code == 404
|
||||
#
|
||||
#
|
||||
#def test_issue_custom_attributes_values_patch(client, data):
|
||||
# public_url = reverse('issue-custom-attributes-values-detail', args=[data.public_issue_cav.issue.id])
|
||||
# private1_url = reverse('issue-custom-attributes-values-detail', args=[data.private_issue_cav1.issue.id])
|
||||
# private2_url = reverse('issue-custom-attributes-values-detail', args=[data.private_issue_cav2.issue.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, 'patch', public_url,
|
||||
# '{{"values": {{"{}": "test-update"}}, "version": 1}}'.format(data.public_issue_ca.id), users)
|
||||
# assert results == [401, 403, 403, 403, 200]
|
||||
# results = helper_test_http_method(client, 'patch', private1_url,
|
||||
# '{{"values": {{"{}": "test-update"}}, "version": 1}}'.format(data.private_issue_ca1.id), users)
|
||||
# assert results == [401, 403, 403, 403, 200]
|
||||
# results = helper_test_http_method(client, 'patch', private2_url,
|
||||
# '{{"values": {{"{}": "test-update"}}, "version": 1}}'.format(data.private_issue_ca2.id), users)
|
||||
# assert results == [401, 403, 403, 403, 200]
|
|
@ -0,0 +1,287 @@
|
|||
# Copyright (C) 2015 Andrey Antukh <niwi@niwi.be>
|
||||
# Copyright (C) 2015 Jesús Espino <jespinog@gmail.com>
|
||||
# Copyright (C) 2015 David Barragán <bameda@dbarragan.com>
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from taiga.base.utils import json
|
||||
from taiga.projects.custom_attributes import serializers
|
||||
from taiga.permissions.permissions import MEMBERS_PERMISSIONS
|
||||
|
||||
from tests import factories as f
|
||||
from tests.utils import helper_test_http_method
|
||||
|
||||
import pytest
|
||||
pytestmark = pytest.mark.django_db(transaction=True)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
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.superuser = f.UserFactory.create(is_superuser=True)
|
||||
|
||||
m.public_project = f.ProjectFactory(is_private=False,
|
||||
anon_permissions=['view_project'],
|
||||
public_permissions=['view_project'],
|
||||
owner=m.project_owner)
|
||||
m.private_project1 = f.ProjectFactory(is_private=True,
|
||||
anon_permissions=['view_project'],
|
||||
public_permissions=['view_project'],
|
||||
owner=m.project_owner)
|
||||
m.private_project2 = f.ProjectFactory(is_private=True,
|
||||
anon_permissions=[],
|
||||
public_permissions=[],
|
||||
owner=m.project_owner)
|
||||
|
||||
m.public_membership = f.MembershipFactory(project=m.public_project,
|
||||
user=m.project_member_with_perms,
|
||||
email=m.project_member_with_perms.email,
|
||||
role__project=m.public_project,
|
||||
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
|
||||
m.private_membership1 = f.MembershipFactory(project=m.private_project1,
|
||||
user=m.project_member_with_perms,
|
||||
email=m.project_member_with_perms.email,
|
||||
role__project=m.private_project1,
|
||||
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
|
||||
|
||||
f.MembershipFactory(project=m.private_project1,
|
||||
user=m.project_member_without_perms,
|
||||
email=m.project_member_without_perms.email,
|
||||
role__project=m.private_project1,
|
||||
role__permissions=[])
|
||||
|
||||
m.private_membership2 = f.MembershipFactory(project=m.private_project2,
|
||||
user=m.project_member_with_perms,
|
||||
email=m.project_member_with_perms.email,
|
||||
role__project=m.private_project2,
|
||||
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
|
||||
f.MembershipFactory(project=m.private_project2,
|
||||
user=m.project_member_without_perms,
|
||||
email=m.project_member_without_perms.email,
|
||||
role__project=m.private_project2,
|
||||
role__permissions=[])
|
||||
|
||||
f.MembershipFactory(project=m.public_project,
|
||||
user=m.project_owner,
|
||||
is_owner=True)
|
||||
|
||||
f.MembershipFactory(project=m.private_project1,
|
||||
user=m.project_owner,
|
||||
is_owner=True)
|
||||
|
||||
f.MembershipFactory(project=m.private_project2,
|
||||
user=m.project_owner,
|
||||
is_owner=True)
|
||||
|
||||
m.public_task_ca = f.TaskCustomAttributeFactory(project=m.public_project)
|
||||
m.private_task_ca1 = f.TaskCustomAttributeFactory(project=m.private_project1)
|
||||
m.private_task_ca2 = f.TaskCustomAttributeFactory(project=m.private_project2)
|
||||
|
||||
return m
|
||||
|
||||
|
||||
#########################################################
|
||||
# Task Custom Attribute
|
||||
#########################################################
|
||||
|
||||
def test_task_custom_attribute_retrieve(client, data):
|
||||
public_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.public_task_ca.pk})
|
||||
private1_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.private_task_ca1.pk})
|
||||
private2_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.private_task_ca2.pk})
|
||||
|
||||
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 == [200, 200, 200, 200, 200]
|
||||
results = helper_test_http_method(client, 'get', private1_url, None, users)
|
||||
assert results == [200, 200, 200, 200, 200]
|
||||
results = helper_test_http_method(client, 'get', private2_url, None, users)
|
||||
assert results == [401, 403, 403, 200, 200]
|
||||
|
||||
|
||||
def test_task_custom_attribute_create(client, data):
|
||||
public_url = reverse('task-custom-attributes-list')
|
||||
private1_url = reverse('task-custom-attributes-list')
|
||||
private2_url = reverse('task-custom-attributes-list')
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
task_ca_data = {"name": "test-new", "project": data.public_project.id}
|
||||
task_ca_data = json.dumps(task_ca_data)
|
||||
results = helper_test_http_method(client, 'post', public_url, task_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 201]
|
||||
|
||||
task_ca_data = {"name": "test-new", "project": data.private_project1.id}
|
||||
task_ca_data = json.dumps(task_ca_data)
|
||||
results = helper_test_http_method(client, 'post', private1_url, task_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 201]
|
||||
|
||||
task_ca_data = {"name": "test-new", "project": data.private_project2.id}
|
||||
task_ca_data = json.dumps(task_ca_data)
|
||||
results = helper_test_http_method(client, 'post', private2_url, task_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 201]
|
||||
|
||||
|
||||
def test_task_custom_attribute_update(client, data):
|
||||
public_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.public_task_ca.pk})
|
||||
private1_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.private_task_ca1.pk})
|
||||
private2_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.private_task_ca2.pk})
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
task_ca_data = serializers.TaskCustomAttributeSerializer(data.public_task_ca).data
|
||||
task_ca_data["name"] = "test"
|
||||
task_ca_data = json.dumps(task_ca_data)
|
||||
results = helper_test_http_method(client, 'put', public_url, task_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
task_ca_data = serializers.TaskCustomAttributeSerializer(data.private_task_ca1).data
|
||||
task_ca_data["name"] = "test"
|
||||
task_ca_data = json.dumps(task_ca_data)
|
||||
results = helper_test_http_method(client, 'put', private1_url, task_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
task_ca_data = serializers.TaskCustomAttributeSerializer(data.private_task_ca2).data
|
||||
task_ca_data["name"] = "test"
|
||||
task_ca_data = json.dumps(task_ca_data)
|
||||
results = helper_test_http_method(client, 'put', private2_url, task_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
|
||||
def test_task_custom_attribute_delete(client, data):
|
||||
public_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.public_task_ca.pk})
|
||||
private1_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.private_task_ca1.pk})
|
||||
private2_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.private_task_ca2.pk})
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
results = helper_test_http_method(client, 'delete', public_url, None, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
results = helper_test_http_method(client, 'delete', private1_url, None, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
results = helper_test_http_method(client, 'delete', private2_url, None, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
|
||||
|
||||
def test_task_custom_attribute_list(client, data):
|
||||
url = reverse('task-custom-attributes-list')
|
||||
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 2
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.registered_user)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 2
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.project_member_without_perms)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 2
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.project_member_with_perms)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 3
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.project_owner)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 3
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
def test_task_custom_attribute_patch(client, data):
|
||||
public_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.public_task_ca.pk})
|
||||
private1_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.private_task_ca1.pk})
|
||||
private2_url = reverse('task-custom-attributes-detail', kwargs={"pk": data.private_task_ca2.pk})
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
results = helper_test_http_method(client, 'patch', public_url, '{"name": "Test"}', users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
results = helper_test_http_method(client, 'patch', private1_url, '{"name": "Test"}', users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
results = helper_test_http_method(client, 'patch', private2_url, '{"name": "Test"}', users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
|
||||
def test_task_custom_attribute_action_bulk_update_order(client, data):
|
||||
url = reverse('task-custom-attributes-bulk-update-order')
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
post_data = json.dumps({
|
||||
"bulk_task_custom_attributes": [(1,2)],
|
||||
"project": data.public_project.pk
|
||||
})
|
||||
results = helper_test_http_method(client, 'post', url, post_data, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
|
||||
post_data = json.dumps({
|
||||
"bulk_task_custom_attributes": [(1,2)],
|
||||
"project": data.private_project1.pk
|
||||
})
|
||||
results = helper_test_http_method(client, 'post', url, post_data, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
|
||||
post_data = json.dumps({
|
||||
"bulk_task_custom_attributes": [(1,2)],
|
||||
"project": data.private_project2.pk
|
||||
})
|
||||
results = helper_test_http_method(client, 'post', url, post_data, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
|
@ -0,0 +1,287 @@
|
|||
# Copyright (C) 2015 Andrey Antukh <niwi@niwi.be>
|
||||
# Copyright (C) 2015 Jesús Espino <jespinog@gmail.com>
|
||||
# Copyright (C) 2015 David Barragán <bameda@dbarragan.com>
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from taiga.base.utils import json
|
||||
from taiga.projects.custom_attributes import serializers
|
||||
from taiga.permissions.permissions import MEMBERS_PERMISSIONS
|
||||
|
||||
from tests import factories as f
|
||||
from tests.utils import helper_test_http_method
|
||||
|
||||
import pytest
|
||||
pytestmark = pytest.mark.django_db(transaction=True)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
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.superuser = f.UserFactory.create(is_superuser=True)
|
||||
|
||||
m.public_project = f.ProjectFactory(is_private=False,
|
||||
anon_permissions=['view_project'],
|
||||
public_permissions=['view_project'],
|
||||
owner=m.project_owner)
|
||||
m.private_project1 = f.ProjectFactory(is_private=True,
|
||||
anon_permissions=['view_project'],
|
||||
public_permissions=['view_project'],
|
||||
owner=m.project_owner)
|
||||
m.private_project2 = f.ProjectFactory(is_private=True,
|
||||
anon_permissions=[],
|
||||
public_permissions=[],
|
||||
owner=m.project_owner)
|
||||
|
||||
m.public_membership = f.MembershipFactory(project=m.public_project,
|
||||
user=m.project_member_with_perms,
|
||||
email=m.project_member_with_perms.email,
|
||||
role__project=m.public_project,
|
||||
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
|
||||
m.private_membership1 = f.MembershipFactory(project=m.private_project1,
|
||||
user=m.project_member_with_perms,
|
||||
email=m.project_member_with_perms.email,
|
||||
role__project=m.private_project1,
|
||||
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
|
||||
|
||||
f.MembershipFactory(project=m.private_project1,
|
||||
user=m.project_member_without_perms,
|
||||
email=m.project_member_without_perms.email,
|
||||
role__project=m.private_project1,
|
||||
role__permissions=[])
|
||||
|
||||
m.private_membership2 = f.MembershipFactory(project=m.private_project2,
|
||||
user=m.project_member_with_perms,
|
||||
email=m.project_member_with_perms.email,
|
||||
role__project=m.private_project2,
|
||||
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
|
||||
f.MembershipFactory(project=m.private_project2,
|
||||
user=m.project_member_without_perms,
|
||||
email=m.project_member_without_perms.email,
|
||||
role__project=m.private_project2,
|
||||
role__permissions=[])
|
||||
|
||||
f.MembershipFactory(project=m.public_project,
|
||||
user=m.project_owner,
|
||||
is_owner=True)
|
||||
|
||||
f.MembershipFactory(project=m.private_project1,
|
||||
user=m.project_owner,
|
||||
is_owner=True)
|
||||
|
||||
f.MembershipFactory(project=m.private_project2,
|
||||
user=m.project_owner,
|
||||
is_owner=True)
|
||||
|
||||
m.public_userstory_ca = f.UserStoryCustomAttributeFactory(project=m.public_project)
|
||||
m.private_userstory_ca1 = f.UserStoryCustomAttributeFactory(project=m.private_project1)
|
||||
m.private_userstory_ca2 = f.UserStoryCustomAttributeFactory(project=m.private_project2)
|
||||
|
||||
return m
|
||||
|
||||
|
||||
#########################################################
|
||||
# User Story Custom Attribute
|
||||
#########################################################
|
||||
|
||||
def test_userstory_custom_attribute_retrieve(client, data):
|
||||
public_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.public_userstory_ca.pk})
|
||||
private1_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.private_userstory_ca1.pk})
|
||||
private2_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.private_userstory_ca2.pk})
|
||||
|
||||
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 == [200, 200, 200, 200, 200]
|
||||
results = helper_test_http_method(client, 'get', private1_url, None, users)
|
||||
assert results == [200, 200, 200, 200, 200]
|
||||
results = helper_test_http_method(client, 'get', private2_url, None, users)
|
||||
assert results == [401, 403, 403, 200, 200]
|
||||
|
||||
|
||||
def test_userstory_custom_attribute_create(client, data):
|
||||
public_url = reverse('userstory-custom-attributes-list')
|
||||
private1_url = reverse('userstory-custom-attributes-list')
|
||||
private2_url = reverse('userstory-custom-attributes-list')
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
userstory_ca_data = {"name": "test-new", "project": data.public_project.id}
|
||||
userstory_ca_data = json.dumps(userstory_ca_data)
|
||||
results = helper_test_http_method(client, 'post', public_url, userstory_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 201]
|
||||
|
||||
userstory_ca_data = {"name": "test-new", "project": data.private_project1.id}
|
||||
userstory_ca_data = json.dumps(userstory_ca_data)
|
||||
results = helper_test_http_method(client, 'post', private1_url, userstory_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 201]
|
||||
|
||||
userstory_ca_data = {"name": "test-new", "project": data.private_project2.id}
|
||||
userstory_ca_data = json.dumps(userstory_ca_data)
|
||||
results = helper_test_http_method(client, 'post', private2_url, userstory_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 201]
|
||||
|
||||
|
||||
def test_userstory_custom_attribute_update(client, data):
|
||||
public_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.public_userstory_ca.pk})
|
||||
private1_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.private_userstory_ca1.pk})
|
||||
private2_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.private_userstory_ca2.pk})
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
userstory_ca_data = serializers.UserStoryCustomAttributeSerializer(data.public_userstory_ca).data
|
||||
userstory_ca_data["name"] = "test"
|
||||
userstory_ca_data = json.dumps(userstory_ca_data)
|
||||
results = helper_test_http_method(client, 'put', public_url, userstory_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
userstory_ca_data = serializers.UserStoryCustomAttributeSerializer(data.private_userstory_ca1).data
|
||||
userstory_ca_data["name"] = "test"
|
||||
userstory_ca_data = json.dumps(userstory_ca_data)
|
||||
results = helper_test_http_method(client, 'put', private1_url, userstory_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
userstory_ca_data = serializers.UserStoryCustomAttributeSerializer(data.private_userstory_ca2).data
|
||||
userstory_ca_data["name"] = "test"
|
||||
userstory_ca_data = json.dumps(userstory_ca_data)
|
||||
results = helper_test_http_method(client, 'put', private2_url, userstory_ca_data, users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
|
||||
def test_userstory_custom_attribute_delete(client, data):
|
||||
public_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.public_userstory_ca.pk})
|
||||
private1_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.private_userstory_ca1.pk})
|
||||
private2_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.private_userstory_ca2.pk})
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
results = helper_test_http_method(client, 'delete', public_url, None, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
results = helper_test_http_method(client, 'delete', private1_url, None, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
results = helper_test_http_method(client, 'delete', private2_url, None, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
|
||||
|
||||
def test_userstory_custom_attribute_list(client, data):
|
||||
url = reverse('userstory-custom-attributes-list')
|
||||
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 2
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.registered_user)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 2
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.project_member_without_perms)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 2
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.project_member_with_perms)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 3
|
||||
assert response.status_code == 200
|
||||
|
||||
client.login(data.project_owner)
|
||||
response = client.json.get(url)
|
||||
assert len(response.data) == 3
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
def test_userstory_custom_attribute_patch(client, data):
|
||||
public_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.public_userstory_ca.pk})
|
||||
private1_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.private_userstory_ca1.pk})
|
||||
private2_url = reverse('userstory-custom-attributes-detail', kwargs={"pk": data.private_userstory_ca2.pk})
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
results = helper_test_http_method(client, 'patch', public_url, '{"name": "Test"}', users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
results = helper_test_http_method(client, 'patch', private1_url, '{"name": "Test"}', users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
results = helper_test_http_method(client, 'patch', private2_url, '{"name": "Test"}', users)
|
||||
assert results == [401, 403, 403, 403, 200]
|
||||
|
||||
|
||||
def test_userstory_custom_attribute_action_bulk_update_order(client, data):
|
||||
url = reverse('userstory-custom-attributes-bulk-update-order')
|
||||
|
||||
users = [
|
||||
None,
|
||||
data.registered_user,
|
||||
data.project_member_without_perms,
|
||||
data.project_member_with_perms,
|
||||
data.project_owner
|
||||
]
|
||||
|
||||
post_data = json.dumps({
|
||||
"bulk_userstory_custom_attributes": [(1,2)],
|
||||
"project": data.public_project.pk
|
||||
})
|
||||
results = helper_test_http_method(client, 'post', url, post_data, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
|
||||
post_data = json.dumps({
|
||||
"bulk_userstory_custom_attributes": [(1,2)],
|
||||
"project": data.private_project1.pk
|
||||
})
|
||||
results = helper_test_http_method(client, 'post', url, post_data, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
||||
|
||||
post_data = json.dumps({
|
||||
"bulk_userstory_custom_attributes": [(1,2)],
|
||||
"project": data.private_project2.pk
|
||||
})
|
||||
results = helper_test_http_method(client, 'post', url, post_data, users)
|
||||
assert results == [401, 403, 403, 403, 204]
|
|
@ -1,189 +0,0 @@
|
|||
# Copyright (C) 2015 Andrey Antukh <niwi@niwi.be>
|
||||
# Copyright (C) 2015 Jesús Espino <jespinog@gmail.com>
|
||||
# Copyright (C) 2015 David Barragán <bameda@dbarragan.com>
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from taiga.base.utils import json
|
||||
|
||||
from .. import factories as f
|
||||
|
||||
import pytest
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
#########################################################
|
||||
# User Story Custom Fields
|
||||
#########################################################
|
||||
|
||||
def test_userstory_custom_attribute_duplicate_name_error_on_create(client):
|
||||
custom_attr_1 = f.UserStoryCustomAttributeFactory()
|
||||
member = f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_1.project,
|
||||
is_owner=True)
|
||||
|
||||
|
||||
url = reverse("userstory-custom-attributes-list")
|
||||
data = {"name": custom_attr_1.name,
|
||||
"project": custom_attr_1.project.pk}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.post(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_userstory_custom_attribute_duplicate_name_error_on_update(client):
|
||||
custom_attr_1 = f.UserStoryCustomAttributeFactory()
|
||||
custom_attr_2 = f.UserStoryCustomAttributeFactory(project=custom_attr_1.project)
|
||||
member = f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_1.project,
|
||||
is_owner=True)
|
||||
|
||||
|
||||
url = reverse("userstory-custom-attributes-detail", kwargs={"pk": custom_attr_2.pk})
|
||||
data = {"name": custom_attr_1.name}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.patch(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_userstory_custom_attribute_duplicate_name_error_on_move_between_projects(client):
|
||||
custom_attr_1 = f.UserStoryCustomAttributeFactory()
|
||||
custom_attr_2 = f.UserStoryCustomAttributeFactory(name=custom_attr_1.name)
|
||||
member = f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_1.project,
|
||||
is_owner=True)
|
||||
f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_2.project,
|
||||
is_owner=True)
|
||||
|
||||
|
||||
url = reverse("userstory-custom-attributes-detail", kwargs={"pk": custom_attr_2.pk})
|
||||
data = {"project": custom_attr_1.project.pk}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.patch(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
#########################################################
|
||||
# Task Custom Fields
|
||||
#########################################################
|
||||
|
||||
def test_task_custom_attribute_duplicate_name_error_on_create(client):
|
||||
custom_attr_1 = f.TaskCustomAttributeFactory()
|
||||
member = f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_1.project,
|
||||
is_owner=True)
|
||||
|
||||
|
||||
url = reverse("task-custom-attributes-list")
|
||||
data = {"name": custom_attr_1.name,
|
||||
"project": custom_attr_1.project.pk}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.post(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_task_custom_attribute_duplicate_name_error_on_update(client):
|
||||
custom_attr_1 = f.TaskCustomAttributeFactory()
|
||||
custom_attr_2 = f.TaskCustomAttributeFactory(project=custom_attr_1.project)
|
||||
member = f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_1.project,
|
||||
is_owner=True)
|
||||
|
||||
|
||||
url = reverse("task-custom-attributes-detail", kwargs={"pk": custom_attr_2.pk})
|
||||
data = {"name": custom_attr_1.name}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.patch(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_task_custom_attribute_duplicate_name_error_on_move_between_projects(client):
|
||||
custom_attr_1 = f.TaskCustomAttributeFactory()
|
||||
custom_attr_2 = f.TaskCustomAttributeFactory(name=custom_attr_1.name)
|
||||
member = f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_1.project,
|
||||
is_owner=True)
|
||||
f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_2.project,
|
||||
is_owner=True)
|
||||
|
||||
|
||||
url = reverse("task-custom-attributes-detail", kwargs={"pk": custom_attr_2.pk})
|
||||
data = {"project": custom_attr_1.project.pk}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.patch(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
#########################################################
|
||||
# Issue Custom Fields
|
||||
#########################################################
|
||||
|
||||
def test_issue_custom_attribute_duplicate_name_error_on_create(client):
|
||||
custom_attr_1 = f.IssueCustomAttributeFactory()
|
||||
member = f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_1.project,
|
||||
is_owner=True)
|
||||
|
||||
|
||||
url = reverse("issue-custom-attributes-list")
|
||||
data = {"name": custom_attr_1.name,
|
||||
"project": custom_attr_1.project.pk}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.post(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_issue_custom_attribute_duplicate_name_error_on_update(client):
|
||||
custom_attr_1 = f.IssueCustomAttributeFactory()
|
||||
custom_attr_2 = f.IssueCustomAttributeFactory(project=custom_attr_1.project)
|
||||
member = f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_1.project,
|
||||
is_owner=True)
|
||||
|
||||
|
||||
url = reverse("issue-custom-attributes-detail", kwargs={"pk": custom_attr_2.pk})
|
||||
data = {"name": custom_attr_1.name}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.patch(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_issue_custom_attribute_duplicate_name_error_on_move_between_projects(client):
|
||||
custom_attr_1 = f.IssueCustomAttributeFactory()
|
||||
custom_attr_2 = f.IssueCustomAttributeFactory(name=custom_attr_1.name)
|
||||
member = f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_1.project,
|
||||
is_owner=True)
|
||||
f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_2.project,
|
||||
is_owner=True)
|
||||
|
||||
|
||||
url = reverse("issue-custom-attributes-detail", kwargs={"pk": custom_attr_2.pk})
|
||||
data = {"project": custom_attr_1.project.pk}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.patch(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
|
@ -0,0 +1,271 @@
|
|||
# Copyright (C) 2015 Andrey Antukh <niwi@niwi.be>
|
||||
# Copyright (C) 2015 Jesús Espino <jespinog@gmail.com>
|
||||
# Copyright (C) 2015 David Barragán <bameda@dbarragan.com>
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from taiga.base.utils import json
|
||||
|
||||
from .. import factories as f
|
||||
|
||||
import pytest
|
||||
pytestmark = pytest.mark.django_db(transaction=True)
|
||||
|
||||
|
||||
#########################################################
|
||||
# Issue Custom Attributes
|
||||
#########################################################
|
||||
|
||||
def test_issue_custom_attribute_duplicate_name_error_on_create(client):
|
||||
custom_attr_1 = f.IssueCustomAttributeFactory()
|
||||
member = f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_1.project,
|
||||
is_owner=True)
|
||||
|
||||
|
||||
url = reverse("issue-custom-attributes-list")
|
||||
data = {"name": custom_attr_1.name,
|
||||
"project": custom_attr_1.project.pk}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.post(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_issue_custom_attribute_duplicate_name_error_on_update(client):
|
||||
custom_attr_1 = f.IssueCustomAttributeFactory()
|
||||
custom_attr_2 = f.IssueCustomAttributeFactory(project=custom_attr_1.project)
|
||||
member = f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_1.project,
|
||||
is_owner=True)
|
||||
|
||||
|
||||
url = reverse("issue-custom-attributes-detail", kwargs={"pk": custom_attr_2.pk})
|
||||
data = {"name": custom_attr_1.name}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.patch(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_issue_custom_attribute_duplicate_name_error_on_move_between_projects(client):
|
||||
custom_attr_1 = f.IssueCustomAttributeFactory()
|
||||
custom_attr_2 = f.IssueCustomAttributeFactory(name=custom_attr_1.name)
|
||||
member = f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_1.project,
|
||||
is_owner=True)
|
||||
f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_2.project,
|
||||
is_owner=True)
|
||||
|
||||
|
||||
url = reverse("issue-custom-attributes-detail", kwargs={"pk": custom_attr_2.pk})
|
||||
data = {"project": custom_attr_1.project.pk}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.patch(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
#########################################################
|
||||
# Issue Custom Attributes Values
|
||||
#########################################################
|
||||
|
||||
def test_issue_custom_attributes_values_list(client):
|
||||
member = f.MembershipFactory(is_owner=True)
|
||||
|
||||
url = reverse("issue-custom-attributes-values-list")
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.get(url)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_issue_custom_attributes_values_create(client):
|
||||
issue = f.IssueFactory()
|
||||
member = f.MembershipFactory(user=issue.project.owner,
|
||||
project=issue.project,
|
||||
is_owner=True)
|
||||
|
||||
custom_attr_1 = f.IssueCustomAttributeFactory(project=issue.project)
|
||||
ct1_id = "{}".format(custom_attr_1.id)
|
||||
custom_attr_2 = f.IssueCustomAttributeFactory(project=issue.project)
|
||||
ct2_id = "{}".format(custom_attr_2.id)
|
||||
|
||||
url = reverse("issue-custom-attributes-values-list")
|
||||
data = {
|
||||
"issue": issue.id,
|
||||
"values": {
|
||||
ct1_id: "test_1",
|
||||
ct2_id: "test_2"
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.post(url, json.dumps(data))
|
||||
assert response.status_code == 201
|
||||
assert json.loads(response.data["values"]) == data["values"]
|
||||
issue = issue.__class__.objects.get(id=issue.id)
|
||||
assert issue.custom_attributes_values.values == data["values"]
|
||||
|
||||
|
||||
def test_issue_custom_attributes_values_create_with_error_invalid_key(client):
|
||||
issue = f.IssueFactory()
|
||||
member = f.MembershipFactory(user=issue.project.owner,
|
||||
project=issue.project,
|
||||
is_owner=True)
|
||||
|
||||
custom_attr_1 = f.IssueCustomAttributeFactory(project=issue.project)
|
||||
ct1_id = "{}".format(custom_attr_1.id)
|
||||
custom_attr_2 = f.IssueCustomAttributeFactory(project=issue.project)
|
||||
|
||||
url = reverse("issue-custom-attributes-values-list")
|
||||
data = {
|
||||
"issue": issue.id,
|
||||
"values": {
|
||||
ct1_id: "test_1",
|
||||
"123456": "test_2"
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.post(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_issue_custom_attributes_values_update(client):
|
||||
issue = f.IssueFactory()
|
||||
member = f.MembershipFactory(user=issue.project.owner,
|
||||
project=issue.project,
|
||||
is_owner=True)
|
||||
|
||||
custom_attr_1 = f.IssueCustomAttributeFactory(project=issue.project)
|
||||
ct1_id = "{}".format(custom_attr_1.id)
|
||||
custom_attr_2 = f.IssueCustomAttributeFactory(project=issue.project)
|
||||
ct2_id = "{}".format(custom_attr_2.id)
|
||||
|
||||
custom_attrs_val = f.IssueCustomAttributesValuesFactory(
|
||||
issue=issue,
|
||||
values= {
|
||||
ct1_id: "test_1",
|
||||
ct2_id: "test_2"
|
||||
},
|
||||
)
|
||||
|
||||
url = reverse("issue-custom-attributes-values-detail", args=[issue.id])
|
||||
data = {
|
||||
"values": {
|
||||
ct1_id: "test_1_updated",
|
||||
ct2_id: "test_2_updated"
|
||||
},
|
||||
"version": custom_attrs_val.version
|
||||
}
|
||||
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.patch(url, json.dumps(data))
|
||||
assert response.status_code == 200
|
||||
assert json.loads(response.data["values"]) == data["values"]
|
||||
issue = issue.__class__.objects.get(id=issue.id)
|
||||
assert issue.custom_attributes_values.values == data["values"]
|
||||
|
||||
|
||||
def test_issue_custom_attributes_values_update_with_error_invalid_key(client):
|
||||
issue = f.IssueFactory()
|
||||
member = f.MembershipFactory(user=issue.project.owner,
|
||||
project=issue.project,
|
||||
is_owner=True)
|
||||
|
||||
custom_attr_1 = f.IssueCustomAttributeFactory(project=issue.project)
|
||||
ct1_id = "{}".format(custom_attr_1.id)
|
||||
custom_attr_2 = f.IssueCustomAttributeFactory(project=issue.project)
|
||||
ct2_id = "{}".format(custom_attr_2.id)
|
||||
|
||||
custom_attrs_val = f.IssueCustomAttributesValuesFactory(
|
||||
issue=issue,
|
||||
values= {
|
||||
ct1_id: "test_1",
|
||||
ct2_id: "test_2"
|
||||
},
|
||||
)
|
||||
|
||||
url = reverse("issue-custom-attributes-values-detail", args=[issue.id])
|
||||
data = {
|
||||
"values": {
|
||||
ct1_id: "test_1_updated",
|
||||
"123456": "test_2_updated"
|
||||
},
|
||||
"version": custom_attrs_val.version
|
||||
}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.patch(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_issue_custom_attributes_values_delete(client):
|
||||
issue = f.IssueFactory()
|
||||
member = f.MembershipFactory(user=issue.project.owner,
|
||||
project=issue.project,
|
||||
is_owner=True)
|
||||
|
||||
custom_attr_1 = f.IssueCustomAttributeFactory(project=issue.project)
|
||||
ct1_id = "{}".format(custom_attr_1.id)
|
||||
custom_attr_2 = f.IssueCustomAttributeFactory(project=issue.project)
|
||||
ct2_id = "{}".format(custom_attr_2.id)
|
||||
|
||||
url = reverse("issue-custom-attributes-values-detail", args=[issue.id])
|
||||
custom_attrs_val = f.IssueCustomAttributesValuesFactory(
|
||||
issue=issue,
|
||||
values= {
|
||||
ct1_id: "test_1",
|
||||
ct2_id: "test_2"
|
||||
},
|
||||
)
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.delete(url)
|
||||
assert response.status_code == 204
|
||||
assert issue.__class__.objects.filter(id=issue.id).exists()
|
||||
assert not custom_attrs_val.__class__.objects.filter(id=custom_attrs_val.id).exists()
|
||||
|
||||
|
||||
def test_issue_custom_attributes_values_delete_us(client):
|
||||
issue = f.IssueFactory()
|
||||
member = f.MembershipFactory(user=issue.project.owner,
|
||||
project=issue.project,
|
||||
is_owner=True)
|
||||
|
||||
custom_attr_1 = f.IssueCustomAttributeFactory(project=issue.project)
|
||||
ct1_id = "{}".format(custom_attr_1.id)
|
||||
custom_attr_2 = f.IssueCustomAttributeFactory(project=issue.project)
|
||||
ct2_id = "{}".format(custom_attr_2.id)
|
||||
|
||||
url = reverse("issues-detail", args=[issue.id])
|
||||
custom_attrs_val = f.IssueCustomAttributesValuesFactory(
|
||||
issue=issue,
|
||||
values= {
|
||||
ct1_id: "test_1",
|
||||
ct2_id: "test_2"
|
||||
},
|
||||
)
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.delete(url)
|
||||
assert response.status_code == 204
|
||||
assert not issue.__class__.objects.filter(id=issue.id).exists()
|
||||
assert not custom_attrs_val.__class__.objects.filter(id=custom_attrs_val.id).exists()
|
|
@ -0,0 +1,268 @@
|
|||
# Copyright (C) 2015 Andrey Antukh <niwi@niwi.be>
|
||||
# Copyright (C) 2015 Jesús Espino <jespinog@gmail.com>
|
||||
# Copyright (C) 2015 David Barragán <bameda@dbarragan.com>
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from taiga.base.utils import json
|
||||
|
||||
from .. import factories as f
|
||||
|
||||
import pytest
|
||||
pytestmark = pytest.mark.django_db(transaction=True)
|
||||
|
||||
|
||||
#########################################################
|
||||
# Task Custom Attributes
|
||||
#########################################################
|
||||
|
||||
def test_task_custom_attribute_duplicate_name_error_on_create(client):
|
||||
custom_attr_1 = f.TaskCustomAttributeFactory()
|
||||
member = f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_1.project,
|
||||
is_owner=True)
|
||||
|
||||
|
||||
url = reverse("task-custom-attributes-list")
|
||||
data = {"name": custom_attr_1.name,
|
||||
"project": custom_attr_1.project.pk}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.post(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_task_custom_attribute_duplicate_name_error_on_update(client):
|
||||
custom_attr_1 = f.TaskCustomAttributeFactory()
|
||||
custom_attr_2 = f.TaskCustomAttributeFactory(project=custom_attr_1.project)
|
||||
member = f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_1.project,
|
||||
is_owner=True)
|
||||
|
||||
|
||||
url = reverse("task-custom-attributes-detail", kwargs={"pk": custom_attr_2.pk})
|
||||
data = {"name": custom_attr_1.name}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.patch(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_task_custom_attribute_duplicate_name_error_on_move_between_projects(client):
|
||||
custom_attr_1 = f.TaskCustomAttributeFactory()
|
||||
custom_attr_2 = f.TaskCustomAttributeFactory(name=custom_attr_1.name)
|
||||
member = f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_1.project,
|
||||
is_owner=True)
|
||||
f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_2.project,
|
||||
is_owner=True)
|
||||
|
||||
|
||||
url = reverse("task-custom-attributes-detail", kwargs={"pk": custom_attr_2.pk})
|
||||
data = {"project": custom_attr_1.project.pk}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.patch(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
#########################################################
|
||||
# Task Custom Attributes Values
|
||||
#########################################################
|
||||
|
||||
def test_task_custom_attributes_values_list(client):
|
||||
member = f.MembershipFactory(is_owner=True)
|
||||
|
||||
url = reverse("task-custom-attributes-values-list")
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.get(url)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_task_custom_attributes_values_create(client):
|
||||
task = f.TaskFactory()
|
||||
member = f.MembershipFactory(user=task.project.owner,
|
||||
project=task.project,
|
||||
is_owner=True)
|
||||
|
||||
custom_attr_1 = f.TaskCustomAttributeFactory(project=task.project)
|
||||
ct1_id = "{}".format(custom_attr_1.id)
|
||||
custom_attr_2 = f.TaskCustomAttributeFactory(project=task.project)
|
||||
ct2_id = "{}".format(custom_attr_2.id)
|
||||
|
||||
url = reverse("task-custom-attributes-values-list")
|
||||
data = {
|
||||
"task": task.id,
|
||||
"values": {
|
||||
ct1_id: "test_1",
|
||||
ct2_id: "test_2"
|
||||
},
|
||||
}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.post(url, json.dumps(data))
|
||||
assert response.status_code == 201
|
||||
assert json.loads(response.data["values"]) == data["values"]
|
||||
task = task.__class__.objects.get(id=task.id)
|
||||
assert task.custom_attributes_values.values == data["values"]
|
||||
|
||||
|
||||
def test_task_custom_attributes_values_create_with_error_invalid_key(client):
|
||||
task = f.TaskFactory()
|
||||
member = f.MembershipFactory(user=task.project.owner,
|
||||
project=task.project,
|
||||
is_owner=True)
|
||||
|
||||
custom_attr_1 = f.TaskCustomAttributeFactory(project=task.project)
|
||||
ct1_id = "{}".format(custom_attr_1.id)
|
||||
custom_attr_2 = f.TaskCustomAttributeFactory(project=task.project)
|
||||
|
||||
url = reverse("task-custom-attributes-values-list")
|
||||
data = {
|
||||
"task": task.id,
|
||||
"values": {
|
||||
ct1_id: "test_1",
|
||||
"123456": "test_2"
|
||||
},
|
||||
}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.post(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_task_custom_attributes_values_update(client):
|
||||
task = f.TaskFactory()
|
||||
member = f.MembershipFactory(user=task.project.owner,
|
||||
project=task.project,
|
||||
is_owner=True)
|
||||
|
||||
custom_attr_1 = f.TaskCustomAttributeFactory(project=task.project)
|
||||
ct1_id = "{}".format(custom_attr_1.id)
|
||||
custom_attr_2 = f.TaskCustomAttributeFactory(project=task.project)
|
||||
ct2_id = "{}".format(custom_attr_2.id)
|
||||
|
||||
custom_attrs_val = f.TaskCustomAttributesValuesFactory(
|
||||
task=task,
|
||||
values= {
|
||||
ct1_id: "test_1",
|
||||
ct2_id: "test_2"
|
||||
},
|
||||
)
|
||||
|
||||
url = reverse("task-custom-attributes-values-detail", args=[task.id])
|
||||
data = {
|
||||
"values": {
|
||||
ct1_id: "test_1_updated",
|
||||
ct2_id: "test_2_updated"
|
||||
},
|
||||
"version": custom_attrs_val.version
|
||||
}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.patch(url, json.dumps(data))
|
||||
assert response.status_code == 200
|
||||
assert json.loads(response.data["values"]) == data["values"]
|
||||
task = task.__class__.objects.get(id=task.id)
|
||||
assert task.custom_attributes_values.values == data["values"]
|
||||
|
||||
|
||||
def test_task_custom_attributes_values_update_with_error_invalid_key(client):
|
||||
task = f.TaskFactory()
|
||||
member = f.MembershipFactory(user=task.project.owner,
|
||||
project=task.project,
|
||||
is_owner=True)
|
||||
|
||||
custom_attr_1 = f.TaskCustomAttributeFactory(project=task.project)
|
||||
ct1_id = "{}".format(custom_attr_1.id)
|
||||
custom_attr_2 = f.TaskCustomAttributeFactory(project=task.project)
|
||||
ct2_id = "{}".format(custom_attr_2.id)
|
||||
|
||||
custom_attrs_val = f.TaskCustomAttributesValuesFactory(
|
||||
task=task,
|
||||
values= {
|
||||
ct1_id: "test_1",
|
||||
ct2_id: "test_2"
|
||||
},
|
||||
)
|
||||
url = reverse("task-custom-attributes-values-detail", args=[task.id])
|
||||
data = {
|
||||
"values": {
|
||||
ct1_id: "test_1_updated",
|
||||
"123456": "test_2_updated"
|
||||
},
|
||||
"version": custom_attrs_val.version
|
||||
}
|
||||
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.patch(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_task_custom_attributes_values_delete(client):
|
||||
task = f.TaskFactory()
|
||||
member = f.MembershipFactory(user=task.project.owner,
|
||||
project=task.project,
|
||||
is_owner=True)
|
||||
|
||||
custom_attr_1 = f.TaskCustomAttributeFactory(project=task.project)
|
||||
ct1_id = "{}".format(custom_attr_1.id)
|
||||
custom_attr_2 = f.TaskCustomAttributeFactory(project=task.project)
|
||||
ct2_id = "{}".format(custom_attr_2.id)
|
||||
|
||||
url = reverse("task-custom-attributes-values-detail", args=[task.id])
|
||||
custom_attrs_val = f.TaskCustomAttributesValuesFactory(
|
||||
task=task,
|
||||
values= {
|
||||
ct1_id: "test_1",
|
||||
ct2_id: "test_2"
|
||||
},
|
||||
)
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.delete(url)
|
||||
assert response.status_code == 204
|
||||
assert task.__class__.objects.filter(id=task.id).exists()
|
||||
assert not custom_attrs_val.__class__.objects.filter(id=custom_attrs_val.id).exists()
|
||||
|
||||
|
||||
def test_task_custom_attributes_values_delete_us(client):
|
||||
task = f.TaskFactory()
|
||||
member = f.MembershipFactory(user=task.project.owner,
|
||||
project=task.project,
|
||||
is_owner=True)
|
||||
|
||||
custom_attr_1 = f.TaskCustomAttributeFactory(project=task.project)
|
||||
ct1_id = "{}".format(custom_attr_1.id)
|
||||
custom_attr_2 = f.TaskCustomAttributeFactory(project=task.project)
|
||||
ct2_id = "{}".format(custom_attr_2.id)
|
||||
|
||||
url = reverse("tasks-detail", args=[task.id])
|
||||
custom_attrs_val = f.TaskCustomAttributesValuesFactory(
|
||||
task=task,
|
||||
values= {
|
||||
ct1_id: "test_1",
|
||||
ct2_id: "test_2"
|
||||
},
|
||||
)
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.delete(url)
|
||||
assert response.status_code == 204
|
||||
assert not task.__class__.objects.filter(id=task.id).exists()
|
||||
assert not custom_attrs_val.__class__.objects.filter(id=custom_attrs_val.id).exists()
|
|
@ -0,0 +1,268 @@
|
|||
# Copyright (C) 2015 Andrey Antukh <niwi@niwi.be>
|
||||
# Copyright (C) 2015 Jesús Espino <jespinog@gmail.com>
|
||||
# Copyright (C) 2015 David Barragán <bameda@dbarragan.com>
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from taiga.base.utils import json
|
||||
|
||||
from .. import factories as f
|
||||
|
||||
import pytest
|
||||
pytestmark = pytest.mark.django_db(transaction=True)
|
||||
|
||||
|
||||
#########################################################
|
||||
# User Story Custom Attributes
|
||||
#########################################################
|
||||
|
||||
def test_userstory_custom_attribute_duplicate_name_error_on_create(client):
|
||||
custom_attr_1 = f.UserStoryCustomAttributeFactory()
|
||||
member = f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_1.project,
|
||||
is_owner=True)
|
||||
|
||||
|
||||
url = reverse("userstory-custom-attributes-list")
|
||||
data = {"name": custom_attr_1.name,
|
||||
"project": custom_attr_1.project.pk}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.post(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_userstory_custom_attribute_duplicate_name_error_on_update(client):
|
||||
custom_attr_1 = f.UserStoryCustomAttributeFactory()
|
||||
custom_attr_2 = f.UserStoryCustomAttributeFactory(project=custom_attr_1.project)
|
||||
member = f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_1.project,
|
||||
is_owner=True)
|
||||
|
||||
|
||||
url = reverse("userstory-custom-attributes-detail", kwargs={"pk": custom_attr_2.pk})
|
||||
data = {"name": custom_attr_1.name}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.patch(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_userstory_custom_attribute_duplicate_name_error_on_move_between_projects(client):
|
||||
custom_attr_1 = f.UserStoryCustomAttributeFactory()
|
||||
custom_attr_2 = f.UserStoryCustomAttributeFactory(name=custom_attr_1.name)
|
||||
member = f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_1.project,
|
||||
is_owner=True)
|
||||
f.MembershipFactory(user=custom_attr_1.project.owner,
|
||||
project=custom_attr_2.project,
|
||||
is_owner=True)
|
||||
|
||||
|
||||
url = reverse("userstory-custom-attributes-detail", kwargs={"pk": custom_attr_2.pk})
|
||||
data = {"project": custom_attr_1.project.pk}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.patch(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
#########################################################
|
||||
# User Story Custom Attributes Values
|
||||
#########################################################
|
||||
|
||||
def test_userstory_custom_attributes_values_list(client):
|
||||
member = f.MembershipFactory(is_owner=True)
|
||||
|
||||
url = reverse("userstory-custom-attributes-values-list")
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.get(url)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_userstory_custom_attributes_values_create(client):
|
||||
user_story = f.UserStoryFactory()
|
||||
member = f.MembershipFactory(user=user_story.project.owner,
|
||||
project=user_story.project,
|
||||
is_owner=True)
|
||||
|
||||
custom_attr_1 = f.UserStoryCustomAttributeFactory(project=user_story.project)
|
||||
ct1_id = "{}".format(custom_attr_1.id)
|
||||
custom_attr_2 = f.UserStoryCustomAttributeFactory(project=user_story.project)
|
||||
ct2_id = "{}".format(custom_attr_2.id)
|
||||
|
||||
url = reverse("userstory-custom-attributes-values-list")
|
||||
data = {
|
||||
"user_story": user_story.id,
|
||||
"values": {
|
||||
ct1_id: "test_1",
|
||||
ct2_id: "test_2"
|
||||
},
|
||||
}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.post(url, json.dumps(data))
|
||||
assert response.status_code == 201
|
||||
assert json.loads(response.data["values"]) == data["values"]
|
||||
user_story = user_story.__class__.objects.get(id=user_story.id)
|
||||
assert user_story.custom_attributes_values.values == data["values"]
|
||||
|
||||
|
||||
def test_userstory_custom_attributes_values_create_with_error_invalid_key(client):
|
||||
user_story = f.UserStoryFactory()
|
||||
member = f.MembershipFactory(user=user_story.project.owner,
|
||||
project=user_story.project,
|
||||
is_owner=True)
|
||||
|
||||
custom_attr_1 = f.UserStoryCustomAttributeFactory(project=user_story.project)
|
||||
ct1_id = "{}".format(custom_attr_1.id)
|
||||
custom_attr_2 = f.UserStoryCustomAttributeFactory(project=user_story.project)
|
||||
|
||||
url = reverse("userstory-custom-attributes-values-list")
|
||||
data = {
|
||||
"user_story": user_story.id,
|
||||
"values": {
|
||||
ct1_id: "test_1",
|
||||
"123456": "test_2"
|
||||
},
|
||||
}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.post(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_userstory_custom_attributes_values_update(client):
|
||||
user_story = f.UserStoryFactory()
|
||||
member = f.MembershipFactory(user=user_story.project.owner,
|
||||
project=user_story.project,
|
||||
is_owner=True)
|
||||
|
||||
custom_attr_1 = f.UserStoryCustomAttributeFactory(project=user_story.project)
|
||||
ct1_id = "{}".format(custom_attr_1.id)
|
||||
custom_attr_2 = f.UserStoryCustomAttributeFactory(project=user_story.project)
|
||||
ct2_id = "{}".format(custom_attr_2.id)
|
||||
|
||||
custom_attrs_val = f.UserStoryCustomAttributesValuesFactory(
|
||||
user_story=user_story,
|
||||
values= {
|
||||
ct1_id: "test_1",
|
||||
ct2_id: "test_2"
|
||||
},
|
||||
)
|
||||
|
||||
url = reverse("userstory-custom-attributes-values-detail", args=[user_story.id])
|
||||
data = {
|
||||
"values": {
|
||||
ct1_id: "test_1_updated",
|
||||
ct2_id: "test_2_updated"
|
||||
},
|
||||
"version": custom_attrs_val.version
|
||||
}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.patch(url, json.dumps(data))
|
||||
assert response.status_code == 200
|
||||
assert json.loads(response.data["values"]) == data["values"]
|
||||
user_story = user_story.__class__.objects.get(id=user_story.id)
|
||||
assert user_story.custom_attributes_values.values == data["values"]
|
||||
|
||||
|
||||
def test_userstory_custom_attributes_values_update_with_error_invalid_key(client):
|
||||
user_story = f.UserStoryFactory()
|
||||
member = f.MembershipFactory(user=user_story.project.owner,
|
||||
project=user_story.project,
|
||||
is_owner=True)
|
||||
|
||||
custom_attr_1 = f.UserStoryCustomAttributeFactory(project=user_story.project)
|
||||
ct1_id = "{}".format(custom_attr_1.id)
|
||||
custom_attr_2 = f.UserStoryCustomAttributeFactory(project=user_story.project)
|
||||
ct2_id = "{}".format(custom_attr_2.id)
|
||||
|
||||
custom_attrs_val = f.UserStoryCustomAttributesValuesFactory(
|
||||
user_story=user_story,
|
||||
values= {
|
||||
ct1_id: "test_1",
|
||||
ct2_id: "test_2"
|
||||
},
|
||||
)
|
||||
|
||||
url = reverse("userstory-custom-attributes-values-detail", args=[user_story.id])
|
||||
data = {
|
||||
"values": {
|
||||
ct1_id: "test_1_updated",
|
||||
"123456": "test_2_updated"
|
||||
},
|
||||
"version": custom_attrs_val.version
|
||||
}
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.patch(url, json.dumps(data))
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_userstory_custom_attributes_values_delete(client):
|
||||
user_story = f.UserStoryFactory()
|
||||
member = f.MembershipFactory(user=user_story.project.owner,
|
||||
project=user_story.project,
|
||||
is_owner=True)
|
||||
|
||||
custom_attr_1 = f.UserStoryCustomAttributeFactory(project=user_story.project)
|
||||
ct1_id = "{}".format(custom_attr_1.id)
|
||||
custom_attr_2 = f.UserStoryCustomAttributeFactory(project=user_story.project)
|
||||
ct2_id = "{}".format(custom_attr_2.id)
|
||||
|
||||
url = reverse("userstory-custom-attributes-values-detail", args=[user_story.id])
|
||||
custom_attrs_val = f.UserStoryCustomAttributesValuesFactory(
|
||||
user_story=user_story,
|
||||
values= {
|
||||
ct1_id: "test_1",
|
||||
ct2_id: "test_2"
|
||||
},
|
||||
)
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.delete(url)
|
||||
assert response.status_code == 204
|
||||
assert user_story.__class__.objects.filter(id=user_story.id).exists()
|
||||
assert not custom_attrs_val.__class__.objects.filter(id=custom_attrs_val.id).exists()
|
||||
|
||||
|
||||
def test_userstory_custom_attributes_values_delete_us(client):
|
||||
user_story = f.UserStoryFactory()
|
||||
member = f.MembershipFactory(user=user_story.project.owner,
|
||||
project=user_story.project,
|
||||
is_owner=True)
|
||||
|
||||
custom_attr_1 = f.UserStoryCustomAttributeFactory(project=user_story.project)
|
||||
ct1_id = "{}".format(custom_attr_1.id)
|
||||
custom_attr_2 = f.UserStoryCustomAttributeFactory(project=user_story.project)
|
||||
ct2_id = "{}".format(custom_attr_2.id)
|
||||
|
||||
url = reverse("userstories-detail", args=[user_story.id])
|
||||
custom_attrs_val = f.UserStoryCustomAttributesValuesFactory(
|
||||
user_story=user_story,
|
||||
values= {
|
||||
ct1_id: "test_1",
|
||||
ct2_id: "test_2"
|
||||
},
|
||||
)
|
||||
|
||||
client.login(member.user)
|
||||
response = client.json.delete(url)
|
||||
assert response.status_code == 204
|
||||
assert not user_story.__class__.objects.filter(id=user_story.id).exists()
|
||||
assert not custom_attrs_val.__class__.objects.filter(id=custom_attrs_val.id).exists()
|
Loading…
Reference in New Issue