From 59ae3123380d2178f2d00e56b8c34e7186cbaaa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89lie=20Bouttier?= Date: Sat, 2 Aug 2014 23:43:49 -0700 Subject: [PATCH] milestone & improvements --- issue/models.py | 67 +++++++++++--- issue/templates/issue/issue.html | 39 +++++--- issue/templates/issue/label_edit.html | 2 +- issue/templates/issue/milestone_list.html | 53 +++++++++-- issue/urls.py | 5 +- issue/views.py | 106 ++++++++++++++++++++-- ponytracker/settings.py | 1 + requirements.txt | 1 + 8 files changed, 228 insertions(+), 46 deletions(-) diff --git a/issue/models.py b/issue/models.py index 3e6daac..6b57a14 100644 --- a/issue/models.py +++ b/issue/models.py @@ -65,16 +65,36 @@ class Label(models.Model): class Milestone(models.Model): + name_validator = RegexValidator(regex='^[a-z0-9_.-]+$', + message="Please enter only lowercase characters, number, " + "dot, underscores or hyphens.") + project = models.ForeignKey(Project, related_name='milestones') - name = models.CharField(max_length=32) + name = models.CharField(max_length=32, validators=[name_validator]) class Meta: unique_together = [ 'project', 'name' ] - progression = models.SmallIntegerField(default=0) + due_date = models.DateTimeField(blank=True,null=True) - due_date = models.DateTimeField(null=True) + def closed_issues(self): + + return self.issues.filter(closed=True).count() + + def total_issues(self): + + return self.issues.count() + + def progress(self): + + closed = self.closed_issues() + total = self.total_issues() + + if total: + return int(100 * closed / total); + else: + return 0 def __str__(self): return self.name @@ -99,6 +119,8 @@ class Issue(models.Model): labels = models.ManyToManyField(Label, blank=True, null=True, related_name='issues') + milestone = models.ForeignKey(Milestone, blank=True, null=True, related_name='issues') + assignee = models.ForeignKey(User, blank=True, null=True, related_name='+') @staticmethod @@ -154,6 +176,28 @@ class Issue(models.Model): code=Event.DEL_LABEL, args={'label': label.id}) event.save() + def add_milestone(self, author, milestone, commit=True): + if self.milestone: + event = Event(issue=self, author=author, code=Event.CHANGE_MILESTONE, + args={'old_milestone': self.milestone.name, + 'new_milestone': milestone.name}) + event.save() + else: + event = Event(issue=self, author=author, code=Event.SET_MILESTONE, + args={'milestone': milestone.name}) + event.save() + self.milestone = milestone + if commit: + self.save() + + def remove_milestone(self, author, milestone, commit=True): + self.milestone = None + if commit: + self.save() + event = Event(issue=self, author=author, code=Event.UNSET_MILESTONE, + args={'milestone': milestone.name}) + event.save() + def __str__(self): return self.title @@ -167,7 +211,7 @@ class Event(models.Model): DEL_LABEL = 5 SET_MILESTONE = 6 CHANGE_MILESTONE = 7 - DEL_MILESTONE = 8 + UNSET_MILESTONE = 8 REFERENCE = 9 COMMENT = 10 DESCRIBE = 11 @@ -198,14 +242,11 @@ class Event(models.Model): return self.code == Event.COMMENT or self.code == Event.DESCRIBE - def boxed(self): - - return self.code == Event.COMMENT or self.code == Event.DESCRIBE - def glyphicon(self): - if self.code == Event.COMMENT \ - or self.code == Event.DESCRIBE: + if self.code == Event.COMMENT: + return "bullhorn" + elif self.code == Event.DESCRIBE: return "pencil" elif self.code == Event.CLOSE: return "ban-circle" @@ -218,7 +259,7 @@ class Event(models.Model): return "tag" elif self.code == Event.SET_MILESTONE \ or self.code == Event.CHANGE_MILESTONE \ - or self.code == Event.DEL_MILESTONE: + or self.code == Event.UNSET_MILESTONE: return "road" elif self.code == Event.REFERENCE: return "transfer" @@ -253,8 +294,8 @@ class Event(models.Model): elif self.code == Event.SET_MILESTONE: description = "added this to the {milestone} milestone" elif self.code == Event.CHANGE_MILESTONE: - description = "moved this from the {old_milestone} milestone to the {new_mileston} milestone" - elif self.code == Event.DEL_MILESTONE: + description = "moved this from the {old_milestone} milestone to the {new_milestone} milestone" + elif self.code == Event.UNSET_MILESTONE: description = "deleted this from the {milestone} milestone" elif self.code == Event.REFERENCE: description = "referenced this issue" diff --git a/issue/templates/issue/issue.html b/issue/templates/issue/issue.html index ad3a38b..41118ad 100644 --- a/issue/templates/issue/issue.html +++ b/issue/templates/issue/issue.html @@ -35,15 +35,11 @@ {{ event.author}} {{ event }} {{ event.date|naturaltime }} {% if event.code == event.DESCRIBE %}
- - - +
{% elif event.code == event.COMMENT %}
- - - +
{% endif %} @@ -119,16 +115,29 @@ None yet {% endif %}
-
- Milestons -
- + Milestone +
+ -
- {% if issue.milestones.count %} - {% for milestone in issue.milestones.all %} - {{ milestone }} - {% endfor %} + +

+ {% if issue.milestone %} + + {{ issue.milestone }} {% else %} No milestone {% endif %} diff --git a/issue/templates/issue/label_edit.html b/issue/templates/issue/label_edit.html index 371c4db..bbfee25 100644 --- a/issue/templates/issue/label_edit.html +++ b/issue/templates/issue/label_edit.html @@ -7,7 +7,7 @@ {% block content %}
-
+
{{ form|crispy }} diff --git a/issue/templates/issue/milestone_list.html b/issue/templates/issue/milestone_list.html index a9df302..3f3eec9 100644 --- a/issue/templates/issue/milestone_list.html +++ b/issue/templates/issue/milestone_list.html @@ -2,16 +2,55 @@ {% block milestonetab %} class="active"{% endblock %} -{% block core %} +{% block content %} -Milestones : +
-
    +
    +

    + Milestone + +

    +
    + + {% if milestones.count %} + {% for milestone in milestones %} -
  • - {{ milestone }} -
  • + + + {% endfor %} - +
    + + + {{ milestone }} + +   + + {% if milestone.due_date %}Due by {{ milestone.due_date }}{% else %}No due date{% endif %} + +

    +
    +
    + {{ milestone.progress }}% complete +
    +
    +
    + {% else %} +
    + There aren't any milestones for this repository quite yet. +
    + {% endif %} + +
{% endblock %} diff --git a/issue/urls.py b/issue/urls.py index 0d7b158..6c5d3d7 100644 --- a/issue/urls.py +++ b/issue/urls.py @@ -16,13 +16,16 @@ urlpatterns = [ url(r'^(?P[a-z0-9_-]+)/issues/(?P[0-9]+)/delete$', 'issue.views.issue_delete', name='delete-issue'), url(r'^(?P[a-z0-9_-]+)/issues/(?P[0-9]+)/add-label/(?P