Add task & issues due dates configuration

remotes/origin/endpoint-for-estimation-system-new
Álex Hermida 2018-06-06 12:39:15 +02:00 committed by Alex Hermida
parent 758109ac22
commit 6a5e870564
7 changed files with 205 additions and 2 deletions

View File

@ -596,7 +596,7 @@ class UserStoryDueDateViewSet(BlockedByProjectMixin, ModelCrudViewSet):
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
project_id = request.DATA.get("project", 0) project_id = request.DATA.get("project", 0)
with advisory_lock("user-story-duedate-creation-{}".format(project_id)): with advisory_lock("user-story-due-date-creation-{}".format(project_id)):
return super().create(request, *args, **kwargs) return super().create(request, *args, **kwargs)
@ -622,6 +622,21 @@ class TaskStatusViewSet(MoveOnDestroyMixin, BlockedByProjectMixin,
return super().create(request, *args, **kwargs) return super().create(request, *args, **kwargs)
class TaskDueDateViewSet(BlockedByProjectMixin, ModelCrudViewSet):
model = models.TaskDueDate
serializer_class = serializers.TaskDueDateSerializer
validator_class = validators.TaskDueDateValidator
permission_classes = (permissions.TaskDueDatePermission,)
filter_backends = (filters.CanViewProjectFilterBackend,)
filter_fields = ('project',)
def create(self, request, *args, **kwargs):
project_id = request.DATA.get("project", 0)
with advisory_lock("task-due-date-creation-{}".format(project_id)):
return super().create(request, *args, **kwargs)
class SeverityViewSet(MoveOnDestroyMixin, BlockedByProjectMixin, class SeverityViewSet(MoveOnDestroyMixin, BlockedByProjectMixin,
ModelCrudViewSet, BulkUpdateOrderMixin): ModelCrudViewSet, BulkUpdateOrderMixin):
@ -707,6 +722,21 @@ class IssueStatusViewSet(MoveOnDestroyMixin, BlockedByProjectMixin,
return super().create(request, *args, **kwargs) return super().create(request, *args, **kwargs)
class IssueDueDateViewSet(BlockedByProjectMixin, ModelCrudViewSet):
model = models.IssueDueDate
serializer_class = serializers.IssueDueDateSerializer
validator_class = validators.IssueDueDateValidator
permission_classes = (permissions.IssueDueDatePermission,)
filter_backends = (filters.CanViewProjectFilterBackend,)
filter_fields = ('project',)
def create(self, request, *args, **kwargs):
project_id = request.DATA.get("project", 0)
with advisory_lock("issue-due-date-creation-{}".format(project_id)):
return super().create(request, *args, **kwargs)
###################################################### ######################################################
## Project Template ## Project Template
###################################################### ######################################################

View File

@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.2 on 2018-06-06 10:34
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('projects', '0060_auto_20180605_1042'),
]
operations = [
migrations.CreateModel(
name='IssueDueDate',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='name')),
('slug', models.SlugField(blank=True, max_length=255, verbose_name='slug')),
('order', models.IntegerField(default=10, verbose_name='order')),
('by_default', models.BooleanField(default=False, verbose_name='by default')),
('color', models.CharField(default='#999999', max_length=20, verbose_name='color')),
('days_to_due', models.IntegerField(blank=True, default=None, null=True, verbose_name='days to due')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='issue_duedates', to='projects.Project', verbose_name='project')),
],
options={
'verbose_name': 'issue due date',
'verbose_name_plural': 'issue due dates',
'ordering': ['project', 'order', 'name'],
},
),
migrations.CreateModel(
name='TaskDueDate',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='name')),
('slug', models.SlugField(blank=True, max_length=255, verbose_name='slug')),
('order', models.IntegerField(default=10, verbose_name='order')),
('by_default', models.BooleanField(default=False, verbose_name='by default')),
('color', models.CharField(default='#999999', max_length=20, verbose_name='color')),
('days_to_due', models.IntegerField(blank=True, default=None, null=True, verbose_name='days to due')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='task_duedates', to='projects.Project', verbose_name='project')),
],
options={
'verbose_name': 'task due date',
'verbose_name_plural': 'task due dates',
'ordering': ['project', 'order', 'name'],
},
),
migrations.AlterUniqueTogether(
name='taskduedate',
unique_together=set([('project', 'name'), ('project', 'slug')]),
),
migrations.AlterUniqueTogether(
name='issueduedate',
unique_together=set([('project', 'name'), ('project', 'slug')]),
),
]

View File

@ -677,6 +677,40 @@ class TaskStatus(models.Model):
return super().save(*args, **kwargs) return super().save(*args, **kwargs)
class TaskDueDate(models.Model):
name = models.CharField(max_length=255, null=False, blank=False,
verbose_name=_("name"))
slug = models.SlugField(max_length=255, null=False, blank=True,
verbose_name=_("slug"))
order = models.IntegerField(default=10, null=False, blank=False,
verbose_name=_("order"))
by_default = models.BooleanField(default=False, null=False, blank=True,
verbose_name=_("by default"))
color = models.CharField(max_length=20, null=False, blank=False, default="#999999",
verbose_name=_("color"))
days_to_due = models.IntegerField(null=True, blank=True, default=None,
verbose_name=_("days to due"))
project = models.ForeignKey("Project", null=False, blank=False,
related_name="task_duedates", verbose_name=_("project"))
class Meta:
verbose_name = "task due date"
verbose_name_plural = "task due dates"
ordering = ["project", "order", "name"]
unique_together = (("project", "name"), ("project", "slug"))
def __str__(self):
return self.name
def save(self, *args, **kwargs):
qs = self.project.task_duedates
if self.id:
qs = qs.exclude(id=self.id)
self.slug = slugify_uniquely_for_queryset(self.name, qs)
return super().save(*args, **kwargs)
# Issue common Models # Issue common Models
class Priority(models.Model): class Priority(models.Model):
@ -771,6 +805,40 @@ class IssueType(models.Model):
return self.name return self.name
class IssueDueDate(models.Model):
name = models.CharField(max_length=255, null=False, blank=False,
verbose_name=_("name"))
slug = models.SlugField(max_length=255, null=False, blank=True,
verbose_name=_("slug"))
order = models.IntegerField(default=10, null=False, blank=False,
verbose_name=_("order"))
by_default = models.BooleanField(default=False, null=False, blank=True,
verbose_name=_("by default"))
color = models.CharField(max_length=20, null=False, blank=False, default="#999999",
verbose_name=_("color"))
days_to_due = models.IntegerField(null=True, blank=True, default=None,
verbose_name=_("days to due"))
project = models.ForeignKey("Project", null=False, blank=False,
related_name="issue_duedates", verbose_name=_("project"))
class Meta:
verbose_name = "issue due date"
verbose_name_plural = "issue due dates"
ordering = ["project", "order", "name"]
unique_together = (("project", "name"), ("project", "slug"))
def __str__(self):
return self.name
def save(self, *args, **kwargs):
qs = self.project.issue_duedates
if self.id:
qs = qs.exclude(id=self.id)
self.slug = slugify_uniquely_for_queryset(self.name, qs)
return super().save(*args, **kwargs)
class ProjectTemplate(TaggedMixin, TagsColorsMixin, models.Model): class ProjectTemplate(TaggedMixin, TagsColorsMixin, models.Model):
name = models.CharField(max_length=250, null=False, blank=False, name = models.CharField(max_length=250, null=False, blank=False,
verbose_name=_("name")) verbose_name=_("name"))

View File

@ -167,6 +167,15 @@ class TaskStatusPermission(TaigaResourcePermission):
bulk_update_order_perms = IsProjectAdmin() bulk_update_order_perms = IsProjectAdmin()
class TaskDueDatePermission(TaigaResourcePermission):
retrieve_perms = HasProjectPerm('view_project')
create_perms = IsProjectAdmin()
update_perms = IsProjectAdmin()
partial_update_perms = IsProjectAdmin()
destroy_perms = IsProjectAdmin()
list_perms = AllowAny()
bulk_update_order_perms = IsProjectAdmin()
# Issues # Issues
class SeverityPermission(TaigaResourcePermission): class SeverityPermission(TaigaResourcePermission):
@ -209,6 +218,16 @@ class IssueTypePermission(TaigaResourcePermission):
bulk_update_order_perms = IsProjectAdmin() bulk_update_order_perms = IsProjectAdmin()
class IssueDueDatePermission(TaigaResourcePermission):
retrieve_perms = HasProjectPerm('view_project')
create_perms = IsProjectAdmin()
update_perms = IsProjectAdmin()
partial_update_perms = IsProjectAdmin()
destroy_perms = IsProjectAdmin()
list_perms = AllowAny()
bulk_update_order_perms = IsProjectAdmin()
# Project Templates # Project Templates
class ProjectTemplatePermission(TaigaResourcePermission): class ProjectTemplatePermission(TaigaResourcePermission):

View File

@ -67,7 +67,7 @@ class PointsSerializer(serializers.LightSerializer):
project = Field(attr="project_id") project = Field(attr="project_id")
class UserStoryDueDateSerializer(serializers.LightSerializer): class BaseDueDateSerializer(serializers.LightSerializer):
id = Field() id = Field()
name = I18NField() name = I18NField()
slug = Field() slug = Field()
@ -78,6 +78,10 @@ class UserStoryDueDateSerializer(serializers.LightSerializer):
project = Field(attr="project_id") project = Field(attr="project_id")
class UserStoryDueDateSerializer(BaseDueDateSerializer):
pass
class TaskStatusSerializer(serializers.LightSerializer): class TaskStatusSerializer(serializers.LightSerializer):
id = Field() id = Field()
name = I18NField() name = I18NField()
@ -88,6 +92,10 @@ class TaskStatusSerializer(serializers.LightSerializer):
project = Field(attr="project_id") project = Field(attr="project_id")
class TaskDueDateSerializer(BaseDueDateSerializer):
pass
class SeveritySerializer(serializers.LightSerializer): class SeveritySerializer(serializers.LightSerializer):
id = Field() id = Field()
name = I18NField() name = I18NField()
@ -122,6 +130,10 @@ class IssueTypeSerializer(serializers.LightSerializer):
project = Field(attr="project_id") project = Field(attr="project_id")
class IssueDueDateSerializer(BaseDueDateSerializer):
pass
###################################################### ######################################################
# Members # Members
###################################################### ######################################################

View File

@ -94,6 +94,11 @@ class TaskStatusValidator(DuplicatedNameInProjectValidator, validators.ModelVali
model = models.TaskStatus model = models.TaskStatus
class TaskDueDateValidator(DuplicatedNameInProjectValidator, validators.ModelValidator):
class Meta:
model = models.TaskDueDate
class SeverityValidator(DuplicatedNameInProjectValidator, validators.ModelValidator): class SeverityValidator(DuplicatedNameInProjectValidator, validators.ModelValidator):
class Meta: class Meta:
model = models.Severity model = models.Severity
@ -114,6 +119,11 @@ class IssueTypeValidator(DuplicatedNameInProjectValidator, validators.ModelValid
model = models.IssueType model = models.IssueType
class IssueDueDateValidator(DuplicatedNameInProjectValidator, validators.ModelValidator):
class Meta:
model = models.IssueDueDate
###################################################### ######################################################
# Members # Members
###################################################### ######################################################

View File

@ -60,8 +60,10 @@ from taiga.projects.api import UserStoryStatusViewSet
from taiga.projects.api import PointsViewSet from taiga.projects.api import PointsViewSet
from taiga.projects.api import UserStoryDueDateViewSet from taiga.projects.api import UserStoryDueDateViewSet
from taiga.projects.api import TaskStatusViewSet from taiga.projects.api import TaskStatusViewSet
from taiga.projects.api import TaskDueDateViewSet
from taiga.projects.api import IssueStatusViewSet from taiga.projects.api import IssueStatusViewSet
from taiga.projects.api import IssueTypeViewSet from taiga.projects.api import IssueTypeViewSet
from taiga.projects.api import IssueDueDateViewSet
from taiga.projects.api import PriorityViewSet from taiga.projects.api import PriorityViewSet
from taiga.projects.api import SeverityViewSet from taiga.projects.api import SeverityViewSet
from taiga.projects.api import ProjectTemplateViewSet from taiga.projects.api import ProjectTemplateViewSet
@ -77,8 +79,10 @@ router.register(r"userstory-statuses", UserStoryStatusViewSet, base_name="userst
router.register(r"points", PointsViewSet, base_name="points") router.register(r"points", PointsViewSet, base_name="points")
router.register(r"userstory-due-dates", UserStoryDueDateViewSet, base_name="userstory-due-dates") router.register(r"userstory-due-dates", UserStoryDueDateViewSet, base_name="userstory-due-dates")
router.register(r"task-statuses", TaskStatusViewSet, base_name="task-statuses") router.register(r"task-statuses", TaskStatusViewSet, base_name="task-statuses")
router.register(r"task-due-dates", TaskDueDateViewSet, base_name="task-due-dates")
router.register(r"issue-statuses", IssueStatusViewSet, base_name="issue-statuses") router.register(r"issue-statuses", IssueStatusViewSet, base_name="issue-statuses")
router.register(r"issue-types", IssueTypeViewSet, base_name="issue-types") router.register(r"issue-types", IssueTypeViewSet, base_name="issue-types")
router.register(r"issue-due-dates", IssueDueDateViewSet, base_name="issue-due-dates")
router.register(r"priorities", PriorityViewSet, base_name="priorities") router.register(r"priorities", PriorityViewSet, base_name="priorities")
router.register(r"severities",SeverityViewSet , base_name="severities") router.register(r"severities",SeverityViewSet , base_name="severities")