From c98adad07534adc1cf92e2ac444a5ac2b69a535b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?= Date: Wed, 9 Oct 2013 16:41:04 +0200 Subject: [PATCH] Refactor: Moved some models to projects app --- .../base/users/fixtures/initial_role.json | 42 ++-- greenmine/projects/admin.py | 56 +++++ greenmine/projects/api.py | 74 ++++++- greenmine/projects/issues/admin.py | 25 --- greenmine/projects/issues/api.py | 33 +-- greenmine/projects/issues/models.py | 87 +------- greenmine/projects/issues/permissions.py | 36 ---- greenmine/projects/issues/serializers.py | 20 -- greenmine/projects/models.py | 191 ++++++++++++++++-- greenmine/projects/permissions.py | 82 ++++++++ greenmine/projects/questions/admin.py | 6 - greenmine/projects/questions/api.py | 10 +- greenmine/projects/questions/models.py | 23 +-- greenmine/projects/questions/permissions.py | 9 - greenmine/projects/questions/serializers.py | 5 - greenmine/projects/serializers.py | 48 +++++ greenmine/projects/tasks/admin.py | 8 - greenmine/projects/tasks/api.py | 10 +- greenmine/projects/tasks/models.py | 22 +- greenmine/projects/tasks/permissions.py | 9 - greenmine/projects/tasks/serializers.py | 5 - greenmine/projects/userstories/admin.py | 12 -- greenmine/projects/userstories/api.py | 18 +- greenmine/projects/userstories/models.py | 46 +---- greenmine/projects/userstories/permissions.py | 18 -- greenmine/projects/userstories/serializers.py | 11 - greenmine/routers.py | 45 +++-- 27 files changed, 494 insertions(+), 457 deletions(-) diff --git a/greenmine/base/users/fixtures/initial_role.json b/greenmine/base/users/fixtures/initial_role.json index 4a53be0f..0a606a39 100644 --- a/greenmine/base/users/fixtures/initial_role.json +++ b/greenmine/base/users/fixtures/initial_role.json @@ -206,32 +206,32 @@ ], [ "add_issuestatus", - "issues", + "projects", "issuestatus" ], [ "change_issuestatus", - "issues", + "projects", "issuestatus" ], [ "delete_issuestatus", - "issues", + "projects", "issuestatus" ], [ "add_issuetype", - "issues", + "projects", "issuetype" ], [ "change_issuetype", - "issues", + "projects", "issuetype" ], [ "delete_issuetype", - "issues", + "projects", "issuetype" ], [ @@ -271,32 +271,32 @@ ], [ "add_points", - "userstories", + "projects", "points" ], [ "change_points", - "userstories", + "projects", "points" ], [ "delete_points", - "userstories", + "projects", "points" ], [ "add_priority", - "issues", + "projects", "priority" ], [ "change_priority", - "issues", + "projects", "priority" ], [ "delete_priority", - "issues", + "projects", "priority" ], [ @@ -346,17 +346,17 @@ ], [ "add_severity", - "issues", + "projects", "severity" ], [ "change_severity", - "issues", + "projects", "severity" ], [ "delete_severity", - "issues", + "projects", "severity" ], [ @@ -416,17 +416,17 @@ ], [ "add_taskstatus", - "tasks", + "projects", "taskstatus" ], [ "change_taskstatus", - "tasks", + "projects", "taskstatus" ], [ "delete_taskstatus", - "tasks", + "projects", "taskstatus" ], [ @@ -466,17 +466,17 @@ ], [ "add_userstorystatus", - "userstories", + "projects", "userstorystatus" ], [ "change_userstorystatus", - "userstories", + "projects", "userstorystatus" ], [ "delete_userstorystatus", - "userstories", + "projects", "userstorystatus" ], [ diff --git a/greenmine/projects/admin.py b/greenmine/projects/admin.py index a0a76973..d97e0eeb 100644 --- a/greenmine/projects/admin.py +++ b/greenmine/projects/admin.py @@ -34,3 +34,59 @@ class ProjectAdmin(reversion.VersionAdmin): # inlines = [MembershipInline, MilestoneInline] admin.site.register(models.Project, ProjectAdmin) + + +# User Stories common admins + +class PointsAdmin(admin.ModelAdmin): + list_display = ["name", "order", "project"] + +admin.site.register(models.Points, PointsAdmin) + + +class UserStoryStatusAdmin(admin.ModelAdmin): + list_display = ["name", "order", "is_closed", "project"] + +admin.site.register(models.UserStoryStatus, UserStoryStatusAdmin) + + +# Tasks common admins + +class TaskStatusAdmin(admin.ModelAdmin): + list_display = ["name", "order", "is_closed", "project"] + +admin.site.register(models.TaskStatus, TaskStatusAdmin) + + +# Issues common admins + +class SeverityAdmin(admin.ModelAdmin): + list_display = ["name", "order", "project"] + +admin.site.register(models.Severity, SeverityAdmin) + + +class PriorityAdmin(admin.ModelAdmin): + list_display = ["name", "order", "project"] + +admin.site.register(models.Priority, PriorityAdmin) + + +class IssueTypeAdmin(admin.ModelAdmin): + list_display = ["name", "order", "project"] + +admin.site.register(models.IssueType, IssueTypeAdmin) + + +class IssueStatusAdmin(admin.ModelAdmin): + list_display = ["name", "order", "is_closed", "project"] + +admin.site.register(models.IssueStatus, IssueStatusAdmin) + + +# Questions common admins + +class QuestionStatusAdmin(admin.ModelAdmin): + list_display = ["name", "order", "is_closed", "project"] + +admin.site.register(models.QuestionStatus, QuestionStatusAdmin) diff --git a/greenmine/projects/api.py b/greenmine/projects/api.py index d56132ac..f334dc1a 100644 --- a/greenmine/projects/api.py +++ b/greenmine/projects/api.py @@ -5,7 +5,7 @@ from django.db.models import Q from rest_framework.permissions import IsAuthenticated from greenmine.base import filters -from greenmine.base.api import ModelCrudViewSet +from greenmine.base.api import ModelCrudViewSet, ModelListViewSet from greenmine.base.notifications.api import NotificationSenderMixin from . import serializers @@ -27,3 +27,75 @@ class ProjectViewSet(ModelCrudViewSet): def pre_save(self, obj): super(ProjectViewSet, self).pre_save(obj) obj.owner = self.request.user + + +# User Stories commin ViewSets + +class PointsViewSet(ModelListViewSet): + model = models.Points + serializer_class = serializers.PointsSerializer + permission_classes = (IsAuthenticated, permissions.PointsPermission) + filter_backends = (filters.IsProjectMemberFilterBackend,) + filter_fields = ('project',) + + +class UserStoryStatusViewSet(ModelListViewSet): + model = models.UserStoryStatus + serializer_class = serializers.UserStoryStatusSerializer + permission_classes = (IsAuthenticated, permissions.UserStoryStatusPermission) + filter_backends = (filters.IsProjectMemberFilterBackend,) + filter_fields = ('project',) + + +# Tasks commin ViewSets + +class TaskStatusViewSet(ModelListViewSet): + model = models.TaskStatus + serializer_class = serializers.TaskStatusSerializer + permission_classes = (IsAuthenticated, permissions.TaskStatusPermission) + filter_backends = (filters.IsProjectMemberFilterBackend,) + filter_fields = ("project",) + + +# Issues commin ViewSets + +class SeverityViewSet(ModelListViewSet): + model = models.Severity + serializer_class = serializers.SeveritySerializer + permission_classes = (IsAuthenticated, permissions.SeverityPermission) + filter_backends = (filters.IsProjectMemberFilterBackend,) + filter_fields = ("project",) + + +class PriorityViewSet(ModelListViewSet): + model = models.Priority + serializer_class = serializers.PrioritySerializer + permission_classes = (IsAuthenticated, permissions.PriorityPermission) + filter_backends = (filters.IsProjectMemberFilterBackend,) + filter_fields = ("project",) + + +class IssueTypeViewSet(ModelListViewSet): + model = models.IssueType + serializer_class = serializers.IssueTypeSerializer + permission_classes = (IsAuthenticated, permissions.IssueTypePermission) + filter_backends = (filters.IsProjectMemberFilterBackend,) + filter_fields = ("project",) + + +class IssueStatusViewSet(ModelListViewSet): + model = models.IssueStatus + serializer_class = serializers.IssueStatusSerializer + permission_classes = (IsAuthenticated, permissions.IssueStatusPermission) + filter_backends = (filters.IsProjectMemberFilterBackend,) + filter_fields = ("project",) + + +# Questions commin ViewSets + +class QuestionStatusViewSet(ModelListViewSet): + model = models.QuestionStatus + serializer_class = serializers.QuestionStatusSerializer + permission_classes = (IsAuthenticated, permissions.QuestionStatusPermission) + filter_backends = (filters.IsProjectMemberFilterBackend,) + filter_fields = ("project",) diff --git a/greenmine/projects/issues/admin.py b/greenmine/projects/issues/admin.py index 1050895c..57c37831 100644 --- a/greenmine/projects/issues/admin.py +++ b/greenmine/projects/issues/admin.py @@ -7,31 +7,6 @@ from . import models import reversion - -class SeverityAdmin(admin.ModelAdmin): - list_display = ["name", "order", "project"] - -admin.site.register(models.Severity, SeverityAdmin) - - -class PriorityAdmin(admin.ModelAdmin): - list_display = ["name", "order", "project"] - -admin.site.register(models.Priority, PriorityAdmin) - - -class IssueTypeAdmin(admin.ModelAdmin): - list_display = ["name", "order", "project"] - -admin.site.register(models.IssueType, IssueTypeAdmin) - - -class IssueStatusAdmin(admin.ModelAdmin): - list_display = ["name", "order", "is_closed", "project"] - -admin.site.register(models.IssueStatus, IssueStatusAdmin) - - class IssueAdmin(reversion.VersionAdmin): list_display = ["subject", "type"] diff --git a/greenmine/projects/issues/api.py b/greenmine/projects/issues/api.py index 3a1e68ba..04fcabaf 100644 --- a/greenmine/projects/issues/api.py +++ b/greenmine/projects/issues/api.py @@ -5,7 +5,7 @@ from django.contrib.contenttypes.models import ContentType from rest_framework.permissions import IsAuthenticated from greenmine.base import filters -from greenmine.base.api import ModelCrudViewSet, ModelListViewSet +from greenmine.base.api import ModelCrudViewSet from greenmine.base.notifications.api import NotificationSenderMixin from greenmine.projects.permissions import AttachmentPermission from greenmine.projects.serializers import AttachmentSerializer @@ -17,37 +17,6 @@ from . import serializers import reversion -class SeverityViewSet(ModelListViewSet): - model = models.Severity - serializer_class = serializers.SeveritySerializer - permission_classes = (IsAuthenticated, permissions.SeverityPermission) - filter_backends = (filters.IsProjectMemberFilterBackend,) - filter_fields = ("project",) - - -class PriorityViewSet(ModelListViewSet): - model = models.Priority - serializer_class = serializers.PrioritySerializer - permission_classes = (IsAuthenticated, permissions.PriorityPermission) - filter_backends = (filters.IsProjectMemberFilterBackend,) - filter_fields = ("project",) - - -class IssueTypeViewSet(ModelListViewSet): - model = models.IssueType - serializer_class = serializers.IssueTypeSerializer - permission_classes = (IsAuthenticated, permissions.IssueTypePermission) - filter_backends = (filters.IsProjectMemberFilterBackend,) - filter_fields = ("project",) - - -class IssueStatusViewSet(ModelListViewSet): - model = models.IssueStatus - serializer_class = serializers.IssueStatusSerializer - permission_classes = (IsAuthenticated, permissions.IssueStatusPermission) - filter_backends = (filters.IsProjectMemberFilterBackend,) - filter_fields = ("project",) - class IssueAttachmentViewSet(ModelCrudViewSet): model = Attachment diff --git a/greenmine/projects/issues/models.py b/greenmine/projects/issues/models.py index df5ed220..dd0e9488 100644 --- a/greenmine/projects/issues/models.py +++ b/greenmine/projects/issues/models.py @@ -14,72 +14,6 @@ from greenmine.base.notifications.models import WatchedMixin import reversion -class Priority(models.Model): - name = models.CharField(max_length=255, null=False, blank=False, verbose_name=_("name")) - order = models.IntegerField(default=10, null=False, blank=False, verbose_name=_("order")) - project = models.ForeignKey("projects.Project", null=False, blank=False, - related_name="priorities", verbose_name=_("project")) - - class Meta: - verbose_name = u"priority" - verbose_name_plural = u"priorities" - ordering = ["project", "name"] - unique_together = ("project", "name") - - def __str__(self): - return u"project {0} - {1}".format(self.project_id, self.name) - - -class Severity(models.Model): - name = models.CharField(max_length=255, null=False, blank=False, verbose_name=_("name")) - order = models.IntegerField(default=10, null=False, blank=False, verbose_name=_("order")) - project = models.ForeignKey("projects.Project", null=False, blank=False, - related_name="severities", verbose_name=_("project")) - - class Meta: - verbose_name = u"severity" - verbose_name_plural = u"severities" - ordering = ["project", "name"] - unique_together = ("project", "name") - - def __str__(self): - return u"project {0} - {1}".format(self.project_id, self.name) - - -class IssueStatus(models.Model): - name = models.CharField(max_length=255, null=False, blank=False, verbose_name=_("name")) - order = models.IntegerField(default=10, null=False, blank=False, verbose_name=_("order")) - is_closed = models.BooleanField(default=False, null=False, blank=True, - verbose_name=_("is closed")) - project = models.ForeignKey("projects.Project", null=False, blank=False, - related_name="issue_statuses", verbose_name=_("project")) - - class Meta: - verbose_name = u"issue status" - verbose_name_plural = u"issue statuses" - ordering = ["project", "name"] - unique_together = ("project", "name") - - def __str__(self): - return u"project {0} - {1}".format(self.project_id, self.name) - - -class IssueType(models.Model): - name = models.CharField(max_length=255, null=False, blank=False, verbose_name=_("name")) - order = models.IntegerField(default=10, null=False, blank=False, verbose_name=_("order")) - project = models.ForeignKey("projects.Project", null=False, blank=False, - related_name="issue_types", verbose_name=_("project")) - - class Meta: - verbose_name = u"issue type" - verbose_name_plural = u"issue types" - ordering = ["project", "name"] - unique_together = ("project", "name") - - def __str__(self): - return u"project {0} - {1}".format(self.project_id, self.name) - - class Issue(models.Model, WatchedMixin): uuid = models.CharField(max_length=40, unique=True, null=False, blank=True, verbose_name=_("uuid")) @@ -87,16 +21,17 @@ class Issue(models.Model, WatchedMixin): verbose_name=_("ref")) owner = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, default=None, related_name="owned_issues", verbose_name=_("owner")) - status = models.ForeignKey("IssueStatus", null=False, blank=False, related_name="issues", - verbose_name=_("status")) - severity = models.ForeignKey("Severity", null=False, blank=False, related_name="issues", - verbose_name=_("severity")) - priority = models.ForeignKey("Priority", null=False, blank=False, related_name="issues", - verbose_name=_("priority")) - type = models.ForeignKey("IssueType", null=False, blank=False, related_name="issues", - verbose_name=_("type")) - milestone = models.ForeignKey("milestones.Milestone", null=True, blank=True, default=None, - related_name="issues", verbose_name=_("milestone")) + status = models.ForeignKey("projects.IssueStatus", null=False, blank=False, + related_name="issues", verbose_name=_("status")) + severity = models.ForeignKey("projects.Severity", null=False, blank=False, + related_name="issues", verbose_name=_("severity")) + priority = models.ForeignKey("projects.Priority", null=False, blank=False, + related_name="issues", verbose_name=_("priority")) + type = models.ForeignKey("projects.IssueType", null=False, blank=False, + related_name="issues", verbose_name=_("type")) + milestone = models.ForeignKey("milestones.Milestone", null=True, blank=True, + default=None, related_name="issues", + verbose_name=_("milestone")) project = models.ForeignKey("projects.Project", null=False, blank=False, related_name="issues", verbose_name=_("project")) created_date = models.DateTimeField(auto_now_add=True, null=False, blank=False, diff --git a/greenmine/projects/issues/permissions.py b/greenmine/projects/issues/permissions.py index 6b334c87..85d30771 100644 --- a/greenmine/projects/issues/permissions.py +++ b/greenmine/projects/issues/permissions.py @@ -3,42 +3,6 @@ from greenmine.base.permissions import BasePermission -class SeverityPermission(BasePermission): - get_permission = "view_severity" - put_permission = "change_severity" - patch_permission = "change_severity" - delete_permission = "delete_severity" - safe_methods = ["HEAD", "OPTIONS"] - path_to_project = ["project"] - - -class PriorityPermission(BasePermission): - get_permission = "view_priority" - put_permission = "change_priority" - patch_permission = "change_priority" - delete_permission = "delete_priority" - safe_methods = ["HEAD", "OPTIONS"] - path_to_project = ["project"] - - -class IssueStatusPermission(BasePermission): - get_permission = "view_issuestatus" - put_permission = "change_issuestatus" - patch_permission = "change_issuestatus" - delete_permission = "delete_issuestatus" - safe_methods = ["HEAD", "OPTIONS"] - path_to_project = ["project"] - - -class IssueTypePermission(BasePermission): - get_permission = "view_issuetype" - put_permission = "severity_issuetype" - patch_permission = "severity_issuetype" - delete_permission = "delete_issuetype" - safe_methods = ["HEAD", "OPTIONS"] - path_to_project = ["project"] - - class IssuePermission(BasePermission): get_permission = "view_issue" put_permission = "change_issue" diff --git a/greenmine/projects/issues/serializers.py b/greenmine/projects/issues/serializers.py index 1a6b2b50..cfa10a7c 100644 --- a/greenmine/projects/issues/serializers.py +++ b/greenmine/projects/issues/serializers.py @@ -9,26 +9,6 @@ from . import models import reversion -class SeveritySerializer(serializers.ModelSerializer): - class Meta: - model = models.Severity - - -class PrioritySerializer(serializers.ModelSerializer): - class Meta: - model = models.Priority - - -class IssueStatusSerializer(serializers.ModelSerializer): - class Meta: - model = models.IssueStatus - - -class IssueTypeSerializer(serializers.ModelSerializer): - class Meta: - model = models.IssueType - - class IssueSerializer(serializers.ModelSerializer): tags = PickleField() comment = serializers.SerializerMethodField("get_comment") diff --git a/greenmine/projects/models.py b/greenmine/projects/models.py index 23f94b0e..c67426d5 100644 --- a/greenmine/projects/models.py +++ b/greenmine/projects/models.py @@ -151,6 +151,161 @@ class Project(models.Model): rp_query.delete() +# User Stories common Models + +class UserStoryStatus(models.Model): + name = models.CharField(max_length=255, null=False, blank=False, + verbose_name=_("name")) + order = models.IntegerField(default=10, null=False, blank=False, + verbose_name=_("order")) + is_closed = models.BooleanField(default=False, null=False, blank=True, + verbose_name=_("is closed")) + project = models.ForeignKey("Project", null=False, blank=False, + related_name="us_statuses", verbose_name=_("project")) + + class Meta: + verbose_name = u"user story status" + verbose_name_plural = u"user story statuses" + ordering = ["project", "name"] + unique_together = ("project", "name") + + def __str__(self): + return u"project {0} - {1}".format(self.project_id, self.name) + + +class Points(models.Model): + name = models.CharField(max_length=255, null=False, blank=False, + verbose_name=_("name")) + order = models.IntegerField(default=10, null=False, blank=False, + verbose_name=_("order")) + value = models.FloatField(default=None, null=True, blank=True, + verbose_name=_("value")) + project = models.ForeignKey("Project", null=False, blank=False, + related_name="points", verbose_name=_("project")) + + class Meta: + verbose_name = u"point" + verbose_name_plural = u"points" + ordering = ["project", "name"] + unique_together = ("project", "name") + + def __str__(self): + return u"project {0} - {1}".format(self.project_id, self.name) + + +# Tasks common models + +class TaskStatus(models.Model): + name = models.CharField(max_length=255, null=False, blank=False, verbose_name=_("name")) + order = models.IntegerField(default=10, null=False, blank=False, verbose_name=_("order")) + is_closed = models.BooleanField(default=False, null=False, blank=True, + verbose_name=_("is closed")) + color = models.CharField(max_length=20, null=False, blank=False, default="#999999", + verbose_name=_("color")) + project = models.ForeignKey("Project", null=False, blank=False, + related_name="task_statuses", verbose_name=_("project")) + + class Meta: + verbose_name = u"task status" + verbose_name_plural = u"task statuses" + ordering = ["project", "name"] + unique_together = ("project", "name") + + def __str__(self): + return u"project {0} - {1}".format(self.project_id, self.name) + + +# Issue common Models + +class Priority(models.Model): + name = models.CharField(max_length=255, null=False, blank=False, verbose_name=_("name")) + order = models.IntegerField(default=10, null=False, blank=False, verbose_name=_("order")) + project = models.ForeignKey("Project", null=False, blank=False, + related_name="priorities", verbose_name=_("project")) + + class Meta: + verbose_name = u"priority" + verbose_name_plural = u"priorities" + ordering = ["project", "name"] + unique_together = ("project", "name") + + def __str__(self): + return u"project {0} - {1}".format(self.project_id, self.name) + + +class Severity(models.Model): + name = models.CharField(max_length=255, null=False, blank=False, verbose_name=_("name")) + order = models.IntegerField(default=10, null=False, blank=False, verbose_name=_("order")) + project = models.ForeignKey("Project", null=False, blank=False, + related_name="severities", verbose_name=_("project")) + + class Meta: + verbose_name = u"severity" + verbose_name_plural = u"severities" + ordering = ["project", "name"] + unique_together = ("project", "name") + + def __str__(self): + return u"project {0} - {1}".format(self.project_id, self.name) + + +class IssueStatus(models.Model): + name = models.CharField(max_length=255, null=False, blank=False, verbose_name=_("name")) + order = models.IntegerField(default=10, null=False, blank=False, verbose_name=_("order")) + is_closed = models.BooleanField(default=False, null=False, blank=True, + verbose_name=_("is closed")) + project = models.ForeignKey("Project", null=False, blank=False, + related_name="issue_statuses", verbose_name=_("project")) + + class Meta: + verbose_name = u"issue status" + verbose_name_plural = u"issue statuses" + ordering = ["project", "name"] + unique_together = ("project", "name") + + def __str__(self): + return u"project {0} - {1}".format(self.project_id, self.name) + + +class IssueType(models.Model): + name = models.CharField(max_length=255, null=False, blank=False, verbose_name=_("name")) + order = models.IntegerField(default=10, null=False, blank=False, verbose_name=_("order")) + project = models.ForeignKey("Project", null=False, blank=False, + related_name="issue_types", verbose_name=_("project")) + + class Meta: + verbose_name = u"issue type" + verbose_name_plural = u"issue types" + ordering = ["project", "name"] + unique_together = ("project", "name") + + def __str__(self): + return u"project {0} - {1}".format(self.project_id, self.name) + + +# Questions common models + +class QuestionStatus(models.Model): + name = models.CharField(max_length=255, null=False, blank=False, + verbose_name=_("name")) + order = models.IntegerField(default=10, null=False, blank=False, + verbose_name=_("order")) + is_closed = models.BooleanField(default=False, null=False, blank=True, + verbose_name=_("is closed")) + project = models.ForeignKey("Project", null=False, blank=False, + related_name="question_status", + verbose_name=_("project")) + + class Meta: + verbose_name = u"question status" + verbose_name_plural = u"question status" + ordering = ["project", "name"] + unique_together = ("project", "name") + + def __str__(self): + return u"project {0} - {1}".format(self.project_id, self.name) + + # Reversion registration (usufull for base.notification and for meke a historical) reversion.register(Project) @@ -178,40 +333,36 @@ def project_post_save(sender, instance, created, **kwargs): if not created: return - points_model = get_model("userstories", "Points") - userstorystatus_model = get_model("userstories", "UserStoryStatus") - taskstatus_model = get_model("tasks", "TaskStatus") - severity_model = get_model("issues", "Severity") - priority_model = get_model("issues", "Priority") - issuestatus_model = get_model("issues", "IssueStatus") - issuetype_model = get_model("issues", "IssueType") - questionstatus_model = get_model("questions", "QuestionStatus") - # Populate new project dependen default data - for order, name in choices.PRIORITY_CHOICES: - priority_model.objects.create(project=instance, name=name, order=order) - - for order, name in choices.SEVERITY_CHOICES: - severity_model.objects.create(project=instance, name=name, order=order) + # USs for order, name, value in choices.POINTS_CHOICES: - points_model.objects.create(project=instance, name=name, order=order, value=value) + Points.objects.create(project=instance, name=name, order=order, value=value) for order, name, is_closed in choices.US_STATUSES: - userstorystatus_model.objects.create(name=name, order=order, + UserStoryStatus.objects.create(name=name, order=order, is_closed=is_closed, project=instance) + # Tasks for order, name, is_closed, color in choices.TASK_STATUSES: - taskstatus_model.objects.create(name=name, order=order, color=color, + TaskStatus.objects.create(name=name, order=order, color=color, is_closed=is_closed, project=instance) + # Issues + for order, name in choices.PRIORITY_CHOICES: + Priority.objects.create(project=instance, name=name, order=order) + + for order, name in choices.SEVERITY_CHOICES: + Severity.objects.create(project=instance, name=name, order=order) + for order, name, is_closed in choices.ISSUE_STATUSES: - issuestatus_model.objects.create(name=name, order=order, + IssueStatus.objects.create(name=name, order=order, is_closed=is_closed, project=instance) for order, name in choices.ISSUE_TYPES: - issuetype_model.objects.create(project=instance, name=name, order=order) + IssueType.objects.create(project=instance, name=name, order=order) + # Questions for order, name, is_closed in choices.QUESTION_STATUS: - questionstatus_model.objects.create(name=name, order=order, + QuestionStatus.objects.create(name=name, order=order, is_closed=is_closed, project=instance) diff --git a/greenmine/projects/permissions.py b/greenmine/projects/permissions.py index 3f13ee0e..755577a4 100644 --- a/greenmine/projects/permissions.py +++ b/greenmine/projects/permissions.py @@ -19,3 +19,85 @@ class AttachmentPermission(BasePermission): delete_permission = "delete_attachment" safe_methods = ["HEAD", "OPTIONS"] path_to_project = ["project"] + + +# User Stories + +class PointsPermission(BasePermission): + get_permission = "view_points" + put_permission = "severity_points" + patch_permission = "severity_points" + delete_permission = "delete_points" + safe_methods = ["HEAD", "OPTIONS"] + path_to_project = ["project"] + + +class UserStoryStatusPermission(BasePermission): + get_permission = "view_userstorystatus" + put_permission = "change_userstorystatus" + patch_permission = "change_userstorystatus" + delete_permission = "delete_userstorystatus" + safe_methods = ["HEAD", "OPTIONS"] + path_to_project = ["project"] + + +# Tasks + +class TaskStatusPermission(BasePermission): + get_permission = "view_taskstatus" + put_permission = "change_taskstatus" + patch_permission = "change_taskstatus" + delete_permission = "delete_taskstatus" + safe_methods = ["HEAD", "OPTIONS"] + path_to_project = ["project"] + + +# Issues + +class SeverityPermission(BasePermission): + get_permission = "view_severity" + put_permission = "change_severity" + patch_permission = "change_severity" + delete_permission = "delete_severity" + safe_methods = ["HEAD", "OPTIONS"] + path_to_project = ["project"] + + +class PriorityPermission(BasePermission): + get_permission = "view_priority" + put_permission = "change_priority" + patch_permission = "change_priority" + delete_permission = "delete_priority" + safe_methods = ["HEAD", "OPTIONS"] + path_to_project = ["project"] + + +class IssueStatusPermission(BasePermission): + get_permission = "view_issuestatus" + put_permission = "change_issuestatus" + patch_permission = "change_issuestatus" + delete_permission = "delete_issuestatus" + safe_methods = ["HEAD", "OPTIONS"] + path_to_project = ["project"] + + +class IssueTypePermission(BasePermission): + get_permission = "view_issuetype" + put_permission = "severity_issuetype" + patch_permission = "severity_issuetype" + delete_permission = "delete_issuetype" + safe_methods = ["HEAD", "OPTIONS"] + path_to_project = ["project"] + + +# Questions + +class QuestionStatusPermission(BasePermission): + get_permission = "view_questionstatus" + put_permission = "change_questionstatus" + patch_permission = "change_questionstatus" + delete_permission = "delete_questionstatus" + safe_methods = ["HEAD", "OPTIONS"] + path_to_project = ["project"] + + diff --git a/greenmine/projects/questions/admin.py b/greenmine/projects/questions/admin.py index c18a5f52..a0e2044c 100644 --- a/greenmine/projects/questions/admin.py +++ b/greenmine/projects/questions/admin.py @@ -7,12 +7,6 @@ from . import models import reversion -class QuestionStatusAdmin(admin.ModelAdmin): - list_display = ["name", "order", "is_closed", "project"] - -admin.site.register(models.QuestionStatus, QuestionStatusAdmin) - - class QuestionAdmin(reversion.VersionAdmin): list_display = ["subject", "project", "owner"] diff --git a/greenmine/projects/questions/api.py b/greenmine/projects/questions/api.py index e5356e97..384d4b1d 100644 --- a/greenmine/projects/questions/api.py +++ b/greenmine/projects/questions/api.py @@ -5,7 +5,7 @@ from django.contrib.contenttypes.models import ContentType from rest_framework.permissions import IsAuthenticated from greenmine.base import filters -from greenmine.base.api import ModelCrudViewSet, ModelListViewSet +from greenmine.base.api import ModelCrudViewSet from greenmine.base.notifications.api import NotificationSenderMixin from greenmine.projects.permissions import AttachmentPermission from greenmine.projects.serializers import AttachmentSerializer @@ -18,14 +18,6 @@ from . import permissions import reversion -class QuestionStatusViewSet(ModelListViewSet): - model = models.QuestionStatus - serializer_class = serializers.QuestionStatusSerializer - permission_classes = (IsAuthenticated, permissions.QuestionStatusPermission) - filter_backends = (filters.IsProjectMemberFilterBackend,) - filter_fields = ("project",) - - class QuestionAttachmentViewSet(ModelCrudViewSet): model = Attachment serializer_class = AttachmentSerializer diff --git a/greenmine/projects/questions/models.py b/greenmine/projects/questions/models.py index 830a1948..24306107 100644 --- a/greenmine/projects/questions/models.py +++ b/greenmine/projects/questions/models.py @@ -14,33 +14,12 @@ from picklefield.fields import PickledObjectField import reversion -class QuestionStatus(models.Model): - name = models.CharField(max_length=255, null=False, blank=False, - verbose_name=_("name")) - order = models.IntegerField(default=10, null=False, blank=False, - verbose_name=_("order")) - is_closed = models.BooleanField(default=False, null=False, blank=True, - verbose_name=_("is closed")) - project = models.ForeignKey("projects.Project", null=False, blank=False, - related_name="question_status", - verbose_name=_("project")) - - class Meta: - verbose_name = u"question status" - verbose_name_plural = u"question status" - ordering = ["project", "name"] - unique_together = ("project", "name") - - def __str__(self): - return u"project {0} - {1}".format(self.project_id, self.name) - - class Question(models.Model, WatchedMixin): ref = models.BigIntegerField(db_index=True, null=True, blank=True, default=None, verbose_name=_("ref")) owner = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, default=None, related_name="owned_questions", verbose_name=_("owner")) - status = models.ForeignKey("QuestionStatus", null=False, blank=False, + status = models.ForeignKey("projects.QuestionStatus", null=False, blank=False, related_name="questions", verbose_name=_("status")) subject = models.CharField(max_length=250, null=False, blank=False, verbose_name=_("subject")) diff --git a/greenmine/projects/questions/permissions.py b/greenmine/projects/questions/permissions.py index 5bb50f1f..a9df6e17 100644 --- a/greenmine/projects/questions/permissions.py +++ b/greenmine/projects/questions/permissions.py @@ -3,15 +3,6 @@ from greenmine.base.permissions import BasePermission -class QuestionStatusPermission(BasePermission): - get_permission = "view_questionstatus" - put_permission = "change_questionstatus" - patch_permission = "change_questionstatus" - delete_permission = "delete_questionstatus" - safe_methods = ["HEAD", "OPTIONS"] - path_to_project = ["project"] - - class QuestionPermission(BasePermission): get_permission = "can_view_question" put_permission = "change_question" diff --git a/greenmine/projects/questions/serializers.py b/greenmine/projects/questions/serializers.py index 928ef20c..df2aa8f9 100644 --- a/greenmine/projects/questions/serializers.py +++ b/greenmine/projects/questions/serializers.py @@ -9,11 +9,6 @@ from greenmine.base.serializers import PickleField from . import models -class QuestionStatusSerializer(serializers.ModelSerializer): - class Meta: - model = models.QuestionStatus - - class QuestionSerializer(serializers.ModelSerializer): tags = PickleField() comment = serializers.SerializerMethodField("get_comment") diff --git a/greenmine/projects/serializers.py b/greenmine/projects/serializers.py index 0ca71bf3..2840a555 100644 --- a/greenmine/projects/serializers.py +++ b/greenmine/projects/serializers.py @@ -30,3 +30,51 @@ class ProjectSerializer(serializers.ModelSerializer): class Meta: model = models.Project + + +# User Stories common serializers + +class PointsSerializer(serializers.ModelSerializer): + class Meta: + model = models.Points + + +class UserStoryStatusSerializer(serializers.ModelSerializer): + class Meta: + model = models.UserStoryStatus + + +# Task common serializers + +class TaskStatusSerializer(serializers.ModelSerializer): + class Meta: + model = models.TaskStatus + + +# Issues common serializers + +class SeveritySerializer(serializers.ModelSerializer): + class Meta: + model = models.Severity + + +class PrioritySerializer(serializers.ModelSerializer): + class Meta: + model = models.Priority + + +class IssueStatusSerializer(serializers.ModelSerializer): + class Meta: + model = models.IssueStatus + + +class IssueTypeSerializer(serializers.ModelSerializer): + class Meta: + model = models.IssueType + + +# Questions common serializers + +class QuestionStatusSerializer(serializers.ModelSerializer): + class Meta: + model = models.QuestionStatus diff --git a/greenmine/projects/tasks/admin.py b/greenmine/projects/tasks/admin.py index 6172ed0b..f5236a24 100644 --- a/greenmine/projects/tasks/admin.py +++ b/greenmine/projects/tasks/admin.py @@ -7,12 +7,6 @@ from . import models import reversion -class TaskStatusAdmin(admin.ModelAdmin): - list_display = ["name", "order", "is_closed", "project"] - -admin.site.register(models.TaskStatus, TaskStatusAdmin) - - class TaskAdmin(reversion.VersionAdmin): list_display = ["subject", "ref", "user_story", "milestone", "project", "user_story_id"] list_filter = ["user_story", "milestone", "project"] @@ -21,5 +15,3 @@ class TaskAdmin(reversion.VersionAdmin): return instance.user_story.id admin.site.register(models.Task, TaskAdmin) - - diff --git a/greenmine/projects/tasks/api.py b/greenmine/projects/tasks/api.py index 0689a5dc..ff8c3236 100644 --- a/greenmine/projects/tasks/api.py +++ b/greenmine/projects/tasks/api.py @@ -5,7 +5,7 @@ from django.contrib.contenttypes.models import ContentType from rest_framework.permissions import IsAuthenticated from greenmine.base import filters -from greenmine.base.api import ModelCrudViewSet, ModelListViewSet +from greenmine.base.api import ModelCrudViewSet from greenmine.base.notifications.api import NotificationSenderMixin from greenmine.projects.permissions import AttachmentPermission from greenmine.projects.serializers import AttachmentSerializer @@ -18,14 +18,6 @@ from . import serializers import reversion -class TaskStatusViewSet(ModelListViewSet): - model = models.TaskStatus - serializer_class = serializers.TaskStatusSerializer - permission_classes = (IsAuthenticated, permissions.TaskStatusPermission) - filter_backends = (filters.IsProjectMemberFilterBackend,) - filter_fields = ("project",) - - class TaskAttachmentViewSet(ModelCrudViewSet): model = Attachment serializer_class = AttachmentSerializer diff --git a/greenmine/projects/tasks/models.py b/greenmine/projects/tasks/models.py index 877fede0..92e6b420 100644 --- a/greenmine/projects/tasks/models.py +++ b/greenmine/projects/tasks/models.py @@ -14,26 +14,6 @@ from greenmine.base.notifications.models import WatchedMixin import reversion -class TaskStatus(models.Model): - name = models.CharField(max_length=255, null=False, blank=False, verbose_name=_("name")) - order = models.IntegerField(default=10, null=False, blank=False, verbose_name=_("order")) - is_closed = models.BooleanField(default=False, null=False, blank=True, - verbose_name=_("is closed")) - color = models.CharField(max_length=20, null=False, blank=False, default="#999999", - verbose_name=_("color")) - project = models.ForeignKey("projects.Project", null=False, blank=False, - related_name="task_statuses", verbose_name=_("project")) - - class Meta: - verbose_name = u"task status" - verbose_name_plural = u"task statuses" - ordering = ["project", "name"] - unique_together = ("project", "name") - - def __str__(self): - return u"project {0} - {1}".format(self.project_id, self.name) - - class Task(models.Model, WatchedMixin): uuid = models.CharField(max_length=40, unique=True, null=False, blank=True, verbose_name=_("uuid")) @@ -43,7 +23,7 @@ class Task(models.Model, WatchedMixin): verbose_name=_("ref")) owner = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, default=None, related_name="owned_tasks", verbose_name=_("owner")) - status = models.ForeignKey("TaskStatus", null=False, blank=False, + status = models.ForeignKey("projects.TaskStatus", null=False, blank=False, related_name="tasks", verbose_name=_("status")) project = models.ForeignKey("projects.Project", null=False, blank=False, related_name="tasks", verbose_name=_("project")) diff --git a/greenmine/projects/tasks/permissions.py b/greenmine/projects/tasks/permissions.py index bbee043e..4e89bb85 100644 --- a/greenmine/projects/tasks/permissions.py +++ b/greenmine/projects/tasks/permissions.py @@ -10,12 +10,3 @@ class TaskPermission(BasePermission): delete_permission = "delete_task" safe_methods = ["HEAD", "OPTIONS"] path_to_project = ["project"] - - -class TaskStatusPermission(BasePermission): - get_permission = "view_taskstatus" - put_permission = "change_taskstatus" - patch_permission = "change_taskstatus" - delete_permission = "delete_taskstatus" - safe_methods = ["HEAD", "OPTIONS"] - path_to_project = ["project"] diff --git a/greenmine/projects/tasks/serializers.py b/greenmine/projects/tasks/serializers.py index 5803f921..38389fd5 100644 --- a/greenmine/projects/tasks/serializers.py +++ b/greenmine/projects/tasks/serializers.py @@ -9,11 +9,6 @@ from . import models import reversion -class TaskStatusSerializer(serializers.ModelSerializer): - class Meta: - model = models.TaskStatus - - class TaskSerializer(serializers.ModelSerializer): tags = PickleField(blank=True, default=[]) comment = serializers.SerializerMethodField("get_comment") diff --git a/greenmine/projects/userstories/admin.py b/greenmine/projects/userstories/admin.py index 4451ad40..fb673dc7 100644 --- a/greenmine/projects/userstories/admin.py +++ b/greenmine/projects/userstories/admin.py @@ -20,18 +20,6 @@ class UserStoryInline(admin.TabularInline): return models.UserStory.objects.none() -class PointsAdmin(admin.ModelAdmin): - list_display = ["name", "order", "project"] - -admin.site.register(models.Points, PointsAdmin) - - -class UserStoryStatusAdmin(admin.ModelAdmin): - list_display = ["name", "order", "is_closed", "project"] - -admin.site.register(models.UserStoryStatus, UserStoryStatusAdmin) - - class RolePointsInline(admin.TabularInline): model = models.RolePoints sortable_field_name = 'role' diff --git a/greenmine/projects/userstories/api.py b/greenmine/projects/userstories/api.py index 2ac4a2c8..bc444009 100644 --- a/greenmine/projects/userstories/api.py +++ b/greenmine/projects/userstories/api.py @@ -5,7 +5,7 @@ from django.contrib.contenttypes.models import ContentType from rest_framework.permissions import IsAuthenticated from greenmine.base import filters -from greenmine.base.api import ModelCrudViewSet, ModelListViewSet +from greenmine.base.api import ModelCrudViewSet from greenmine.base.notifications.api import NotificationSenderMixin from greenmine.projects.permissions import AttachmentPermission from greenmine.projects.serializers import AttachmentSerializer @@ -18,22 +18,6 @@ from . import permissions import reversion -class PointsViewSet(ModelListViewSet): - model = models.Points - serializer_class = serializers.PointsSerializer - permission_classes = (IsAuthenticated, permissions.PointsPermission) - filter_backends = (filters.IsProjectMemberFilterBackend,) - filter_fields = ('project',) - - -class UserStoryStatusViewSet(ModelListViewSet): - model = models.UserStoryStatus - serializer_class = serializers.UserStoryStatusSerializer - permission_classes = (IsAuthenticated, permissions.UserStoryStatusPermission) - filter_backends = (filters.IsProjectMemberFilterBackend,) - filter_fields = ('project',) - - class UserStoryAttachmentViewSet(ModelCrudViewSet): model = Attachment serializer_class = AttachmentSerializer diff --git a/greenmine/projects/userstories/models.py b/greenmine/projects/userstories/models.py index 055fcfa2..aa1329da 100644 --- a/greenmine/projects/userstories/models.py +++ b/greenmine/projects/userstories/models.py @@ -13,46 +13,6 @@ from greenmine.base.notifications.models import WatchedMixin import reversion -class UserStoryStatus(models.Model): - name = models.CharField(max_length=255, null=False, blank=False, - verbose_name=_("name")) - order = models.IntegerField(default=10, null=False, blank=False, - verbose_name=_("order")) - is_closed = models.BooleanField(default=False, null=False, blank=True, - verbose_name=_("is closed")) - project = models.ForeignKey("projects.Project", null=False, blank=False, - related_name="us_statuses", verbose_name=_("project")) - - class Meta: - verbose_name = u"user story status" - verbose_name_plural = u"user story statuses" - ordering = ["project", "name"] - unique_together = ("project", "name") - - def __str__(self): - return u"project {0} - {1}".format(self.project_id, self.name) - - -class Points(models.Model): - name = models.CharField(max_length=255, null=False, blank=False, - verbose_name=_("name")) - order = models.IntegerField(default=10, null=False, blank=False, - verbose_name=_("order")) - value = models.FloatField(default=None, null=True, blank=True, - verbose_name=_("value")) - project = models.ForeignKey("projects.Project", null=False, blank=False, - related_name="points", verbose_name=_("project")) - - class Meta: - verbose_name = u"point" - verbose_name_plural = u"points" - ordering = ["project", "name"] - unique_together = ("project", "name") - - def __str__(self): - return u"project {0} - {1}".format(self.project_id, self.name) - - class RolePoints(models.Model): user_story = models.ForeignKey("UserStory", null=False, blank=False, related_name="role_points", @@ -60,7 +20,7 @@ class RolePoints(models.Model): role = models.ForeignKey("users.Role", null=False, blank=False, related_name="role_points", verbose_name=_("role")) - points = models.ForeignKey("Points", null=False, blank=False, + points = models.ForeignKey("projects.Points", null=False, blank=False, related_name="role_points", verbose_name=_("points")) @@ -79,9 +39,9 @@ class UserStory(WatchedMixin, models.Model): related_name="user_stories", verbose_name=_("project")) owner = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, related_name="owned_user_stories", verbose_name=_("owner")) - status = models.ForeignKey("UserStoryStatus", null=False, blank=False, + status = models.ForeignKey("projects.UserStoryStatus", null=False, blank=False, related_name="user_stories", verbose_name=_("status")) - points = models.ManyToManyField("Points", null=False, blank=False, + points = models.ManyToManyField("projects.Points", null=False, blank=False, related_name="userstories", through="RolePoints", verbose_name=_("points")) order = models.PositiveSmallIntegerField(null=False, blank=False, default=100, diff --git a/greenmine/projects/userstories/permissions.py b/greenmine/projects/userstories/permissions.py index f0d6bab9..0c7e0c81 100644 --- a/greenmine/projects/userstories/permissions.py +++ b/greenmine/projects/userstories/permissions.py @@ -3,24 +3,6 @@ from greenmine.base.permissions import BasePermission -class PointsPermission(BasePermission): - get_permission = "view_points" - put_permission = "severity_points" - patch_permission = "severity_points" - delete_permission = "delete_points" - safe_methods = ["HEAD", "OPTIONS"] - path_to_project = ["project"] - - -class UserStoryStatusPermission(BasePermission): - get_permission = "view_userstorystatus" - put_permission = "change_userstorystatus" - patch_permission = "change_userstorystatus" - delete_permission = "delete_userstorystatus" - safe_methods = ["HEAD", "OPTIONS"] - path_to_project = ["project"] - - class UserStoryPermission(BasePermission): get_permission = "view_userstory" put_permission = "change_userstory" diff --git a/greenmine/projects/userstories/serializers.py b/greenmine/projects/userstories/serializers.py index 6f59948b..77e48b54 100644 --- a/greenmine/projects/userstories/serializers.py +++ b/greenmine/projects/userstories/serializers.py @@ -7,12 +7,6 @@ from greenmine.base.serializers import PickleField from . import models - -class PointsSerializer(serializers.ModelSerializer): - class Meta: - model = models.Points - - class RolePointsField(serializers.WritableField): def to_native(self, obj): return {str(o.role.id): o.points.order for o in obj.all()} @@ -23,11 +17,6 @@ class RolePointsField(serializers.WritableField): return json.loads(obj) -class UserStoryStatusSerializer(serializers.ModelSerializer): - class Meta: - model = models.UserStoryStatus - - class UserStorySerializer(serializers.ModelSerializer): tags = PickleField(blank=True, default=[]) is_closed = serializers.Field(source="is_closed") diff --git a/greenmine/routers.py b/greenmine/routers.py index e9eec5d8..c8d7dc4f 100644 --- a/greenmine/routers.py +++ b/greenmine/routers.py @@ -3,17 +3,16 @@ from greenmine.base import routers from greenmine.base.users.api import AuthViewSet, RolesViewSet, UsersViewSet from greenmine.base.searches.api import SearchViewSet -from greenmine.projects.api import ProjectViewSet +from greenmine.projects.api import (ProjectViewSet, PointsViewSet, UserStoryStatusViewSet, + TaskStatusViewSet,PriorityViewSet, SeverityViewSet, + IssueStatusViewSet, IssueTypeViewSet, + QuestionStatusViewSet, ) from greenmine.projects.milestones.api import MilestoneViewSet -from greenmine.projects.userstories.api import (PointsViewSet, UserStoryStatusViewSet, - UserStoryAttachmentViewSet, UserStoryViewSet,) -from greenmine.projects.tasks.api import TaskStatusViewSet, TaskViewSet, TaskAttachmentViewSet -from greenmine.projects.issues.api import (PriorityViewSet, SeverityViewSet, - IssueStatusViewSet, IssueTypeViewSet, - IssueViewSet, IssueAttachmentViewSet,) -from greenmine.projects.questions.api import (QuestionStatusViewSet, QuestionViewSet, - QuestionAttachmentViewSet,) -from greenmine.projects.wiki.api import (WikiViewSet, WikiAttachmentViewSet,) +from greenmine.projects.userstories.api import UserStoryViewSet, UserStoryAttachmentViewSet +from greenmine.projects.tasks.api import TaskViewSet, TaskAttachmentViewSet +from greenmine.projects.issues.api import IssueViewSet, IssueAttachmentViewSet +from greenmine.projects.questions.api import QuestionViewSet, QuestionAttachmentViewSet +from greenmine.projects.wiki.api import WikiViewSet, WikiAttachmentViewSet router = routers.DefaultRouter(trailing_slash=False) @@ -28,34 +27,36 @@ router.register(r"search", SearchViewSet, base_name="search") # greenmine.projects router.register(r"projects", ProjectViewSet, base_name="projects") +router.register(r"points", PointsViewSet, base_name="points") +router.register(r"userstory-statuses", UserStoryStatusViewSet, + base_name="userstory-statuses") +router.register(r"task-statuses", TaskStatusViewSet, base_name="task-statuses") +router.register(r"severities", SeverityViewSet, base_name="severities") +router.register(r"priorities", PriorityViewSet, base_name="priorities") +router.register(r"issue-statuses", IssueStatusViewSet, base_name="issue-statuses") +router.register(r"issue-types", IssueTypeViewSet, base_name="issue-types") +router.register(r"question-statuses", QuestionStatusViewSet, base_name="question-statuses") # greenmine.projects.milestones router.register(r"milestones", MilestoneViewSet, base_name="milestones") # greenmine.projects.userstories -router.register(r"points", PointsViewSet, base_name="points") -router.register(r"userstory-statuses", UserStoryStatusViewSet, base_name="userstory-statuses") -router.register(r"userstory-attachments", UserStoryAttachmentViewSet, base_name="userstory-attachments") router.register(r"userstories", UserStoryViewSet, base_name="userstories") +router.register(r"userstory-attachments", UserStoryAttachmentViewSet, + base_name="userstory-attachments") # greenmine.projects.tasks -router.register(r"task-statuses", TaskStatusViewSet, base_name="task-statuses") -router.register(r"task-attachments", TaskAttachmentViewSet, base_name="task-attachments") router.register(r"tasks", TaskViewSet, base_name="tasks") +router.register(r"task-attachments", TaskAttachmentViewSet, base_name="task-attachments") # greenmine.projects.issues -router.register(r"severities", SeverityViewSet, base_name="severities") -router.register(r"priorities", PriorityViewSet, base_name="priorities") -router.register(r"issue-statuses", IssueStatusViewSet, base_name="issue-statuses") -router.register(r"issue-types", IssueTypeViewSet, base_name="issue-types") -router.register(r"issue-attachments", IssueAttachmentViewSet, base_name="issue-attachments") router.register(r"issues", IssueViewSet, base_name="issues") +router.register(r"issue-attachments", IssueAttachmentViewSet, base_name="issue-attachments") #greenmine.projects.questions -router.register(r"question-statuses", QuestionStatusViewSet, base_name="question-statuses") +router.register(r"questions", QuestionViewSet, base_name="questions") router.register(r"question-attachments", QuestionAttachmentViewSet, base_name="question-attachments") -router.register(r"questions", QuestionViewSet, base_name="questions") #greenmine.projects.documents # TODO