From 7c4cf7002f18b6f7f3525b1e60b48093a4c1667e Mon Sep 17 00:00:00 2001 From: Robert Sparks Date: Thu, 3 Oct 2013 22:36:57 +0000 Subject: [PATCH 1/4] Allow the secretariat and ads to change the title of a status change document. Fixes bug 1141 Commit ready to merge. - Legacy-Id: 6361 --- ietf/doc/tests_status_change.py | 19 +++++++++ ietf/doc/urls_status_change.py | 1 + ietf/doc/views_status_change.py | 35 ++++++++++++++++ ietf/templates/doc/change_title.html | 42 +++++++++++++++++++ .../templates/doc/document_status_change.html | 7 +++- 5 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 ietf/templates/doc/change_title.html diff --git a/ietf/doc/tests_status_change.py b/ietf/doc/tests_status_change.py index 4412ec951..a5b3c5982 100644 --- a/ietf/doc/tests_status_change.py +++ b/ietf/doc/tests_status_change.py @@ -150,6 +150,25 @@ class StatusChangeTestCase(TestCase): self.assertEquals(doc.notify,newlist) self.assertTrue(doc.latest_event(DocEvent,type="added_comment").desc.startswith('Notification list changed')) + def test_edit_title(self): + doc = Document.objects.get(name='status-change-imaginary-mid-review') + url = urlreverse('status_change_title',kwargs=dict(name=doc.name)) + + login_testing_unauthorized(self, "ad", url) + + # normal get + r = self.client.get(url) + self.assertEquals(r.status_code, 200) + q = PyQuery(r.content) + self.assertEquals(len(q('input[name=title]')),1) + + # change title + r = self.client.post(url,dict(title='New title')) + self.assertEquals(r.status_code,302) + doc = Document.objects.get(name='status-change-imaginary-mid-review') + self.assertEquals(doc.title,'New title') + self.assertTrue(doc.latest_event(DocEvent,type="added_comment").desc.startswith('Title changed')) + def test_edit_ad(self): doc = Document.objects.get(name='status-change-imaginary-mid-review') url = urlreverse('status_change_ad',kwargs=dict(name=doc.name)) diff --git a/ietf/doc/urls_status_change.py b/ietf/doc/urls_status_change.py index 573835833..94f6899f0 100644 --- a/ietf/doc/urls_status_change.py +++ b/ietf/doc/urls_status_change.py @@ -5,6 +5,7 @@ urlpatterns = patterns('ietf.doc.views_status_change', url(r'^submit/$', "submit", name='status_change_submit'), url(r'^notices/$', "edit_notices", name='status_change_notices'), url(r'^ad/$', "edit_ad", name='status_change_ad'), + url(r'^title/$', "edit_title", name='status_change_title'), url(r'^approve/$', "approve", name='status_change_approve'), url(r'^telechat/$', "telechat_date", name='status_change_telechat_date'), url(r'^relations/$', "edit_relations", name='status_change_relations'), diff --git a/ietf/doc/views_status_change.py b/ietf/doc/views_status_change.py index 8c4094fd7..21d3334b4 100644 --- a/ietf/doc/views_status_change.py +++ b/ietf/doc/views_status_change.py @@ -236,6 +236,41 @@ def edit_notices(request, name): }, context_instance = RequestContext(request)) +class ChangeTitleForm(forms.Form): + title = forms.CharField(max_length=255, label="Title", required=True) + +@role_required("Area Director", "Secretariat") +def edit_title(request, name): + """Change the title for this status_change document.""" + + status_change = get_object_or_404(Document, type="statchg", name=name) + + if request.method == 'POST': + form = ChangeTitleForm(request.POST) + if form.is_valid(): + + status_change.title = form.cleaned_data['title'] + status_change.save() + + login = request.user.get_profile() + c = DocEvent(type="added_comment", doc=status_change, by=login) + c.desc = "Title changed to '%s'"%status_change.title + c.save() + + return redirect("doc_view", name=status_change.name) + + else: + init = { "title" : status_change.title } + form = ChangeTitleForm(initial=init) + + titletext = '%s-%s.txt' % (status_change.canonical_name(),status_change.rev) + return render_to_response('doc/change_title.html', + {'form': form, + 'doc': status_change, + 'titletext' : titletext, + }, + context_instance = RequestContext(request)) + @role_required("Area Director", "Secretariat") def edit_ad(request, name): """Change the shepherding Area Director for this status_change.""" diff --git a/ietf/templates/doc/change_title.html b/ietf/templates/doc/change_title.html new file mode 100644 index 000000000..8a27e7ed0 --- /dev/null +++ b/ietf/templates/doc/change_title.html @@ -0,0 +1,42 @@ +{% extends "base.html" %} + +{% block morecss %} +.warning { + font-weight: bold; + color: #a00; +} +form.edit-info #id_title { + width: 600px; +} +{% endblock %} + +{% block title %} +Change the title for {{titletext}} +{% endblock %} + +{% block content %} +

Change the title for {{titletext}}

+ +
+ + {% for field in form.visible_fields %} + + + + + {% endfor %} + + + + +
{{ field.label_tag }}: + {{ field }} + {% if field.help_text %}
{{ field.help_text }}
{% endif %} + {{ field.errors }} +
+ Back + +
+
+ +{% endblock %} diff --git a/ietf/templates/doc/document_status_change.html b/ietf/templates/doc/document_status_change.html index 152b5e4e4..fb52143d2 100644 --- a/ietf/templates/doc/document_status_change.html +++ b/ietf/templates/doc/document_status_change.html @@ -24,7 +24,12 @@
{% if snapshot %}Snapshot of{% endif %} {% if doc.get_state_slug not in approved_states %}Proposed{% endif %} - Status change : {{ doc.title }} + Status change : + + {{ doc.title }}
From 3814b60c5d5aca6983ecdda8a5bcaee83df282a3 Mon Sep 17 00:00:00 2001 From: Robert Sparks Date: Thu, 10 Oct 2013 20:59:06 +0000 Subject: [PATCH 2/4] Removed redundant call to not_duplicated from the nomcom/private_index template It was already applied in the view, and interacted badly with the list comprehension method of filtering for NomineePositions that had associated questionnaire responses. Fixes bug 1151 Commit ready for merge - Legacy-Id: 6413 --- ietf/templates/nomcom/private_index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ietf/templates/nomcom/private_index.html b/ietf/templates/nomcom/private_index.html index 7c7319334..65b6973c1 100644 --- a/ietf/templates/nomcom/private_index.html +++ b/ietf/templates/nomcom/private_index.html @@ -103,7 +103,7 @@ replied to the nomination notification they have received.){% endif %}

- {% for np in nominee_positions.not_duplicated %} + {% for np in nominee_positions %} {% if is_chair %} @@ -123,4 +123,4 @@ replied to the nomination notification they have received.){% endif %}

{% endif %} Date: Fri, 18 Oct 2013 16:08:37 +0000 Subject: [PATCH 3/4] Added the ability to send reminders to complete questionnaires to nominees in the accepted state. Changed the send_reminders management command to not take any arguments and run against all active nomcoms. Removed bugs from the send_reminders management command and added tests for it. Adjusted several dbtemplate titles and content. Fixes bug 1157 Commit ready for merge - Legacy-Id: 6465 --- ietf/dbtemplate/fixtures/nomcom_templates.xml | 22 +++++-- .../management/commands/send_reminders.py | 65 ++++++++----------- ietf/nomcom/tests.py | 65 ++++++++++++++++++- ietf/nomcom/urls.py | 6 +- ietf/nomcom/utils.py | 53 ++++++++++++--- ietf/nomcom/views.py | 41 ++++++++---- .../templates/nomcom/nomcom_private_base.html | 3 +- ietf/templates/nomcom/private_index.html | 2 - ietf/templates/nomcom/send_reminder_mail.html | 19 +++--- 9 files changed, 195 insertions(+), 81 deletions(-) diff --git a/ietf/dbtemplate/fixtures/nomcom_templates.xml b/ietf/dbtemplate/fixtures/nomcom_templates.xml index bd15def85..1059d7073 100644 --- a/ietf/dbtemplate/fixtures/nomcom_templates.xml +++ b/ietf/dbtemplate/fixtures/nomcom_templates.xml @@ -96,8 +96,8 @@ $position: Position - - /nomcom/defaults/email/nomination_reminder.txt + + /nomcom/defaults/email/nomination_accept_reminder.txt Email sent to nominees asking them to accept (or decline) the nominations. $positions: Nomination positions plain @@ -114,7 +114,7 @@ If you accept, you will need to fill out a questionnaire. Best regards, - + /nomcom/defaults/email/nomination_receipt.txt Email sent to nominator to get a confirmation mail containing feedback in cleartext $nominee: Full name of the nominee @@ -137,7 +137,7 @@ $comments Thank you, - + /nomcom/defaults/email/feedback_receipt.txt Email sent to feedback author to get a confirmation mail containing feedback in cleartext $nominee: Full name of the nominee @@ -158,4 +158,18 @@ $comments Thank you, + + /nomcom/defaults/email/questionnaire_reminder.txt + Email sent to nominees reminding them to complete a questionnaire + $positions: Nomination positions + plain + +Thank you for accepting your nomination for the position of $position. + +Please remember to complete and return the questionnaire for this position at your earliest opportunity. +The questionaire is repeated below for your convenience. + +-------- + + diff --git a/ietf/nomcom/management/commands/send_reminders.py b/ietf/nomcom/management/commands/send_reminders.py index 8a0d55529..7d1350bc5 100644 --- a/ietf/nomcom/management/commands/send_reminders.py +++ b/ietf/nomcom/management/commands/send_reminders.py @@ -1,48 +1,35 @@ import datetime import syslog from optparse import make_option +from django.core.management.base import BaseCommand +from ietf.nomcom.models import NomCom, NomineePosition +from nomcom.utils import send_accept_reminder_to_nominee,send_questionnaire_reminder_to_nominee -from django.core.management.base import BaseCommand, CommandError - -from ietf.nomcom.models import Nominee, NomCom -from nomcom.utils import send_reminder_to_nominee +def log(message): + syslog.syslog(message) +def is_time_to_send(nomcom,send_date,nomination_date): + if nomcom.reminder_interval: + days_passed = (send_date - nomination_date).days + return days_passed > 0 and days_passed % nomcom.reminder_interval == 0 + else: + return bool(nomcom.reminderdates_set.filter(date=send_date)) class Command(BaseCommand): - help = (u"Send reminders to nominees") - option_list = BaseCommand.option_list + ( - make_option('--nomcom-year', dest='year', help='NomCom year'),) + help = (u"Send acceptance and questionnaire reminders to nominees") def handle(self, *args, **options): - year = options.get('year', None) - help_message = 'Usage: send_reminders --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() - - if nomcom.reminder_interval: - nominees = Nominee.objects.get_by_nomcom(nomcom).not_duplicated().filter(nomineeposition__state='pending').distinct() - for nominee in nominees: - for nominee_position in nominee.nomineeposition_set.all(): - nomination_date = nominee_position.time.date() - if not (today - nomination_date).days <= 0: - if (today - nomination_date).days % nomcom.reminder_interval == 0: - send_reminder_to_nominee(nominee_position) - syslog.syslog(u"Sent reminder to %s" % nominee_position.nominee.email.address) - print u"Sent reminder to %s" % nominee_position.nominee.email.address - 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: - for nominee_position in nominee.nomineeposition_set.pending(): - send_reminder_to_nominee(nominee_position) - syslog.syslog(u"Sent reminder to %s" % nominee_position.nominee.email.address) - print u"Sent reminder (by dates) to %s" % nominee_position.nominee.email.address + for nomcom in NomCom.objects.filter(group__state__slug='active'): + for state in ('pending','accepted'): + for nominee_position in NomineePosition.objects.filter(nominee__nomcom=nomcom, + state=state, + nominee__duplicated__isnull=True): + if is_time_to_send(nomcom, datetime.date.today(), nominee_position.time.date()): + if state=='pending': + send_accept_reminder_to_nominee(nominee_position) + log('Sent accept reminder to %s' % nominee_position.nominee.email.address) + elif state=='accepted': + send_questionnaire_reminder_to_nominee(nominee_position) + log('Sent questionnaire reminder to %s' % nominee_position.nominee.email.address) + else: + pass diff --git a/ietf/nomcom/tests.py b/ietf/nomcom/tests.py index f5f9f4428..3a10ad102 100644 --- a/ietf/nomcom/tests.py +++ b/ietf/nomcom/tests.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import os import tempfile +import datetime from ietf.utils import TestCase from django.db import IntegrityError @@ -9,6 +10,7 @@ from django.core.files import File from django.contrib.formtools.preview import security_hash from ietf.utils.test_utils import login_testing_unauthorized +from ietf.utils.mail import outbox from ietf.person.models import Email, Person @@ -20,7 +22,8 @@ from ietf.nomcom.models import NomineePosition, Position, Nominee, \ NomineePositionState, Feedback, FeedbackType, \ Nomination from ietf.nomcom.forms import EditChairForm, EditMembersForm -from ietf.nomcom.utils import get_nomcom_by_year +from ietf.nomcom.utils import get_nomcom_by_year, get_or_create_nominee +from ietf.nomcom.management.commands.send_reminders import Command, is_time_to_send class NomcomViewsTest(TestCase): @@ -653,3 +656,63 @@ class FeedbackTest(TestCase): os.unlink(self.privatekey_file.name) os.unlink(self.cert_file.name) + +class ReminderCommandTest(TestCase): + perma_fixtures = ['names', 'nomcom_templates'] + + def setUp(self): + nomcom_test_data() + self.nomcom = get_nomcom_by_year(NOMCOM_YEAR) + + gen = Position.objects.get(nomcom=self.nomcom,name='GEN') + rai = Position.objects.get(nomcom=self.nomcom,name='RAI') + iab = Position.objects.get(nomcom=self.nomcom,name='IAB') + + today = datetime.date.today() + t_minus_3 = today - datetime.timedelta(days=3) + t_minus_4 = today - datetime.timedelta(days=4) + n = get_or_create_nominee(self.nomcom,"Nominee 1","nominee1@example.org",gen,None) + np = n.nomineeposition_set.get(position=gen) + np.time = t_minus_3 + np.save() + n = get_or_create_nominee(self.nomcom,"Nominee 1","nominee1@example.org",iab,None) + np = n.nomineeposition_set.get(position=iab) + np.state = NomineePositionState.objects.get(slug='accepted') + np.time = t_minus_3 + np.save() + n = get_or_create_nominee(self.nomcom,"Nominee 2","nominee2@example.org",rai,None) + np = n.nomineeposition_set.get(position=rai) + np.time = t_minus_4 + np.save() + + def test_is_time_to_send(self): + self.nomcom.reminder_interval = 4 + today = datetime.date.today() + self.assertTrue(is_time_to_send(self.nomcom,today+datetime.timedelta(days=4),today)) + for delta in range(4): + self.assertFalse(is_time_to_send(self.nomcom,today+datetime.timedelta(days=delta),today)) + self.nomcom.reminder_interval = None + self.assertFalse(is_time_to_send(self.nomcom,today,today)) + self.nomcom.reminderdates_set.create(date=today) + self.assertTrue(is_time_to_send(self.nomcom,today,today)) + + def test_command(self): + c = Command() + messages_before=len(outbox) + self.nomcom.reminder_interval = 3 + self.nomcom.save() + c.handle(None,None) + self.assertEqual(len(outbox), messages_before + 2) + self.assertTrue('nominee1@example.org' in outbox[-1]['To']) + self.assertTrue('please complete' in outbox[-1]['Subject']) + self.assertTrue('nominee1@example.org' in outbox[-2]['To']) + self.assertTrue('please accept' in outbox[-2]['Subject']) + messages_before=len(outbox) + self.nomcom.reminder_interval = 4 + self.nomcom.save() + c.handle(None,None) + self.assertEqual(len(outbox), messages_before + 1) + self.assertTrue('nominee2@example.org' in outbox[-1]['To']) + self.assertTrue('please accept' in outbox[-1]['Subject']) + + diff --git a/ietf/nomcom/urls.py b/ietf/nomcom/urls.py index 8e3ccd308..4bfdbfca0 100644 --- a/ietf/nomcom/urls.py +++ b/ietf/nomcom/urls.py @@ -1,5 +1,6 @@ from django.conf.urls.defaults import patterns, url -from django.views.generic.simple import direct_to_template +from django.views.generic.simple import direct_to_template, redirect_to +from ietf.utils.lazy import reverse_lazy from ietf.nomcom.forms import EditChairForm, EditChairFormPreview, \ EditMembersForm, EditMembersFormPreview @@ -17,7 +18,8 @@ urlpatterns = patterns('ietf.nomcom.views', url(r'^(?P\d{4})/private/view-feedback/nominee/(?P\d+)$', 'view_feedback_nominee', name='nomcom_view_feedback_nominee'), url(r'^(?P\d{4})/private/edit/nominee/(?P\d+)$', 'edit_nominee', name='nomcom_edit_nominee'), url(r'^(?P\d{4})/private/merge/$', 'private_merge', name='nomcom_private_merge'), - url(r'^(?P\d{4})/private/send-reminder-mail/$', 'send_reminder_mail', name='nomcom_send_reminder_mail'), +# url(r'^(?P\d{4})/private/send-reminder-mail/$', redirect_to, { 'url': reverse_lazy('nomcom_send_reminder_mail',kwargs={'year':year,'type':'accept'})}), + url(r'^(?P\d{4})/private/send-reminder-mail/(?P\w+)/$', 'send_reminder_mail', name='nomcom_send_reminder_mail'), url(r'^(?P\d{4})/private/edit-members/$', EditMembersFormPreview(EditMembersForm), name='nomcom_edit_members'), url(r'^(?P\d{4})/private/edit-chair/$', EditChairFormPreview(EditChairForm), name='nomcom_edit_chair'), url(r'^(?P\d{4})/private/edit-nomcom/$', 'edit_nomcom', name='nomcom_edit_nomcom'), diff --git a/ietf/nomcom/utils.py b/ietf/nomcom/utils.py index 869925b27..4361cacd6 100644 --- a/ietf/nomcom/utils.py +++ b/ietf/nomcom/utils.py @@ -32,7 +32,8 @@ HOME_TEMPLATE = 'home.rst' INEXISTENT_PERSON_TEMPLATE = 'email/inexistent_person.txt' NOMINEE_EMAIL_TEMPLATE = 'email/new_nominee.txt' NOMINATION_EMAIL_TEMPLATE = 'email/new_nomination.txt' -NOMINEE_REMINDER_TEMPLATE = 'email/nomination_reminder.txt' +NOMINEE_ACCEPT_REMINDER_TEMPLATE = 'email/nomination_accept_reminder.txt' +NOMINEE_QUESTIONNAIRE_REMINDER_TEMPLATE = 'email/questionnaire_reminder.txt' NOMINATION_RECEIPT_TEMPLATE = 'email/nomination_receipt.txt' FEEDBACK_RECEIPT_TEMPLATE = 'email/feedback_receipt.txt' @@ -40,7 +41,8 @@ DEFAULT_NOMCOM_TEMPLATES = [HOME_TEMPLATE, INEXISTENT_PERSON_TEMPLATE, NOMINEE_EMAIL_TEMPLATE, NOMINATION_EMAIL_TEMPLATE, - NOMINEE_REMINDER_TEMPLATE, + NOMINEE_ACCEPT_REMINDER_TEMPLATE, + NOMINEE_QUESTIONNAIRE_REMINDER_TEMPLATE, NOMINATION_RECEIPT_TEMPLATE, FEEDBACK_RECEIPT_TEMPLATE] @@ -107,7 +109,7 @@ def initialize_questionnaire_for_position(position): content=header_template.content) questionnaire = DBTemplate.objects.create( group=position.nomcom.group, - title=template.title + '[%s]' % position.name, + title=template.title + ' [%s]' % position.name, path='/nomcom/' + position.nomcom.group.acronym + '/' + str(position.id) + '/' + QUESTIONNAIRE_TEMPLATE, variables=template.variables, type_id=template.type_id, @@ -191,15 +193,15 @@ def validate_public_key(public_key): return (not error, error) -def send_reminder_to_nominee(nominee_position): +def send_accept_reminder_to_nominee(nominee_position): today = datetime.date.today().strftime('%Y%m%d') - subject = 'IETF Nomination Information' + subject = 'Reminder: please accept (or decline) your nomination.' from_email = settings.NOMCOM_FROM_EMAIL domain = Site.objects.get_current().domain position = nominee_position.position nomcom = position.nomcom nomcom_template_path = '/nomcom/%s/' % nomcom.group.acronym - mail_path = nomcom_template_path + NOMINEE_REMINDER_TEMPLATE + mail_path = nomcom_template_path + NOMINEE_ACCEPT_REMINDER_TEMPLATE nominee = nominee_position.nominee to_email = nominee.email.address @@ -229,11 +231,42 @@ def send_reminder_to_nominee(nominee_position): body += '\n\n%s' % render_to_string(path, context) send_mail_text(None, to_email, from_email, subject, body) +def send_questionnaire_reminder_to_nominee(nominee_position): + today = datetime.date.today().strftime('%Y%m%d') + subject = 'Reminder: please complete the Nomcom questionnaires for your nomination.' + from_email = settings.NOMCOM_FROM_EMAIL + domain = Site.objects.get_current().domain + position = nominee_position.position + nomcom = position.nomcom + nomcom_template_path = '/nomcom/%s/' % nomcom.group.acronym + mail_path = nomcom_template_path + NOMINEE_QUESTIONNAIRE_REMINDER_TEMPLATE + nominee = nominee_position.nominee + to_email = nominee.email.address -def send_reminder_to_nominees(nominees): - for nominee in nominees: - for nominee_position in nominee.nomineeposition_set.pending(): - send_reminder_to_nominee(nominee_position) + hash = get_hash_nominee_position(today, nominee_position.id) + + context = {'nominee': nominee, + 'position': position, + 'domain': domain, + } + body = render_to_string(mail_path, context) + path = '%s%d/%s' % (nomcom_template_path, position.id, QUESTIONNAIRE_TEMPLATE) + body += '\n\n%s' % render_to_string(path, context) + send_mail_text(None, to_email, from_email, subject, body) + +def send_reminder_to_nominees(nominees,type): + addrs = [] + if type=='accept': + for nominee in nominees: + for nominee_position in nominee.nomineeposition_set.pending(): + send_accept_reminder_to_nominee(nominee_position) + addrs.append(nominee_position.nominee.email.address) + elif type=='questionnaire': + for nominee in nominees: + for nominee_position in nominee.nomineeposition_set.accepted(): + send_questionnaire_reminder_to_nominee(nominee_position) + addrs.append(nominee_position.nominee.email.address) + return addrs def get_or_create_nominee(nomcom, candidate_name, candidate_email, position, author): diff --git a/ietf/nomcom/views.py b/ietf/nomcom/views.py index 8b4ec220c..bb095ee87 100644 --- a/ietf/nomcom/views.py +++ b/ietf/nomcom/views.py @@ -31,11 +31,9 @@ from ietf.nomcom.forms import (NominateForm, FeedbackForm, QuestionnaireForm, from ietf.nomcom.models import Position, NomineePosition, Nominee, Feedback, NomCom, ReminderDates from ietf.nomcom.utils import (get_nomcom_by_year, store_nomcom_private_key, get_hash_nominee_position, send_reminder_to_nominees, - HOME_TEMPLATE, NOMINEE_REMINDER_TEMPLATE) + HOME_TEMPLATE, NOMINEE_ACCEPT_REMINDER_TEMPLATE,NOMINEE_QUESTIONNAIRE_REMINDER_TEMPLATE) from ietf.ietfauth.utils import role_required -import debug - def index(request): nomcom_list = Group.objects.filter(type__slug='nomcom').order_by('acronym') for nomcom in nomcom_list: @@ -166,11 +164,27 @@ def private_index(request, year): @role_required("Nomcom Chair", "Nomcom Advisor") -def send_reminder_mail(request, year): +def send_reminder_mail(request, year, type): nomcom = get_nomcom_by_year(year) - 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 + + if type=='accept': + interesting_state = 'pending' + mail_path = nomcom_template_path + NOMINEE_ACCEPT_REMINDER_TEMPLATE + reminder_description = 'accept (or decline) a nomination' + selected_tab = 'send_accept_reminder' + elif type=='questionnaire': + interesting_state = 'accepted' + mail_path = nomcom_template_path + NOMINEE_QUESTIONNAIRE_REMINDER_TEMPLATE + reminder_description = 'complete the questionnaire for a nominated position' + selected_tab = 'send_questionnaire_reminder' + else: + raise Http404 + + nominees = Nominee.objects.get_by_nomcom(nomcom).not_duplicated().filter(nomineeposition__state=interesting_state).distinct() + annotated_nominees = list(nominees) + for nominee in annotated_nominees: + nominee.interesting_positions = [x.position.name for x in nominee.nomineeposition_set.all() if x.state.slug==interesting_state] mail_template = DBTemplate.objects.filter(group=nomcom.group, path=mail_path) mail_template = mail_template and mail_template[0] or None message = None @@ -179,16 +193,21 @@ def send_reminder_mail(request, year): selected_nominees = request.POST.getlist('selected') selected_nominees = nominees.filter(id__in=selected_nominees) if selected_nominees: - send_reminder_to_nominees(selected_nominees) - message = ('success', 'An query has been sent to each person, asking them to accept (or decline) the nominations') + addrs = send_reminder_to_nominees(selected_nominees,type) + if addrs: + message = ('success', 'A copy of "%s" has been sent to %s'%(mail_template.title,", ".join(addrs))) + else: + message = {'warning', 'No messages were sent.'} else: - message = ('warning', "Please, select some nominee") + message = ('warning', "Please, select at least one nominee") return render_to_response('nomcom/send_reminder_mail.html', {'nomcom': nomcom, 'year': year, - 'nominees': nominees, + 'nominees': annotated_nominees, 'mail_template': mail_template, - 'selected': 'send_reminder_mail', + 'selected': selected_tab, + 'reminder_description': reminder_description, + 'state_description': NomineePositionState.objects.get(slug=interesting_state).name, 'message': message}, RequestContext(request)) diff --git a/ietf/templates/nomcom/nomcom_private_base.html b/ietf/templates/nomcom/nomcom_private_base.html index 8573fa715..6b5a20451 100644 --- a/ietf/templates/nomcom/nomcom_private_base.html +++ b/ietf/templates/nomcom/nomcom_private_base.html @@ -19,7 +19,8 @@ {% if user|is_chair:year %} | {% if selected == "feedback_pending" %}Pending Feedback{% else %}Pending Feedback{% endif %} | {% if selected == "feedback_email" %}Enter Email Feedback{% else %}Enter Email Feedback{% endif %} | - {% if selected == "send_reminder_mail" %}Send Reminder{% else %}Send Reminder{% endif %} + {% if selected == "send_accept_reminder" %}Send Accept Reminder{% else %}Send Accept Reminder{% endif %} | + {% if selected == "send_questionnaire_reminder" %}Send Questionnaire Reminder{% else %}Send Questionnaire Reminder{% endif %} {% endif %} {% if user|is_chair:year %} diff --git a/ietf/templates/nomcom/private_index.html b/ietf/templates/nomcom/private_index.html index 65b6973c1..5815ec168 100644 --- a/ietf/templates/nomcom/private_index.html +++ b/ietf/templates/nomcom/private_index.html @@ -33,8 +33,6 @@

List of nominees by position

The following is a list of registered nominees. -{% if is_chair %}(You can request confirmation from nominees if they haven't -replied to the nomination notification they have received.){% endif %}

diff --git a/ietf/templates/nomcom/send_reminder_mail.html b/ietf/templates/nomcom/send_reminder_mail.html index 456a32b6c..eea18e111 100644 --- a/ietf/templates/nomcom/send_reminder_mail.html +++ b/ietf/templates/nomcom/send_reminder_mail.html @@ -1,18 +1,15 @@ {% extends "nomcom/nomcom_private_base.html" %} +{% load ietf_filters %} -{% block subtitle %} - Send reminder emails {% endblock %} +{% block subtitle %} - Send reminder messages {% endblock %} {% block nomcom_content %} -

Request nomination acceptance from the listed nominees

+

Send a message to the selected nominees reminding them to {{reminder_description}}

-

-An query will be sent to each person, asking them to accept (or decline) the nomination. +

These are the nominees that are in the '{{state_description}}' state for the listed positions.

-The list has been pre-populated with the selected list of nominees - -The message that will be sent is shown below the address entry form. -

+

The message that will be sent is shown below the list of nominees.

Nominees who have not responded

@@ -31,7 +28,7 @@ The message that will be sent is shown below the address entry form.
- + {% endfor %}
State Questionnaire response
{{ nominee }}{% for nominee_position in nominee.nomineeposition_set.all %}{% ifequal nominee_position.state.slug "pending" %} {{ nominee_position.position.name }}, {% endifequal %}{% endfor %}{{nominee.interesting_positions|join:", "}}
@@ -46,6 +43,6 @@ The message that will be sent is shown below the address entry form.

The message that will be sent is as follows: {% if mail_template %}(Edit the message){% endif %}

-{% include mail_template.path %} +
{{ mail_template.content|wrap_text:80|escape }}
-{% endblock %} \ No newline at end of file +{% endblock %} From a461e6c4a42526005bc53740675094df8ea2b011 Mon Sep 17 00:00:00 2001 From: Robert Sparks Date: Fri, 18 Oct 2013 16:10:44 +0000 Subject: [PATCH 4/4] Missed adding the new migrations to the last commit - apologies Commit ready to merge - Legacy-Id: 6466 --- .../0004_split_reminder_template.py | 329 +++++++++++++++ .../migrations/0005_default_template_edits.py | 379 ++++++++++++++++++ 2 files changed, 708 insertions(+) create mode 100644 ietf/nomcom/migrations/0004_split_reminder_template.py create mode 100644 ietf/nomcom/migrations/0005_default_template_edits.py diff --git a/ietf/nomcom/migrations/0004_split_reminder_template.py b/ietf/nomcom/migrations/0004_split_reminder_template.py new file mode 100644 index 000000000..65cb0bce9 --- /dev/null +++ b/ietf/nomcom/migrations/0004_split_reminder_template.py @@ -0,0 +1,329 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models + +import textwrap +from ietf.dbtemplate.models import DBTemplate +from ietf.name.models import DBTemplateTypeName +from ietf.group.models import Group + +new_template_content = textwrap.dedent("""\ + Thank you for accepting your nomination for the position of $position. + + Please remember to complete and return the questionnaire for this position at your earliest opportunity. + The questionaire is repeated below for your convenience. + + -------- + +""") + +class Migration(DataMigration): + + def forwards(self, orm): + for group_name in ['defaults','nomcom2013']: + template = DBTemplate.objects.get(path='/nomcom/%s/email/nomination_reminder.txt'%group_name) + template.path='/nomcom/%s/email/nomination_accept_reminder.txt'%group_name + template.title='Email sent to nominees reminding them to accept (or decline) the nominations.' + template.save() + # variables below are copied from the current reminder template. It's not clear this value is what it should be + DBTemplate.objects.create(path='/nomcom/%s/email/questionnaire_reminder.txt'%group_name, + title='Email sent to nominees reminding them to submit completed questionnaires.', + variables='$positions: Nomination positions', + type=DBTemplateTypeName.objects.get(slug='plain'), + content=new_template_content, + group= None if group_name=='defaults' else Group.objects.get(acronym='nomcom2013'), + ) + + + def backwards(self, orm): + for group_name in ['defaults','nomcom2013']: + template = DBTemplate.objects.get(path='/nomcom/%s/email/nomination_accept_reminder.txt'%group_name) + template.path='/nomcom/%s/email/nomination_reminder.txt'%group_name + template.title='Email sent to nominees asking them to accept (or decline) the nominations.' + template.save() + DBTemplate.objects.filter(path='/nomcom/%s/email/questionnaire_reminder.txt'%group_name).delete() + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'dbtemplate.dbtemplate': { + 'Meta': {'object_name': 'DBTemplate'}, + 'content': ('django.db.models.fields.TextField', [], {}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DBTemplateTypeName']"}), + 'variables': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + 'doc.document': { + 'Meta': {'object_name': 'Document'}, + 'abstract': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'ad': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ad_document_set'", 'null': 'True', 'to': "orm['person.Person']"}), + 'authors': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['person.Email']", 'symmetrical': 'False', 'through': "orm['doc.DocumentAuthor']", 'blank': 'True'}), + 'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'external_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}), + 'intended_std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IntendedStdLevelName']", 'null': 'True', 'blank': 'True'}), + 'internal_comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'primary_key': 'True'}), + 'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'notify': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1', 'blank': 'True'}), + 'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'rev': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}), + 'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'shepherd_document_set'", 'null': 'True', 'to': "orm['person.Person']"}), + 'states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}), + 'std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StdLevelName']", 'null': 'True', 'blank': 'True'}), + 'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StreamName']", 'null': 'True', 'blank': 'True'}), + 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['name.DocTagName']", 'null': 'True', 'blank': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'}) + }, + 'doc.documentauthor': { + 'Meta': {'ordering': "['document', 'order']", 'object_name': 'DocumentAuthor'}, + 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}) + }, + 'doc.state': { + 'Meta': {'ordering': "['type', 'order']", 'object_name': 'State'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'next_states': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'previous_states'", 'blank': 'True', 'to': "orm['doc.State']"}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.StateType']"}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'doc.statetype': { + 'Meta': {'object_name': 'StateType'}, + 'label': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '30', 'primary_key': 'True'}) + }, + 'group.group': { + 'Meta': {'object_name': 'Group'}, + 'acronym': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}), + 'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True', 'blank': 'True'}), + 'charter': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'chartered_group'", 'unique': 'True', 'null': 'True', 'to': "orm['doc.Document']"}), + 'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'list_archive': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'list_email': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}), + 'list_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupStateName']", 'null': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupTypeName']", 'null': 'True'}), + 'unused_states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}), + 'unused_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.DocTagName']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'name.dbtemplatetypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'DBTemplateTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.doctagname': { + 'Meta': {'ordering': "['order']", 'object_name': 'DocTagName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.doctypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'DocTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.feedbacktype': { + 'Meta': {'ordering': "['order']", 'object_name': 'FeedbackType'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.groupstatename': { + 'Meta': {'ordering': "['order']", 'object_name': 'GroupStateName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.grouptypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'GroupTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.intendedstdlevelname': { + 'Meta': {'ordering': "['order']", 'object_name': 'IntendedStdLevelName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.nomineepositionstate': { + 'Meta': {'ordering': "['order']", 'object_name': 'NomineePositionState'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.stdlevelname': { + 'Meta': {'ordering': "['order']", 'object_name': 'StdLevelName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.streamname': { + 'Meta': {'ordering': "['order']", 'object_name': 'StreamName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'nomcom.feedback': { + 'Meta': {'ordering': "['time']", 'object_name': 'Feedback'}, + 'author': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'comments': ('ietf.nomcom.fields.EncryptedTextField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'nomcom': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.NomCom']"}), + 'nominees': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['nomcom.Nominee']", 'null': 'True', 'blank': 'True'}), + 'positions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['nomcom.Position']", 'null': 'True', 'blank': 'True'}), + 'subject': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.FeedbackType']", 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}) + }, + 'nomcom.nomcom': { + 'Meta': {'object_name': 'NomCom'}, + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'initial_text': ('django.db.models.fields.TextField', [], {'blank': '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': { + 'Meta': {'object_name': 'Nomination'}, + 'candidate_email': ('django.db.models.fields.EmailField', [], {'max_length': '255'}), + 'candidate_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'candidate_phone': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'comments': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Feedback']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'nominator_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'nominee': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Nominee']"}), + 'position': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Position']"}), + 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'nomcom.nominee': { + 'Meta': {'unique_together': "(('email', 'nomcom'),)", 'object_name': 'Nominee'}, + 'duplicated': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Nominee']", 'null': 'True', 'blank': 'True'}), + 'email': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'nomcom': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.NomCom']"}), + 'nominee_position': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['nomcom.Position']", 'through': "orm['nomcom.NomineePosition']", 'symmetrical': 'False'}) + }, + 'nomcom.nomineeposition': { + 'Meta': {'ordering': "['nominee']", 'unique_together': "(('position', 'nominee'),)", 'object_name': 'NomineePosition'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'nominee': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Nominee']"}), + 'position': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Position']"}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.NomineePositionState']"}), + 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}) + }, + 'nomcom.position': { + 'Meta': {'object_name': 'Position'}, + 'description': ('django.db.models.fields.TextField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'incumbent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}), + 'is_open': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'nomcom': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.NomCom']"}), + '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'}), + 'address': ('django.db.models.fields.CharField', [], {'max_length': '64', 'primary_key': 'True'}), + 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}) + }, + 'person.person': { + 'Meta': {'object_name': 'Person'}, + 'address': ('django.db.models.fields.TextField', [], {'max_length': '255', 'blank': 'True'}), + 'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'ascii': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'ascii_short': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['nomcom'] diff --git a/ietf/nomcom/migrations/0005_default_template_edits.py b/ietf/nomcom/migrations/0005_default_template_edits.py new file mode 100644 index 000000000..c98528604 --- /dev/null +++ b/ietf/nomcom/migrations/0005_default_template_edits.py @@ -0,0 +1,379 @@ +# encoding: utf-8 +import datetime +import textwrap +from south.db import db +from south.v2 import DataMigration +from django.db import models +from ietf.dbtemplate.models import DBTemplate + + +class Migration(DataMigration): + + def forwards(self, orm): + + for template in DBTemplate.objects.filter(title__startswith="Questionnaire sent to the nomine"): + template.title = self.change_nomine_to_nominee(template.title) + template.save() + + direct_substitutions = { + + 'Email sent to nominator to get a confirmation mail containing feedback in cleartext' + :'Email sent confirming nomination with provided comments in cleartext', + + 'Email sent to feedback author to get a confirmation mail containing feedback in cleartext' + :'Email sent confirming feedback with provided comments in cleartext', + + 'Header of the email that contains the questionnaire sent to the nomine' + :'Header of the email that contains the questionnaire sent to the nominee', + + } + + for str in direct_substitutions: + DBTemplate.objects.filter(title=str).update(title=direct_substitutions[str]) + + template = DBTemplate.objects.get(group=None,title__startswith="Email sent to nominees when") + template.content = textwrap.dedent("""\ + You have been nominated for the position of $position. + + Please follow one of the links below to accept or decline this nomination. + + Accept: http://$domain$accept_url + + Decline: http://$domain$decline_url + + If you accept, you will receive a questionnaire for the position in a subsequent email. + + Best Regards, + """) + template.save() + + template = DBTemplate.objects.get(group=None,title__startswith="Email sent to nominators and secretariat") + template.content = textwrap.dedent("""\ + A new nomination has been received. + + Nominator: $nominator ($nominator_email) + Nominee: $nominee ($nominee_email) + Position: $position + """) + template.save() + + + template = DBTemplate.objects.get(group=None,title__startswith="Header of the email that contains") + template.content = textwrap.dedent("""\ + Hi $nominee, this is the questionnaire for the position $position. + Please follow the directions in the questionnaire closely - you may see that some changes have been made from previous years, so please take note. + + We look forward to reading your questionnaire response! If you have any administrative questions, please send mail to nomcom-chair@ietf.org. Thank you! + """) + template.save() + + template = DBTemplate.objects.get(group=None,title__startswith="Email sent to nominees reminding them to accept ") + template.content = textwrap.dedent("""\ + This is a reminder that you have been nominated for the position of $position. + The Nomcom would like to know if you are willing to be considered. + + Please follow one of the links below to accept or decline this nomination. + + Accept: http://$domain$accept_url + + Decline: http://$domain$decline_url + + If you accept, you will receive a questionnaire for the position in a subsequent email. + + Best Regards, + """) + template.save() + + + def backwards(self, orm): + pass + + def change_nomine_to_nominee(self,string): + p=string.find('[') + if p<0: + return string+"e" + else: + return string[:p]+"e "+string[p:] + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'dbtemplate.dbtemplate': { + 'Meta': {'object_name': 'DBTemplate'}, + 'content': ('django.db.models.fields.TextField', [], {}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DBTemplateTypeName']"}), + 'variables': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + 'doc.document': { + 'Meta': {'object_name': 'Document'}, + 'abstract': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'ad': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ad_document_set'", 'null': 'True', 'to': "orm['person.Person']"}), + 'authors': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['person.Email']", 'symmetrical': 'False', 'through': "orm['doc.DocumentAuthor']", 'blank': 'True'}), + 'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'external_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}), + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}), + 'intended_std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IntendedStdLevelName']", 'null': 'True', 'blank': 'True'}), + 'internal_comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'primary_key': 'True'}), + 'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'notify': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1', 'blank': 'True'}), + 'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'rev': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}), + 'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'shepherd_document_set'", 'null': 'True', 'to': "orm['person.Person']"}), + 'states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}), + 'std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StdLevelName']", 'null': 'True', 'blank': 'True'}), + 'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StreamName']", 'null': 'True', 'blank': 'True'}), + 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['name.DocTagName']", 'null': 'True', 'blank': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'}) + }, + 'doc.documentauthor': { + 'Meta': {'ordering': "['document', 'order']", 'object_name': 'DocumentAuthor'}, + 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}) + }, + 'doc.state': { + 'Meta': {'ordering': "['type', 'order']", 'object_name': 'State'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'next_states': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'previous_states'", 'blank': 'True', 'to': "orm['doc.State']"}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.StateType']"}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'doc.statetype': { + 'Meta': {'object_name': 'StateType'}, + 'label': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '30', 'primary_key': 'True'}) + }, + 'group.group': { + 'Meta': {'object_name': 'Group'}, + 'acronym': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}), + 'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True', 'blank': 'True'}), + 'charter': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'chartered_group'", 'unique': 'True', 'null': 'True', 'to': "orm['doc.Document']"}), + 'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'list_archive': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'list_email': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}), + 'list_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupStateName']", 'null': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupTypeName']", 'null': 'True'}), + 'unused_states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}), + 'unused_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.DocTagName']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'name.dbtemplatetypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'DBTemplateTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.doctagname': { + 'Meta': {'ordering': "['order']", 'object_name': 'DocTagName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.doctypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'DocTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.feedbacktype': { + 'Meta': {'ordering': "['order']", 'object_name': 'FeedbackType'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.groupstatename': { + 'Meta': {'ordering': "['order']", 'object_name': 'GroupStateName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.grouptypename': { + 'Meta': {'ordering': "['order']", 'object_name': 'GroupTypeName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.intendedstdlevelname': { + 'Meta': {'ordering': "['order']", 'object_name': 'IntendedStdLevelName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.nomineepositionstate': { + 'Meta': {'ordering': "['order']", 'object_name': 'NomineePositionState'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.stdlevelname': { + 'Meta': {'ordering': "['order']", 'object_name': 'StdLevelName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'name.streamname': { + 'Meta': {'ordering': "['order']", 'object_name': 'StreamName'}, + 'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}), + 'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'nomcom.feedback': { + 'Meta': {'ordering': "['time']", 'object_name': 'Feedback'}, + 'author': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'comments': ('ietf.nomcom.fields.EncryptedTextField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'nomcom': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.NomCom']"}), + 'nominees': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['nomcom.Nominee']", 'null': 'True', 'blank': 'True'}), + 'positions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['nomcom.Position']", 'null': 'True', 'blank': 'True'}), + 'subject': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.FeedbackType']", 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}) + }, + 'nomcom.nomcom': { + 'Meta': {'object_name': 'NomCom'}, + 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'initial_text': ('django.db.models.fields.TextField', [], {'blank': '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': { + 'Meta': {'object_name': 'Nomination'}, + 'candidate_email': ('django.db.models.fields.EmailField', [], {'max_length': '255'}), + 'candidate_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'candidate_phone': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'comments': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Feedback']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'nominator_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'nominee': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Nominee']"}), + 'position': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Position']"}), + 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'nomcom.nominee': { + 'Meta': {'unique_together': "(('email', 'nomcom'),)", 'object_name': 'Nominee'}, + 'duplicated': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Nominee']", 'null': 'True', 'blank': 'True'}), + 'email': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'nomcom': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.NomCom']"}), + 'nominee_position': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['nomcom.Position']", 'through': "orm['nomcom.NomineePosition']", 'symmetrical': 'False'}) + }, + 'nomcom.nomineeposition': { + 'Meta': {'ordering': "['nominee']", 'unique_together': "(('position', 'nominee'),)", 'object_name': 'NomineePosition'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'nominee': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Nominee']"}), + 'position': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Position']"}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.NomineePositionState']"}), + 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}) + }, + 'nomcom.position': { + 'Meta': {'object_name': 'Position'}, + 'description': ('django.db.models.fields.TextField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'incumbent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}), + 'is_open': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'nomcom': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.NomCom']"}), + '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'}), + 'address': ('django.db.models.fields.CharField', [], {'max_length': '64', 'primary_key': 'True'}), + 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}) + }, + 'person.person': { + 'Meta': {'object_name': 'Person'}, + 'address': ('django.db.models.fields.TextField', [], {'max_length': '255', 'blank': 'True'}), + 'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'ascii': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'ascii_short': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['nomcom']