Skip to content

Commit 66c4a32

Browse files
committed
Add subject field to feedback model
New form to fill feedback mail via web. Fixes ietf-tools#1042 ietf-tools#1043 - Legacy-Id: 5748
1 parent f998e0d commit 66c4a32

11 files changed

Lines changed: 458 additions & 25 deletions

File tree

ietf/nomcom/forms.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
Position, Feedback, ReminderDates
2121
from ietf.nomcom.utils import (NOMINATION_RECEIPT_TEMPLATE, FEEDBACK_RECEIPT_TEMPLATE,
2222
get_user_email, validate_private_key, validate_public_key,
23-
get_or_create_nominee)
23+
get_or_create_nominee, create_feedback_email)
2424
from ietf.nomcom.decorators import nomcom_member_required
2525

2626

@@ -609,6 +609,24 @@ class Media:
609609
"/js/nomcom.js", )
610610

611611

612+
class FeedbackEmailForm(BaseNomcomForm, forms.Form):
613+
614+
email_text = forms.CharField(label='Email text', widget=forms.Textarea())
615+
616+
fieldsets = [('Feedback email', ('email_text',))]
617+
618+
def __init__(self, *args, **kwargs):
619+
self.nomcom = kwargs.pop('nomcom', None)
620+
super(FeedbackEmailForm, self).__init__(*args, **kwargs)
621+
622+
def save(self, commit=True):
623+
create_feedback_email(self.nomcom, self.cleaned_data['email_text'])
624+
625+
class Media:
626+
js = ("/js/jquery-1.5.1.min.js",
627+
"/js/nomcom.js", )
628+
629+
612630
class QuestionnaireForm(BaseNomcomForm, forms.ModelForm):
613631

614632
comments = forms.CharField(label='Questionnaire response from this candidate',
Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
11
from optparse import make_option
2-
from email.utils import parseaddr
32
import syslog
43

54
from django.core.management.base import BaseCommand, CommandError
65

7-
from ietf.nomcom.utils import parse_email
8-
from ietf.nomcom.models import NomCom, Feedback
6+
from ietf.nomcom.models import NomCom
7+
from ietf.nomcom.utils import create_feedback_email
98

109

1110
class Command(BaseCommand):
1211
help = (u"Registry feedback from email. Usage: feeback_email --nomcom-year <nomcom-year> --email-file <email-file>")
1312
option_list = BaseCommand.option_list + (
1413
make_option('--nomcom-year', dest='year', help='NomCom year'),
15-
make_option('--email-file', dest='email', help='Feedback email'),
16-
)
14+
make_option('--email-file', dest='email', help='Feedback email'),)
1715

1816
def handle(self, *args, **options):
1917
email = options.get('email', None)
@@ -36,13 +34,5 @@ def handle(self, *args, **options):
3634
except NomCom.DoesNotExist:
3735
raise CommandError("NomCom %s does not exist or it isn't active" % year)
3836

39-
by, subject, body = parse_email(msg)
40-
body = 'Subject: %s\n\n%s' % (subject, body)
41-
name, addr = parseaddr(by)
42-
43-
feedback = Feedback(nomcom=nomcom,
44-
author=addr,
45-
comments=body)
46-
feedback.save()
47-
48-
syslog.syslog(u"Read feedback email by %s" % by)
37+
feedback = create_feedback_email(nomcom, msg)
38+
syslog.syslog(u"Read feedback email by %s" % feedback.author)

ietf/nomcom/migrations/0003_auto__add_field_feedback_subject.py

Lines changed: 324 additions & 0 deletions
Large diffs are not rendered by default.

ietf/nomcom/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ class Feedback(models.Model):
185185
author = models.EmailField(verbose_name='Author', blank=True)
186186
positions = models.ManyToManyField('Position', blank=True, null=True)
187187
nominees = models.ManyToManyField('Nominee', blank=True, null=True)
188+
subject = models.TextField(verbose_name='Subject', blank=True)
188189
comments = EncryptedTextField(verbose_name='Comments')
189190
type = models.ForeignKey(FeedbackType, blank=True, null=True)
190191
user = models.ForeignKey(User, editable=False, blank=True, null=True)

ietf/nomcom/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
url(r'^(?P<year>\d{4})/private/key/$', 'private_key', name='nomcom_private_key'),
99
url(r'^(?P<year>\d{4})/private/nominate/$', 'private_nominate', name='nomcom_private_nominate'),
1010
url(r'^(?P<year>\d{4})/private/feedback/$', 'private_feedback', name='nomcom_private_feedback'),
11+
url(r'^(?P<year>\d{4})/private/feedback-email/$', 'private_feedback_email', name='nomcom_private_feedback_email'),
1112
url(r'^(?P<year>\d{4})/private/questionnaire-response/$', 'private_questionnaire', name='nomcom_private_questionnaire'),
1213
url(r'^(?P<year>\d{4})/private/view-feedback/$', 'view_feedback', name='nomcom_view_feedback'),
1314
url(r'^(?P<year>\d{4})/private/view-feedback/unrelated/$', 'view_feedback_unrelated', name='nomcom_view_feedback_unrelated'),

ietf/nomcom/utils.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import re
66
import tempfile
77

8+
from email.utils import parseaddr
9+
810
from django.conf import settings
911
from django.contrib.sites.models import Site
1012
from django.core.exceptions import PermissionDenied
@@ -155,7 +157,8 @@ def extract_body(payload):
155157
if isinstance(payload, str):
156158
return payload
157159
else:
158-
return '\n'.join([extract_body(part.get_payload()) for part in payload])
160+
if payload:
161+
return '\n'.join([extract_body(part.get_payload()) for part in payload])
159162

160163

161164
def parse_email(text):
@@ -164,7 +167,7 @@ def parse_email(text):
164167
# comment
165168
#body = quopri.decodestring(extract_body(msg.get_payload()))
166169
charset = msg.get_content_charset()
167-
body = extract_body(msg.get_payload(decode=True))
170+
body = extract_body(msg.get_payload())
168171
if charset:
169172
body = body.decode(charset)
170173

@@ -339,3 +342,16 @@ def get_or_create_nominee(nomcom, candidate_name, candidate_email, position, aut
339342
send_mail(None, to_email, from_email, subject, path, context)
340343

341344
return nominee
345+
346+
347+
def create_feedback_email(nomcom, msg):
348+
from ietf.nomcom.models import Feedback
349+
by, subject, body = parse_email(msg)
350+
name, addr = parseaddr(by)
351+
352+
feedback = Feedback(nomcom=nomcom,
353+
author=addr,
354+
subject=subject,
355+
comments=body)
356+
feedback.save()
357+
return feedback

ietf/nomcom/views.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
from ietf.nomcom.forms import (NominateForm, FeedbackForm, QuestionnaireForm,
2525
MergeForm, NomComTemplateForm, PositionForm,
2626
PrivateKeyForm, EditNomcomForm, EditNomineeForm,
27-
PendingFeedbackForm, ReminderDatesForm, FullFeedbackFormSet)
27+
PendingFeedbackForm, ReminderDatesForm, FullFeedbackFormSet,
28+
FeedbackEmailForm)
2829
from ietf.nomcom.models import Position, NomineePosition, Nominee, Feedback, NomCom, ReminderDates
2930
from ietf.nomcom.utils import (get_nomcom_by_year, store_nomcom_private_key,
3031
get_hash_nominee_position, send_reminder_to_nominees,
@@ -304,6 +305,38 @@ def feedback(request, year, public):
304305
'selected': 'feedback'}, RequestContext(request))
305306

306307

308+
@nomcom_member_required(role='chair')
309+
def private_feedback_email(request, year):
310+
nomcom = get_nomcom_by_year(year)
311+
has_publickey = nomcom.public_key and True or False
312+
message = None
313+
template = 'nomcom/private_feedback_email.html'
314+
315+
if not has_publickey:
316+
message = ('warning', "This Nomcom is not yet accepting feedback email")
317+
return render_to_response(template,
318+
{'message': message,
319+
'nomcom': nomcom,
320+
'year': year,
321+
'selected': 'feedback_email'}, RequestContext(request))
322+
323+
form = FeedbackEmailForm(nomcom=nomcom)
324+
325+
if request.method == 'POST':
326+
form = FeedbackEmailForm(data=request.POST,
327+
nomcom=nomcom)
328+
if form.is_valid():
329+
form.save()
330+
message = ('success', 'The feedback email has been registered.')
331+
332+
return render_to_response(template,
333+
{'form': form,
334+
'message': message,
335+
'nomcom': nomcom,
336+
'year': year,
337+
'selected': 'feedback_email'}, RequestContext(request))
338+
339+
307340
@nomcom_member_required(role='chair')
308341
def private_questionnaire(request, year):
309342
nomcom = get_nomcom_by_year(year)

ietf/templates/nomcom/nomcom_private_base.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ <h1>Nomcom {{ year }} Private Area</h1>
1616
{% if selected == "view_feedback" %}<span class="selected">View comments</span>{% else %}<a href="{% url nomcom_view_feedback year %}">View comments</a>{% endif %} |
1717
{% if selected == "private_key" %}<span class="selected">Private key</span>{% else %}<a href="{% url nomcom_private_key year %}">Private key</a>{% endif %}
1818
{% if user|is_chair:year %} |
19+
{% if selected == "feedback_email" %}<span class="selected">Provide Email Feedback</span>{% else %}<a href="{% url nomcom_private_feedback_email year %}">Provide Email Feedback</a>{% endif %} |
1920
{% if selected == "merge" %}<span class="selected">Merge nominee email addr</span>{% else %}<a href="{% url nomcom_private_merge year %}">Merge nominee email addr</a>{% endif %} |
2021
{% if selected == "send_reminder_mail" %}<span class="selected">Send Reminder Mail</span>{% else %}<a href="{% url nomcom_send_reminder_mail year %}">Send reminder mail</a>{% endif %} |
2122
{% if selected == "edit_members" %}<span class="selected">Nomcom members</span>{% else %}<a href="{% url nomcom_edit_members year %}">Nomcom members</a>{% endif %} |
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{% extends "nomcom/nomcom_private_base.html" %}
2+
3+
{% load nomcom_tags %}
4+
5+
{% block subtitle %} - Provide feeback email{% endblock %}
6+
7+
{% block pagehead %}
8+
{{ form.media }}
9+
{% endblock %}
10+
11+
{% block nomcom_content %}
12+
13+
14+
{% if message %}
15+
<div class="info-message-{{ message.0 }}">{{ message.1 }}</div>
16+
{% endif %}
17+
18+
{% if nomcom|has_publickey %}
19+
20+
<div class="js-info">
21+
Your browser has Javascript disabled. Please enable javascript and reload the page.
22+
<script type="text/javascript">
23+
(function ($) {
24+
$(".js-info").hide();
25+
})(jQuery);
26+
</script>
27+
</div>
28+
29+
<div>
30+
{% if form.errors %}<div class="info-message-error">Please correct the following errors</div>{% endif %}
31+
32+
<form id="questionnnaireform" action="" method="post">{% csrf_token %}
33+
{{ form }}
34+
35+
<div class="submitrow">
36+
<input type="submit" value="Save" name="save" {% if submit_disabled %}disabled="disabled"{% endif %}/>
37+
</div>
38+
39+
</form>
40+
</div>
41+
42+
{% endif %}
43+
44+
45+
{% endblock %}

ietf/templates/nomcom/view_feedback_nominee.html

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,19 @@ <h3 class="ietf-divider">From {{ feedback.author|formatted_email|default:"Anonym
3434
{% ifequal ft.slug "nomina" %}
3535
{% for fn in feedback.nomination_set.all %}
3636
{% if fn.candidate_name %}
37-
<p><b>Candidate name:</b> {{ fn.candidate_name }}</p>
37+
<h3>Candidate name:</h3> <pre>{{ fn.candidate_name }}</pre>
3838
{% endif %}
3939
{% if fn.candidate_phone %}
40-
<p><b>Candidate phone:</b> {{ fn.candidate_phone }}</p>
40+
<h3>Candidate phone:</h3> <pre>{{ fn.candidate_phone }}</pre>
4141
{% endif %}
4242
{% endfor %}
4343
{% endifequal %}
44-
<b>Positions:</b> {{ feedback.positions.all|join:"," }}
45-
<p>
46-
{% decrypt feedback.comments request year %}
47-
</p>
44+
<h3>Positions:</h3> <pre>{{ feedback.positions.all|join:"," }}</pre>
45+
{% if feedback.subject %}
46+
<h3>Subject:</h3> <pre>{{ feedback.subject }}</pre>
47+
{% endif %}
48+
<h3>Body</h3>
49+
<pre>{% decrypt feedback.comments request year %}</pre>
4850
</div>
4951
{% endifequal %}
5052
{% endfor %}

0 commit comments

Comments
 (0)