Add US duedates configuration

remotes/origin/3.4.0rc
Álex Hermida 2018-06-05 12:30:00 +02:00 committed by Alex Hermida
parent d94e444b57
commit 99256df22c
8 changed files with 145 additions and 1 deletions

View File

@ -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):

View File

@ -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')]),
),
]

View File

@ -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"))

View File

@ -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):

View File

@ -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()

View File

@ -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

View File

@ -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")

View File

@ -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'),
),
]