Skip to content

Commit 40fd14d

Browse files
committed
* Add skek view to manage feedback generated from email.
* Now, nominee, type and user fields in feedback model can be null See ietf-tools#975 - Legacy-Id: 5576
1 parent 3f64b53 commit 40fd14d

9 files changed

Lines changed: 133 additions & 26 deletions

File tree

ietf/nomcom/forms.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from django.conf import settings
22
from django import forms
3+
from django.forms.models import BaseModelFormSet
34
from django.contrib.formtools.preview import FormPreview, AUTO_ID
45
from django.http import HttpResponseRedirect
56
from django.shortcuts import get_object_or_404
@@ -8,6 +9,7 @@
89
from django.utils.decorators import method_decorator
910
from django.shortcuts import render_to_response
1011
from django.template.context import RequestContext
12+
from django.db.models import Q
1113

1214
from ietf.dbtemplate.forms import DBTemplateForm
1315
from ietf.utils import unaccent
@@ -568,6 +570,14 @@ class Media:
568570
"/js/nomcom.js", )
569571

570572

573+
class BaseFeedbackFormSet(BaseModelFormSet):
574+
def __init__(self, *args, **kwargs):
575+
super(BaseFeedbackFormSet, self).__init__(*args, **kwargs)
576+
self.queryset = Feedback.objects.filter(Q(type__isnull=True) |
577+
Q(nominee__isnull=True) |
578+
Q(positions=True))
579+
580+
571581
class NomComTemplateForm(BaseNomcomForm, DBTemplateForm):
572582

573583
fieldsets = [('Template content', ('content', )),

ietf/nomcom/migrations/0001_initial.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ def forwards(self, orm):
7272
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
7373
('nomcom', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['nomcom.NomCom'])),
7474
('author', self.gf('django.db.models.fields.EmailField')(max_length=75, blank=True)),
75-
('nominee', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['nomcom.Nominee'])),
75+
('nominee', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['nomcom.Nominee'], null=True, blank=True)),
7676
('comments', self.gf('ietf.nomcom.fields.EncryptedTextField')()),
77-
('type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.FeedbackType'])),
77+
('type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.FeedbackType'], null=True, blank=True)),
7878
('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)),
7979
('time', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
8080
))
@@ -332,15 +332,15 @@ def backwards(self, orm):
332332
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
333333
},
334334
'nomcom.feedback': {
335-
'Meta': {'object_name': 'Feedback'},
335+
'Meta': {'ordering': "['time']", 'object_name': 'Feedback'},
336336
'author': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
337337
'comments': ('ietf.nomcom.fields.EncryptedTextField', [], {}),
338338
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
339339
'nomcom': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.NomCom']"}),
340-
'nominee': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Nominee']"}),
340+
'nominee': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Nominee']", 'null': 'True', 'blank': 'True'}),
341341
'positions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['nomcom.Position']", 'null': 'True', 'blank': 'True'}),
342342
'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
343-
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.FeedbackType']"}),
343+
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.FeedbackType']", 'null': 'True', 'blank': 'True'}),
344344
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'})
345345
},
346346
'nomcom.nomcom': {

ietf/nomcom/models.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class Nomination(models.Model):
5454
nominee = models.ForeignKey('Nominee')
5555
comments = models.ForeignKey('Feedback')
5656
nominator_email = models.EmailField(verbose_name='Nominator Email', blank=True)
57-
user = models.ForeignKey(User)
57+
user = models.ForeignKey(User, editable=False)
5858
time = models.DateTimeField(auto_now_add=True)
5959

6060
class Meta:
@@ -153,16 +153,16 @@ class Feedback(models.Model):
153153
nomcom = models.ForeignKey('NomCom')
154154
author = models.EmailField(verbose_name='Author', blank=True)
155155
positions = models.ManyToManyField('Position', blank=True, null=True)
156-
nominee = models.ForeignKey('Nominee')
156+
nominee = models.ForeignKey('Nominee', blank=True, null=True)
157157
comments = EncryptedTextField(verbose_name='Comments')
158-
type = models.ForeignKey(FeedbackType)
159-
user = models.ForeignKey(User, blank=True, null=True)
158+
type = models.ForeignKey(FeedbackType, blank=True, null=True)
159+
user = models.ForeignKey(User, editable=False, blank=True, null=True)
160160
time = models.DateTimeField(auto_now_add=True)
161161

162162
objects = FeedbackManager()
163163

164164
def __unicode__(self):
165-
return u"%s - %s" % (self.author, self.nominee)
165+
return u"from %s to %s" % (self.author, self.nominee)
166166

167167
class Meta:
168168
ordering = ['time']

ietf/nomcom/tests.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,29 @@ def test_private_feedback(self):
258258
self.client.logout()
259259

260260
def feedback_view(self, *args, **kwargs):
261-
pass
261+
public = kwargs.pop('public', True)
262+
nominee_email = kwargs.pop('nominee_email', u'nominee@example.com')
263+
position_name = kwargs.pop('position', 'IAOC')
264+
265+
if public:
266+
nominate_url = self.public_feedback_url
267+
else:
268+
nominate_url = self.private_feedback_url
269+
270+
response = self.client.get(nominate_url)
271+
self.assertEqual(response.status_code, 200)
272+
273+
nomcom = get_nomcom_by_year(self.year)
274+
if not nomcom.public_key:
275+
self.assertNotContains(response, "feedbackform")
276+
277+
# save the cert file in tmp
278+
nomcom.public_key.storage.location = tempfile.gettempdir()
279+
nomcom.public_key.save('cert', File(open(self.cert_file.name, 'r')))
280+
281+
response = self.client.get(nominate_url)
282+
self.assertEqual(response.status_code, 200)
283+
self.assertContains(response, "feedbackform")
262284

263285
def test_public_nominate(self):
264286
login_testing_unauthorized(self, COMMUNITY_USER, self.public_nominate_url)

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/nominate/$', 'private_nominate', name='nomcom_private_nominate'),
99
url(r'^(?P<year>\d{4})/private/feedback/$', 'private_feedback', name='nomcom_private_feedback'),
1010
url(r'^(?P<year>\d{4})/private/view-feedback/$', 'view_feedback', name='nomcom_view_feedback'),
11+
url(r'^(?P<year>\d{4})/private/view-feedback/pending/$', 'view_feedback_pending', name='nomcom_view_feedback_pending'),
1112
url(r'^(?P<year>\d{4})/private/view-feedback/nominee/(?P<nominee_id>\d+)$', 'view_feedback_nominee', name='nomcom_view_feedback_nominee'),
1213
url(r'^(?P<year>\d{4})/private/merge/$', 'private_merge', name='nomcom_private_merge'),
1314
url(r'^(?P<year>\d{4})/private/send-reminder-mail/$', 'send_reminder_mail', name='nomcom_send_reminder_mail'),

ietf/nomcom/views.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from django.template.loader import render_to_string
99
from django.utils import simplejson
1010
from django.db.models import Count
11+
from django.forms.models import modelformset_factory
1112

1213
from ietf.utils.mail import send_mail
1314

@@ -17,7 +18,8 @@
1718

1819
from ietf.nomcom.decorators import member_required, private_key_required
1920
from ietf.nomcom.forms import (EditPublicKeyForm, NominateForm, FeedbackForm, MergeForm,
20-
NomComTemplateForm, PositionForm, PrivateKeyForm)
21+
NomComTemplateForm, PositionForm, PrivateKeyForm,
22+
BaseFeedbackFormSet)
2123
from ietf.nomcom.models import Position, NomineePosition, Nominee, Feedback
2224
from ietf.nomcom.utils import (get_nomcom_by_year, HOME_TEMPLATE,
2325
retrieve_nomcom_private_key,
@@ -315,6 +317,30 @@ def view_feedback(request, year):
315317
'nomcom': nomcom}, RequestContext(request))
316318

317319

320+
@member_required(role='chair')
321+
@private_key_required
322+
def view_feedback_pending(request, year):
323+
nomcom = get_nomcom_by_year(year)
324+
message = None
325+
FeedbackFormSet = modelformset_factory(Feedback,
326+
formset=BaseFeedbackFormSet,
327+
exclude=('nomcom', 'comments'),
328+
extra=0)
329+
if request.method == 'POST':
330+
formset = FeedbackFormSet(request.POST)
331+
if formset.is_valid():
332+
formset.save()
333+
message = ('success', 'The feedbacks has been saved.')
334+
else:
335+
formset = FeedbackFormSet()
336+
return render_to_response('nomcom/view_feedback_pending.html',
337+
{'year': year,
338+
'selected': 'view_feedback',
339+
'formset': formset,
340+
'message': message,
341+
'nomcom': nomcom}, RequestContext(request))
342+
343+
318344
@member_required(role='member')
319345
@private_key_required
320346
def view_feedback_nominee(request, year, nominee_id):

ietf/templates/nomcom/view_feedback.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
{% block nomcom_content %}
88

9+
<p><a href="{% url nomcom_view_feedback_pending year %}">Feedbak pending</a></p>
10+
911
<h2>List of Nominees</h2>
1012

1113
<table class="ietf-table ietf-doctable">
@@ -17,7 +19,7 @@ <h2>List of Nominees</h2>
1719
</tr>
1820
{% for nominee in nominees %}
1921
<tr class="{{ forloop.counter|divisibleby:2|yesno:"oddrow,evenrow" }}">
20-
<td><a href="{% url nomcom_view_feedback_nominee year nominee.id %}">{{ nominee.email.person.name }}</td>
22+
<td><a href="{% url nomcom_view_feedback_nominee year nominee.id %}#comment">{{ nominee.email.person.name }}</td>
2123
<td>{{ nominee.feedback_set.nominations.count }}</td>
2224
<td>{{ nominee.feedback_set.comments.count }}</td>
2325
<td>{{ nominee.feedback_set.questionnaires.count }}</td>

ietf/templates/nomcom/view_feedback_nominee.html

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,33 @@ <h2>Feedback of {{ nominee.email.person.name }} </h2>
2020
<div id="mytabs" class="yui-navset">
2121
<ul class="yui-nav">
2222
{% for ft in feedback_types %}
23-
<li><a href="#{{ ft.name }}"><em>{{ ft.name }}</em></a></li>
23+
<li><a href="#{{ ft.slug }}"><em>{{ ft.name }}</em></a></li>
2424
{% endfor %}
2525
</ul>
2626
Pick the feedback type to view from the list immediately above
2727
<div class="yui-content">
2828
{% for ft in feedback_types %}
29-
<div id="{{ ft.name }}">
30-
{% for feedback in nominee.feedback_set.all %}
31-
{% ifequal feedback.type.slug ft.slug %}
32-
<div>
33-
<h3 class="ietf-divider">From {{ feedback.author|get_person|default:"Anonymous" }} ({{ feedback.time|date:"Y-m-d" }})</h3>
34-
<b>Positions:</b> {{ feedback.positions.all|join:"," }}
35-
<p>
36-
{% decrypt feedback.comments request year %}
37-
</p>
38-
</div>
39-
{% endifequal %}
40-
{% endfor %}
29+
<div id="#{{ ft.slug }}">
30+
{% ifequal ft.slug "comment" %}
31+
<b>Number of comments: {{ nominee.feedback_set.comments.count|default:"0" }}</b>
32+
{% endifequal %}
33+
{% ifequal ft.slug "questio" %}
34+
<b>Number of questionnaires: {{ nominee.feedback_set.questionaires.count|default:"0" }}</b>
35+
{% endifequal %}
36+
{% ifequal ft.slug "nomina" %}
37+
<b>Number of nominations: {{ nominee.feedback_set.nominations.count|default:"0" }}</b>
38+
{% endifequal %}
39+
{% for feedback in nominee.feedback_set.all %}
40+
{% ifequal feedback.type.slug ft.slug %}
41+
<div>
42+
<h3 class="ietf-divider">From {{ feedback.author|get_person|default:"Anonymous" }} ({{ feedback.time|date:"Y-m-d" }})</h3>
43+
<b>Positions:</b> {{ feedback.positions.all|join:"," }}
44+
<p>
45+
{% decrypt feedback.comments request year %}
46+
</p>
47+
</div>
48+
{% endifequal %}
49+
{% endfor %}
4150
</div>
4251
{% endfor %}
4352
</div>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{% extends "nomcom/nomcom_private_base.html" %}
2+
3+
{% load nomcom_tags %}
4+
5+
6+
{% block subtitle %} - Feeback pending{% endblock %}
7+
8+
{% block nomcom_content %}
9+
10+
<p>Back to <a href="{% url nomcom_view_feedback year %}">feedback index</a></p>
11+
12+
<h2>Feedback pending from email list</h2>
13+
14+
{% if message %}
15+
<div class="info-message-{{ message.0 }}">{{ message.1 }}</div>
16+
{% endif %}
17+
18+
<div>
19+
<form id="feedbackformset" action="" method="post">{% csrf_token %}
20+
{{ formset.management_form }}
21+
{% for form in formset.forms %}
22+
<div class="ietf-divider"></div>
23+
<div>
24+
{% for field in form %}
25+
<div>
26+
{{ field.label_tag }}: {{ field }}
27+
</div>
28+
{% endfor %}
29+
{% decrypt form.instance.comments request year %}
30+
</div>
31+
{% endfor %}
32+
<div class="ietf-divider"></div>
33+
<input type="submit" value="Submit" />
34+
</form>
35+
</div>
36+
37+
{% endblock %}

0 commit comments

Comments
 (0)