diff --git a/dumpdata_role.sh b/dumpdata_role.sh deleted file mode 100755 index 594a5d1d..00000000 --- a/dumpdata_role.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -python ./manage.py dumpdata -n --indent=4 users.Role > taiga/users/fixtures/initial_role.json diff --git a/regenerate.sh b/regenerate.sh index 4592a94e..c7761833 100755 --- a/regenerate.sh +++ b/regenerate.sh @@ -15,10 +15,11 @@ echo "-> Load initial domain" python manage.py loaddata initial_domains --traceback echo "-> Load initial user" python manage.py loaddata initial_user --traceback +echo "-> Load initial project_templates" +python manage.py loaddata initial_project_templates --traceback echo "-> Load initial roles" python manage.py loaddata initial_role --traceback echo "-> Generate sample data" python manage.py sample_data --traceback echo "-> Generate initial versions of objects" python manage.py createinitialrevisions --traceback - diff --git a/settings/common.py b/settings/common.py index 19527515..8a301574 100644 --- a/settings/common.py +++ b/settings/common.py @@ -293,6 +293,7 @@ REST_FRAMEWORK = { "MAX_PAGINATE_BY": 1000, } +DEFAULT_PROJECT_TEMPLATE = "scrum" # NOTE: DON'T INSERT MORE SETTINGS AFTER THIS LINE diff --git a/taiga/auth/tests.py b/taiga/auth/tests.py index 529ae4d1..e7e8bb52 100644 --- a/taiga/auth/tests.py +++ b/taiga/auth/tests.py @@ -56,7 +56,7 @@ urls.urlpatterns += patterns("", class AuthServicesTests(test.TestCase): - fixtures = ["initial_domains.json",] + fixtures = ["initial_domains.json", "initial_project_templates.json",] def setUp(self): self.user1 = create_user(1) @@ -184,7 +184,7 @@ class TokenAuthenticationBackendTests(test.TestCase): class RegisterApiTests(test.TestCase): - fixtures = ["initial_domains.json",] + fixtures = ["initial_domains.json", "initial_project_templates.json",] def setUp(self): self.user1 = create_user(1) diff --git a/taiga/base/serializers.py b/taiga/base/serializers.py index d5d8dd17..eb5b3580 100644 --- a/taiga/base/serializers.py +++ b/taiga/base/serializers.py @@ -21,6 +21,8 @@ from rest_framework import serializers from reversion.models import Version import reversion +from taiga.domains.base import get_active_domain + class PickleField(serializers.WritableField): """ @@ -33,6 +35,27 @@ class PickleField(serializers.WritableField): return data +class JsonField(serializers.WritableField): + """ + Json objects serializer. + """ + def to_native(self, obj): + return obj + + def from_native(self, data): + return data + +class AutoDomainField(serializers.WritableField): + """ + Automatically set domain field serializer. + """ + def to_native(self, obj): + return obj + + def from_native(self, data): + domain = get_active_domain() + return domain.id + class VersionSerializer(serializers.ModelSerializer): created_date = serializers.SerializerMethodField("get_created_date") content_type = serializers.SerializerMethodField("get_content_type") diff --git a/taiga/domains/serializers.py b/taiga/domains/serializers.py index 1537aa04..3f0ccb26 100644 --- a/taiga/domains/serializers.py +++ b/taiga/domains/serializers.py @@ -12,6 +12,8 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +from django.conf import settings + from rest_framework import serializers from taiga.users.serializers import UserSerializer @@ -20,14 +22,18 @@ from .models import Domain, DomainMember class DomainSerializer(serializers.ModelSerializer): projects = serializers.SerializerMethodField('get_projects') + default_project_template = serializers.SerializerMethodField('get_default_project_template') class Meta: model = Domain - fields = ('public_register', 'default_language', "projects") + fields = ('public_register', 'default_language', "projects", "default_project_template") def get_projects(self, obj): return map(lambda x: {"id": x.id, "name": x.name, "slug": x.slug, "owner": x.owner.id}, obj.projects.all().order_by('name')) + def get_default_project_template(self, obj): + return settings.DEFAULT_PROJECT_TEMPLATE + class DomainMemberSerializer(serializers.ModelSerializer): user = UserSerializer() diff --git a/taiga/events/tests.py b/taiga/events/tests.py index b8c02be1..ea714a65 100644 --- a/taiga/events/tests.py +++ b/taiga/events/tests.py @@ -51,7 +51,7 @@ from unittest.mock import MagicMock from unittest.mock import patch class ChangesTest(test.TestCase): - fixtures = ["initial_domains.json"] + fixtures = ["initial_domains.json", "initial_project_templates.json"] def test_emit_change_for_model(self): user = create_user(1) # Project owner diff --git a/taiga/projects/api.py b/taiga/projects/api.py index 58d52b93..c079a49f 100644 --- a/taiga/projects/api.py +++ b/taiga/projects/api.py @@ -298,3 +298,12 @@ class QuestionStatusViewSet(ModelCrudViewSet, BulkUpdateOrderMixin): bulk_update_param = "bulk_question_statuses" bulk_update_perm = "change_questionstatus" bulk_update_order = services.bulk_update_question_status_order + +class ProjectTemplateViewSet(ModelCrudViewSet): + model = models.ProjectTemplate + serializer_class = serializers.ProjectTemplateSerializer + permission_classes = (IsAuthenticated, permissions.ProjectTemplatePermission) + + def get_queryset(self): + domain = get_active_domain() + return models.ProjectTemplate.objects.filter(Q(domain=domain) | Q(domain__isnull=True)) diff --git a/taiga/projects/choices.py b/taiga/projects/choices.py index 3a67a4f2..d1c9171b 100644 --- a/taiga/projects/choices.py +++ b/taiga/projects/choices.py @@ -14,463 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from django.utils.translation import ugettext_lazy as _ - - VIDEOCONFERENCES_CHOICES = ( ("appear-in", "AppearIn"), ("talky", "Talky"), ) - -US_STATUSES = ( - (1, _("Open"), False, True, "#669933"), - (2, _("Closed"), True, False, "#999999"), -) - -TASK_STATUSES = ( - (1, _("New"), False, True, "#999999"), - (2, _("In progress"), False, False, "#ff9900"), - (3, _("Ready for test"), True, False, "#ffcc00"), - (4, _("Closed"), True, False, "#669900"), - (5, _("Needs Info"), False, False, "#999999"), -) - -POINTS_CHOICES = ( - (1, u"?", None, True), - (2, u"0", 0, False), - (3, u"1/2", 0.5, False), - (4, u"1", 1, False), - (5, u"2", 2, False), - (6, u"3", 3, False), - (7, u"5", 5, False), - (8, u"8", 8, False), - (9, u"10", 10, False), - (10, u"15", 15, False), - (11, u"20", 20, False), - (12, u"40", 40, False), -) - -PRIORITY_CHOICES = ( - (1, _(u"Low"), "#666666", False), - (3, _(u"Normal"), "#669933", True), - (5, _(u"High"), "#CC0000", False), -) - -SEVERITY_CHOICES = ( - (1, _(u"Wishlist"), "#666666", False), - (2, _(u"Minor"), "#669933", False), - (3, _(u"Normal"), "#0000FF", True), - (4, _(u"Important"), "#FFA500", False), - (5, _(u"Critical"), "#CC0000", False), -) - -ISSUE_STATUSES = ( - (1, _("New"), False, "#8C2318", True), - (2, _("In progress"), False, "#5E8C6A", False), - (3, _("Ready for test"), True, "#88A65E", False), - (4, _("Closed"), True, "#BFB35A", False), - (5, _("Needs Info"), False, "#89BAB4", False), - (6, _("Rejected"), True, "#CC0000", False), - (7, _("Postponed"), False, "#666666", False), -) - -ISSUE_TYPES = ( - (1, _(u"Bug"), "#89BAB4", True), -) - -QUESTION_STATUS = ( - (1, _("Pending"), False, "#FFA500", True), - (2, _("Answered"), False, "#669933", False), - (3, _("Closed"), True,"#BFB35A", False), -) - -ROLES = ( - (10, "ux", "UX", True, [ - [ "add_issue", "issues", "issue" ], - [ "change_issue", "issues", "issue" ], - [ "delete_issue", "issues", "issue" ], - [ "view_issue", "issues", "issue" ], - [ "add_milestone", "milestones", "milestone" ], - [ "change_milestone", "milestones", "milestone" ], - [ "delete_milestone", "milestones", "milestone" ], - [ "view_milestone", "milestones", "milestone" ], - [ "add_attachment", "projects", "attachment" ], - [ "change_attachment", "projects", "attachment" ], - [ "delete_attachment", "projects", "attachment" ], - [ "view_attachment", "projects", "attachment" ], - [ "add_issuestatus", "projects", "issuestatus" ], - [ "change_issuestatus", "projects", "issuestatus" ], - [ "delete_issuestatus", "projects", "issuestatus" ], - [ "view_issuestatus", "projects", "issuestatus" ], - [ "add_issuetype", "projects", "issuetype" ], - [ "change_issuetype", "projects", "issuetype" ], - [ "delete_issuetype", "projects", "issuetype" ], - [ "view_issuetype", "projects", "issuetype" ], - [ "add_membership", "projects", "membership" ], - [ "change_membership", "projects", "membership" ], - [ "delete_membership", "projects", "membership" ], - [ "view_membership", "projects", "membership" ], - [ "add_points", "projects", "points" ], - [ "change_points", "projects", "points" ], - [ "delete_points", "projects", "points" ], - [ "view_points", "projects", "points" ], - [ "add_priority", "projects", "priority" ], - [ "change_priority", "projects", "priority" ], - [ "delete_priority", "projects", "priority" ], - [ "view_priority", "projects", "priority" ], - [ "add_project", "projects", "project" ], - [ "change_project", "projects", "project" ], - [ "delete_project", "projects", "project" ], - [ "view_project", "projects", "project" ], - [ "add_severity", "projects", "severity" ], - [ "change_severity", "projects", "severity" ], - [ "delete_severity", "projects", "severity" ], - [ "view_severity", "projects", "severity" ], - [ "add_taskstatus", "projects", "taskstatus" ], - [ "change_taskstatus", "projects", "taskstatus" ], - [ "delete_taskstatus", "projects", "taskstatus" ], - [ "view_taskstatus", "projects", "taskstatus" ], - [ "add_userstorystatus", "projects", "userstorystatus" ], - [ "change_userstorystatus", "projects", "userstorystatus" ], - [ "delete_userstorystatus", "projects", "userstorystatus" ], - [ "view_userstorystatus", "projects", "userstorystatus" ], - [ "add_task", "tasks", "task" ], - [ "change_task", "tasks", "task" ], - [ "delete_task", "tasks", "task" ], - [ "view_task", "tasks", "task" ], - [ "add_role", "users", "role" ], - [ "change_role", "users", "role" ], - [ "delete_role", "users", "role" ], - [ "view_role", "users", "role" ], - [ "change_user", "users", "user" ], - [ "view_user", "users", "user" ], - [ "add_rolepoints", "userstories", "rolepoints" ], - [ "change_rolepoints", "userstories", "rolepoints" ], - [ "delete_rolepoints", "userstories", "rolepoints" ], - [ "view_rolepoints", "userstories", "rolepoints" ], - [ "add_userstory", "userstories", "userstory" ], - [ "change_userstory", "userstories", "userstory" ], - [ "delete_userstory", "userstories", "userstory" ], - [ "view_userstory", "userstories", "userstory" ], - [ "add_wikipage", "wiki", "wikipage" ], - [ "change_wikipage", "wiki", "wikipage" ], - [ "delete_wikipage", "wiki", "wikipage" ], - [ "view_wikipage", "wiki", "wikipage" ] - ]), - (20, "design", "Design", True, [ - [ "add_issue", "issues", "issue" ], - [ "change_issue", "issues", "issue" ], - [ "delete_issue", "issues", "issue" ], - [ "view_issue", "issues", "issue" ], - [ "add_milestone", "milestones", "milestone" ], - [ "change_milestone", "milestones", "milestone" ], - [ "delete_milestone", "milestones", "milestone" ], - [ "view_milestone", "milestones", "milestone" ], - [ "add_attachment", "projects", "attachment" ], - [ "change_attachment", "projects", "attachment" ], - [ "delete_attachment", "projects", "attachment" ], - [ "view_attachment", "projects", "attachment" ], - [ "add_issuestatus", "projects", "issuestatus" ], - [ "change_issuestatus", "projects", "issuestatus" ], - [ "delete_issuestatus", "projects", "issuestatus" ], - [ "view_issuestatus", "projects", "issuestatus" ], - [ "add_issuetype", "projects", "issuetype" ], - [ "change_issuetype", "projects", "issuetype" ], - [ "delete_issuetype", "projects", "issuetype" ], - [ "view_issuetype", "projects", "issuetype" ], - [ "add_membership", "projects", "membership" ], - [ "change_membership", "projects", "membership" ], - [ "delete_membership", "projects", "membership" ], - [ "view_membership", "projects", "membership" ], - [ "add_points", "projects", "points" ], - [ "change_points", "projects", "points" ], - [ "delete_points", "projects", "points" ], - [ "view_points", "projects", "points" ], - [ "add_priority", "projects", "priority" ], - [ "change_priority", "projects", "priority" ], - [ "delete_priority", "projects", "priority" ], - [ "view_priority", "projects", "priority" ], - [ "add_project", "projects", "project" ], - [ "change_project", "projects", "project" ], - [ "delete_project", "projects", "project" ], - [ "view_project", "projects", "project" ], - [ "add_severity", "projects", "severity" ], - [ "change_severity", "projects", "severity" ], - [ "delete_severity", "projects", "severity" ], - [ "view_severity", "projects", "severity" ], - [ "add_taskstatus", "projects", "taskstatus" ], - [ "change_taskstatus", "projects", "taskstatus" ], - [ "delete_taskstatus", "projects", "taskstatus" ], - [ "view_taskstatus", "projects", "taskstatus" ], - [ "add_userstorystatus", "projects", "userstorystatus" ], - [ "change_userstorystatus", "projects", "userstorystatus" ], - [ "delete_userstorystatus", "projects", "userstorystatus" ], - [ "view_userstorystatus", "projects", "userstorystatus" ], - [ "add_task", "tasks", "task" ], - [ "change_task", "tasks", "task" ], - [ "delete_task", "tasks", "task" ], - [ "view_task", "tasks", "task" ], - [ "add_role", "users", "role" ], - [ "change_role", "users", "role" ], - [ "delete_role", "users", "role" ], - [ "view_role", "users", "role" ], - [ "change_user", "users", "user" ], - [ "view_user", "users", "user" ], - [ "add_rolepoints", "userstories", "rolepoints" ], - [ "change_rolepoints", "userstories", "rolepoints" ], - [ "delete_rolepoints", "userstories", "rolepoints" ], - [ "view_rolepoints", "userstories", "rolepoints" ], - [ "add_userstory", "userstories", "userstory" ], - [ "change_userstory", "userstories", "userstory" ], - [ "delete_userstory", "userstories", "userstory" ], - [ "view_userstory", "userstories", "userstory" ], - [ "add_wikipage", "wiki", "wikipage" ], - [ "change_wikipage", "wiki", "wikipage" ], - [ "delete_wikipage", "wiki", "wikipage" ], - [ "view_wikipage", "wiki", "wikipage" ] - ]), - (30, "front", "Front", True, [ - [ "add_issue", "issues", "issue" ], - [ "change_issue", "issues", "issue" ], - [ "delete_issue", "issues", "issue" ], - [ "view_issue", "issues", "issue" ], - [ "add_milestone", "milestones", "milestone" ], - [ "change_milestone", "milestones", "milestone" ], - [ "delete_milestone", "milestones", "milestone" ], - [ "view_milestone", "milestones", "milestone" ], - [ "add_attachment", "projects", "attachment" ], - [ "change_attachment", "projects", "attachment" ], - [ "delete_attachment", "projects", "attachment" ], - [ "view_attachment", "projects", "attachment" ], - [ "add_issuestatus", "projects", "issuestatus" ], - [ "change_issuestatus", "projects", "issuestatus" ], - [ "delete_issuestatus", "projects", "issuestatus" ], - [ "view_issuestatus", "projects", "issuestatus" ], - [ "add_issuetype", "projects", "issuetype" ], - [ "change_issuetype", "projects", "issuetype" ], - [ "delete_issuetype", "projects", "issuetype" ], - [ "view_issuetype", "projects", "issuetype" ], - [ "add_membership", "projects", "membership" ], - [ "change_membership", "projects", "membership" ], - [ "delete_membership", "projects", "membership" ], - [ "view_membership", "projects", "membership" ], - [ "add_points", "projects", "points" ], - [ "change_points", "projects", "points" ], - [ "delete_points", "projects", "points" ], - [ "view_points", "projects", "points" ], - [ "add_priority", "projects", "priority" ], - [ "change_priority", "projects", "priority" ], - [ "delete_priority", "projects", "priority" ], - [ "view_priority", "projects", "priority" ], - [ "add_project", "projects", "project" ], - [ "change_project", "projects", "project" ], - [ "delete_project", "projects", "project" ], - [ "view_project", "projects", "project" ], - [ "add_severity", "projects", "severity" ], - [ "change_severity", "projects", "severity" ], - [ "delete_severity", "projects", "severity" ], - [ "view_severity", "projects", "severity" ], - [ "add_taskstatus", "projects", "taskstatus" ], - [ "change_taskstatus", "projects", "taskstatus" ], - [ "delete_taskstatus", "projects", "taskstatus" ], - [ "view_taskstatus", "projects", "taskstatus" ], - [ "add_userstorystatus", "projects", "userstorystatus" ], - [ "change_userstorystatus", "projects", "userstorystatus" ], - [ "delete_userstorystatus", "projects", "userstorystatus" ], - [ "view_userstorystatus", "projects", "userstorystatus" ], - [ "add_task", "tasks", "task" ], - [ "change_task", "tasks", "task" ], - [ "delete_task", "tasks", "task" ], - [ "view_task", "tasks", "task" ], - [ "add_role", "users", "role" ], - [ "change_role", "users", "role" ], - [ "delete_role", "users", "role" ], - [ "view_role", "users", "role" ], - [ "change_user", "users", "user" ], - [ "view_user", "users", "user" ], - [ "add_rolepoints", "userstories", "rolepoints" ], - [ "change_rolepoints", "userstories", "rolepoints" ], - [ "delete_rolepoints", "userstories", "rolepoints" ], - [ "view_rolepoints", "userstories", "rolepoints" ], - [ "add_userstory", "userstories", "userstory" ], - [ "change_userstory", "userstories", "userstory" ], - [ "delete_userstory", "userstories", "userstory" ], - [ "view_userstory", "userstories", "userstory" ], - [ "add_wikipage", "wiki", "wikipage" ], - [ "change_wikipage", "wiki", "wikipage" ], - [ "delete_wikipage", "wiki", "wikipage" ], - [ "view_wikipage", "wiki", "wikipage" ] - ]), - (40, "back", "Back", True, [ - [ "add_issue", "issues", "issue" ], - [ "change_issue", "issues", "issue" ], - [ "delete_issue", "issues", "issue" ], - [ "view_issue", "issues", "issue" ], - [ "add_milestone", "milestones", "milestone" ], - [ "change_milestone", "milestones", "milestone" ], - [ "delete_milestone", "milestones", "milestone" ], - [ "view_milestone", "milestones", "milestone" ], - [ "add_attachment", "projects", "attachment" ], - [ "change_attachment", "projects", "attachment" ], - [ "delete_attachment", "projects", "attachment" ], - [ "view_attachment", "projects", "attachment" ], - [ "add_issuestatus", "projects", "issuestatus" ], - [ "change_issuestatus", "projects", "issuestatus" ], - [ "delete_issuestatus", "projects", "issuestatus" ], - [ "view_issuestatus", "projects", "issuestatus" ], - [ "add_issuetype", "projects", "issuetype" ], - [ "change_issuetype", "projects", "issuetype" ], - [ "delete_issuetype", "projects", "issuetype" ], - [ "view_issuetype", "projects", "issuetype" ], - [ "add_membership", "projects", "membership" ], - [ "change_membership", "projects", "membership" ], - [ "delete_membership", "projects", "membership" ], - [ "view_membership", "projects", "membership" ], - [ "add_points", "projects", "points" ], - [ "change_points", "projects", "points" ], - [ "delete_points", "projects", "points" ], - [ "view_points", "projects", "points" ], - [ "add_priority", "projects", "priority" ], - [ "change_priority", "projects", "priority" ], - [ "delete_priority", "projects", "priority" ], - [ "view_priority", "projects", "priority" ], - [ "add_project", "projects", "project" ], - [ "change_project", "projects", "project" ], - [ "delete_project", "projects", "project" ], - [ "view_project", "projects", "project" ], - [ "add_severity", "projects", "severity" ], - [ "change_severity", "projects", "severity" ], - [ "delete_severity", "projects", "severity" ], - [ "view_severity", "projects", "severity" ], - [ "add_taskstatus", "projects", "taskstatus" ], - [ "change_taskstatus", "projects", "taskstatus" ], - [ "delete_taskstatus", "projects", "taskstatus" ], - [ "view_taskstatus", "projects", "taskstatus" ], - [ "add_userstorystatus", "projects", "userstorystatus" ], - [ "change_userstorystatus", "projects", "userstorystatus" ], - [ "delete_userstorystatus", "projects", "userstorystatus" ], - [ "view_userstorystatus", "projects", "userstorystatus" ], - [ "add_task", "tasks", "task" ], - [ "change_task", "tasks", "task" ], - [ "delete_task", "tasks", "task" ], - [ "view_task", "tasks", "task" ], - [ "add_role", "users", "role" ], - [ "change_role", "users", "role" ], - [ "delete_role", "users", "role" ], - [ "view_role", "users", "role" ], - [ "change_user", "users", "user" ], - [ "view_user", "users", "user" ], - [ "add_rolepoints", "userstories", "rolepoints" ], - [ "change_rolepoints", "userstories", "rolepoints" ], - [ "delete_rolepoints", "userstories", "rolepoints" ], - [ "view_rolepoints", "userstories", "rolepoints" ], - [ "add_userstory", "userstories", "userstory" ], - [ "change_userstory", "userstories", "userstory" ], - [ "delete_userstory", "userstories", "userstory" ], - [ "view_userstory", "userstories", "userstory" ], - [ "add_wikipage", "wiki", "wikipage" ], - [ "change_wikipage", "wiki", "wikipage" ], - [ "delete_wikipage", "wiki", "wikipage" ], - [ "view_wikipage", "wiki", "wikipage" ] - ]), - (50, "product-ouner", "Product Owner", False, [ - [ "add_issue", "issues", "issue" ], - [ "change_issue", "issues", "issue" ], - [ "delete_issue", "issues", "issue" ], - [ "view_issue", "issues", "issue" ], - [ "add_milestone", "milestones", "milestone" ], - [ "change_milestone", "milestones", "milestone" ], - [ "delete_milestone", "milestones", "milestone" ], - [ "view_milestone", "milestones", "milestone" ], - [ "add_attachment", "projects", "attachment" ], - [ "change_attachment", "projects", "attachment" ], - [ "delete_attachment", "projects", "attachment" ], - [ "view_attachment", "projects", "attachment" ], - [ "add_issuestatus", "projects", "issuestatus" ], - [ "change_issuestatus", "projects", "issuestatus" ], - [ "delete_issuestatus", "projects", "issuestatus" ], - [ "view_issuestatus", "projects", "issuestatus" ], - [ "add_issuetype", "projects", "issuetype" ], - [ "change_issuetype", "projects", "issuetype" ], - [ "delete_issuetype", "projects", "issuetype" ], - [ "view_issuetype", "projects", "issuetype" ], - [ "add_membership", "projects", "membership" ], - [ "change_membership", "projects", "membership" ], - [ "delete_membership", "projects", "membership" ], - [ "view_membership", "projects", "membership" ], - [ "add_points", "projects", "points" ], - [ "change_points", "projects", "points" ], - [ "delete_points", "projects", "points" ], - [ "view_points", "projects", "points" ], - [ "add_priority", "projects", "priority" ], - [ "change_priority", "projects", "priority" ], - [ "delete_priority", "projects", "priority" ], - [ "view_priority", "projects", "priority" ], - [ "add_project", "projects", "project" ], - [ "change_project", "projects", "project" ], - [ "delete_project", "projects", "project" ], - [ "view_project", "projects", "project" ], - [ "add_severity", "projects", "severity" ], - [ "change_severity", "projects", "severity" ], - [ "delete_severity", "projects", "severity" ], - [ "view_severity", "projects", "severity" ], - [ "add_taskstatus", "projects", "taskstatus" ], - [ "change_taskstatus", "projects", "taskstatus" ], - [ "delete_taskstatus", "projects", "taskstatus" ], - [ "view_taskstatus", "projects", "taskstatus" ], - [ "add_userstorystatus", "projects", "userstorystatus" ], - [ "change_userstorystatus", "projects", "userstorystatus" ], - [ "delete_userstorystatus", "projects", "userstorystatus" ], - [ "view_userstorystatus", "projects", "userstorystatus" ], - [ "add_task", "tasks", "task" ], - [ "change_task", "tasks", "task" ], - [ "delete_task", "tasks", "task" ], - [ "view_task", "tasks", "task" ], - [ "add_role", "users", "role" ], - [ "change_role", "users", "role" ], - [ "delete_role", "users", "role" ], - [ "view_role", "users", "role" ], - [ "change_user", "users", "user" ], - [ "view_user", "users", "user" ], - [ "add_rolepoints", "userstories", "rolepoints" ], - [ "change_rolepoints", "userstories", "rolepoints" ], - [ "delete_rolepoints", "userstories", "rolepoints" ], - [ "view_rolepoints", "userstories", "rolepoints" ], - [ "add_userstory", "userstories", "userstory" ], - [ "change_userstory", "userstories", "userstory" ], - [ "delete_userstory", "userstories", "userstory" ], - [ "view_userstory", "userstories", "userstory" ], - [ "add_wikipage", "wiki", "wikipage" ], - [ "change_wikipage", "wiki", "wikipage" ], - [ "delete_wikipage", "wiki", "wikipage" ], - [ "view_wikipage", "wiki", "wikipage" ] - ]), - (60, "stakeholder", "Stakeholder", False, [ - [ "add_issue", "issues", "issue" ], - [ "change_issue", "issues", "issue" ], - [ "delete_issue", "issues", "issue" ], - [ "view_issue", "issues", "issue" ], - [ "view_milestone", "milestones", "milestone" ], - [ "add_attachment", "projects", "attachment" ], - [ "change_attachment", "projects", "attachment" ], - [ "delete_attachment", "projects", "attachment" ], - [ "view_attachment", "projects", "attachment" ], - [ "view_issuestatus", "projects", "issuestatus" ], - [ "view_issuetype", "projects", "issuetype" ], - [ "view_membership", "projects", "membership" ], - [ "view_points", "projects", "points" ], - [ "view_priority", "projects", "priority" ], - [ "view_project", "projects", "project" ], - [ "view_severity", "projects", "severity" ], - [ "view_taskstatus", "projects", "taskstatus" ], - [ "view_userstorystatus", "projects", "userstorystatus" ], - [ "view_task", "tasks", "task" ], - [ "view_role", "users", "role" ], - [ "change_user", "users", "user" ], - [ "view_user", "users", "user" ], - [ "view_rolepoints", "userstories", "rolepoints" ], - [ "view_userstory", "userstories", "userstory" ], - [ "change_wikipage", "wiki", "wikipage" ], - [ "view_wikipage", "wiki", "wikipage" ] - ]) -) diff --git a/taiga/projects/fixtures/initial_project_templates.json b/taiga/projects/fixtures/initial_project_templates.json new file mode 100644 index 00000000..1a306ff7 --- /dev/null +++ b/taiga/projects/fixtures/initial_project_templates.json @@ -0,0 +1,56 @@ +[ +{ + "model": "projects.projecttemplate", + "pk": 1, + "fields": { + "modified_date": "2014-04-22T14:48:43.596Z", + "roles": "[{\"order\": 10, \"slug\": \"ux\", \"name\": \"UX\", \"permissions\": [\"add_issue\", \"change_issue\", \"delete_issue\", \"view_issue\", \"add_milestone\", \"change_milestone\", \"delete_milestone\", \"view_milestone\", \"add_attachment\", \"change_attachment\", \"delete_attachment\", \"view_attachment\", \"add_issuestatus\", \"change_issuestatus\", \"delete_issuestatus\", \"view_issuestatus\", \"add_issuetype\", \"change_issuetype\", \"delete_issuetype\", \"view_issuetype\", \"add_membership\", \"change_membership\", \"delete_membership\", \"view_membership\", \"add_points\", \"change_points\", \"delete_points\", \"view_points\", \"add_priority\", \"change_priority\", \"delete_priority\", \"view_priority\", \"add_project\", \"change_project\", \"delete_project\", \"view_project\", \"add_severity\", \"change_severity\", \"delete_severity\", \"view_severity\", \"add_taskstatus\", \"change_taskstatus\", \"delete_taskstatus\", \"view_taskstatus\", \"add_userstorystatus\", \"change_userstorystatus\", \"delete_userstorystatus\", \"view_userstorystatus\", \"add_task\", \"change_task\", \"delete_task\", \"view_task\", \"add_role\", \"change_role\", \"delete_role\", \"view_role\", \"change_user\", \"view_user\", \"add_rolepoints\", \"change_rolepoints\", \"delete_rolepoints\", \"view_rolepoints\", \"add_userstory\", \"change_userstory\", \"delete_userstory\", \"view_userstory\", \"add_wikipage\", \"change_wikipage\", \"delete_wikipage\", \"view_wikipage\"], \"computable\": true}, {\"order\": 20, \"slug\": \"design\", \"name\": \"Design\", \"permissions\": [\"add_issue\", \"change_issue\", \"delete_issue\", \"view_issue\", \"add_milestone\", \"change_milestone\", \"delete_milestone\", \"view_milestone\", \"add_attachment\", \"change_attachment\", \"delete_attachment\", \"view_attachment\", \"add_issuestatus\", \"change_issuestatus\", \"delete_issuestatus\", \"view_issuestatus\", \"add_issuetype\", \"change_issuetype\", \"delete_issuetype\", \"view_issuetype\", \"add_membership\", \"change_membership\", \"delete_membership\", \"view_membership\", \"add_points\", \"change_points\", \"delete_points\", \"view_points\", \"add_priority\", \"change_priority\", \"delete_priority\", \"view_priority\", \"add_project\", \"change_project\", \"delete_project\", \"view_project\", \"add_severity\", \"change_severity\", \"delete_severity\", \"view_severity\", \"add_taskstatus\", \"change_taskstatus\", \"delete_taskstatus\", \"view_taskstatus\", \"add_userstorystatus\", \"change_userstorystatus\", \"delete_userstorystatus\", \"view_userstorystatus\", \"add_task\", \"change_task\", \"delete_task\", \"view_task\", \"add_role\", \"change_role\", \"delete_role\", \"view_role\", \"change_user\", \"view_user\", \"add_rolepoints\", \"change_rolepoints\", \"delete_rolepoints\", \"view_rolepoints\", \"add_userstory\", \"change_userstory\", \"delete_userstory\", \"view_userstory\", \"add_wikipage\", \"change_wikipage\", \"delete_wikipage\", \"view_wikipage\"], \"computable\": true}, {\"order\": 30, \"slug\": \"front\", \"name\": \"Front\", \"permissions\": [\"add_issue\", \"change_issue\", \"delete_issue\", \"view_issue\", \"add_milestone\", \"change_milestone\", \"delete_milestone\", \"view_milestone\", \"add_attachment\", \"change_attachment\", \"delete_attachment\", \"view_attachment\", \"add_issuestatus\", \"change_issuestatus\", \"delete_issuestatus\", \"view_issuestatus\", \"add_issuetype\", \"change_issuetype\", \"delete_issuetype\", \"view_issuetype\", \"add_membership\", \"change_membership\", \"delete_membership\", \"view_membership\", \"add_points\", \"change_points\", \"delete_points\", \"view_points\", \"add_priority\", \"change_priority\", \"delete_priority\", \"view_priority\", \"add_project\", \"change_project\", \"delete_project\", \"view_project\", \"add_severity\", \"change_severity\", \"delete_severity\", \"view_severity\", \"add_taskstatus\", \"change_taskstatus\", \"delete_taskstatus\", \"view_taskstatus\", \"add_userstorystatus\", \"change_userstorystatus\", \"delete_userstorystatus\", \"view_userstorystatus\", \"add_task\", \"change_task\", \"delete_task\", \"view_task\", \"add_role\", \"change_role\", \"delete_role\", \"view_role\", \"change_user\", \"view_user\", \"add_rolepoints\", \"change_rolepoints\", \"delete_rolepoints\", \"view_rolepoints\", \"add_userstory\", \"change_userstory\", \"delete_userstory\", \"view_userstory\", \"add_wikipage\", \"change_wikipage\", \"delete_wikipage\", \"view_wikipage\"], \"computable\": true}, {\"order\": 40, \"slug\": \"back\", \"name\": \"Back\", \"permissions\": [\"add_issue\", \"change_issue\", \"delete_issue\", \"view_issue\", \"add_milestone\", \"change_milestone\", \"delete_milestone\", \"view_milestone\", \"add_attachment\", \"change_attachment\", \"delete_attachment\", \"view_attachment\", \"add_issuestatus\", \"change_issuestatus\", \"delete_issuestatus\", \"view_issuestatus\", \"add_issuetype\", \"change_issuetype\", \"delete_issuetype\", \"view_issuetype\", \"add_membership\", \"change_membership\", \"delete_membership\", \"view_membership\", \"add_points\", \"change_points\", \"delete_points\", \"view_points\", \"add_priority\", \"change_priority\", \"delete_priority\", \"view_priority\", \"add_project\", \"change_project\", \"delete_project\", \"view_project\", \"add_severity\", \"change_severity\", \"delete_severity\", \"view_severity\", \"add_taskstatus\", \"change_taskstatus\", \"delete_taskstatus\", \"view_taskstatus\", \"add_userstorystatus\", \"change_userstorystatus\", \"delete_userstorystatus\", \"view_userstorystatus\", \"add_task\", \"change_task\", \"delete_task\", \"view_task\", \"add_role\", \"change_role\", \"delete_role\", \"view_role\", \"change_user\", \"view_user\", \"add_rolepoints\", \"change_rolepoints\", \"delete_rolepoints\", \"view_rolepoints\", \"add_userstory\", \"change_userstory\", \"delete_userstory\", \"view_userstory\", \"add_wikipage\", \"change_wikipage\", \"delete_wikipage\", \"view_wikipage\"], \"computable\": true}, {\"order\": 50, \"slug\": \"product-ouner\", \"name\": \"Product Owner\", \"permissions\": [\"add_issue\", \"change_issue\", \"delete_issue\", \"view_issue\", \"add_milestone\", \"change_milestone\", \"delete_milestone\", \"view_milestone\", \"add_attachment\", \"change_attachment\", \"delete_attachment\", \"view_attachment\", \"add_issuestatus\", \"change_issuestatus\", \"delete_issuestatus\", \"view_issuestatus\", \"add_issuetype\", \"change_issuetype\", \"delete_issuetype\", \"view_issuetype\", \"add_membership\", \"change_membership\", \"delete_membership\", \"view_membership\", \"add_points\", \"change_points\", \"delete_points\", \"view_points\", \"add_priority\", \"change_priority\", \"delete_priority\", \"view_priority\", \"add_project\", \"change_project\", \"delete_project\", \"view_project\", \"add_severity\", \"change_severity\", \"delete_severity\", \"view_severity\", \"add_taskstatus\", \"change_taskstatus\", \"delete_taskstatus\", \"view_taskstatus\", \"add_userstorystatus\", \"change_userstorystatus\", \"delete_userstorystatus\", \"view_userstorystatus\", \"add_task\", \"change_task\", \"delete_task\", \"view_task\", \"add_role\", \"change_role\", \"delete_role\", \"view_role\", \"change_user\", \"view_user\", \"add_rolepoints\", \"change_rolepoints\", \"delete_rolepoints\", \"view_rolepoints\", \"add_userstory\", \"change_userstory\", \"delete_userstory\", \"view_userstory\", \"add_wikipage\", \"change_wikipage\", \"delete_wikipage\", \"view_wikipage\"], \"computable\": false}, {\"order\": 60, \"slug\": \"stakeholder\", \"name\": \"Stakeholder\", \"permissions\": [\"add_issue\", \"change_issue\", \"delete_issue\", \"view_issue\", \"view_milestone\", \"add_attachment\", \"change_attachment\", \"delete_attachment\", \"view_attachment\", \"view_issuestatus\", \"view_issuetype\", \"view_membership\", \"view_points\", \"view_priority\", \"view_project\", \"view_severity\", \"view_taskstatus\", \"view_userstorystatus\", \"view_task\", \"view_role\", \"change_user\", \"view_user\", \"view_rolepoints\", \"view_userstory\", \"change_wikipage\", \"view_wikipage\"], \"computable\": false}]", + "is_kanban_activated": false, + "is_wiki_activated": true, + "points": "[{\"order\": 1, \"name\": \"?\", \"value\": null}, {\"order\": 2, \"name\": \"0\", \"value\": 0.0}, {\"order\": 3, \"name\": \"1/2\", \"value\": 0.5}, {\"order\": 4, \"name\": \"1\", \"value\": 1.0}, {\"order\": 5, \"name\": \"2\", \"value\": 2.0}, {\"order\": 6, \"name\": \"3\", \"value\": 3.0}, {\"order\": 7, \"name\": \"5\", \"value\": 5.0}, {\"order\": 8, \"name\": \"8\", \"value\": 8.0}, {\"order\": 9, \"name\": \"10\", \"value\": 10.0}, {\"order\": 10, \"name\": \"15\", \"value\": 15.0}, {\"order\": 11, \"name\": \"20\", \"value\": 20.0}, {\"order\": 12, \"name\": \"40\", \"value\": 40.0}]", + "videoconferences": null, + "name": "Scrum", + "issue_types": "[{\"order\": 1, \"name\": \"Bug\", \"color\": \"#89BAB4\"}]", + "is_issues_activated": true, + "description": "", + "created_date": "2014-04-22T14:48:43.596Z", + "issue_statuses": "[{\"order\": 1, \"name\": \"New\", \"color\": \"#8C2318\", \"is_closed\": false}, {\"order\": 2, \"name\": \"In progress\", \"color\": \"#5E8C6A\", \"is_closed\": false}, {\"order\": 3, \"name\": \"Ready for test\", \"color\": \"#88A65E\", \"is_closed\": true}, {\"order\": 4, \"name\": \"Closed\", \"color\": \"#BFB35A\", \"is_closed\": true}, {\"order\": 5, \"name\": \"Needs Info\", \"color\": \"#89BAB4\", \"is_closed\": false}, {\"order\": 6, \"name\": \"Rejected\", \"color\": \"#CC0000\", \"is_closed\": true}, {\"order\": 7, \"name\": \"Postponed\", \"color\": \"#666666\", \"is_closed\": false}]", + "slug": "scrum", + "task_statuses": "[{\"order\": 1, \"name\": \"New\", \"color\": \"#999999\", \"is_closed\": false}, {\"order\": 2, \"name\": \"In progress\", \"color\": \"#ff9900\", \"is_closed\": false}, {\"order\": 3, \"name\": \"Ready for test\", \"color\": \"#ffcc00\", \"is_closed\": true}, {\"order\": 4, \"name\": \"Closed\", \"color\": \"#669900\", \"is_closed\": true}, {\"order\": 5, \"name\": \"Needs Info\", \"color\": \"#999999\", \"is_closed\": false}]", + "default_options": "{\"us_status\": \"Open\", \"priority\": \"Normal\", \"issue_status\": \"New\", \"issue_type\": \"Bug\", \"points\": \"?\", \"severity\": \"Normal\", \"task_status\": \"New\"}", + "is_backlog_activated": true, + "us_statuses": "[{\"order\": 1, \"name\": \"Open\", \"color\": \"#669933\", \"is_closed\": false, \"wip_limit\": null}, {\"order\": 2, \"name\": \"Closed\", \"color\": \"#999999\", \"is_closed\": true, \"wip_limit\": null}]", + "videoconferences_salt": null, + "priorities": "[{\"order\": 1, \"name\": \"Low\", \"color\": \"#666666\"}, {\"order\": 3, \"name\": \"Normal\", \"color\": \"#669933\"}, {\"order\": 5, \"name\": \"High\", \"color\": \"#CC0000\"}]", + "severities": "[{\"order\": 1, \"name\": \"Wishlist\", \"color\": \"#666666\"}, {\"order\": 2, \"name\": \"Minor\", \"color\": \"#669933\"}, {\"order\": 3, \"name\": \"Normal\", \"color\": \"#0000FF\"}, {\"order\": 4, \"name\": \"Important\", \"color\": \"#FFA500\"}, {\"order\": 5, \"name\": \"Critical\", \"color\": \"#CC0000\"}]", + "domain": null + } +}, +{ + "model": "projects.projecttemplate", + "pk": 2, + "fields": { + "modified_date": "2014-04-22T14:50:19.738Z", + "roles": "[{\"permissions\": [\"add_issue\", \"change_issue\", \"delete_issue\", \"view_issue\", \"add_milestone\", \"change_milestone\", \"delete_milestone\", \"view_milestone\", \"add_attachment\", \"change_attachment\", \"delete_attachment\", \"view_attachment\", \"add_issuestatus\", \"change_issuestatus\", \"delete_issuestatus\", \"view_issuestatus\", \"add_issuetype\", \"change_issuetype\", \"delete_issuetype\", \"view_issuetype\", \"add_membership\", \"change_membership\", \"delete_membership\", \"view_membership\", \"add_points\", \"change_points\", \"delete_points\", \"view_points\", \"add_priority\", \"change_priority\", \"delete_priority\", \"view_priority\", \"add_project\", \"change_project\", \"delete_project\", \"view_project\", \"add_severity\", \"change_severity\", \"delete_severity\", \"view_severity\", \"add_taskstatus\", \"change_taskstatus\", \"delete_taskstatus\", \"view_taskstatus\", \"add_userstorystatus\", \"change_userstorystatus\", \"delete_userstorystatus\", \"view_userstorystatus\", \"add_task\", \"change_task\", \"delete_task\", \"view_task\", \"add_role\", \"change_role\", \"delete_role\", \"view_role\", \"change_user\", \"view_user\", \"add_rolepoints\", \"change_rolepoints\", \"delete_rolepoints\", \"view_rolepoints\", \"add_userstory\", \"change_userstory\", \"delete_userstory\", \"view_userstory\", \"add_wikipage\", \"change_wikipage\", \"delete_wikipage\", \"view_wikipage\"], \"slug\": \"ux\", \"computable\": true, \"order\": 10, \"name\": \"UX\"}, {\"permissions\": [\"add_issue\", \"change_issue\", \"delete_issue\", \"view_issue\", \"add_milestone\", \"change_milestone\", \"delete_milestone\", \"view_milestone\", \"add_attachment\", \"change_attachment\", \"delete_attachment\", \"view_attachment\", \"add_issuestatus\", \"change_issuestatus\", \"delete_issuestatus\", \"view_issuestatus\", \"add_issuetype\", \"change_issuetype\", \"delete_issuetype\", \"view_issuetype\", \"add_membership\", \"change_membership\", \"delete_membership\", \"view_membership\", \"add_points\", \"change_points\", \"delete_points\", \"view_points\", \"add_priority\", \"change_priority\", \"delete_priority\", \"view_priority\", \"add_project\", \"change_project\", \"delete_project\", \"view_project\", \"add_severity\", \"change_severity\", \"delete_severity\", \"view_severity\", \"add_taskstatus\", \"change_taskstatus\", \"delete_taskstatus\", \"view_taskstatus\", \"add_userstorystatus\", \"change_userstorystatus\", \"delete_userstorystatus\", \"view_userstorystatus\", \"add_task\", \"change_task\", \"delete_task\", \"view_task\", \"add_role\", \"change_role\", \"delete_role\", \"view_role\", \"change_user\", \"view_user\", \"add_rolepoints\", \"change_rolepoints\", \"delete_rolepoints\", \"view_rolepoints\", \"add_userstory\", \"change_userstory\", \"delete_userstory\", \"view_userstory\", \"add_wikipage\", \"change_wikipage\", \"delete_wikipage\", \"view_wikipage\"], \"slug\": \"design\", \"computable\": true, \"order\": 20, \"name\": \"Design\"}, {\"permissions\": [\"add_issue\", \"change_issue\", \"delete_issue\", \"view_issue\", \"add_milestone\", \"change_milestone\", \"delete_milestone\", \"view_milestone\", \"add_attachment\", \"change_attachment\", \"delete_attachment\", \"view_attachment\", \"add_issuestatus\", \"change_issuestatus\", \"delete_issuestatus\", \"view_issuestatus\", \"add_issuetype\", \"change_issuetype\", \"delete_issuetype\", \"view_issuetype\", \"add_membership\", \"change_membership\", \"delete_membership\", \"view_membership\", \"add_points\", \"change_points\", \"delete_points\", \"view_points\", \"add_priority\", \"change_priority\", \"delete_priority\", \"view_priority\", \"add_project\", \"change_project\", \"delete_project\", \"view_project\", \"add_severity\", \"change_severity\", \"delete_severity\", \"view_severity\", \"add_taskstatus\", \"change_taskstatus\", \"delete_taskstatus\", \"view_taskstatus\", \"add_userstorystatus\", \"change_userstorystatus\", \"delete_userstorystatus\", \"view_userstorystatus\", \"add_task\", \"change_task\", \"delete_task\", \"view_task\", \"add_role\", \"change_role\", \"delete_role\", \"view_role\", \"change_user\", \"view_user\", \"add_rolepoints\", \"change_rolepoints\", \"delete_rolepoints\", \"view_rolepoints\", \"add_userstory\", \"change_userstory\", \"delete_userstory\", \"view_userstory\", \"add_wikipage\", \"change_wikipage\", \"delete_wikipage\", \"view_wikipage\"], \"slug\": \"front\", \"computable\": true, \"order\": 30, \"name\": \"Front\"}, {\"permissions\": [\"add_issue\", \"change_issue\", \"delete_issue\", \"view_issue\", \"add_milestone\", \"change_milestone\", \"delete_milestone\", \"view_milestone\", \"add_attachment\", \"change_attachment\", \"delete_attachment\", \"view_attachment\", \"add_issuestatus\", \"change_issuestatus\", \"delete_issuestatus\", \"view_issuestatus\", \"add_issuetype\", \"change_issuetype\", \"delete_issuetype\", \"view_issuetype\", \"add_membership\", \"change_membership\", \"delete_membership\", \"view_membership\", \"add_points\", \"change_points\", \"delete_points\", \"view_points\", \"add_priority\", \"change_priority\", \"delete_priority\", \"view_priority\", \"add_project\", \"change_project\", \"delete_project\", \"view_project\", \"add_severity\", \"change_severity\", \"delete_severity\", \"view_severity\", \"add_taskstatus\", \"change_taskstatus\", \"delete_taskstatus\", \"view_taskstatus\", \"add_userstorystatus\", \"change_userstorystatus\", \"delete_userstorystatus\", \"view_userstorystatus\", \"add_task\", \"change_task\", \"delete_task\", \"view_task\", \"add_role\", \"change_role\", \"delete_role\", \"view_role\", \"change_user\", \"view_user\", \"add_rolepoints\", \"change_rolepoints\", \"delete_rolepoints\", \"view_rolepoints\", \"add_userstory\", \"change_userstory\", \"delete_userstory\", \"view_userstory\", \"add_wikipage\", \"change_wikipage\", \"delete_wikipage\", \"view_wikipage\"], \"slug\": \"back\", \"computable\": true, \"order\": 40, \"name\": \"Back\"}, {\"permissions\": [\"add_issue\", \"change_issue\", \"delete_issue\", \"view_issue\", \"add_milestone\", \"change_milestone\", \"delete_milestone\", \"view_milestone\", \"add_attachment\", \"change_attachment\", \"delete_attachment\", \"view_attachment\", \"add_issuestatus\", \"change_issuestatus\", \"delete_issuestatus\", \"view_issuestatus\", \"add_issuetype\", \"change_issuetype\", \"delete_issuetype\", \"view_issuetype\", \"add_membership\", \"change_membership\", \"delete_membership\", \"view_membership\", \"add_points\", \"change_points\", \"delete_points\", \"view_points\", \"add_priority\", \"change_priority\", \"delete_priority\", \"view_priority\", \"add_project\", \"change_project\", \"delete_project\", \"view_project\", \"add_severity\", \"change_severity\", \"delete_severity\", \"view_severity\", \"add_taskstatus\", \"change_taskstatus\", \"delete_taskstatus\", \"view_taskstatus\", \"add_userstorystatus\", \"change_userstorystatus\", \"delete_userstorystatus\", \"view_userstorystatus\", \"add_task\", \"change_task\", \"delete_task\", \"view_task\", \"add_role\", \"change_role\", \"delete_role\", \"view_role\", \"change_user\", \"view_user\", \"add_rolepoints\", \"change_rolepoints\", \"delete_rolepoints\", \"view_rolepoints\", \"add_userstory\", \"change_userstory\", \"delete_userstory\", \"view_userstory\", \"add_wikipage\", \"change_wikipage\", \"delete_wikipage\", \"view_wikipage\"], \"slug\": \"product-ouner\", \"computable\": false, \"order\": 50, \"name\": \"Product Owner\"}, {\"permissions\": [\"add_issue\", \"change_issue\", \"delete_issue\", \"view_issue\", \"view_milestone\", \"add_attachment\", \"change_attachment\", \"delete_attachment\", \"view_attachment\", \"view_issuestatus\", \"view_issuetype\", \"view_membership\", \"view_points\", \"view_priority\", \"view_project\", \"view_severity\", \"view_taskstatus\", \"view_userstorystatus\", \"view_task\", \"view_role\", \"change_user\", \"view_user\", \"view_rolepoints\", \"view_userstory\", \"change_wikipage\", \"view_wikipage\"], \"slug\": \"stakeholder\", \"computable\": false, \"order\": 60, \"name\": \"Stakeholder\"}]", + "is_kanban_activated": true, + "is_wiki_activated": false, + "points": "[{\"order\": 1, \"name\": \"?\", \"value\": null}, {\"order\": 2, \"name\": \"0\", \"value\": 0.0}, {\"order\": 3, \"name\": \"1/2\", \"value\": 0.5}, {\"order\": 4, \"name\": \"1\", \"value\": 1.0}, {\"order\": 5, \"name\": \"2\", \"value\": 2.0}, {\"order\": 6, \"name\": \"3\", \"value\": 3.0}, {\"order\": 7, \"name\": \"5\", \"value\": 5.0}, {\"order\": 8, \"name\": \"8\", \"value\": 8.0}, {\"order\": 9, \"name\": \"10\", \"value\": 10.0}, {\"order\": 10, \"name\": \"15\", \"value\": 15.0}, {\"order\": 11, \"name\": \"20\", \"value\": 20.0}, {\"order\": 12, \"name\": \"40\", \"value\": 40.0}]", + "videoconferences": null, + "name": "Kanban", + "issue_types": "[{\"order\": 1, \"name\": \"Bug\", \"color\": \"#89BAB4\"}]", + "is_issues_activated": false, + "description": "", + "created_date": "2014-04-22T14:50:19.738Z", + "issue_statuses": "[{\"order\": 1, \"name\": \"New\", \"color\": \"#8C2318\", \"is_closed\": false}, {\"order\": 2, \"name\": \"In progress\", \"color\": \"#5E8C6A\", \"is_closed\": false}, {\"order\": 3, \"name\": \"Ready for test\", \"color\": \"#88A65E\", \"is_closed\": true}, {\"order\": 4, \"name\": \"Closed\", \"color\": \"#BFB35A\", \"is_closed\": true}, {\"order\": 5, \"name\": \"Needs Info\", \"color\": \"#89BAB4\", \"is_closed\": false}, {\"order\": 6, \"name\": \"Rejected\", \"color\": \"#CC0000\", \"is_closed\": true}, {\"order\": 7, \"name\": \"Postponed\", \"color\": \"#666666\", \"is_closed\": false}]", + "slug": "kanban", + "task_statuses": "[{\"order\": 1, \"name\": \"New\", \"color\": \"#999999\", \"is_closed\": false}, {\"order\": 2, \"name\": \"In progress\", \"color\": \"#ff9900\", \"is_closed\": false}, {\"order\": 3, \"name\": \"Ready for test\", \"color\": \"#ffcc00\", \"is_closed\": true}, {\"order\": 4, \"name\": \"Closed\", \"color\": \"#669900\", \"is_closed\": true}, {\"order\": 5, \"name\": \"Needs Info\", \"color\": \"#999999\", \"is_closed\": false}]", + "default_options": "{\"us_status\": \"To do\", \"priority\": \"Normal\", \"issue_status\": \"New\", \"issue_type\": \"Bug\", \"points\": \"?\", \"severity\": \"Normal\", \"task_status\": \"New\"}", + "is_backlog_activated": false, + "us_statuses": "[{\"order\": 1, \"name\": \"To do\", \"color\": \"#999999\", \"is_closed\": false, \"wip_limit\": null}, {\"order\": 2, \"name\": \"Doing\", \"color\": \"#ff9900\", \"is_closed\": false, \"wip_limit\": null}, {\"order\": 3, \"name\": \"Done\", \"color\": \"#ffcc00\", \"is_closed\": true, \"wip_limit\": null}]", + "videoconferences_salt": null, + "priorities": "[{\"order\": 1, \"name\": \"Low\", \"color\": \"#666666\"}, {\"order\": 3, \"name\": \"Normal\", \"color\": \"#669933\"}, {\"order\": 5, \"name\": \"High\", \"color\": \"#CC0000\"}]", + "severities": "[{\"order\": 1, \"name\": \"Wishlist\", \"color\": \"#666666\"}, {\"order\": 2, \"name\": \"Minor\", \"color\": \"#669933\"}, {\"order\": 3, \"name\": \"Normal\", \"color\": \"#0000FF\"}, {\"order\": 4, \"name\": \"Important\", \"color\": \"#FFA500\"}, {\"order\": 5, \"name\": \"Critical\", \"color\": \"#CC0000\"}]", + "domain": null + } +} +] diff --git a/taiga/projects/issues/tests/tests_api.py b/taiga/projects/issues/tests/tests_api.py index b9b193f6..0ebfdc44 100644 --- a/taiga/projects/issues/tests/tests_api.py +++ b/taiga/projects/issues/tests/tests_api.py @@ -15,7 +15,7 @@ from . import create_issue class IssuesTestCase(test.TestCase): - fixtures = ["initial_domains.json"] + fixtures = ["initial_domains.json", "initial_project_templates.json"] def setUp(self): self.user1 = create_user(1) # Project owner diff --git a/taiga/projects/milestones/tests/tests_api.py b/taiga/projects/milestones/tests/tests_api.py index f4277531..2197cce3 100644 --- a/taiga/projects/milestones/tests/tests_api.py +++ b/taiga/projects/milestones/tests/tests_api.py @@ -30,7 +30,7 @@ from . import create_milestone class MilestonesTestCase(test.TestCase): - fixtures = ["initial_domains.json",] + fixtures = ["initial_domains.json", "initial_project_templates.json",] def setUp(self): self.user1 = create_user(1) diff --git a/taiga/projects/models.py b/taiga/projects/models.py index 1ac45bd5..6553d412 100644 --- a/taiga/projects/models.py +++ b/taiga/projects/models.py @@ -31,6 +31,7 @@ from django.utils.translation import ugettext_lazy as _ from django.utils import timezone from picklefield.fields import PickledObjectField +from django_pgjson.fields import JsonField from taiga.users.models import Role from taiga.domains.models import DomainMember @@ -520,6 +521,241 @@ class QuestionStatus(models.Model): return self.name +class ProjectTemplate(models.Model): + name = models.CharField(max_length=250, unique=True, null=False, blank=False, + verbose_name=_("name")) + slug = models.SlugField(max_length=250, unique=True, null=False, blank=True, + verbose_name=_("slug")) + description = models.TextField(null=False, blank=False, + verbose_name=_("description")) + created_date = models.DateTimeField(auto_now_add=True, null=False, blank=False, + verbose_name=_("created date")) + modified_date = models.DateTimeField(auto_now=True, null=False, blank=False, + verbose_name=_("modified date")) + domain = models.ForeignKey("domains.Domain", related_name="templates", null=True, blank=True, + default=None, verbose_name=_("domain")) + + is_backlog_activated = models.BooleanField(default=True, null=False, blank=True, + verbose_name=_("active backlog panel")) + is_kanban_activated = models.BooleanField(default=False, null=False, blank=True, + verbose_name=_("active kanban panel")) + is_wiki_activated = models.BooleanField(default=True, null=False, blank=True, + verbose_name=_("active wiki panel")) + is_issues_activated = models.BooleanField(default=True, null=False, blank=True, + verbose_name=_("active issues panel")) + videoconferences = models.CharField(max_length=250, null=True, blank=True, + choices=choices.VIDEOCONFERENCES_CHOICES, + verbose_name=_("videoconference system")) + videoconferences_salt = models.CharField(max_length=250, null=True, blank=True, + verbose_name=_("videoconference room salt")) + + default_options = JsonField(null=True, blank=True, default=None, verbose_name=_("default options")) + us_statuses = JsonField(null=True, blank=True, default=None, verbose_name=_("us statuses")) + points = JsonField(null=True, blank=True, default=None, verbose_name=_("us points")) + task_statuses = JsonField(null=True, blank=True, default=None, verbose_name=_("task statuses")) + issue_statuses = JsonField(null=True, blank=True, default=None, verbose_name=_("issue statuses")) + issue_types = JsonField(null=True, blank=True, default=None, verbose_name=_("issue types")) + priorities = JsonField(null=True, blank=True, default=None, verbose_name=_("issue types")) + severities = JsonField(null=True, blank=True, default=None, verbose_name=_("issue types")) + roles = JsonField(null=True, blank=True, default=None, verbose_name=_("roles")) + + class Meta: + verbose_name = "project template" + verbose_name_plural = "project templates" + ordering = ["name"] + + def __str__(self): + return self.name + + def __repr__(self): + return "".format(self.slug) + + def save(self, *args, **kwargs): + super().save(*args, **kwargs) + + def load_data_from_project(self, project): + self.is_backlog_activated = project.is_backlog_activated + self.is_kanban_activated = project.is_kanban_activated + self.is_wiki_activated = project.is_wiki_activated + self.is_issues_activated = project.is_issues_activated + self.videoconferences = project.videoconferences + self.videoconferences_salt = project.videoconferences_salt + + self.default_options = { + "points": project.default_points.name, + "us_status": project.default_us_status.name, + "task_status": project.default_task_status.name, + "issue_status": project.default_issue_status.name, + "issue_type": project.default_issue_type.name, + "priority": project.default_priority.name, + "severity": project.default_severity.name + } + + + self.us_statuses = [] + for us_status in project.us_statuses.all(): + self.us_statuses.append({ + "name": us_status.name, + "is_closed": us_status.is_closed, + "color": us_status.color, + "wip_limit": us_status.wip_limit, + "order": us_status.order, + }) + + self.points = [] + for us_point in project.points.all(): + self.points.append({ + "name": us_point.name, + "value": us_point.value, + "order": us_point.order, + }) + + self.task_statuses = [] + for task_status in project.task_statuses.all(): + self.task_statuses.append({ + "name": task_status.name, + "is_closed": task_status.is_closed, + "color": task_status.color, + "order": task_status.order, + }) + + self.issue_statuses = [] + for issue_status in project.issue_statuses.all(): + self.issue_statuses.append({ + "name": issue_status.name, + "is_closed": issue_status.is_closed, + "color": issue_status.color, + "order": issue_status.order, + }) + + self.issue_types = [] + for issue_type in project.issue_types.all(): + self.issue_types.append({ + "name": issue_type.name, + "color": issue_type.color, + "order": issue_type.order, + }) + + self.priorities = [] + for priority in project.priorities.all(): + self.priorities.append({ + "name": priority.name, + "color": priority.color, + "order": priority.order, + }) + + self.severities = [] + for severity in project.severities.all(): + self.severities.append({ + "name": severity.name, + "color": severity.color, + "order": severity.order, + }) + + self.roles = [] + for role in project.roles.all(): + permissions = [p.codename for p in role.permissions.all()] + self.roles.append({ + "name": role.name, + "slug": role.slug, + "permissions": permissions, + "order": role.order, + "computable": role.computable + }) + + def apply_to_project(self, project): + if project.id is None: + raise "Project need an id (must be a saved project)" + + project.is_backlog_activated = self.is_backlog_activated + project.is_kanban_activated = self.is_kanban_activated + project.is_wiki_activated = self.is_wiki_activated + project.is_issues_activated = self.is_issues_activated + project.videoconferences = self.videoconferences + project.videoconferences_salt = self.videoconferences_salt + + for us_status in self.us_statuses: + UserStoryStatus.objects.create( + name=us_status["name"], + is_closed=us_status["is_closed"], + color=us_status["color"], + wip_limit=us_status["wip_limit"], + order=us_status["order"], + project=project + ) + + for point in self.points: + Points.objects.create( + name=point["name"], + value=point["value"], + order=point["order"], + project=project + ) + + for task_status in self.task_statuses: + TaskStatus.objects.create( + name=task_status["name"], + is_closed=task_status["is_closed"], + color=task_status["color"], + order=task_status["order"], + project=project + ) + + for issue_status in self.issue_statuses: + IssueStatus.objects.create( + name=issue_status["name"], + is_closed=issue_status["is_closed"], + color=issue_status["color"], + order=issue_status["order"], + project=project + ) + + for issue_type in self.issue_types: + IssueType.objects.create( + name=issue_type["name"], + color=issue_type["color"], + order=issue_type["order"], + project=project + ) + + for priority in self.priorities: + Priority.objects.create( + name=priority["name"], + color=priority["color"], + order=priority["order"], + project=project + ) + + for severity in self.severities: + Severity.objects.create( + name=severity["name"], + color=severity["color"], + order=severity["order"], + project=project + ) + + for role in self.roles: + newRoleInstance = Role.objects.create( + name=role["name"], + slug=role["slug"], + order=role["order"], + computable=role["computable"], + project=project + ) + permissions = [Permission.objects.get(codename=codename) for codename in role["permissions"]] + for permission in permissions: + newRoleInstance.permissions.add(permission) + + project.default_points = Points.objects.get(name=self.default_options["points"], project=project) + project.default_us_status = UserStoryStatus.objects.get(name=self.default_options["us_status"], project=project) + project.default_task_status = TaskStatus.objects.get(name=self.default_options["task_status"], project=project) + project.default_issue_status = IssueStatus.objects.get(name=self.default_options["issue_status"], project=project) + project.default_issue_type = IssueType.objects.get(name=self.default_options["issue_type"], project=project) + project.default_priority = Priority.objects.get(name=self.default_options["priority"], project=project) + project.default_severity = Severity.objects.get(name=self.default_options["severity"], project=project) + + return project + # Reversion registration (usufull for base.notification and for meke a historical) reversion.register(Project) reversion.register(Attachment) @@ -570,67 +806,7 @@ def project_post_save(sender, instance, created, **kwargs): if not created: return - # USs - for order, name, value, is_default in choices.POINTS_CHOICES: - obj = Points.objects.create(project=instance, name=name, order=order, value=value) - if is_default: - instance.default_points = obj - - for order, name, is_closed, is_default, color in choices.US_STATUSES: - obj = UserStoryStatus.objects.create(name=name, order=order, color=color, - is_closed=is_closed, project=instance) - if is_default: - instance.default_us_status = obj - - # Tasks - for order, name, is_closed, is_default, color in choices.TASK_STATUSES: - obj = TaskStatus.objects.create(name=name, order=order, color=color, - is_closed=is_closed, project=instance) - if is_default: - instance.default_task_status = obj - - # Issues - for order, name, color, is_default in choices.PRIORITY_CHOICES: - obj = Priority.objects.create(project=instance, name=name, order=order, color=color) - if is_default: - instance.default_priority = obj - - for order, name, color, is_default in choices.SEVERITY_CHOICES: - obj = Severity.objects.create(project=instance, name=name, order=order, color=color) - if is_default: - instance.default_severity = obj - - for order, name, is_closed, color, is_default in choices.ISSUE_STATUSES: - obj = IssueStatus.objects.create(name=name, order=order, - is_closed=is_closed, project=instance, color=color) - if is_default: - instance.default_issue_status = obj - - for order, name, color, is_default in choices.ISSUE_TYPES: - obj = IssueType.objects.create(project=instance, name=name, order=order, color=color) - if is_default: - instance.default_issue_type = obj - - # Questions - for order, name, is_closed, color, is_default in choices.QUESTION_STATUS: - obj = QuestionStatus.objects.create(name=name, order=order, - is_closed=is_closed, project=instance, color=color) - if is_default: - instance.default_question_status = obj - - # Permissions - for order, slug, name, computable, permissions in choices.ROLES: - obj = Role.objects.create(slug=slug, name=name, order=order, computable=computable, project=instance) - for permission in permissions: - try: - perm = Permission.objects.get(codename=permission[0], content_type__app_label=permission[1], content_type__model=permission[2]) - obj.permissions.add(perm) - except Permission.DoesNotExist: - pass - + template_slug = getattr(instance, "template", settings.DEFAULT_PROJECT_TEMPLATE) + template = ProjectTemplate.objects.get(slug=template_slug, domain__isnull=True) + template.apply_to_project(instance) instance.save() - - from taiga.projects.template_manager import ProjectTemplateManager - if hasattr(instance, "template"): - template_manager = ProjectTemplateManager() - template_manager.apply(instance.template, instance) diff --git a/taiga/projects/permissions.py b/taiga/projects/permissions.py index 0e1f9a0a..12ed9455 100644 --- a/taiga/projects/permissions.py +++ b/taiga/projects/permissions.py @@ -168,3 +168,12 @@ class QuestionStatusPermission(BasePermission): delete_permission = "delete_questionstatus" safe_methods = ["HEAD", "OPTIONS"] path_to_project = ["project"] + +class ProjectTemplatePermission(BasePermission): + def has_permission(self, request, view): + domain = get_active_domain() + return domain.user_is_owner(request.user) + + def has_object_permission(self, request, view, obj): + domain = get_active_domain() + return domain.user_is_owner(request.user) diff --git a/taiga/projects/serializers.py b/taiga/projects/serializers.py index 749b466d..c465d55c 100644 --- a/taiga/projects/serializers.py +++ b/taiga/projects/serializers.py @@ -17,7 +17,7 @@ from os import path from rest_framework import serializers -from taiga.base.serializers import PickleField +from taiga.base.serializers import PickleField, JsonField, AutoDomainField from taiga.users.models import Role from . import models @@ -182,3 +182,20 @@ class RoleSerializer(serializers.ModelSerializer): class Meta: model = Role fields = ('id', 'name', 'permissions', 'computable', 'project', 'order') + + +class ProjectTemplateSerializer(serializers.ModelSerializer): + domain = AutoDomainField() + + default_options = JsonField() + us_statuses = JsonField() + points = JsonField() + task_statuses = JsonField() + issue_statuses = JsonField() + issue_types = JsonField() + priorities = JsonField() + severities = JsonField() + roles = JsonField() + + class Meta: + model = models.ProjectTemplate diff --git a/taiga/projects/tasks/tests/tests_api.py b/taiga/projects/tasks/tests/tests_api.py index 5f12f495..feb2f582 100644 --- a/taiga/projects/tasks/tests/tests_api.py +++ b/taiga/projects/tasks/tests/tests_api.py @@ -34,7 +34,7 @@ from . import create_task class TasksTestCase(test.TestCase): - fixtures = ["initial_domains.json"] + fixtures = ["initial_domains.json", "initial_project_templates.json"] def setUp(self): self.user1 = create_user(1) # Project owner diff --git a/taiga/projects/template_manager.py b/taiga/projects/template_manager.py deleted file mode 100644 index 08d8b77c..00000000 --- a/taiga/projects/template_manager.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (C) 2014 Andrey Antukh -# Copyright (C) 2014 Jesús Espino -# Copyright (C) 2014 David Barragán -# 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 taiga.projects.models import UserStoryStatus - - -class ProjectTemplateManager(object): - def apply(self, template, project): - if not hasattr(self, "template"): - return False - template = getattr(self, "template") - template(project) - - def legal(self, project): - pass - - def pure_kanban(self, project): - project.is_backlog_activated = False - project.is_kanban_activated = True - project.is_wiki_activated = False - project.is_issues_activated = False - project.save() - - us_status = project.us_statuses.get(order=1) - us_status.name = "To do" - us_status.color = "#999999" - us_status.save() - - us_status = project.us_statuses.get(order=2) - us_status.name = "Doing" - us_status.color = "#ff9900" - us_status.is_closed = False - us_status.save() - - us_status = UserStoryStatus() - us_status.order = 3 - us_status.name = "Done" - us_status.color = "#ffcc00" - us_status.project = project - us_status.is_closed = True - us_status.save() diff --git a/taiga/projects/tests/tests_api.py b/taiga/projects/tests/tests_api.py index 44651753..37bba1f2 100644 --- a/taiga/projects/tests/tests_api.py +++ b/taiga/projects/tests/tests_api.py @@ -24,14 +24,15 @@ from django.core import mail from django.db.models import get_model from taiga.users.tests import create_user -from taiga.projects.models import Project, Membership +from taiga.projects.models import Project, Membership, ProjectTemplate +from taiga.domains.models import Domain from . import create_project from . import add_membership class ProfileTestCase(test.TestCase): - fixtures = ["initial_domains.json"] + fixtures = ["initial_domains.json", "initial_project_templates.json"] def setUp(self): self.user1 = create_user(1, is_superuser=True) @@ -182,7 +183,7 @@ class ProfileTestCase(test.TestCase): class ProjectsTestCase(test.TestCase): - fixtures = ["initial_role.json", "initial_domains.json"] + fixtures = ["initial_domains.json", "initial_project_templates.json"] def setUp(self): self.user1 = create_user(1) @@ -462,3 +463,264 @@ class ProjectsTestCase(test.TestCase): self.assertEqual(response.status_code, 404) self.assertEqual(Project.objects.all().count(), 4) self.client.logout() + +class ProjectTemplatesTestCase(test.TestCase): + fixtures = ["initial_domains.json", "initial_project_templates.json"] + + def setUp(self): + self.user1 = create_user(1) + self.user2 = create_user(2) + self.domain = Domain.objects.all()[0] + self.domain.owner = self.user1 + + def test_list_project_templates_by_anon(self): + response = self.client.get(reverse("project-templates-list")) + self.assertEqual(response.status_code, 401) + + def test_list_project_templates_by_domain_owner(self): + response = self.client.login(username=self.user1.username, + password=self.user1.username) + self.assertTrue(response) + response = self.client.get(reverse("project-templates-list")) + self.assertEqual(response.status_code, 200) + projects_list = response.data + self.assertEqual(len(projects_list), 2) + self.client.logout() + + def test_list_projects_by_not_domain_owner(self): + response = self.client.login(username=self.user2.username, + password=self.user2.username) + self.assertTrue(response) + response = self.client.get(reverse("project-templates-list")) + self.assertEqual(response.status_code, 403) + + def test_view_project_template_by_anon(self): + response = self.client.get(reverse("project-templates-detail", args=(1,))) + self.assertEqual(response.status_code, 401) + + def test_view_project_template_by_domain_owner(self): + response = self.client.login(username=self.user1.username, + password=self.user1.username) + self.assertTrue(response) + response = self.client.get(reverse("project-templates-detail", args=(1,))) + self.assertEqual(response.status_code, 200) + response = self.client.get(reverse("project-templates-detail", args=(2,))) + self.assertEqual(response.status_code, 200) + self.client.logout() + + def test_view_project_template_by_not_domain_owner(self): + response = self.client.login(username=self.user2.username, + password=self.user2.username) + self.assertTrue(response) + response = self.client.get(reverse("project-templates-detail", args=(1,))) + self.assertEqual(response.status_code, 403) + response = self.client.get(reverse("project-templates-detail", args=(2,))) + self.assertEqual(response.status_code, 403) + self.client.logout() + + def test_create_project_template_by_anon(self): + data = { + "name": "Test Project Template", + "slug": "test-project-template", + "description": "A new Test Project Template", + } + + self.assertEqual(ProjectTemplate.objects.all().count(), 2) + response = self.client.post( + reverse("project-templates-list"), + json.dumps(data), + content_type="application/json") + self.assertEqual(response.status_code, 401) + self.assertEqual(ProjectTemplate.objects.all().count(), 2) + + data = { + "name": "Test Project Template 2", + "slug": "test-project-template-2", + "description": "A new Test Project Template", + "domain": 100, + } + + response = self.client.post( + reverse("project-templates-list"), + json.dumps(data), + content_type="application/json") + self.assertEqual(response.status_code, 401) + self.assertEqual(ProjectTemplate.objects.all().count(), 2) + + def test_create_project_template_by_domain_owner(self): + data = { + "name": "Test Project Template", + "slug": "test-project-template", + "description": "A new Test Project Template", + } + + self.assertEqual(ProjectTemplate.objects.all().count(), 2) + response = self.client.login(username=self.user1.username, + password=self.user1.username) + self.assertTrue(response) + response = self.client.post(reverse("project-templates-list"), json.dumps(data), + content_type="application/json") + + self.assertEqual(response.status_code, 201) + self.assertEqual(ProjectTemplate.objects.all().count(), 3) + + data = { + "name": "Test Project Template 2", + "slug": "test-project-template-2", + "description": "A new Test Project Template", + "domain": 100, + } + + response = self.client.login(username=self.user1.username, + password=self.user1.username) + self.assertTrue(response) + response = self.client.post(reverse("project-templates-list"), json.dumps(data), + content_type="application/json") + + self.assertEqual(response.status_code, 201) + self.assertEqual(ProjectTemplate.objects.all().count(), 4) + template = ProjectTemplate.objects.order_by('-created_date')[0] + self.assertEqual(template.domain.id, 1) + + self.client.logout() + + ProjectTemplate.objects.order_by("created_date")[0:2].delete() + + def test_create_project_template_by_not_domain_owner(self): + data = { + "name": "Test Project Template", + "slug": "test-project-template", + "description": "A new Test Project Template", + } + + self.assertEqual(ProjectTemplate.objects.all().count(), 2) + response = self.client.login(username=self.user1.username, + password=self.user1.username) + self.assertTrue(response) + response = self.client.post( + reverse("project-templates-list"), + json.dumps(data), + content_type="application/json") + self.assertEqual(response.status_code, 401) + self.assertEqual(ProjectTemplate.objects.all().count(), 2) + + data = { + "name": "Test Project Template 2", + "slug": "test-project-template-2", + "description": "A new Test Project Template", + "domain": 100 + } + + response = self.client.post( + reverse("project-templates-list"), + json.dumps(data), + content_type="application/json") + self.assertEqual(response.status_code, 401) + self.assertEqual(ProjectTemplate.objects.all().count(), 2) + self.client.logout() + + # def test_edit_project_by_anon(self): + # data = { + # "description": "Edited project description", + # } + + # self.assertEqual(Project.objects.all().count(), 4) + # self.assertNotEqual(data["description"], self.project1.description) + # response = self.client.patch( + # reverse("projects-detail", args=(self.project1.id,)), + # json.dumps(data), + # content_type="application/json") + # self.assertEqual(response.status_code, 401) + # self.assertEqual(Project.objects.all().count(), 4) + + # def test_edit_project_by_owner(self): + # data = { + # "description": "Modified project description", + # } + + # self.assertEqual(Project.objects.all().count(), 4) + # self.assertNotEqual(data["description"], self.project1.description) + # response = self.client.login(username=self.user1.username, + # password=self.user1.username) + # self.assertTrue(response) + # response = self.client.patch( + # reverse("projects-detail", args=(self.project1.id,)), + # json.dumps(data), + # content_type="application/json") + # self.assertEqual(response.status_code, 200) + # self.assertEqual(data["description"], response.data["description"]) + # self.assertEqual(Project.objects.all().count(), 4) + # self.client.logout() + + # def test_edit_project_by_membership(self): + # data = { + # "description": "Edited project description", + # } + + # self.assertEqual(Project.objects.all().count(), 4) + # self.assertNotEqual(data["description"], self.project1.description) + # response = self.client.login(username=self.user3.username, + # password=self.user3.username) + # self.assertTrue(response) + # response = self.client.patch( + # reverse("projects-detail", args=(self.project1.id,)), + # json.dumps(data), + # content_type="application/json") + # self.assertEqual(response.status_code, 200) + # self.assertEqual(data["description"], response.data["description"]) + # self.assertEqual(Project.objects.all().count(), 4) + # self.client.logout() + + # def test_edit_project_by_not_membership(self): + # data = { + # "description": "Edited project description", + # } + + # self.assertEqual(Project.objects.all().count(), 4) + # self.assertNotEqual(data["description"], self.project1.description) + # response = self.client.login(username=self.user2.username, + # password=self.user2.username) + # self.assertTrue(response) + # response = self.client.patch( + # reverse("projects-detail", args=(self.project1.id,)), + # json.dumps(data), + # content_type="application/json") + # self.assertEqual(response.status_code, 404) + # self.assertEqual(Project.objects.all().count(), 4) + # self.client.logout() + + # def test_delete_project_by_anon(self): + # self.assertEqual(Project.objects.all().count(), 4) + # response = self.client.delete(reverse("projects-detail", args=(self.project1.id,))) + # self.assertEqual(response.status_code, 401) + # self.assertEqual(Project.objects.all().count(), 4) + + # def test_delete_project_by_owner(self): + # self.assertEqual(Project.objects.all().count(), 4) + # response = self.client.login(username=self.user1.username, + # password=self.user1.username) + # self.assertTrue(response) + # response = self.client.delete(reverse("projects-detail", args=(self.project1.id,))) + # self.assertEqual(response.status_code, 204) + # self.assertEqual(Project.objects.all().count(), 3) + # self.client.logout() + + # def test_delete_project_by_membership(self): + # self.assertEqual(Project.objects.all().count(), 4) + # response = self.client.login(username=self.user3.username, + # password=self.user3.username) + # self.assertTrue(response) + # response = self.client.delete(reverse("projects-detail", args=(self.project1.id,))) + # self.assertEqual(response.status_code, 403) + # self.assertEqual(Project.objects.all().count(), 4) + # self.client.logout() + + # def test_delete_project_by_not_membership(self): + # self.assertEqual(Project.objects.all().count(), 4) + # response = self.client.login(username=self.user1.username, + # password=self.user1.username) + # self.assertTrue(response) + # response = self.client.delete(reverse("projects-detail", args=(self.project3.id,))) + # self.assertEqual(response.status_code, 404) + # self.assertEqual(Project.objects.all().count(), 4) + # self.client.logout() diff --git a/taiga/projects/tests/tests_notifications.py b/taiga/projects/tests/tests_notifications.py index f20cff71..ae33602e 100644 --- a/taiga/projects/tests/tests_notifications.py +++ b/taiga/projects/tests/tests_notifications.py @@ -32,7 +32,7 @@ from . import create_project from . import add_membership class AllProjectEventsNotificationsTestCase(test.TestCase): - fixtures = ["initial_domains.json"] + fixtures = ["initial_domains.json", "initial_project_templates.json"] def setUp(self): self.user1 = create_user(1) @@ -82,7 +82,7 @@ class AllProjectEventsNotificationsTestCase(test.TestCase): self.user1.save() class OnlyAssigendNotificationsTestCase(test.TestCase): - fixtures = ["initial_domains.json"] + fixtures = ["initial_domains.json", "initial_project_templates.json"] def setUp(self): self.user1 = create_user(1) @@ -153,7 +153,7 @@ class OnlyAssigendNotificationsTestCase(test.TestCase): self.user1.save() class OnlyOwnerNotificationsTestCase(test.TestCase): - fixtures = ["initial_domains.json"] + fixtures = ["initial_domains.json", "initial_project_templates.json"] def setUp(self): self.user1 = create_user(1) diff --git a/taiga/projects/userstories/tests/tests_api.py b/taiga/projects/userstories/tests/tests_api.py index 5f8a4c70..fe396610 100644 --- a/taiga/projects/userstories/tests/tests_api.py +++ b/taiga/projects/userstories/tests/tests_api.py @@ -33,7 +33,7 @@ import reversion class UserStoriesTestCase(test.TestCase): - fixtures = ["initial_domains.json"] + fixtures = ["initial_domains.json", "initial_project_templates.json"] def setUp(self): self.user1 = create_user(1) # Project owner diff --git a/taiga/projects/userstories/tests/tests_services.py b/taiga/projects/userstories/tests/tests_services.py index dd5d1814..2c90daa9 100644 --- a/taiga/projects/userstories/tests/tests_services.py +++ b/taiga/projects/userstories/tests/tests_services.py @@ -26,7 +26,7 @@ from . import create_userstory class UserStoriesServiceTestCase(test.TestCase): - fixtures = ["initial_domains.json"] + fixtures = ["initial_domains.json", "initial_project_templates.json"] def setUp(self): self.user1 = create_user(1) # Project owner diff --git a/taiga/projects/wiki/tests/tests_api.py b/taiga/projects/wiki/tests/tests_api.py index 4a5ef876..90936111 100644 --- a/taiga/projects/wiki/tests/tests_api.py +++ b/taiga/projects/wiki/tests/tests_api.py @@ -30,7 +30,7 @@ from . import create_wiki_page class WikiPagesTestCase(test.TestCase): - fixtures = ["initial_domains.json"] + fixtures = ["initial_domains.json", "initial_project_templates.json"] def setUp(self): self.user1 = create_user(1) diff --git a/taiga/routers.py b/taiga/routers.py index d9f50b27..e1f80c6b 100644 --- a/taiga/routers.py +++ b/taiga/routers.py @@ -64,9 +64,11 @@ from taiga.projects.api import IssueStatusViewSet from taiga.projects.api import IssueTypeViewSet from taiga.projects.api import PriorityViewSet from taiga.projects.api import SeverityViewSet +from taiga.projects.api import ProjectTemplateViewSet router.register(r"roles", RolesViewSet, base_name="roles") router.register(r"projects", ProjectViewSet, base_name="projects") +router.register(r"project-templates", ProjectTemplateViewSet, base_name="project-templates") router.register(r"memberships", MembershipViewSet, base_name="memberships") router.register(r"invitations", InvitationViewSet, base_name="invitations") router.register(r"userstory-statuses", UserStoryStatusViewSet, base_name="userstory-statuses")