Add task & issues due dates configuration
parent
758109ac22
commit
6a5e870564
|
@ -596,7 +596,7 @@ class UserStoryDueDateViewSet(BlockedByProjectMixin, ModelCrudViewSet):
|
|||
|
||||
def create(self, request, *args, **kwargs):
|
||||
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)
|
||||
|
||||
|
||||
|
@ -622,6 +622,21 @@ class TaskStatusViewSet(MoveOnDestroyMixin, BlockedByProjectMixin,
|
|||
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,
|
||||
ModelCrudViewSet, BulkUpdateOrderMixin):
|
||||
|
||||
|
@ -707,6 +722,21 @@ class IssueStatusViewSet(MoveOnDestroyMixin, BlockedByProjectMixin,
|
|||
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
|
||||
######################################################
|
||||
|
|
|
@ -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')]),
|
||||
),
|
||||
]
|
|
@ -677,6 +677,40 @@ class TaskStatus(models.Model):
|
|||
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
|
||||
|
||||
class Priority(models.Model):
|
||||
|
@ -771,6 +805,40 @@ class IssueType(models.Model):
|
|||
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):
|
||||
name = models.CharField(max_length=250, null=False, blank=False,
|
||||
verbose_name=_("name"))
|
||||
|
|
|
@ -167,6 +167,15 @@ class TaskStatusPermission(TaigaResourcePermission):
|
|||
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
|
||||
|
||||
class SeverityPermission(TaigaResourcePermission):
|
||||
|
@ -209,6 +218,16 @@ class IssueTypePermission(TaigaResourcePermission):
|
|||
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
|
||||
|
||||
class ProjectTemplatePermission(TaigaResourcePermission):
|
||||
|
|
|
@ -67,7 +67,7 @@ class PointsSerializer(serializers.LightSerializer):
|
|||
project = Field(attr="project_id")
|
||||
|
||||
|
||||
class UserStoryDueDateSerializer(serializers.LightSerializer):
|
||||
class BaseDueDateSerializer(serializers.LightSerializer):
|
||||
id = Field()
|
||||
name = I18NField()
|
||||
slug = Field()
|
||||
|
@ -78,6 +78,10 @@ class UserStoryDueDateSerializer(serializers.LightSerializer):
|
|||
project = Field(attr="project_id")
|
||||
|
||||
|
||||
class UserStoryDueDateSerializer(BaseDueDateSerializer):
|
||||
pass
|
||||
|
||||
|
||||
class TaskStatusSerializer(serializers.LightSerializer):
|
||||
id = Field()
|
||||
name = I18NField()
|
||||
|
@ -88,6 +92,10 @@ class TaskStatusSerializer(serializers.LightSerializer):
|
|||
project = Field(attr="project_id")
|
||||
|
||||
|
||||
class TaskDueDateSerializer(BaseDueDateSerializer):
|
||||
pass
|
||||
|
||||
|
||||
class SeveritySerializer(serializers.LightSerializer):
|
||||
id = Field()
|
||||
name = I18NField()
|
||||
|
@ -122,6 +130,10 @@ class IssueTypeSerializer(serializers.LightSerializer):
|
|||
project = Field(attr="project_id")
|
||||
|
||||
|
||||
class IssueDueDateSerializer(BaseDueDateSerializer):
|
||||
pass
|
||||
|
||||
|
||||
######################################################
|
||||
# Members
|
||||
######################################################
|
||||
|
|
|
@ -94,6 +94,11 @@ class TaskStatusValidator(DuplicatedNameInProjectValidator, validators.ModelVali
|
|||
model = models.TaskStatus
|
||||
|
||||
|
||||
class TaskDueDateValidator(DuplicatedNameInProjectValidator, validators.ModelValidator):
|
||||
class Meta:
|
||||
model = models.TaskDueDate
|
||||
|
||||
|
||||
class SeverityValidator(DuplicatedNameInProjectValidator, validators.ModelValidator):
|
||||
class Meta:
|
||||
model = models.Severity
|
||||
|
@ -114,6 +119,11 @@ class IssueTypeValidator(DuplicatedNameInProjectValidator, validators.ModelValid
|
|||
model = models.IssueType
|
||||
|
||||
|
||||
class IssueDueDateValidator(DuplicatedNameInProjectValidator, validators.ModelValidator):
|
||||
class Meta:
|
||||
model = models.IssueDueDate
|
||||
|
||||
|
||||
######################################################
|
||||
# Members
|
||||
######################################################
|
||||
|
|
|
@ -60,8 +60,10 @@ from taiga.projects.api import UserStoryStatusViewSet
|
|||
from taiga.projects.api import PointsViewSet
|
||||
from taiga.projects.api import UserStoryDueDateViewSet
|
||||
from taiga.projects.api import TaskStatusViewSet
|
||||
from taiga.projects.api import TaskDueDateViewSet
|
||||
from taiga.projects.api import IssueStatusViewSet
|
||||
from taiga.projects.api import IssueTypeViewSet
|
||||
from taiga.projects.api import IssueDueDateViewSet
|
||||
from taiga.projects.api import PriorityViewSet
|
||||
from taiga.projects.api import SeverityViewSet
|
||||
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"userstory-due-dates", UserStoryDueDateViewSet, base_name="userstory-due-dates")
|
||||
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-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"severities",SeverityViewSet , base_name="severities")
|
||||
|
||||
|
|
Loading…
Reference in New Issue