datatracker/ietf/review/models.py
Ole Laursen 59180240af Add a simple reminder system for reviewers so that they can opt in to
being reminded X days before deadline of an assignment
 - Legacy-Id: 12101
2016-10-07 16:43:29 +00:00

128 lines
6.1 KiB
Python

import datetime
from django.db import models
from ietf.doc.models import Document
from ietf.group.models import Group
from ietf.person.models import Person, Email
from ietf.name.models import ReviewTypeName, ReviewRequestStateName, ReviewResultName
class ReviewerSettings(models.Model):
"""Keeps track of admin data associated with the reviewer in the
particular team. There will be one record for each combination of
reviewer and team."""
team = models.ForeignKey(Group)
person = models.ForeignKey(Person)
INTERVALS = [
(7, "Once per week"),
(14, "Once per fortnight"),
(30, "Once per month"),
(61, "Once per two months"),
(91, "Once per quarter"),
]
min_interval = models.IntegerField(default=30, verbose_name="Can review at most", choices=INTERVALS)
filter_re = models.CharField(max_length=255, verbose_name="Filter regexp", blank=True, help_text="Draft names matching regular expression should not be assigned")
skip_next = models.IntegerField(default=0, verbose_name="Skip next assignments")
remind_days_before_deadline = models.IntegerField(null=True, blank=True, help_text="To get an email reminder in case you forget to do an assigned review, enter the number of days before a review deadline you want to receive it. Clear the field if you don't want a reminder.")
def __unicode__(self):
return u"{} in {}".format(self.person, self.team)
class UnavailablePeriod(models.Model):
team = models.ForeignKey(Group)
person = models.ForeignKey(Person)
start_date = models.DateField(default=datetime.date.today, help_text="Choose the start date so that you can still do a review if it's assigned just before the start date - this usually means you should mark yourself unavailable for assignment some time before you are actually away.")
end_date = models.DateField(blank=True, null=True, help_text="Leaving the end date blank means that the period continues indefinitely. You can end it later.")
AVAILABILITY_CHOICES = [
("canfinish", "Can do follow-ups"),
("unavailable", "Completely unavailable"),
]
LONG_AVAILABILITY_CHOICES = [
("canfinish", "Can do follow-up reviews and finish outstanding reviews"),
("unavailable", "Completely unavailable - reassign any outstanding reviews"),
]
availability = models.CharField(max_length=30, choices=AVAILABILITY_CHOICES)
def state(self):
import datetime
today = datetime.date.today()
if self.start_date <= today:
if not self.end_date or today <= self.end_date:
return "active"
else:
return "past"
else:
return "future"
def __unicode__(self):
return u"{} is unavailable in {} {} - {}".format(self.person, self.team.acronym, self.start_date, self.end_date or "")
class ReviewWish(models.Model):
"""Reviewer wishes to review a document when it becomes available for review."""
time = models.DateTimeField(default=datetime.datetime.now)
team = models.ForeignKey(Group)
person = models.ForeignKey(Person)
doc = models.ForeignKey(Document)
def __unicode__(self):
return u"{} wishes to review {} in {}".format(self.person, self.doc.name, self.team.acronym)
class ResultUsedInReviewTeam(models.Model):
"""Captures that a result name is valid for a given team for new
reviews. This also implicitly defines which teams are review
teams - if there are no possible review results valid for a given
team, it can't be a review team."""
team = models.ForeignKey(Group)
result = models.ForeignKey(ReviewResultName)
def __unicode__(self):
return u"{} in {}".format(self.result.name, self.team.acronym)
class TypeUsedInReviewTeam(models.Model):
"""Captures that a type name is valid for a given team for new
reviews. """
team = models.ForeignKey(Group)
type = models.ForeignKey(ReviewTypeName)
def __unicode__(self):
return u"{} in {}".format(self.type.name, self.team.acronym)
class NextReviewerInTeam(models.Model):
team = models.ForeignKey(Group)
next_reviewer = models.ForeignKey(Person)
def __unicode__(self):
return u"{} next in {}".format(self.next_reviewer, self.team)
class ReviewRequest(models.Model):
"""Represents a request for a review and the process it goes through.
There should be one ReviewRequest entered for each combination of
document, rev, and reviewer."""
state = models.ForeignKey(ReviewRequestStateName)
old_id = models.IntegerField(blank=True, null=True, help_text="ID in previous review system") # FIXME: remove this when everything has been migrated
# Fields filled in on the initial record creation - these
# constitute the request part.
time = models.DateTimeField(default=datetime.datetime.now)
type = models.ForeignKey(ReviewTypeName)
doc = models.ForeignKey(Document, related_name='reviewrequest_set')
team = models.ForeignKey(Group, limit_choices_to=~models.Q(resultusedinreviewteam=None))
deadline = models.DateField()
requested_by = models.ForeignKey(Person)
requested_rev = models.CharField(verbose_name="requested revision", max_length=16, blank=True, help_text="Fill in if a specific revision is to be reviewed, e.g. 02")
# Fields filled in as reviewer is assigned and as the review is
# uploaded. Once these are filled in and we progress beyond being
# requested/assigned, any changes to the assignment happens by
# closing down the current request and making a new one, copying
# the request-part fields above.
reviewer = models.ForeignKey(Email, blank=True, null=True)
review = models.OneToOneField(Document, blank=True, null=True)
reviewed_rev = models.CharField(verbose_name="reviewed revision", max_length=16, blank=True)
result = models.ForeignKey(ReviewResultName, blank=True, null=True)
def __unicode__(self):
return u"%s review on %s by %s %s" % (self.type, self.doc, self.team, self.state)