datatracker/ietf/nomcom/models.py

228 lines
9.1 KiB
Python

# -*- coding: utf-8 -*-
import os
from django.db import models
from django.db.models.signals import post_delete
from django.conf import settings
from django.contrib.auth.models import User
from django.template.loader import render_to_string
from django.template.defaultfilters import linebreaks
from ietf.nomcom.fields import EncryptedTextField
from ietf.person.models import Person,Email
from ietf.group.models import Group
from ietf.name.models import NomineePositionStateName, FeedbackTypeName
from ietf.dbtemplate.models import DBTemplate
from ietf.nomcom.managers import NomineePositionManager, NomineeManager, \
PositionManager, FeedbackManager
from ietf.nomcom.utils import (initialize_templates_for_group,
initialize_questionnaire_for_position,
initialize_requirements_for_position,
delete_nomcom_templates)
from ietf.utils.storage import NoLocationMigrationFileSystemStorage
def upload_path_handler(instance, filename):
return os.path.join(instance.group.acronym, 'public.cert')
class ReminderDates(models.Model):
date = models.DateField()
nomcom = models.ForeignKey('NomCom')
class NomCom(models.Model):
public_key = models.FileField(storage=NoLocationMigrationFileSystemStorage(location=settings.NOMCOM_PUBLIC_KEYS_DIR),
upload_to=upload_path_handler, blank=True, null=True)
group = models.ForeignKey(Group)
send_questionnaire = models.BooleanField(verbose_name='Send questionnaires automatically', default=False,
help_text='If you check this box, questionnaires are sent automatically after nominations.')
reminder_interval = models.PositiveIntegerField(help_text='If the nomcom user sets the interval field then a cron command will '
'send reminders to the nominees who have not responded using '
'the following formula: (today - nomination_date) % interval == 0.',
blank=True, null=True)
initial_text = models.TextField(verbose_name='Help text for nomination form',
blank=True)
class Meta:
verbose_name_plural = 'NomComs'
verbose_name = 'NomCom'
def __unicode__(self):
return self.group.acronym
def save(self, *args, **kwargs):
created = not self.id
super(NomCom, self).save(*args, **kwargs)
if created:
initialize_templates_for_group(self)
def year(self):
year = getattr(self,'_cached_year',None)
if year is None:
if self.group and self.group.acronym.startswith('nomcom'):
year = int(self.group.acronym[6:])
self._cached_year = year
return year
def delete_nomcom(sender, **kwargs):
nomcom = kwargs.get('instance', None)
delete_nomcom_templates(nomcom)
storage, path = nomcom.public_key.storage, nomcom.public_key.path
storage.delete(path)
post_delete.connect(delete_nomcom, sender=NomCom)
class Nomination(models.Model):
position = models.ForeignKey('Position')
candidate_name = models.CharField(verbose_name='Candidate name', max_length=255)
candidate_email = models.EmailField(verbose_name='Candidate email', max_length=255)
candidate_phone = models.CharField(verbose_name='Candidate phone', blank=True, max_length=255)
nominee = models.ForeignKey('Nominee')
comments = models.ForeignKey('Feedback')
nominator_email = models.EmailField(verbose_name='Nominator Email', blank=True)
user = models.ForeignKey(User, editable=False)
time = models.DateTimeField(auto_now_add=True)
share_nominator = models.BooleanField(verbose_name='Share nominator name with candidate', default=False,
help_text='Check this box to allow the NomCom to let the '
'person you are nominating know that you were '
'one of the people who nominated them. If you '
'do not check this box, your name will be confidential '
'and known only within NomCom.')
class Meta:
verbose_name_plural = 'Nominations'
def __unicode__(self):
return u"%s (%s)" % (self.candidate_name, self.candidate_email)
class Nominee(models.Model):
email = models.ForeignKey(Email)
person = models.ForeignKey(Person, blank=True, null=True)
nominee_position = models.ManyToManyField('Position', through='NomineePosition')
duplicated = models.ForeignKey('Nominee', blank=True, null=True)
nomcom = models.ForeignKey('NomCom')
objects = NomineeManager()
class Meta:
verbose_name_plural = 'Nominees'
unique_together = ('email', 'nomcom')
def __unicode__(self):
if self.email.person and self.email.person.name:
return u'%s <%s>' % (self.email.person.plain_name(), self.email.address)
else:
return self.email.address
def name(self):
if self.email.person and self.email.person.name:
return u'%s' % (self.email.person.plain_name(),)
else:
return self.email.address
class NomineePosition(models.Model):
position = models.ForeignKey('Position')
nominee = models.ForeignKey('Nominee')
state = models.ForeignKey(NomineePositionStateName)
time = models.DateTimeField(auto_now_add=True)
objects = NomineePositionManager()
class Meta:
verbose_name = 'Nominee position'
verbose_name_plural = 'Nominee positions'
unique_together = ('position', 'nominee')
ordering = ['nominee']
def save(self, **kwargs):
if not self.pk and not self.state_id:
self.state = NomineePositionStateName.objects.get(slug='pending')
super(NomineePosition, self).save(**kwargs)
def __unicode__(self):
return u"%s - %s" % (self.nominee, self.position)
@property
def questionnaires(self):
return Feedback.objects.questionnaires().filter(positions__in=[self.position],
nominees__in=[self.nominee])
class Position(models.Model):
nomcom = models.ForeignKey('NomCom')
name = models.CharField(verbose_name='Name', max_length=255, help_text='This short description will appear on the Nomination and Feedback pages. Be as descriptive as necessary. Past examples: "Transport AD", "IAB Member"')
requirement = models.ForeignKey(DBTemplate, related_name='requirement', null=True, editable=False)
questionnaire = models.ForeignKey(DBTemplate, related_name='questionnaire', null=True, editable=False)
is_open = models.BooleanField(verbose_name='Is open', default=False)
objects = PositionManager()
class Meta:
verbose_name_plural = 'Positions'
def __unicode__(self):
return self.name
def save(self, *args, **kwargs):
created = not self.id
super(Position, self).save(*args, **kwargs)
changed = False
if created and self.id and not self.requirement_id:
self.requirement = initialize_requirements_for_position(self)
changed = True
if created and self.id and not self.questionnaire_id:
self.questionnaire = initialize_questionnaire_for_position(self)
changed = True
if changed:
self.save()
def get_templates(self):
if hasattr(self, '_templates'):
return self._templates # pylint: disable=access-member-before-definition
from ietf.dbtemplate.models import DBTemplate
self._templates = DBTemplate.objects.filter(group=self.nomcom.group).filter(path__contains='/%s/position/' % self.id).order_by('title')
return self._templates
def get_questionnaire(self):
return render_to_string(self.questionnaire.path, {'position': self})
def get_requirement(self):
rendered = render_to_string(self.requirement.path, {'position': self})
if self.requirement.type_id=='plain':
rendered = linebreaks(rendered)
return rendered
class Feedback(models.Model):
nomcom = models.ForeignKey('NomCom')
author = models.EmailField(verbose_name='Author', blank=True)
positions = models.ManyToManyField('Position', blank=True, null=True)
nominees = models.ManyToManyField('Nominee', blank=True, null=True)
subject = models.TextField(verbose_name='Subject', blank=True)
comments = EncryptedTextField(verbose_name='Comments')
type = models.ForeignKey(FeedbackTypeName, blank=True, null=True)
user = models.ForeignKey(User, editable=False, blank=True, null=True)
time = models.DateTimeField(auto_now_add=True)
objects = FeedbackManager()
def __unicode__(self):
return u"from %s" % self.author
class Meta:
ordering = ['time']
class FeedbackLastSeen(models.Model):
reviewer = models.ForeignKey(Person)
nominee = models.ForeignKey(Nominee)
time = models.DateTimeField(auto_now=True)