Refactor choices.
parent
28650f46c4
commit
38306a176e
|
@ -23,19 +23,21 @@ def slugify_uniquely(value, model, slugfield="slug"):
|
|||
suffix += 1
|
||||
|
||||
|
||||
def ref_uniquely(project, model, field='ref'):
|
||||
|
||||
def ref_uniquely(p, seq_field, model, field='ref'):
|
||||
"""
|
||||
Returns a unique reference code based on base64 and time.
|
||||
"""
|
||||
project = project.__class__.objects.select_for_update().get(pk=p.pk)
|
||||
|
||||
# this prevents concurrent and inconsistent references.
|
||||
time.sleep(0.001)
|
||||
ref = getattr(project, seq_field) + 1
|
||||
|
||||
new_timestamp = lambda: int("".join(str(time.time()).split(".")))
|
||||
while True:
|
||||
potential = baseconv.base62.encode(new_timestamp())
|
||||
params = {field: potential, 'project': project}
|
||||
params = {field: ref, 'project': _project}
|
||||
if not model.objects.filter(**params).exists():
|
||||
return potential
|
||||
setattr(_project, seq_field, ref)
|
||||
_project.save(update_fields=[seq_field])
|
||||
return ref
|
||||
|
||||
time.sleep(0.0002)
|
||||
ref += 1
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from django.contrib import admin
|
||||
|
||||
from guardian.admin import GuardedModelAdmin
|
||||
from greenmine.scrum import models
|
||||
import reversion
|
||||
|
||||
from greenmine.scrum.models import Project, Milestone, UserStory, Change, \
|
||||
ChangeAttachment, Task
|
||||
|
||||
|
||||
class MilestoneInline(admin.TabularInline):
|
||||
model = Milestone
|
||||
model = models.Milestone
|
||||
fields = ('name', 'owner', 'estimated_start', 'estimated_finish', 'closed', 'disponibility', 'order')
|
||||
sortable_field_name = 'order'
|
||||
extra = 0
|
||||
|
||||
|
||||
class UserStoryInline(admin.TabularInline):
|
||||
model = UserStory
|
||||
model = models.UserStory
|
||||
fields = ('subject', 'order')
|
||||
sortable_field_name = 'order'
|
||||
extra = 0
|
||||
|
@ -24,40 +23,76 @@ class UserStoryInline(admin.TabularInline):
|
|||
if obj:
|
||||
return obj.user_stories.filter(mileston__isnone=True)
|
||||
else:
|
||||
return UserStory.objects.none()
|
||||
return models.UserStory.objects.none()
|
||||
|
||||
class ProjectAdmin(reversion.VersionAdmin):
|
||||
list_display = ["name", "owner"]
|
||||
inlines = [MilestoneInline, UserStoryInline]
|
||||
|
||||
admin.site.register(Project, ProjectAdmin)
|
||||
admin.site.register(models.Project, ProjectAdmin)
|
||||
|
||||
|
||||
class MilestoneAdmin(reversion.VersionAdmin):
|
||||
list_display = ["name", "project", "owner", "closed", "estimated_start", "estimated_finish"]
|
||||
|
||||
admin.site.register(Milestone, MilestoneAdmin)
|
||||
admin.site.register(models.Milestone, MilestoneAdmin)
|
||||
|
||||
|
||||
class UserStoryAdmin(reversion.VersionAdmin):
|
||||
list_display = ["ref", "milestone", "project", "owner"]
|
||||
|
||||
admin.site.register(UserStory, UserStoryAdmin)
|
||||
admin.site.register(models.UserStory, UserStoryAdmin)
|
||||
|
||||
|
||||
class ChangeAdmin(reversion.VersionAdmin):
|
||||
list_display = ["id", "change_type", "project", "owner"]
|
||||
|
||||
admin.site.register(Change, ChangeAdmin)
|
||||
admin.site.register(models.Change, ChangeAdmin)
|
||||
|
||||
|
||||
class ChangeAttachmentAdmin(reversion.VersionAdmin):
|
||||
list_display = ["id", "change", "owner"]
|
||||
|
||||
admin.site.register(ChangeAttachment, ChangeAttachmentAdmin)
|
||||
admin.site.register(models.ChangeAttachment, ChangeAttachmentAdmin)
|
||||
|
||||
|
||||
class TaskAdmin(reversion.VersionAdmin):
|
||||
list_display = ["subject", "type", "user_story"]
|
||||
list_display = ["subject", "user_story"]
|
||||
|
||||
|
||||
class IssueAdmin(reversion.VersionAdmin):
|
||||
list_display = ["subject", "type"]
|
||||
|
||||
|
||||
class SeverityAdmin(admin.ModelAdmin):
|
||||
list_display = ["name", "order", "project"]
|
||||
|
||||
class PriorityAdmin(admin.ModelAdmin):
|
||||
list_display = ["name", "order", "project"]
|
||||
|
||||
class PointsAdmin(admin.ModelAdmin):
|
||||
list_display = ["name", "order", "project"]
|
||||
|
||||
class IssueTypeAdmin(admin.ModelAdmin):
|
||||
list_display = ["name", "order", "project"]
|
||||
|
||||
class IssueStatusAdmin(admin.ModelAdmin):
|
||||
list_display = ["name", "order", "is_closed", "project"]
|
||||
|
||||
class TaskStatusAdmin(admin.ModelAdmin):
|
||||
list_display = ["name", "order", "is_closed", "project"]
|
||||
|
||||
class UserStoryStatusAdmin(admin.ModelAdmin):
|
||||
list_display = ["name", "order", "is_closed", "project"]
|
||||
|
||||
admin.site.register(models.Task, TaskAdmin)
|
||||
admin.site.register(models.Issue, IssueAdmin)
|
||||
|
||||
admin.site.register(models.Severity, SeverityAdmin)
|
||||
admin.site.register(models.IssueStatus, IssueStatusAdmin)
|
||||
admin.site.register(models.TaskStatus, TaskStatusAdmin)
|
||||
admin.site.register(models.UserStoryStatus, UserStoryStatusAdmin)
|
||||
admin.site.register(models.Priority, PriorityAdmin)
|
||||
admin.site.register(models.IssueType, IssueTypeAdmin)
|
||||
admin.site.register(models.Points, PointsAdmin)
|
||||
|
||||
admin.site.register(Task, TaskAdmin)
|
||||
|
|
|
@ -2,27 +2,13 @@
|
|||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from .utils import SCRUM_STATES
|
||||
|
||||
ORG_ROLE_CHOICES = (
|
||||
('owner', _(u'Owner')),
|
||||
('developer', _(u'Developer')),
|
||||
)
|
||||
|
||||
MARKUP_TYPE = (
|
||||
('md', _(u'Markdown')),
|
||||
('rst', _('Restructured Text')),
|
||||
)
|
||||
|
||||
US_STATUS_CHOICES = SCRUM_STATES.get_us_choices()
|
||||
|
||||
TASK_PRIORITY_CHOICES = (
|
||||
PRIORITY_CHOICES = (
|
||||
(1, _(u'Low')),
|
||||
(3, _(u'Normal')),
|
||||
(5, _(u'High')),
|
||||
)
|
||||
|
||||
TASK_SEVERITY_CHOICES = (
|
||||
SEVERITY_CHOICES = (
|
||||
(1, _(u'Wishlist')),
|
||||
(2, _(u'Minor')),
|
||||
(3, _(u'Normal')),
|
||||
|
@ -30,22 +16,42 @@ TASK_SEVERITY_CHOICES = (
|
|||
(5, _(u'Critical')),
|
||||
)
|
||||
|
||||
TASK_TYPE_CHOICES = (
|
||||
('bug', _(u'Bug')),
|
||||
('task', _(u'Task')),
|
||||
TASKSTATUSES = (
|
||||
(1, _(u"New"), False),
|
||||
(2, _(u"In progress"), False),
|
||||
(3, _(u"Ready for test"), True),
|
||||
(4, _(u"Closed"), True),
|
||||
(5, _(u"Needs Info"), False),
|
||||
)
|
||||
|
||||
TASK_STATUS_CHOICES = SCRUM_STATES.get_task_choices()
|
||||
ISSUESTATUSES = (
|
||||
(1, _(u"New"), False),
|
||||
(2, _(u"In progress"), False),
|
||||
(3, _(u"Ready for test"), True),
|
||||
(4, _(u"Closed"), True),
|
||||
(5, _(u"Needs Info"), False),
|
||||
(6, _(u"Rejected"), True),
|
||||
(7, _(u"Postponed"), False),
|
||||
)
|
||||
|
||||
USSTATUSES = (
|
||||
(1, _("Open"), False),
|
||||
(2, _("Closed"), True),
|
||||
)
|
||||
|
||||
ISSUETYPES = (
|
||||
(1, _(u'Bug')),
|
||||
)
|
||||
|
||||
POINTS_CHOICES = (
|
||||
(-1, u'?'),
|
||||
(0, u'0'),
|
||||
(0, u'0'),
|
||||
(-2, u'1/2'),
|
||||
(1, u'1'),
|
||||
(2, u'2'),
|
||||
(3, u'3'),
|
||||
(5, u'5'),
|
||||
(8, u'8'),
|
||||
(1, u'1'),
|
||||
(2, u'2'),
|
||||
(3, u'3'),
|
||||
(5, u'5'),
|
||||
(8, u'8'),
|
||||
(10, u'10'),
|
||||
(15, u'15'),
|
||||
(20, u'20'),
|
||||
|
@ -53,6 +59,8 @@ POINTS_CHOICES = (
|
|||
)
|
||||
|
||||
|
||||
# TODO: pending to refactor
|
||||
|
||||
TASK_COMMENT = 1
|
||||
TASK_STATUS_CHANGE = 2
|
||||
TASK_PRIORITY_CHANGE = 3
|
||||
|
|
|
@ -6,15 +6,106 @@ from django.conf import settings
|
|||
from django.db import models
|
||||
|
||||
from django.utils import timezone
|
||||
from django.dispatch import receiver
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib.contenttypes import generic
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from picklefield.fields import PickledObjectField
|
||||
|
||||
from greenmine.base.utils.slug import slugify_uniquely, ref_uniquely
|
||||
from greenmine.base.fields import DictField
|
||||
from greenmine.base.utils import iter_points
|
||||
from greenmine.scrum.choices import *
|
||||
from greenmine.scrum.utils import SCRUM_STATES
|
||||
|
||||
|
||||
class Severity(models.Model):
|
||||
name = models.CharField(max_length=255, unique=True)
|
||||
order = models.IntegerField(default=10)
|
||||
project = models.ForeignKey("Project", related_name="severities")
|
||||
|
||||
class Meta:
|
||||
unique_together = ('project', 'name')
|
||||
|
||||
def __unicode__(self):
|
||||
return u"project({0})/severity({1})".format(self.project.id, self.name)
|
||||
|
||||
|
||||
class IssueStatus(models.Model):
|
||||
name = models.CharField(max_length=255, unique=True)
|
||||
order = models.IntegerField(default=10)
|
||||
is_closed = models.BooleanField(default=False)
|
||||
project = models.ForeignKey("Project", related_name="issuestatuses")
|
||||
|
||||
class Meta:
|
||||
unique_together = ('project', 'name')
|
||||
|
||||
def __unicode__(self):
|
||||
return u"project({0})/issue-status({1})".format(self.project.id, self.name)
|
||||
|
||||
|
||||
class TaskStatus(models.Model):
|
||||
name = models.CharField(max_length=255, unique=True)
|
||||
order = models.IntegerField(default=10)
|
||||
is_closed = models.BooleanField(default=False)
|
||||
project = models.ForeignKey("Project", related_name="taskstatuses")
|
||||
|
||||
class Meta:
|
||||
unique_together = ('project', 'name')
|
||||
|
||||
def __unicode__(self):
|
||||
return u"project({0})/task-status({1})".format(self.project.id, self.name)
|
||||
|
||||
|
||||
class UserStoryStatus(models.Model):
|
||||
name = models.CharField(max_length=255, unique=True)
|
||||
order = models.IntegerField(default=10)
|
||||
is_closed = models.BooleanField(default=False)
|
||||
project = models.ForeignKey("Project", related_name="usstatuses")
|
||||
|
||||
class Meta:
|
||||
unique_together = ('project', 'name')
|
||||
|
||||
def __unicode__(self):
|
||||
return u"project({0})/us-status({1})".format(self.project.id, self.name)
|
||||
|
||||
|
||||
class Priority(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
order = models.IntegerField(default=10)
|
||||
project = models.ForeignKey("Project", related_name="priorities")
|
||||
|
||||
class Meta:
|
||||
unique_together = ('project', 'name')
|
||||
|
||||
def __unicode__(self):
|
||||
return u"project({0})/priority({1})".format(self.project.id, self.name)
|
||||
|
||||
|
||||
class IssueType(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
order = models.IntegerField(default=10)
|
||||
|
||||
project = models.ForeignKey("Project", related_name="issuetypes")
|
||||
|
||||
class Meta:
|
||||
unique_together = ('project', 'name')
|
||||
|
||||
def __unicode__(self):
|
||||
return u"project({0})/type({1})".format(self.project.id, self.name)
|
||||
|
||||
|
||||
class Points(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
order = models.IntegerField(default=10)
|
||||
|
||||
project = models.ForeignKey("Project", related_name="points")
|
||||
|
||||
class Meta:
|
||||
unique_together = ('project', 'name')
|
||||
|
||||
def __unicode__(self):
|
||||
return u"project({0})/point({1})".format(self.project.id, self.name)
|
||||
|
||||
|
||||
class Project(models.Model):
|
||||
|
@ -28,19 +119,14 @@ class Project(models.Model):
|
|||
|
||||
owner = models.ForeignKey("auth.User", related_name="projects")
|
||||
public = models.BooleanField(default=True)
|
||||
markup = models.CharField(max_length=10, choices=MARKUP_TYPE, default='md')
|
||||
|
||||
last_us_ref = models.BigIntegerField(null=True, default=0)
|
||||
last_task_ref = models.BigIntegerField(null=True, default=0)
|
||||
last_us_ref = models.BigIntegerField(null=True, default=1)
|
||||
last_task_ref = models.BigIntegerField(null=True, default=1)
|
||||
last_issue_ref = models.BigIntegerField(null=True, default=1)
|
||||
|
||||
task_parser_re = models.CharField(max_length=1000, blank=True, null=True, default=None)
|
||||
sprints = models.IntegerField(default=1, blank=True, null=True)
|
||||
show_burndown = models.BooleanField(default=False, blank=True)
|
||||
show_burnup = models.BooleanField(default=False, blank=True)
|
||||
show_sprint_burndown = models.BooleanField(default=False, blank=True)
|
||||
total_story_points = models.FloatField(default=None, null=True)
|
||||
|
||||
tags = DictField(blank=True, null=True)
|
||||
tags = PickledObjectField()
|
||||
|
||||
class Meta:
|
||||
permissions = (
|
||||
|
@ -107,6 +193,7 @@ class Project(models.Model):
|
|||
class Milestone(models.Model):
|
||||
uuid = models.CharField(max_length=40, unique=True, blank=True)
|
||||
name = models.CharField(max_length=200, db_index=True)
|
||||
slug = models.SlugField(max_length=250, unique=True, blank=True)
|
||||
owner = models.ForeignKey('auth.User', related_name="milestones")
|
||||
project = models.ForeignKey('Project', related_name="milestones")
|
||||
|
||||
|
@ -122,6 +209,12 @@ class Milestone(models.Model):
|
|||
|
||||
tags = DictField(blank=True, null=True)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.slug:
|
||||
self.slug = slugify_uniquely(self.name, self.__class__)
|
||||
|
||||
super(Milestone, self).save(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
ordering = ['-created_date']
|
||||
unique_together = ('name', 'project')
|
||||
|
@ -144,35 +237,30 @@ class Milestone(models.Model):
|
|||
|
||||
class UserStory(models.Model):
|
||||
uuid = models.CharField(max_length=40, unique=True, blank=True)
|
||||
ref = models.CharField(max_length=200, db_index=True, null=True, default=None)
|
||||
ref = models.BigIntegerField(db_index=True, null=True, default=None)
|
||||
milestone = models.ForeignKey("Milestone", blank=True,
|
||||
related_name="user_stories", null=True,
|
||||
default=None)
|
||||
project = models.ForeignKey("Project", related_name="user_stories")
|
||||
owner = models.ForeignKey("auth.User", null=True, default=None,
|
||||
related_name="user_stories")
|
||||
priority = models.IntegerField(default=1)
|
||||
points = models.IntegerField(choices=POINTS_CHOICES, default=-1)
|
||||
status = models.CharField(max_length=50,
|
||||
choices=SCRUM_STATES.get_us_choices(),
|
||||
db_index=True, default="open")
|
||||
|
||||
status = models.ForeignKey("UserStoryStatus", related_name="userstories", default=1)
|
||||
points = models.ForeignKey("Points", related_name="userstories", default= -1)
|
||||
order = models.PositiveSmallIntegerField(default=100)
|
||||
|
||||
created_date = models.DateTimeField(auto_now_add=True)
|
||||
modified_date = models.DateTimeField(auto_now_add=True, auto_now=True)
|
||||
tested = models.BooleanField(default=False)
|
||||
finish_date = models.DateTimeField(null=True, blank=True)
|
||||
|
||||
subject = models.CharField(max_length=500)
|
||||
description = models.TextField()
|
||||
finish_date = models.DateTimeField(null=True, blank=True)
|
||||
|
||||
watchers = models.ManyToManyField('auth.User', related_name='us_watch',
|
||||
null=True)
|
||||
watchers = models.ManyToManyField('auth.User', related_name='us_watch', null=True)
|
||||
|
||||
client_requirement = models.BooleanField(default=False)
|
||||
team_requirement = models.BooleanField(default=False)
|
||||
order = models.PositiveSmallIntegerField("Order")
|
||||
|
||||
tags = DictField(blank=True, null=True)
|
||||
tags = PickledObjectField()
|
||||
|
||||
class Meta:
|
||||
ordering = ['order']
|
||||
|
@ -186,7 +274,7 @@ class UserStory(models.Model):
|
|||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.ref:
|
||||
self.ref = ref_uniquely(self.project, self.__class__)
|
||||
self.ref = ref_uniquely(self.project, "last_us_ref", self.__class__)
|
||||
|
||||
super(UserStory, self).save(*args, **kwargs)
|
||||
|
||||
|
@ -216,118 +304,24 @@ class ChangeAttachment(models.Model):
|
|||
tags = DictField(blank=True, null=True)
|
||||
|
||||
|
||||
class TaskQuerySet(models.query.QuerySet):
|
||||
def _add_categories(self, section_dict, category_id, category_element, selected):
|
||||
section_dict[category_id] = section_dict.get(category_id, {
|
||||
'element': unicode(category_element),
|
||||
'count': 0,
|
||||
'id': category_id,
|
||||
'selected': selected,
|
||||
})
|
||||
section_dict[category_id]['count'] += 1
|
||||
|
||||
def _get_category(self, section_dict, order_by='element', reverse=False):
|
||||
values = section_dict.values()
|
||||
values = sorted(values, key=lambda entry: unicode(entry[order_by]))
|
||||
if reverse:
|
||||
values.reverse()
|
||||
return values
|
||||
|
||||
def _get_filter_and_build_filter_dict(self, queryset, milestone_id, status_id, tags_ids, assigned_to_id, severity_id):
|
||||
task_list = list(queryset)
|
||||
milestones = {}
|
||||
status = {}
|
||||
tags = {}
|
||||
assigned_to = {}
|
||||
severity = {}
|
||||
|
||||
for task in task_list:
|
||||
if task.milestone:
|
||||
selected = milestone_id and task.milestone.id == milestone_id
|
||||
self._add_categories(milestones, task.milestone.id, task.milestone.name, selected)
|
||||
|
||||
selected = status_id and task.status == status_id
|
||||
self._add_categories(status, task.status, task.get_status_display(), selected)
|
||||
|
||||
for tag in task.tags.all():
|
||||
selected = tags_ids and tag.id in tags_ids
|
||||
self._add_categories(tags, tag.id, tag.name, selected)
|
||||
|
||||
if task.assigned_to:
|
||||
selected = assigned_to_id and task.assigned_to.id == assigned_to_id
|
||||
self._add_categories(assigned_to, task.assigned_to.id, task.assigned_to.first_name, selected)
|
||||
|
||||
selected = severity_id and task.severity == int(severity_id)
|
||||
self._add_categories(severity, task.severity, task.get_severity_display(), selected)
|
||||
|
||||
return{
|
||||
'list': task_list,
|
||||
'filters': {
|
||||
'milestones': self._get_category(milestones),
|
||||
'status': self._get_category(status),
|
||||
'tags': self._get_category(tags),
|
||||
'assigned_to': self._get_category(assigned_to),
|
||||
'severity': self._get_category(severity),
|
||||
}
|
||||
}
|
||||
|
||||
def filter_and_build_filter_dict(self, milestone=None, status=None, tags=None, assigned_to=None, severity=None):
|
||||
|
||||
queryset = self
|
||||
if milestone:
|
||||
queryset = queryset.filter(milestone=milestone)
|
||||
|
||||
if status:
|
||||
queryset = queryset.filter(status=status)
|
||||
|
||||
if tags:
|
||||
for tag in tags:
|
||||
queryset = queryset.filter(tags__in=[tag])
|
||||
|
||||
if assigned_to:
|
||||
queryset = queryset.filter(assigned_to=assigned_to)
|
||||
|
||||
if severity:
|
||||
queryset = queryset.filter(severity=severity)
|
||||
|
||||
milestone_id = milestone and milestone.id
|
||||
status_id = status
|
||||
tags_ids = tags and tags.values_list('id', flat=True)
|
||||
assigned_to_id = assigned_to and assigned_to.id
|
||||
severity_id = severity
|
||||
|
||||
return self._get_filter_and_build_filter_dict(queryset, milestone_id, status_id, tags_ids, assigned_to_id, severity_id)
|
||||
|
||||
|
||||
class TaskManager(models.Manager):
|
||||
def get_query_set(self):
|
||||
return TaskQuerySet(self.model)
|
||||
|
||||
|
||||
class Task(models.Model):
|
||||
uuid = models.CharField(max_length=40, unique=True, blank=True)
|
||||
user_story = models.ForeignKey('UserStory', related_name='tasks', null=True, blank=True)
|
||||
last_user_story = models.ForeignKey('UserStory', null=True, blank=True)
|
||||
ref = models.CharField(max_length=200, db_index=True, null=True, default=None)
|
||||
status = models.CharField(max_length=50, choices=TASK_STATUS_CHOICES,
|
||||
default='open')
|
||||
user_story = models.ForeignKey('UserStory', related_name='tasks')
|
||||
ref = models.BigIntegerField(db_index=True, null=True, default=None)
|
||||
owner = models.ForeignKey("auth.User", null=True, default=None,
|
||||
related_name="tasks")
|
||||
|
||||
severity = models.IntegerField(choices=TASK_SEVERITY_CHOICES, default=3)
|
||||
priority = models.IntegerField(choices=TASK_PRIORITY_CHOICES, default=3)
|
||||
severity = models.ForeignKey("Severity", related_name="tasks")
|
||||
priority = models.ForeignKey("Priority", related_name="tasks")
|
||||
|
||||
milestone = models.ForeignKey('Milestone', related_name='tasks', null=True,
|
||||
default=None, blank=True)
|
||||
|
||||
project = models.ForeignKey('Project', related_name='tasks')
|
||||
type = models.CharField(max_length=10, choices=TASK_TYPE_CHOICES,
|
||||
default='task')
|
||||
|
||||
created_date = models.DateTimeField(auto_now_add=True)
|
||||
modified_date = models.DateTimeField(auto_now_add=True)
|
||||
finished_date = models.DateTimeField(null=True, blank=True)
|
||||
last_status = models.CharField(max_length=50, choices=TASK_STATUS_CHOICES,
|
||||
null=True, blank=True)
|
||||
|
||||
subject = models.CharField(max_length=500)
|
||||
description = models.TextField(blank=True)
|
||||
|
@ -339,9 +333,7 @@ class Task(models.Model):
|
|||
null=True)
|
||||
|
||||
changes = generic.GenericRelation(Change)
|
||||
tags = DictField(blank=True, null=True)
|
||||
|
||||
objects = TaskManager()
|
||||
tags = PickledObjectField()
|
||||
|
||||
class Meta:
|
||||
unique_together = ('ref', 'project')
|
||||
|
@ -349,38 +341,98 @@ class Task(models.Model):
|
|||
def __unicode__(self):
|
||||
return self.subject
|
||||
|
||||
@property
|
||||
def fake_status(self):
|
||||
return SCRUM_STATES.get_us_state_for_task_state(self.status)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
last_user_story = None
|
||||
if self.last_user_story != self.user_story:
|
||||
last_user_story = self.last_user_story
|
||||
self.last_user_story = self.user_story
|
||||
|
||||
if self.id:
|
||||
self.modified_date = timezone.now()
|
||||
# Store information about close date of a task
|
||||
if self.last_status != self.status:
|
||||
if self.last_status in SCRUM_STATES.get_finished_task_states():
|
||||
if self.status in SCRUM_STATES.get_unfinished_task_states():
|
||||
self.finished_date = None
|
||||
elif self.last_status in SCRUM_STATES.get_unfinished_task_states():
|
||||
if self.status in SCRUM_STATES.get_finished_task_states():
|
||||
self.finished_date = timezone.now()
|
||||
self.last_status = self.status
|
||||
|
||||
if not self.ref:
|
||||
self.ref = ref_uniquely(self.project, self.__class__)
|
||||
self.ref = ref_uniquely(self.project, "last_task_ref", self.__class__)
|
||||
|
||||
super(Task, self).save(*args, **kwargs)
|
||||
|
||||
if last_user_story:
|
||||
last_user_story.update_status()
|
||||
|
||||
if self.user_story:
|
||||
self.user_story.update_status()
|
||||
class Issue(models.Model):
|
||||
uuid = models.CharField(max_length=40, unique=True, blank=True)
|
||||
ref = models.BigIntegerField(db_index=True, null=True, default=None)
|
||||
owner = models.ForeignKey("auth.User", null=True, default=None,
|
||||
related_name="issues")
|
||||
|
||||
severity = models.ForeignKey("Severity", related_name="issues")
|
||||
priority = models.ForeignKey("Priority", related_name="issues")
|
||||
type = models.ForeignKey("IssueType", related_name="issues")
|
||||
|
||||
milestone = models.ForeignKey('Milestone', related_name='issues', null=True,
|
||||
default=None, blank=True)
|
||||
|
||||
project = models.ForeignKey('Project', related_name='issues')
|
||||
|
||||
created_date = models.DateTimeField(auto_now_add=True)
|
||||
modified_date = models.DateTimeField(auto_now_add=True)
|
||||
finished_date = models.DateTimeField(null=True, blank=True)
|
||||
|
||||
subject = models.CharField(max_length=500)
|
||||
description = models.TextField(blank=True)
|
||||
assigned_to = models.ForeignKey('auth.User',
|
||||
related_name='issues_assigned_to_me',
|
||||
blank=True, null=True, default=None)
|
||||
|
||||
watchers = models.ManyToManyField('auth.User', related_name='issue_watch',
|
||||
null=True)
|
||||
|
||||
changes = generic.GenericRelation(Change)
|
||||
tags = PickledObjectField()
|
||||
|
||||
class Meta:
|
||||
unique_together = ('ref', 'project')
|
||||
|
||||
def __unicode__(self):
|
||||
return self.subject
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if self.id:
|
||||
self.modified_date = timezone.now()
|
||||
|
||||
if not self.ref:
|
||||
self.ref = ref_uniquely(self.project, "last_issue_ref", self.__class__)
|
||||
|
||||
super(Task, self).save(*args, **kwargs)
|
||||
|
||||
# Model related signals handlers
|
||||
|
||||
@receiver(models.signals.post_save, sender=Project, dispatch_uid="project_post_save")
|
||||
def project_post_save(sender, instance, created, **kwargs):
|
||||
from greenmine.profile.services import RoleGroupsService
|
||||
|
||||
if not created:
|
||||
return
|
||||
|
||||
RoleGroupsService().replicate_all_roles_on_one_project(instance)
|
||||
|
||||
# Populate new project dependen default data
|
||||
|
||||
for order, name, is_closed in ISSUESTATUSES:
|
||||
IssueStatus.objects.create(name=name, order=order,
|
||||
is_closed=is_closed, project=instance)
|
||||
|
||||
for order, name, is_closed in TASKSTATUSES:
|
||||
TaskStatus.objects.create(name=name, order=order,
|
||||
is_closed=is_closed, project=instance)
|
||||
|
||||
for order, name, is_closed in USSTATUSES:
|
||||
UserStoryStatus.objects.create(name=name, order=order,
|
||||
is_closed=is_closed, project=instance)
|
||||
|
||||
for order, name in POINTS_CHOICES:
|
||||
Priority.objects.create(project=instance, name=name, order=order)
|
||||
|
||||
for order, name in SEVERITY_CHOICES:
|
||||
Severity.objects.create(project=instance, name=name, order=order)
|
||||
|
||||
for order, name in POINTS_CHOICES:
|
||||
Points.objects.create(project=instance, name=name, order=order)
|
||||
|
||||
|
||||
from . import sigdispatch
|
||||
|
||||
# Email alerts signals handlers
|
||||
# TODO: temporary commented (Pending refactor)
|
||||
# from . import sigdispatch
|
||||
|
|
|
@ -106,12 +106,3 @@ def mail_task_assigned(sender, task, user, **kwargs):
|
|||
|
||||
subject = ugettext("Greenmine: task assigned")
|
||||
send_mail.delay(subject, template, [task.assigned_to.email])
|
||||
|
||||
|
||||
@receiver(post_save, sender=Project)
|
||||
def project_post_save(sender, instance, created, **kwargs):
|
||||
"""
|
||||
Recalculate project groups
|
||||
"""
|
||||
if created:
|
||||
RoleGroupsService().replicate_all_roles_on_one_project(instance)
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
from django.conf import settings
|
||||
|
||||
__all__ = ('SCRUM_STATES',)
|
||||
|
||||
|
||||
class GmScrumStates(object):
|
||||
def __init__(self):
|
||||
self._states = settings.GM_SCRUM_STATES
|
||||
|
||||
def get_task_choices(self):
|
||||
task_choices = []
|
||||
for us_state in self._states.values():
|
||||
task_choices += us_state['task_states']
|
||||
return task_choices
|
||||
|
||||
def get_us_choices(self):
|
||||
us_choices = []
|
||||
for key, value in self._states.iteritems():
|
||||
us_choices.append((key, value['name']))
|
||||
return us_choices
|
||||
|
||||
def get_finished_task_states(self):
|
||||
finished_task_states = []
|
||||
for us_state in self._states.values():
|
||||
if us_state['is_finished']:
|
||||
finished_task_states += us_state['task_states']
|
||||
return [x[0] for x in finished_task_states]
|
||||
|
||||
def get_unfinished_task_states(self):
|
||||
unfinished_task_states = []
|
||||
for us_state in self._states.values():
|
||||
if not us_state['is_finished']:
|
||||
unfinished_task_states += us_state['task_states']
|
||||
return [x[0] for x in unfinished_task_states]
|
||||
|
||||
def get_finished_us_states(self):
|
||||
finished_us_states = []
|
||||
for key, value in self._states.iteritems():
|
||||
if value['is_finished']:
|
||||
finished_us_states.append(key)
|
||||
return finished_us_states
|
||||
|
||||
def get_unfinished_us_states(self):
|
||||
finished_us_states = []
|
||||
for key, value in self._states.iteritems():
|
||||
if not value['is_finished']:
|
||||
finished_us_states.append(key)
|
||||
return finished_us_states
|
||||
|
||||
def get_us_state_for_task_state(self, state):
|
||||
for key, value in self._states.iteritems():
|
||||
if state in [x[0] for x in value['task_states']]:
|
||||
return key
|
||||
return None
|
||||
|
||||
def get_task_states_for_us_state(self, state):
|
||||
if state in self._states.keys():
|
||||
return [x[0] for x in self._states[state]['task_states']]
|
||||
return None
|
||||
|
||||
def ordered_us_states(self):
|
||||
ordered = sorted([(value['order'], key) for key, value in self._states.iteritems()])
|
||||
return [x[1] for x in ordered]
|
||||
|
||||
SCRUM_STATES = GmScrumStates()
|
Loading…
Reference in New Issue