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"