* Add feedback view by nominee

* Refactor EncryptedTextField
 * Add feedback model managers 
 * Add templatetag to get person from author email
See #973
 - Legacy-Id: 5574
This commit is contained in:
Emilio Jiménez 2013-03-16 15:43:32 +00:00
parent 4fec10183d
commit 29064193a3
8 changed files with 155 additions and 28 deletions

View file

@ -1,6 +1,3 @@
import os
import tempfile
from django.conf import settings
from django.db import models
@ -17,14 +14,9 @@ class EncryptedTextField(models.TextField):
comments = getattr(instance, 'comments')
nomcom = getattr(instance, 'nomcom')
cert_file = nomcom.public_key.path
comments_file = tempfile.NamedTemporaryFile(delete=False)
comments_file.write(comments)
comments_file.close()
code, out, error = pipe("%s smime -encrypt -in %s %s" % (settings.OPENSSL_COMMAND,
comments_file.name,
cert_file))
os.unlink(comments_file.name)
code, out, error = pipe("%s smime -encrypt -in /dev/stdin %s" % (settings.OPENSSL_COMMAND,
cert_file), comments)
if not error:
instance.comments = out
return out

View file

@ -2,6 +2,14 @@ from django.db import models
from django.db.models.query import QuerySet
class MixinManager(object):
def __getattr__(self, attr, *args):
try:
return getattr(self.__class__, attr, *args)
except AttributeError:
return getattr(self.get_query_set(), attr, *args)
class NomineePositionQuerySet(QuerySet):
def get_by_nomcom(self, nomcom):
@ -23,16 +31,10 @@ class NomineePositionQuerySet(QuerySet):
return self.by_state('declined')
class NomineePositionManager(models.Manager):
class NomineePositionManager(models.Manager, MixinManager):
def get_query_set(self):
return NomineePositionQuerySet(self.model)
def __getattr__(self, attr, *args):
try:
return getattr(self.__class__, attr, *args)
except AttributeError:
return getattr(self.get_query_set(), attr, *args)
class NomineeManager(models.Manager):
def get_by_nomcom(self, nomcom):
@ -53,12 +55,29 @@ class PositionQuerySet(QuerySet):
return self.filter(is_open=False)
class PositionManager(models.Manager):
class PositionManager(models.Manager, MixinManager):
def get_query_set(self):
return PositionQuerySet(self.model)
def __getattr__(self, attr, *args):
try:
return getattr(self.__class__, attr, *args)
except AttributeError:
return getattr(self.get_query_set(), attr, *args)
class FeedbackQuerySet(QuerySet):
def get_by_nomcom(self, nomcom):
return self.filter(nomcom=nomcom)
def by_type(self, type):
return self.filter(type=type)
def comments(self):
return self.by_type('comment')
def questionnaires(self):
return self.by_type('questio')
def nominations(self):
return self.by_type('nomina')
class FeedbackManager(models.Manager, MixinManager):
def get_query_set(self):
return FeedbackQuerySet(self.model)

View file

@ -13,7 +13,8 @@ from ietf.group.models import Group
from ietf.name.models import NomineePositionState, FeedbackType
from ietf.dbtemplate.models import DBTemplate
from ietf.nomcom.managers import NomineePositionManager, NomineeManager, PositionManager
from ietf.nomcom.managers import NomineePositionManager, NomineeManager, \
PositionManager, FeedbackManager
from ietf.nomcom.utils import (initialize_templates_for_group,
initialize_questionnaire_for_position,
initialize_requirements_for_position)
@ -125,7 +126,7 @@ class Position(models.Model):
verbose_name_plural = 'Positions'
def __unicode__(self):
return u"%s: %s" % (self.nomcom, self.name)
return self.name
def save(self, *args, **kwargs):
created = not self.id
@ -158,9 +159,14 @@ class Feedback(models.Model):
user = models.ForeignKey(User, blank=True, null=True)
time = models.DateTimeField(auto_now_add=True)
objects = FeedbackManager()
def __unicode__(self):
return u"%s - %s" % (self.author, self.nominee)
class Meta:
ordering = ['time']
# ----- adding south rules to help introspection -----
add_introspection_rules([], ["^ietf\.nomcom\.fields\.EncryptedTextField"])

View file

@ -3,10 +3,12 @@ import tempfile
from django import template
from django.conf import settings
from django.template.defaultfilters import linebreaksbr
from ietf.utils.pipe import pipe
from ietf.ietfauth.decorators import has_role
from ietf.person.models import Person
from ietf.nomcom.models import Feedback
from ietf.nomcom.utils import get_nomcom_by_year, get_user_email, retrieve_nomcom_private_key
@ -40,6 +42,15 @@ def add_num_nominations(user, position, nominee):
return '<span title="%d earlier comments from you on %s as %s">%s</span>&nbsp;' % (count, nominee, position, mark)
@register.filter
def get_person(email):
person = email
if email:
persons = Person.objects.filter(email__address__in=[email])
person = persons and persons[0].name or person
return person
@register.simple_tag
def decrypt(string, request, year):
key = retrieve_nomcom_private_key(request, year)
@ -60,4 +71,4 @@ def decrypt(string, request, year):
if error:
return '<-Encripted text [Your private key is invalid]->'
return out
return linebreaksbr(out)

View file

@ -8,6 +8,7 @@ urlpatterns = patterns('ietf.nomcom.views',
url(r'^(?P<year>\d{4})/private/nominate/$', 'private_nominate', name='nomcom_private_nominate'),
url(r'^(?P<year>\d{4})/private/feedback/$', 'private_feedback', name='nomcom_private_feedback'),
url(r'^(?P<year>\d{4})/private/view-feedback/$', 'view_feedback', name='nomcom_view_feedback'),
url(r'^(?P<year>\d{4})/private/view-feedback/nominee/(?P<nominee_id>\d+)$', 'view_feedback_nominee', name='nomcom_view_feedback_nominee'),
url(r'^(?P<year>\d{4})/private/merge/$', 'private_merge', name='nomcom_private_merge'),
url(r'^(?P<year>\d{4})/private/send-reminder-mail/$', 'send_reminder_mail', name='nomcom_send_reminder_mail'),
url(r'^(?P<year>\d{4})/private/edit-members/$', EditMembersFormPreview(EditMembersForm), name='nomcom_edit_members'),

View file

@ -3,7 +3,7 @@ from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse
from django.http import HttpResponse, Http404, HttpResponseRedirect
from django.shortcuts import render_to_response
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
from django.template.loader import render_to_string
from django.utils import simplejson
@ -13,7 +13,7 @@ from ietf.utils.mail import send_mail
from ietf.dbtemplate.models import DBTemplate
from ietf.dbtemplate.views import template_edit
from ietf.name.models import NomineePositionState
from ietf.name.models import NomineePositionState, FeedbackType
from ietf.nomcom.decorators import member_required, private_key_required
from ietf.nomcom.forms import (EditPublicKeyForm, NominateForm, FeedbackForm, MergeForm,
@ -306,10 +306,27 @@ def feedback(request, year, public):
@private_key_required
def view_feedback(request, year):
nomcom = get_nomcom_by_year(year)
nominees = Nominee.objects.get_by_nomcom(nomcom).distinct()
return render_to_response('nomcom/view_feedback.html',
{'year': year,
'selected': 'view_feedback',
'nominees': nominees,
'nomcom': nomcom}, RequestContext(request))
@member_required(role='member')
@private_key_required
def view_feedback_nominee(request, year, nominee_id):
nomcom = get_nomcom_by_year(year)
nominee = get_object_or_404(Nominee, id=nominee_id)
feedback_types = FeedbackType.objects.all()
return render_to_response('nomcom/view_feedback_nominee.html',
{'year': year,
'selected': 'view_feedback',
'nominee': nominee,
'feedback_types': feedback_types,
'nomcom': nomcom}, RequestContext(request))

View file

@ -8,4 +8,21 @@
<h2>List of Nominees</h2>
<table class="ietf-table ietf-doctable">
<tr>
<th>Nominee</th>
<th>Nominations</th>
<th>Comments</th>
<th>Questionnaires</th>
</tr>
{% for nominee in nominees %}
<tr class="{{ forloop.counter|divisibleby:2|yesno:"oddrow,evenrow" }}">
<td><a href="{% url nomcom_view_feedback_nominee year nominee.id %}">{{ nominee.email.person.name }}</td>
<td>{{ nominee.feedback_set.nominations.count }}</td>
<td>{{ nominee.feedback_set.comments.count }}</td>
<td>{{ nominee.feedback_set.questionnaires.count }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}

View file

@ -0,0 +1,64 @@
{% extends "nomcom/nomcom_private_base.html" %}
{% load nomcom_tags %}
{% block pagehead %}
{{ block.super }}
<script type="text/javascript" src="/js/lib/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="/js/yui/yui-20100305.js"></script>
<script type="text/javascript" src="/js/base.js"></script>
{% endblock pagehead %}
{% block subtitle %} - View comments of {{ nominee.email.person.name }}{% endblock %}
{% block nomcom_content %}
<p>Back to list of <a href="{% url nomcom_view_feedback year %}">nominees</a></p>
<h2>Feedback of {{ nominee.email.person.name }} </h2>
<div id="mytabs" class="yui-navset">
<ul class="yui-nav">
{% for ft in feedback_types %}
<li><a href="#{{ ft.name }}"><em>{{ ft.name }}</em></a></li>
{% endfor %}
</ul>
Pick the feedback type to view from the list immediately above
<div class="yui-content">
{% for ft in feedback_types %}
<div id="{{ ft.name }}">
{% for feedback in nominee.feedback_set.all %}
{% ifequal feedback.type.slug ft.slug %}
<div>
<h3 class="ietf-divider">From {{ feedback.author|get_person|default:"Anonymous" }} ({{ feedback.time|date:"Y-m-d" }})</h3>
<b>Positions:</b> {{ feedback.positions.all|join:"," }}
<p>
{% decrypt feedback.comments request year %}
</p>
</div>
{% endifequal %}
{% endfor %}
</div>
{% endfor %}
</div>
<script type="text/javascript">
//<![CDATA[
var tabView = new YAHOO.widget.TabView('mytabs');
var url = location.href.split('#');
if (url[1]) {
url[1] = "#"+url[1];
var tabs = tabView.get('tabs');
for (var i = 0; i < tabs.length; i++) {
if (url[1].indexOf(tabs[i].get('href')) == 0) {
tabView.set('activeIndex', i);
break;
}
}
}
//]]>
</script>
{% endblock %}