Skip to content

Commit 2906419

Browse files
committed
* Add feedback view by nominee
* Refactor EncryptedTextField * Add feedback model managers * Add templatetag to get person from author email See ietf-tools#973 - Legacy-Id: 5574
1 parent 4fec101 commit 2906419

8 files changed

Lines changed: 155 additions & 28 deletions

File tree

ietf/nomcom/fields.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
import os
2-
3-
import tempfile
41
from django.conf import settings
52
from django.db import models
63

@@ -17,14 +14,9 @@ def pre_save(self, instance, add):
1714
comments = getattr(instance, 'comments')
1815
nomcom = getattr(instance, 'nomcom')
1916
cert_file = nomcom.public_key.path
20-
comments_file = tempfile.NamedTemporaryFile(delete=False)
21-
comments_file.write(comments)
22-
comments_file.close()
2317

24-
code, out, error = pipe("%s smime -encrypt -in %s %s" % (settings.OPENSSL_COMMAND,
25-
comments_file.name,
26-
cert_file))
27-
os.unlink(comments_file.name)
18+
code, out, error = pipe("%s smime -encrypt -in /dev/stdin %s" % (settings.OPENSSL_COMMAND,
19+
cert_file), comments)
2820
if not error:
2921
instance.comments = out
3022
return out

ietf/nomcom/managers.py

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
from django.db.models.query import QuerySet
33

44

5+
class MixinManager(object):
6+
def __getattr__(self, attr, *args):
7+
try:
8+
return getattr(self.__class__, attr, *args)
9+
except AttributeError:
10+
return getattr(self.get_query_set(), attr, *args)
11+
12+
513
class NomineePositionQuerySet(QuerySet):
614

715
def get_by_nomcom(self, nomcom):
@@ -23,16 +31,10 @@ def declined(self):
2331
return self.by_state('declined')
2432

2533

26-
class NomineePositionManager(models.Manager):
34+
class NomineePositionManager(models.Manager, MixinManager):
2735
def get_query_set(self):
2836
return NomineePositionQuerySet(self.model)
2937

30-
def __getattr__(self, attr, *args):
31-
try:
32-
return getattr(self.__class__, attr, *args)
33-
except AttributeError:
34-
return getattr(self.get_query_set(), attr, *args)
35-
3638

3739
class NomineeManager(models.Manager):
3840
def get_by_nomcom(self, nomcom):
@@ -53,12 +55,29 @@ def closed(self):
5355
return self.filter(is_open=False)
5456

5557

56-
class PositionManager(models.Manager):
58+
class PositionManager(models.Manager, MixinManager):
5759
def get_query_set(self):
5860
return PositionQuerySet(self.model)
5961

60-
def __getattr__(self, attr, *args):
61-
try:
62-
return getattr(self.__class__, attr, *args)
63-
except AttributeError:
64-
return getattr(self.get_query_set(), attr, *args)
62+
63+
class FeedbackQuerySet(QuerySet):
64+
65+
def get_by_nomcom(self, nomcom):
66+
return self.filter(nomcom=nomcom)
67+
68+
def by_type(self, type):
69+
return self.filter(type=type)
70+
71+
def comments(self):
72+
return self.by_type('comment')
73+
74+
def questionnaires(self):
75+
return self.by_type('questio')
76+
77+
def nominations(self):
78+
return self.by_type('nomina')
79+
80+
81+
class FeedbackManager(models.Manager, MixinManager):
82+
def get_query_set(self):
83+
return FeedbackQuerySet(self.model)

ietf/nomcom/models.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
from ietf.name.models import NomineePositionState, FeedbackType
1414
from ietf.dbtemplate.models import DBTemplate
1515

16-
from ietf.nomcom.managers import NomineePositionManager, NomineeManager, PositionManager
16+
from ietf.nomcom.managers import NomineePositionManager, NomineeManager, \
17+
PositionManager, FeedbackManager
1718
from ietf.nomcom.utils import (initialize_templates_for_group,
1819
initialize_questionnaire_for_position,
1920
initialize_requirements_for_position)
@@ -125,7 +126,7 @@ class Meta:
125126
verbose_name_plural = 'Positions'
126127

127128
def __unicode__(self):
128-
return u"%s: %s" % (self.nomcom, self.name)
129+
return self.name
129130

130131
def save(self, *args, **kwargs):
131132
created = not self.id
@@ -158,9 +159,14 @@ class Feedback(models.Model):
158159
user = models.ForeignKey(User, blank=True, null=True)
159160
time = models.DateTimeField(auto_now_add=True)
160161

162+
objects = FeedbackManager()
163+
161164
def __unicode__(self):
162165
return u"%s - %s" % (self.author, self.nominee)
163166

167+
class Meta:
168+
ordering = ['time']
169+
164170
# ----- adding south rules to help introspection -----
165171

166172
add_introspection_rules([], ["^ietf\.nomcom\.fields\.EncryptedTextField"])

ietf/nomcom/templatetags/nomcom_tags.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33

44
from django import template
55
from django.conf import settings
6+
from django.template.defaultfilters import linebreaksbr
67

78
from ietf.utils.pipe import pipe
89
from ietf.ietfauth.decorators import has_role
910

11+
from ietf.person.models import Person
1012
from ietf.nomcom.models import Feedback
1113
from ietf.nomcom.utils import get_nomcom_by_year, get_user_email, retrieve_nomcom_private_key
1214

@@ -40,6 +42,15 @@ def add_num_nominations(user, position, nominee):
4042
return '<span title="%d earlier comments from you on %s as %s">%s</span>&nbsp;' % (count, nominee, position, mark)
4143

4244

45+
@register.filter
46+
def get_person(email):
47+
person = email
48+
if email:
49+
persons = Person.objects.filter(email__address__in=[email])
50+
person = persons and persons[0].name or person
51+
return person
52+
53+
4354
@register.simple_tag
4455
def decrypt(string, request, year):
4556
key = retrieve_nomcom_private_key(request, year)
@@ -60,4 +71,4 @@ def decrypt(string, request, year):
6071
if error:
6172
return '<-Encripted text [Your private key is invalid]->'
6273

63-
return out
74+
return linebreaksbr(out)

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/nominee/(?P<nominee_id>\d+)$', 'view_feedback_nominee', name='nomcom_view_feedback_nominee'),
1112
url(r'^(?P<year>\d{4})/private/merge/$', 'private_merge', name='nomcom_private_merge'),
1213
url(r'^(?P<year>\d{4})/private/send-reminder-mail/$', 'send_reminder_mail', name='nomcom_send_reminder_mail'),
1314
url(r'^(?P<year>\d{4})/private/edit-members/$', EditMembersFormPreview(EditMembersForm), name='nomcom_edit_members'),

ietf/nomcom/views.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from django.contrib.auth.decorators import login_required
44
from django.core.urlresolvers import reverse
55
from django.http import HttpResponse, Http404, HttpResponseRedirect
6-
from django.shortcuts import render_to_response
6+
from django.shortcuts import render_to_response, get_object_or_404
77
from django.template import RequestContext
88
from django.template.loader import render_to_string
99
from django.utils import simplejson
@@ -13,7 +13,7 @@
1313

1414
from ietf.dbtemplate.models import DBTemplate
1515
from ietf.dbtemplate.views import template_edit
16-
from ietf.name.models import NomineePositionState
16+
from ietf.name.models import NomineePositionState, FeedbackType
1717

1818
from ietf.nomcom.decorators import member_required, private_key_required
1919
from ietf.nomcom.forms import (EditPublicKeyForm, NominateForm, FeedbackForm, MergeForm,
@@ -306,10 +306,27 @@ def feedback(request, year, public):
306306
@private_key_required
307307
def view_feedback(request, year):
308308
nomcom = get_nomcom_by_year(year)
309+
nominees = Nominee.objects.get_by_nomcom(nomcom).distinct()
309310

310311
return render_to_response('nomcom/view_feedback.html',
311312
{'year': year,
312313
'selected': 'view_feedback',
314+
'nominees': nominees,
315+
'nomcom': nomcom}, RequestContext(request))
316+
317+
318+
@member_required(role='member')
319+
@private_key_required
320+
def view_feedback_nominee(request, year, nominee_id):
321+
nomcom = get_nomcom_by_year(year)
322+
nominee = get_object_or_404(Nominee, id=nominee_id)
323+
feedback_types = FeedbackType.objects.all()
324+
325+
return render_to_response('nomcom/view_feedback_nominee.html',
326+
{'year': year,
327+
'selected': 'view_feedback',
328+
'nominee': nominee,
329+
'feedback_types': feedback_types,
313330
'nomcom': nomcom}, RequestContext(request))
314331

315332

ietf/templates/nomcom/view_feedback.html

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,21 @@
88

99
<h2>List of Nominees</h2>
1010

11+
<table class="ietf-table ietf-doctable">
12+
<tr>
13+
<th>Nominee</th>
14+
<th>Nominations</th>
15+
<th>Comments</th>
16+
<th>Questionnaires</th>
17+
</tr>
18+
{% for nominee in nominees %}
19+
<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>
21+
<td>{{ nominee.feedback_set.nominations.count }}</td>
22+
<td>{{ nominee.feedback_set.comments.count }}</td>
23+
<td>{{ nominee.feedback_set.questionnaires.count }}</td>
24+
</tr>
25+
{% endfor %}
26+
</table>
27+
1128
{% endblock %}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{% extends "nomcom/nomcom_private_base.html" %}
2+
3+
{% load nomcom_tags %}
4+
5+
{% block pagehead %}
6+
{{ block.super }}
7+
<script type="text/javascript" src="/js/lib/jquery-1.4.2.min.js"></script>
8+
<script type="text/javascript" src="/js/yui/yui-20100305.js"></script>
9+
<script type="text/javascript" src="/js/base.js"></script>
10+
{% endblock pagehead %}
11+
12+
{% block subtitle %} - View comments of {{ nominee.email.person.name }}{% endblock %}
13+
14+
{% block nomcom_content %}
15+
16+
<p>Back to list of <a href="{% url nomcom_view_feedback year %}">nominees</a></p>
17+
18+
<h2>Feedback of {{ nominee.email.person.name }} </h2>
19+
20+
<div id="mytabs" class="yui-navset">
21+
<ul class="yui-nav">
22+
{% for ft in feedback_types %}
23+
<li><a href="#{{ ft.name }}"><em>{{ ft.name }}</em></a></li>
24+
{% endfor %}
25+
</ul>
26+
Pick the feedback type to view from the list immediately above
27+
<div class="yui-content">
28+
{% 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 %}
41+
</div>
42+
{% endfor %}
43+
</div>
44+
45+
<script type="text/javascript">
46+
//<![CDATA[
47+
var tabView = new YAHOO.widget.TabView('mytabs');
48+
var url = location.href.split('#');
49+
if (url[1]) {
50+
url[1] = "#"+url[1];
51+
var tabs = tabView.get('tabs');
52+
for (var i = 0; i < tabs.length; i++) {
53+
if (url[1].indexOf(tabs[i].get('href')) == 0) {
54+
tabView.set('activeIndex', i);
55+
break;
56+
}
57+
}
58+
}
59+
//]]>
60+
</script>
61+
62+
63+
64+
{% endblock %}

0 commit comments

Comments
 (0)