Add command to send reminders
Add fields date an interval in nomcom models to send reminders Refactor some managers Add help_text to pending feedback form Limit types in pending feedback form See #969 #975 - Legacy-Id: 5683
This commit is contained in:
parent
6898c51490
commit
519d628cde
|
@ -51,7 +51,7 @@ class PositionNomineeField(forms.ChoiceField):
|
|||
positions = Position.objects.get_by_nomcom(self.nomcom).opened().order_by('name')
|
||||
results = []
|
||||
for position in positions:
|
||||
nominees = [('%s_%s' % (position.id, i.id), unicode(i)) for i in Nominee.objects.get_by_nomcom(self.nomcom).filter(nominee_position=position)]
|
||||
nominees = [('%s_%s' % (position.id, i.id), unicode(i)) for i in Nominee.objects.get_by_nomcom(self.nomcom).not_duplicated().filter(nominee_position=position)]
|
||||
if nominees:
|
||||
results.append((position.name, nominees))
|
||||
kwargs['choices'] = results
|
||||
|
@ -247,11 +247,11 @@ class EditChairFormPreview(FormPreview):
|
|||
|
||||
class EditNomcomForm(BaseNomcomForm, forms.ModelForm):
|
||||
|
||||
fieldsets = [('Edit nomcom', ('public_key', 'send_questionnaire'))]
|
||||
fieldsets = [('Edit nomcom', ('public_key', 'send_questionnaire', 'reminder_interval'))]
|
||||
|
||||
class Meta:
|
||||
model = NomCom
|
||||
fields = ('public_key', 'send_questionnaire')
|
||||
fields = ('public_key', 'send_questionnaire', 'reminder_interval')
|
||||
|
||||
|
||||
class MergeForm(BaseNomcomForm, forms.Form):
|
||||
|
@ -268,7 +268,7 @@ class MergeForm(BaseNomcomForm, forms.Form):
|
|||
|
||||
def clean_primary_email(self):
|
||||
email = self.cleaned_data['primary_email']
|
||||
nominees = Nominee.objects.get_by_nomcom(self.nomcom).filter(email__address=email)
|
||||
nominees = Nominee.objects.get_by_nomcom(self.nomcom).not_duplicated().filter(email__address=email)
|
||||
if not nominees:
|
||||
msg = "Does not exist a nomiee with this email"
|
||||
self._errors["primary_email"] = self.error_class([msg])
|
||||
|
@ -279,7 +279,7 @@ class MergeForm(BaseNomcomForm, forms.Form):
|
|||
data = self.cleaned_data['secondary_emails']
|
||||
emails = get_list(data)
|
||||
for email in emails:
|
||||
nominees = Nominee.objects.get_by_nomcom(self.nomcom).filter(email__address=email)
|
||||
nominees = Nominee.objects.get_by_nomcom(self.nomcom).not_duplicated().filter(email__address=email)
|
||||
if not nominees:
|
||||
msg = "Does not exist a nomiee with email %s" % email
|
||||
self._errors["primary_email"] = self.error_class([msg])
|
||||
|
@ -736,15 +736,23 @@ class PrivateKeyForm(BaseNomcomForm, forms.Form):
|
|||
|
||||
|
||||
class PendingFeedbackForm(BaseNomcomForm, forms.ModelForm):
|
||||
|
||||
|
||||
class Meta:
|
||||
model = Feedback
|
||||
fields = ('author', 'type', 'nominee')
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(PendingFeedbackForm, self).__init__(*args, **kwargs)
|
||||
self.fields['type'].queryset = FeedbackType.objects.exclude(slug='nomina')
|
||||
|
||||
|
||||
def set_nomcom(self, nomcom, user):
|
||||
self.nomcom = nomcom
|
||||
self.user = user
|
||||
self.fields['nominee'] = MultiplePositionNomineeField(nomcom=self.nomcom, required=True, widget=forms.SelectMultiple)
|
||||
self.fields['nominee'] = MultiplePositionNomineeField(nomcom=self.nomcom,
|
||||
required=True,
|
||||
widget=forms.SelectMultiple,
|
||||
help_text='Hold down "Control", or "Command" on a Mac, to select more than one.')
|
||||
|
||||
def save(self, commit=True):
|
||||
feedback = super(PendingFeedbackForm, self).save(commit=False)
|
||||
|
|
|
@ -9,7 +9,7 @@ from ietf.nomcom.models import Nominee, NomCom, Feedback
|
|||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = (u"Send a remind to each SDO Liaison Manager to update the list of persons authorized to send liaison statements on behalf of his SDO")
|
||||
help = (u"Registry feedback from email. Usage: feeback_email --nomcom-year <nomcom-year> --email-file <email-file>")
|
||||
option_list = BaseCommand.option_list + (
|
||||
make_option('--nomcom-year', dest='year', help='NomCom year'),
|
||||
make_option('--email-file', dest='email', help='Feedback email'),
|
||||
|
@ -35,7 +35,7 @@ class Command(BaseCommand):
|
|||
nomcom = NomCom.objects.get(group__acronym__icontains=year,
|
||||
group__state__slug='active')
|
||||
except NomCom.DoesNotExist:
|
||||
raise CommandError('NomCom %s does not exist' % year)
|
||||
raise CommandError("NomCom %s does not exist or it isn't active" % year)
|
||||
|
||||
by, subject, body = parse_email(msg)
|
||||
name, addr = parseaddr(by)
|
||||
|
|
65
ietf/nomcom/management/commands/send_reminders.py
Normal file
65
ietf/nomcom/management/commands/send_reminders.py
Normal file
|
@ -0,0 +1,65 @@
|
|||
import datetime
|
||||
import syslog
|
||||
from optparse import make_option
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.conf import settings
|
||||
|
||||
from ietf.utils.mail import send_mail
|
||||
|
||||
from ietf.dbtemplate.models import DBTemplate
|
||||
|
||||
from ietf.nomcom.models import Nominee, NomCom
|
||||
from ietf.nomcom.utils import NOMINEE_REMINDER_TEMPLATE
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = (u"Send reminders to nominees")
|
||||
option_list = BaseCommand.option_list + (
|
||||
make_option('--nomcom-year', dest='year', help='NomCom year'),
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
year = options.get('year', None)
|
||||
help_message = 'Usage: send_reminders --nomcom-year <nomcom-year>'
|
||||
|
||||
if not year:
|
||||
raise CommandError(help_message)
|
||||
|
||||
try:
|
||||
nomcom = NomCom.objects.get(group__acronym__icontains=year,
|
||||
group__state__slug='active')
|
||||
except NomCom.DoesNotExist:
|
||||
raise CommandError("NomCom %s does not exist or it isn't active" % year)
|
||||
|
||||
today = datetime.date.today()
|
||||
nomcom_template_path = '/nomcom/%s/' % nomcom.group.acronym
|
||||
mail_path = nomcom_template_path + NOMINEE_REMINDER_TEMPLATE
|
||||
mail_template = DBTemplate.objects.filter(group=nomcom.group, path=mail_path)
|
||||
mail_template = mail_template and mail_template[0] or None
|
||||
subject = 'IETF Nomination Information'
|
||||
from_email = settings.NOMCOM_FROM_EMAIL
|
||||
|
||||
if nomcom.reminder_interval:
|
||||
nominees = Nominee.objects.get_by_nomcom(nomcom).not_duplicated().filter(nomineeposition__state='pending').distinct()
|
||||
for nominee in nominees:
|
||||
positions = []
|
||||
for np in nominee.nomineeposition_set.all():
|
||||
nomination_date = np.time.date()
|
||||
if not (today - nomination_date).days <= 0:
|
||||
if (today - nomination_date).days % nomcom.reminder_interval == 0:
|
||||
positions.append(np.position)
|
||||
if positions:
|
||||
to_email = nominee.email.address
|
||||
context = {'positions': ', '.join([p.name for p in positions])}
|
||||
send_mail(None, to_email, from_email, subject, mail_path, context)
|
||||
syslog.syslog(u"Sent reminder to %s" % to_email)
|
||||
else:
|
||||
if nomcom.reminderdates_set.filter(date=today):
|
||||
nominees = Nominee.objects.get_by_nomcom(nomcom).not_duplicated().filter(nomineeposition__state='pending').distinct()
|
||||
for nominee in nominees:
|
||||
to_email = nominee.email.address
|
||||
positions = ', '.join([nominee_position.position.name for nominee_position in nominee.nomineeposition_set.pending()])
|
||||
context = {'positions': positions}
|
||||
send_mail(None, to_email, from_email, subject, mail_path, context)
|
||||
syslog.syslog(u"Sent reminder to %s" % to_email)
|
|
@ -8,12 +8,21 @@ class Migration(SchemaMigration):
|
|||
|
||||
def forwards(self, orm):
|
||||
|
||||
# Adding model 'ReminderDates'
|
||||
db.create_table('nomcom_reminderdates', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('date', self.gf('django.db.models.fields.DateField')()),
|
||||
('nomcom', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['nomcom.NomCom'])),
|
||||
))
|
||||
db.send_create_signal('nomcom', ['ReminderDates'])
|
||||
|
||||
# Adding model 'NomCom'
|
||||
db.create_table('nomcom_nomcom', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('public_key', self.gf('django.db.models.fields.files.FileField')(max_length=100, null=True, blank=True)),
|
||||
('group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['group.Group'])),
|
||||
('send_questionnaire', self.gf('django.db.models.fields.BooleanField')(default=False)),
|
||||
('reminder_interval', self.gf('django.db.models.fields.PositiveIntegerField')(null=True, blank=True)),
|
||||
))
|
||||
db.send_create_signal('nomcom', ['NomCom'])
|
||||
|
||||
|
@ -108,6 +117,9 @@ class Migration(SchemaMigration):
|
|||
# Removing unique constraint on 'Nominee', fields ['email', 'nomcom']
|
||||
db.delete_unique('nomcom_nominee', ['email_id', 'nomcom_id'])
|
||||
|
||||
# Deleting model 'ReminderDates'
|
||||
db.delete_table('nomcom_reminderdates')
|
||||
|
||||
# Deleting model 'NomCom'
|
||||
db.delete_table('nomcom_nomcom')
|
||||
|
||||
|
@ -365,6 +377,7 @@ class Migration(SchemaMigration):
|
|||
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'public_key': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
|
||||
'reminder_interval': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'send_questionnaire': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
|
||||
},
|
||||
'nomcom.nomination': {
|
||||
|
@ -408,6 +421,12 @@ class Migration(SchemaMigration):
|
|||
'questionnaire': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questionnaire'", 'null': 'True', 'to': "orm['dbtemplate.DBTemplate']"}),
|
||||
'requirement': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'requirement'", 'null': 'True', 'to': "orm['dbtemplate.DBTemplate']"})
|
||||
},
|
||||
'nomcom.reminderdates': {
|
||||
'Meta': {'object_name': 'ReminderDates'},
|
||||
'date': ('django.db.models.fields.DateField', [], {}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'nomcom': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.NomCom']"})
|
||||
},
|
||||
'person.email': {
|
||||
'Meta': {'object_name': 'Email'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
|
|
|
@ -27,6 +27,11 @@ 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=FileSystemStorage(location=settings.PUBLIC_KEYS_URL),
|
||||
upload_to=upload_path_handler, blank=True, null=True)
|
||||
|
@ -34,6 +39,10 @@ class NomCom(models.Model):
|
|||
group = models.ForeignKey(Group)
|
||||
send_questionnaire = models.BooleanField(verbose_name='Send automatically questionnaires"',
|
||||
help_text='If you check this box, questionnaires are sent automatically after nominations')
|
||||
reminder_interval = models.PositiveIntegerField(help_text='If the nomcom user 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)
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = 'NomComs'
|
||||
|
|
|
@ -11,7 +11,7 @@ from django.template import RequestContext
|
|||
from django.template.loader import render_to_string
|
||||
from django.utils import simplejson
|
||||
from django.db.models import Count, Q
|
||||
from django.forms.models import modelformset_factory
|
||||
from django.forms.models import modelformset_factory, inlineformset_factory
|
||||
|
||||
from ietf.utils.mail import send_mail
|
||||
|
||||
|
@ -23,7 +23,7 @@ from ietf.nomcom.decorators import member_required, private_key_required
|
|||
from ietf.nomcom.forms import (NominateForm, FeedbackForm, QuestionnaireForm,
|
||||
MergeForm, NomComTemplateForm, PositionForm,
|
||||
PrivateKeyForm, EditNomcomForm, PendingFeedbackForm)
|
||||
from ietf.nomcom.models import Position, NomineePosition, Nominee, Feedback, NomCom
|
||||
from ietf.nomcom.models import Position, NomineePosition, Nominee, Feedback, NomCom, ReminderDates
|
||||
from ietf.nomcom.utils import (get_nomcom_by_year, HOME_TEMPLATE,
|
||||
store_nomcom_private_key, get_hash_nominee_position,
|
||||
NOMINEE_REMINDER_TEMPLATE)
|
||||
|
@ -129,7 +129,7 @@ def private_index(request, year):
|
|||
@member_required(role='chair')
|
||||
def send_reminder_mail(request, year):
|
||||
nomcom = get_nomcom_by_year(year)
|
||||
nominees = Nominee.objects.get_by_nomcom(nomcom).filter(nomineeposition__state='pending').distinct()
|
||||
nominees = Nominee.objects.get_by_nomcom(nomcom).not_duplicated().filter(nomineeposition__state='pending').distinct()
|
||||
nomcom_template_path = '/nomcom/%s/' % nomcom.group.acronym
|
||||
mail_path = nomcom_template_path + NOMINEE_REMINDER_TEMPLATE
|
||||
mail_template = DBTemplate.objects.filter(group=nomcom.group, path=mail_path)
|
||||
|
@ -442,18 +442,25 @@ def edit_nomcom(request, year):
|
|||
nomcom = get_nomcom_by_year(year)
|
||||
|
||||
message = ('warning', 'Previous data will remain encrypted with the old key')
|
||||
|
||||
ReminderDateInlineFormSet = inlineformset_factory(NomCom, ReminderDates)
|
||||
if request.method == 'POST':
|
||||
formset = ReminderDateInlineFormSet(request.POST, instance=nomcom)
|
||||
form = EditNomcomForm(request.POST,
|
||||
request.FILES,
|
||||
instance=nomcom)
|
||||
if form.is_valid():
|
||||
if form.is_valid() and formset.is_valid():
|
||||
form.save()
|
||||
formset.save()
|
||||
formset = ReminderDateInlineFormSet(instance=nomcom)
|
||||
message = ('success', 'The nomcom has been changed')
|
||||
else:
|
||||
formset = ReminderDateInlineFormSet(instance=nomcom)
|
||||
form = EditNomcomForm(instance=nomcom)
|
||||
|
||||
return render_to_response('nomcom/edit_nomcom.html',
|
||||
{'form': form,
|
||||
'formset': formset,
|
||||
'nomcom': nomcom,
|
||||
'message': message,
|
||||
'year': year,
|
||||
|
|
|
@ -15,6 +15,42 @@
|
|||
<table>
|
||||
{{ form }}
|
||||
</table>
|
||||
|
||||
<h3>Reminder Dates</h3>
|
||||
|
||||
<p>If the "reminder interval" field of nomcom isn't filled, the following dates will be used to send reminders.</p>
|
||||
|
||||
<p>The valid format: <strong>YYYY-MM-DD</strong></p>
|
||||
|
||||
{{ formset.management_form }}
|
||||
{% for form in formset.forms %}
|
||||
{% if form.errors %}<div class="info-message-error">Please correct the following errors</div>{% endif %}
|
||||
<table style="width: 100%;"><tr><td>
|
||||
<div class="baseform">
|
||||
<div class="fieldset">
|
||||
{% for field in form %}
|
||||
<div id="baseform-fieldname-{{ field.html_name }}"
|
||||
{% if field.field.widget.is_hidden %}style="display: none;"{% endif %}
|
||||
class="{% if field.errors %}fieldError {% endif %}field BaseFormStringWidget{% if field.field.column_style %} {{ field.field.column_style }}{% endif %}">
|
||||
<label for="id_{{ field.html_name }}">{{ field.label }}
|
||||
{% if field.field.required %}
|
||||
<span class="fieldRequired" title="Required">*</span>
|
||||
{% endif %}
|
||||
</label>
|
||||
<div class="fieldWidget">
|
||||
<div id="{{ field.html_name }}_help" class="formHelp"> {{ field.help_text }}</div>
|
||||
{{ field }}
|
||||
{{ field.errors }}
|
||||
</div>
|
||||
<div class="endfield"></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</td><td style="width: 50%; vertical-align: top;">
|
||||
</td></tr></table>
|
||||
{% endfor %}
|
||||
|
||||
<p><input type="submit" value="Save" /></p>
|
||||
</form>
|
||||
|
||||
|
|
Loading…
Reference in a new issue