diff --git a/requirements.txt b/requirements.txt index 181e863f..93d225f0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ six==1.10.0 amqp==1.4.9 djmail==0.12.0.post1 django-pgjson==0.3.1 -djorm-pgarray==1.2 +djorm-pgarray==1.2 # Use until Taiga 2.1. Keep compatibility with old migrations django-jinja==2.1.2 jinja2==2.8 pygments==2.0.2 @@ -28,7 +28,7 @@ raven==5.10.2 bleach==1.4.2 django-ipware==1.1.3 premailer==2.9.7 -cssutils==1.0.1 # Compatible with python 3.5 +cssutils==1.0.1 # Compatible with python 3.5 lxml==3.5.0 git+https://github.com/Xof/django-pglocks.git@dbb8d7375066859f897604132bd437832d2014ea pyjwkest==1.1.5 diff --git a/taiga/base/fields.py b/taiga/base/fields.py index 8e95801d..5e5c4b5a 100644 --- a/taiga/base/fields.py +++ b/taiga/base/fields.py @@ -18,7 +18,6 @@ from django.forms import widgets from django.utils.translation import ugettext as _ -from django.utils.translation import ugettext_lazy from taiga.base.api import serializers diff --git a/taiga/projects/issues/migrations/0007_auto_20160614_1201.py b/taiga/projects/issues/migrations/0007_auto_20160614_1201.py new file mode 100644 index 00000000..5cf43d30 --- /dev/null +++ b/taiga/projects/issues/migrations/0007_auto_20160614_1201.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.2 on 2016-06-14 12:01 +from __future__ import unicode_literals + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('issues', '0006_remove_issue_watchers'), + ] + + operations = [ + migrations.AlterField( + model_name='issue', + name='external_reference', + field=django.contrib.postgres.fields.ArrayField(base_field=django.contrib.postgres.fields.ArrayField(base_field=models.TextField(blank=True, null=True), size=2), blank=True, default=[], null=True, size=None, verbose_name='external reference'), + ), + migrations.AlterField( + model_name='issue', + name='tags', + field=django.contrib.postgres.fields.ArrayField(base_field=models.TextField(), blank=True, default=[], null=True, size=None, verbose_name='tags'), + ), + ] diff --git a/taiga/projects/issues/models.py b/taiga/projects/issues/models.py index cd962e08..7c9f6b2e 100644 --- a/taiga/projects/issues/models.py +++ b/taiga/projects/issues/models.py @@ -18,17 +18,16 @@ from django.db import models from django.contrib.contenttypes.fields import GenericRelation +from django.contrib.postgres.fields import ArrayField from django.conf import settings from django.utils import timezone from django.dispatch import receiver from django.utils.translation import ugettext_lazy as _ -from djorm_pgarray.fields import TextArrayField - 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 +from taiga.projects.tagging.models import TaggedMixin class Issue(OCCModelMixin, WatchedModelMixin, BlockedMixin, TaggedMixin, models.Model): @@ -63,7 +62,8 @@ class Issue(OCCModelMixin, WatchedModelMixin, BlockedMixin, TaggedMixin, models. default=None, related_name="issues_assigned_to_me", verbose_name=_("assigned to")) attachments = GenericRelation("attachments.Attachment") - external_reference = TextArrayField(default=None, verbose_name=_("external reference")) + external_reference = ArrayField(ArrayField(models.TextField(null=True, blank=True), size=2), + null=True, blank=True, default=[], verbose_name=_("external reference")) _importing = None class Meta: diff --git a/taiga/projects/migrations/0047_auto_20160614_1201.py b/taiga/projects/migrations/0047_auto_20160614_1201.py new file mode 100644 index 00000000..eccd1f46 --- /dev/null +++ b/taiga/projects/migrations/0047_auto_20160614_1201.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.2 on 2016-06-14 12:01 +from __future__ import unicode_literals + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0046_triggers_to_update_tags_colors'), + ] + + operations = [ + migrations.AlterField( + model_name='project', + name='anon_permissions', + field=django.contrib.postgres.fields.ArrayField(base_field=models.TextField(choices=[('view_project', 'View project'), ('view_milestones', 'View milestones'), ('view_us', 'View user stories'), ('view_tasks', 'View tasks'), ('view_issues', 'View issues'), ('view_wiki_pages', 'View wiki pages'), ('view_wiki_links', 'View wiki links')]), blank=True, default=[], null=True, size=None, verbose_name='anonymous permissions'), + ), + migrations.AlterField( + model_name='project', + name='public_permissions', + field=django.contrib.postgres.fields.ArrayField(base_field=models.TextField(choices=[('view_project', 'View project'), ('view_milestones', 'View milestones'), ('add_milestone', 'Add milestone'), ('modify_milestone', 'Modify milestone'), ('delete_milestone', 'Delete milestone'), ('view_us', 'View user story'), ('add_us', 'Add user story'), ('modify_us', 'Modify user story'), ('comment_us', 'Comment user story'), ('delete_us', 'Delete user story'), ('view_tasks', 'View tasks'), ('add_task', 'Add task'), ('modify_task', 'Modify task'), ('comment_task', 'Comment task'), ('delete_task', 'Delete task'), ('view_issues', 'View issues'), ('add_issue', 'Add issue'), ('modify_issue', 'Modify issue'), ('comment_issue', 'Comment issue'), ('delete_issue', 'Delete issue'), ('view_wiki_pages', 'View wiki pages'), ('add_wiki_page', 'Add wiki page'), ('modify_wiki_page', 'Modify wiki page'), ('comment_wiki_page', 'Comment wiki page'), ('delete_wiki_page', 'Delete wiki page'), ('view_wiki_links', 'View wiki links'), ('add_wiki_link', 'Add wiki link'), ('modify_wiki_link', 'Modify wiki link'), ('delete_wiki_link', 'Delete wiki link')]), blank=True, default=[], null=True, size=None, verbose_name='user permissions'), + ), + migrations.AlterField( + model_name='project', + name='tags', + field=django.contrib.postgres.fields.ArrayField(base_field=models.TextField(), blank=True, default=[], null=True, size=None, verbose_name='tags'), + ), + migrations.AlterField( + model_name='project', + name='tags_colors', + field=django.contrib.postgres.fields.ArrayField(base_field=django.contrib.postgres.fields.ArrayField(base_field=models.TextField(blank=True, null=True), size=2), blank=True, default=[], null=True, size=None, verbose_name='tags colors'), + ), + ] diff --git a/taiga/projects/models.py b/taiga/projects/models.py index 4a369c8d..0c6bcc09 100644 --- a/taiga/projects/models.py +++ b/taiga/projects/models.py @@ -20,21 +20,22 @@ import itertools import uuid from django.conf import settings +from django.contrib.auth import get_user_model +from django.contrib.postgres.fields import ArrayField from django.core.exceptions import ValidationError from django.db import models from django.db.models import signals, Q from django.apps import apps from django.conf import settings from django.dispatch import receiver -from django.contrib.auth import get_user_model from django.utils.translation import ugettext_lazy as _ from django.utils import timezone from django.utils.functional import cached_property from django_pgjson.fields import JsonField -from djorm_pgarray.fields import TextArrayField -from taiga.base.tags import TaggedMixin +from taiga.projects.tagging.models import TaggedMixin +from taiga.projects.tagging.models import TagsColorsdMixin from taiga.base.utils.dicts import dict_sum from taiga.base.utils.files import get_file_path from taiga.base.utils.sequence import arithmetic_progression @@ -141,7 +142,7 @@ class ProjectDefaults(models.Model): abstract = True -class Project(ProjectDefaults, TaggedMixin, models.Model): +class Project(ProjectDefaults, TaggedMixin, TagsColorsdMixin, models.Model): name = models.CharField(max_length=250, null=False, blank=False, verbose_name=_("name")) slug = models.SlugField(max_length=250, unique=True, null=False, blank=True, @@ -186,16 +187,12 @@ class Project(ProjectDefaults, TaggedMixin, models.Model): blank=True, default=None, verbose_name=_("creation template")) - anon_permissions = TextArrayField(blank=True, null=True, - default=[], - verbose_name=_("anonymous permissions"), - choices=ANON_PERMISSIONS) - public_permissions = TextArrayField(blank=True, null=True, - default=[], - verbose_name=_("user permissions"), - choices=MEMBERS_PERMISSIONS) is_private = models.BooleanField(default=True, null=False, blank=True, verbose_name=_("is private")) + anon_permissions = ArrayField(models.TextField(null=False, blank=False, choices=ANON_PERMISSIONS), + null=True, blank=True, default=[], verbose_name=_("anonymous permissions")) + public_permissions = ArrayField(models.TextField(null=False, blank=False, choices=MEMBERS_PERMISSIONS), + null=True, blank=True, default=[], verbose_name=_("user permissions")) is_featured = models.BooleanField(default=False, null=False, blank=True, verbose_name=_("is featured")) @@ -214,9 +211,6 @@ class Project(ProjectDefaults, TaggedMixin, models.Model): null=True, blank=True, default=None, db_index=True) - tags_colors = TextArrayField(dimension=2, default=[], null=False, blank=True, - verbose_name=_("tags colors")) - transfer_token = models.CharField(max_length=255, null=True, blank=True, default=None, verbose_name=_("project transfer token")) diff --git a/taiga/base/tags.py b/taiga/projects/tagging/models.py similarity index 72% rename from taiga/base/tags.py rename to taiga/projects/tagging/models.py index 0e1cd866..970dae40 100644 --- a/taiga/base/tags.py +++ b/taiga/projects/tagging/models.py @@ -18,13 +18,21 @@ # along with this program. If not, see . from django.db import models +from django.contrib.postgres.fields import ArrayField from django.utils.translation import ugettext_lazy as _ -from djorm_pgarray.fields import TextArrayField - class TaggedMixin(models.Model): - tags = TextArrayField(default=None, verbose_name=_("tags")) + tags = ArrayField(models.TextField(), + null=True, blank=True, default=[], verbose_name=_("tags")) + + class Meta: + abstract = True + + +class TagsColorsdMixin(models.Model): + tags_colors = ArrayField(ArrayField(models.TextField(null=True, blank=True), size=2), + null=True, blank=True, default=[], verbose_name=_("tags colors")) class Meta: abstract = True diff --git a/taiga/projects/tasks/migrations/0010_auto_20160614_1201.py b/taiga/projects/tasks/migrations/0010_auto_20160614_1201.py new file mode 100644 index 00000000..4c3968fa --- /dev/null +++ b/taiga/projects/tasks/migrations/0010_auto_20160614_1201.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.2 on 2016-06-14 12:01 +from __future__ import unicode_literals + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tasks', '0009_auto_20151104_1131'), + ] + + operations = [ + migrations.AlterField( + model_name='task', + name='external_reference', + field=django.contrib.postgres.fields.ArrayField(base_field=django.contrib.postgres.fields.ArrayField(base_field=models.TextField(blank=True, null=True), size=2), blank=True, default=[], null=True, size=None, verbose_name='external reference'), + ), + migrations.AlterField( + model_name='task', + name='tags', + field=django.contrib.postgres.fields.ArrayField(base_field=models.TextField(), blank=True, default=[], null=True, size=None, verbose_name='tags'), + ), + ] diff --git a/taiga/projects/tasks/models.py b/taiga/projects/tasks/models.py index 30406387..18ff5750 100644 --- a/taiga/projects/tasks/models.py +++ b/taiga/projects/tasks/models.py @@ -18,16 +18,15 @@ from django.db import models from django.contrib.contenttypes.fields import GenericRelation +from django.contrib.postgres.fields import ArrayField from django.conf import settings from django.utils import timezone from django.utils.translation import ugettext_lazy as _ -from djorm_pgarray.fields import TextArrayField - 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 +from taiga.projects.tagging.models import TaggedMixin class Task(OCCModelMixin, WatchedModelMixin, BlockedMixin, TaggedMixin, models.Model): @@ -66,7 +65,8 @@ class Task(OCCModelMixin, WatchedModelMixin, BlockedMixin, TaggedMixin, models.M attachments = GenericRelation("attachments.Attachment") is_iocaine = models.BooleanField(default=False, null=False, blank=True, verbose_name=_("is iocaine")) - external_reference = TextArrayField(default=None, verbose_name=_("external reference")) + external_reference = ArrayField(ArrayField(models.TextField(null=True, blank=True), size=2), + null=True, blank=True, default=[], verbose_name=_("external reference")) _importing = None class Meta: diff --git a/taiga/projects/userstories/migrations/0012_auto_20160614_1201.py b/taiga/projects/userstories/migrations/0012_auto_20160614_1201.py new file mode 100644 index 00000000..1e9830e5 --- /dev/null +++ b/taiga/projects/userstories/migrations/0012_auto_20160614_1201.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.2 on 2016-06-14 12:01 +from __future__ import unicode_literals + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('userstories', '0011_userstory_tribe_gig'), + ] + + operations = [ + migrations.AlterField( + model_name='userstory', + name='external_reference', + field=django.contrib.postgres.fields.ArrayField(base_field=django.contrib.postgres.fields.ArrayField(base_field=models.TextField(blank=True, null=True), size=2), blank=True, default=[], null=True, size=None, verbose_name='external reference'), + ), + migrations.AlterField( + model_name='userstory', + name='tags', + field=django.contrib.postgres.fields.ArrayField(base_field=models.TextField(), blank=True, default=[], null=True, size=None, verbose_name='tags'), + ), + ] diff --git a/taiga/projects/userstories/models.py b/taiga/projects/userstories/models.py index 86332b46..47019ed3 100644 --- a/taiga/projects/userstories/models.py +++ b/taiga/projects/userstories/models.py @@ -18,14 +18,14 @@ from django.db import models from django.contrib.contenttypes.fields import GenericRelation +from django.contrib.postgres.fields import ArrayField from django.conf import settings from django.utils.translation import ugettext_lazy as _ from django.utils import timezone -from djorm_pgarray.fields import TextArrayField from picklefield.fields import PickledObjectField -from taiga.base.tags import TaggedMixin +from taiga.projects.tagging.models import TaggedMixin from taiga.projects.occ import OCCModelMixin from taiga.projects.notifications.mixins import WatchedModelMixin from taiga.projects.mixins.blocked import BlockedMixin @@ -103,7 +103,8 @@ class UserStory(OCCModelMixin, WatchedModelMixin, BlockedMixin, TaggedMixin, mod on_delete=models.SET_NULL, related_name="generated_user_stories", verbose_name=_("generated from issue")) - external_reference = TextArrayField(default=None, verbose_name=_("external reference")) + external_reference = ArrayField(ArrayField(models.TextField(null=True, blank=True), size=2), + null=True, blank=True, default=[], verbose_name=_("external reference")) tribe_gig = PickledObjectField(null=True, blank=True, default=None, verbose_name="taiga tribe gig") diff --git a/taiga/users/migrations/0021_auto_20160614_1201.py b/taiga/users/migrations/0021_auto_20160614_1201.py new file mode 100644 index 00000000..a9f1bb98 --- /dev/null +++ b/taiga/users/migrations/0021_auto_20160614_1201.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.2 on 2016-06-14 12:01 +from __future__ import unicode_literals + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0020_auto_20160525_1229'), + ] + + operations = [ + migrations.AlterField( + model_name='role', + name='permissions', + field=django.contrib.postgres.fields.ArrayField(base_field=models.TextField(choices=[('view_project', 'View project'), ('view_milestones', 'View milestones'), ('add_milestone', 'Add milestone'), ('modify_milestone', 'Modify milestone'), ('delete_milestone', 'Delete milestone'), ('view_us', 'View user story'), ('add_us', 'Add user story'), ('modify_us', 'Modify user story'), ('comment_us', 'Comment user story'), ('delete_us', 'Delete user story'), ('view_tasks', 'View tasks'), ('add_task', 'Add task'), ('modify_task', 'Modify task'), ('comment_task', 'Comment task'), ('delete_task', 'Delete task'), ('view_issues', 'View issues'), ('add_issue', 'Add issue'), ('modify_issue', 'Modify issue'), ('comment_issue', 'Comment issue'), ('delete_issue', 'Delete issue'), ('view_wiki_pages', 'View wiki pages'), ('add_wiki_page', 'Add wiki page'), ('modify_wiki_page', 'Modify wiki page'), ('comment_wiki_page', 'Comment wiki page'), ('delete_wiki_page', 'Delete wiki page'), ('view_wiki_links', 'View wiki links'), ('add_wiki_link', 'Add wiki link'), ('modify_wiki_link', 'Modify wiki link'), ('delete_wiki_link', 'Delete wiki link')]), blank=True, default=[], null=True, size=None, verbose_name='permissions'), + ), + ] diff --git a/taiga/users/models.py b/taiga/users/models.py index 2d8fcb33..264d1539 100644 --- a/taiga/users/models.py +++ b/taiga/users/models.py @@ -26,6 +26,7 @@ from django.apps.config import MODELS_MODULE_NAME from django.conf import settings from django.contrib.auth.models import UserManager, AbstractBaseUser from django.contrib.contenttypes.models import ContentType +from django.contrib.postgres.fields import ArrayField from django.core import validators from django.core.exceptions import AppRegistryNotReady from django.db import models @@ -34,7 +35,6 @@ from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from django_pgjson.fields import JsonField -from djorm_pgarray.fields import TextArrayField from taiga.auth.tokens import get_token_for_user from taiga.base.utils.slug import slugify_uniquely @@ -53,8 +53,8 @@ def get_user_model_safe(): registry not being ready yet. Raises LookupError if model isn't found. - Based on: https://github.com/django-oscar/django-oscar/blob/1.0/oscar/core/loading.py#L310-L340 - Ongoing Django issue: https://code.djangoproject.com/ticket/22872 + Based on: https://github.com/django-oscar/django-oscar/blob/1.0/oscar/core/loading.py#L310-L340 + Ongoing Django issue: https://code.djangoproject.com/ticket/22872 """ user_app, user_model = settings.AUTH_USER_MODEL.split('.') @@ -293,10 +293,8 @@ class Role(models.Model): verbose_name=_("name")) slug = models.SlugField(max_length=250, null=False, blank=True, verbose_name=_("slug")) - permissions = TextArrayField(blank=True, null=True, - default=[], - verbose_name=_("permissions"), - choices=MEMBERS_PERMISSIONS) + permissions = ArrayField(models.TextField(null=False, blank=False, choices=MEMBERS_PERMISSIONS), + null=True, blank=True, default=[], verbose_name=_("permissions")) order = models.IntegerField(default=10, null=False, blank=False, verbose_name=_("order")) # null=True is for make work django 1.7 migrations. project diff --git a/tests/integration/test_importer_api.py b/tests/integration/test_importer_api.py index 490ba83b..6a2e7883 100644 --- a/tests/integration/test_importer_api.py +++ b/tests/integration/test_importer_api.py @@ -68,7 +68,7 @@ def test_valid_project_import_without_extra_data(client): } response = client.json.post(url, json.dumps(data)) - assert response.status_code == 201 + assert response.status_code == 201, response.data must_empty_children = [ "issues", "user_stories", "us_statuses", "wiki_pages", "priorities", "severities", "milestones", "points", "issue_types", "task_statuses", diff --git a/tests/models.py b/tests/models.py index 9583b8c0..e69de29b 100644 --- a/tests/models.py +++ b/tests/models.py @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino -# Copyright (C) 2014-2016 David Barragán -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Anler Hernández -# 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 . - -from django.db import models -from taiga.base import tags - - -class TaggedModel(tags.TaggedMixin, models.Model): - class Meta: - app_label = "tests"