Add US duedates configuration
parent
d94e444b57
commit
99256df22c
|
@ -585,6 +585,21 @@ class PointsViewSet(MoveOnDestroyMixin, BlockedByProjectMixin,
|
|||
return super().create(request, *args, **kwargs)
|
||||
|
||||
|
||||
class UserStoryDueDateViewSet(BlockedByProjectMixin, ModelCrudViewSet):
|
||||
|
||||
model = models.UserStoryDueDate
|
||||
serializer_class = serializers.UserStoryDueDateSerializer
|
||||
validator_class = validators.UserStoryDueDateValidator
|
||||
permission_classes = (permissions.UserStoryDueDatePermission,)
|
||||
filter_backends = (filters.CanViewProjectFilterBackend,)
|
||||
filter_fields = ('project',)
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
project_id = request.DATA.get("project", 0)
|
||||
with advisory_lock("user-story-duedate-creation-{}".format(project_id)):
|
||||
return super().create(request, *args, **kwargs)
|
||||
|
||||
|
||||
class TaskStatusViewSet(MoveOnDestroyMixin, BlockedByProjectMixin,
|
||||
ModelCrudViewSet, BulkUpdateOrderMixin):
|
||||
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2018-06-05 10:42
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('projects', '0059_auto_20170116_1633'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='UserStoryDueDate',
|
||||
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='us_duedates', to='projects.Project', verbose_name='project')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'user story due date',
|
||||
'verbose_name_plural': 'user story due dates',
|
||||
'ordering': ['project', 'order', 'name'],
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='project',
|
||||
name='default_us_duedate',
|
||||
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='projects.UserStoryDueDate', verbose_name='default US duedate'),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='userstoryduedate',
|
||||
unique_together=set([('project', 'slug'), ('project', 'name')]),
|
||||
),
|
||||
]
|
|
@ -120,6 +120,11 @@ class ProjectDefaults(models.Model):
|
|||
default_points = models.OneToOneField("projects.Points", on_delete=models.SET_NULL,
|
||||
related_name="+", null=True, blank=True,
|
||||
verbose_name=_("default points"))
|
||||
default_us_duedate = models.OneToOneField("projects.UserStoryDueDate",
|
||||
on_delete=models.SET_NULL,
|
||||
related_name="+",
|
||||
null=True, blank=True,
|
||||
verbose_name=_("default US duedate"))
|
||||
default_task_status = models.OneToOneField("projects.TaskStatus",
|
||||
on_delete=models.SET_NULL, related_name="+",
|
||||
null=True, blank=True,
|
||||
|
@ -605,8 +610,41 @@ class Points(models.Model):
|
|||
return self.name
|
||||
|
||||
|
||||
# Tasks common models
|
||||
class UserStoryDueDate(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="us_duedates", verbose_name=_("project"))
|
||||
|
||||
class Meta:
|
||||
verbose_name = "user story due date"
|
||||
verbose_name_plural = "user story 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.us_duedates
|
||||
if self.id:
|
||||
qs = qs.exclude(id=self.id)
|
||||
|
||||
self.slug = slugify_uniquely_for_queryset(self.name, qs)
|
||||
return super().save(*args, **kwargs)
|
||||
|
||||
|
||||
# Tasks common models
|
||||
class TaskStatus(models.Model):
|
||||
name = models.CharField(max_length=255, null=False, blank=False,
|
||||
verbose_name=_("name"))
|
||||
|
|
|
@ -145,6 +145,16 @@ class UserStoryStatusPermission(TaigaResourcePermission):
|
|||
bulk_update_order_perms = IsProjectAdmin()
|
||||
|
||||
|
||||
class UserStoryDueDatePermission(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()
|
||||
|
||||
|
||||
# Tasks
|
||||
|
||||
class TaskStatusPermission(TaigaResourcePermission):
|
||||
|
|
|
@ -67,6 +67,17 @@ class PointsSerializer(serializers.LightSerializer):
|
|||
project = Field(attr="project_id")
|
||||
|
||||
|
||||
class UserStoryDueDateSerializer(serializers.LightSerializer):
|
||||
id = Field()
|
||||
name = I18NField()
|
||||
slug = Field()
|
||||
order = Field()
|
||||
by_default = Field()
|
||||
days_to_due = Field()
|
||||
color = Field()
|
||||
project = Field(attr="project_id")
|
||||
|
||||
|
||||
class TaskStatusSerializer(serializers.LightSerializer):
|
||||
id = Field()
|
||||
name = I18NField()
|
||||
|
|
|
@ -84,6 +84,11 @@ class PointsValidator(DuplicatedNameInProjectValidator, validators.ModelValidato
|
|||
model = models.Points
|
||||
|
||||
|
||||
class UserStoryDueDateValidator(DuplicatedNameInProjectValidator, validators.ModelValidator):
|
||||
class Meta:
|
||||
model = models.UserStoryDueDate
|
||||
|
||||
|
||||
class TaskStatusValidator(DuplicatedNameInProjectValidator, validators.ModelValidator):
|
||||
class Meta:
|
||||
model = models.TaskStatus
|
||||
|
|
|
@ -58,6 +58,7 @@ from taiga.projects.api import InvitationViewSet
|
|||
from taiga.projects.api import EpicStatusViewSet
|
||||
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 IssueStatusViewSet
|
||||
from taiga.projects.api import IssueTypeViewSet
|
||||
|
@ -74,6 +75,7 @@ router.register(r"invitations", InvitationViewSet, base_name="invitations")
|
|||
router.register(r"epic-statuses", EpicStatusViewSet, base_name="epic-statuses")
|
||||
router.register(r"userstory-statuses", UserStoryStatusViewSet, base_name="userstory-statuses")
|
||||
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"issue-statuses", IssueStatusViewSet, base_name="issue-statuses")
|
||||
router.register(r"issue-types", IssueTypeViewSet, base_name="issue-types")
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2018-06-05 10:31
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('users', '0026_auto_20180514_1513'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
name='read_new_terms',
|
||||
field=models.BooleanField(default=False, verbose_name='new terms read'),
|
||||
),
|
||||
]
|
Loading…
Reference in New Issue