* Add skek view to manage feedback generated from email.

* Now, nominee, type and user fields in feedback model can be null
See #975
 - Legacy-Id: 5576
This commit is contained in:
Emilio Jiménez 2013-03-17 21:34:25 +00:00
parent 3f64b5303b
commit 40fd14da25
9 changed files with 133 additions and 26 deletions

View file

@ -1,5 +1,6 @@
from django.conf import settings
from django import forms
from django.forms.models import BaseModelFormSet
from django.contrib.formtools.preview import FormPreview, AUTO_ID
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
@ -8,6 +9,7 @@ from django.template.loader import render_to_string
from django.utils.decorators import method_decorator
from django.shortcuts import render_to_response
from django.template.context import RequestContext
from django.db.models import Q
from ietf.dbtemplate.forms import DBTemplateForm
from ietf.utils import unaccent
@ -568,6 +570,14 @@ class FeedbackForm(BaseNomcomForm, forms.ModelForm):
"/js/nomcom.js", )
class BaseFeedbackFormSet(BaseModelFormSet):
def __init__(self, *args, **kwargs):
super(BaseFeedbackFormSet, self).__init__(*args, **kwargs)
self.queryset = Feedback.objects.filter(Q(type__isnull=True) |
Q(nominee__isnull=True) |
Q(positions=True))
class NomComTemplateForm(BaseNomcomForm, DBTemplateForm):
fieldsets = [('Template content', ('content', )),

View file

@ -72,9 +72,9 @@ class Migration(SchemaMigration):
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('nomcom', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['nomcom.NomCom'])),
('author', self.gf('django.db.models.fields.EmailField')(max_length=75, blank=True)),
('nominee', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['nomcom.Nominee'])),
('nominee', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['nomcom.Nominee'], null=True, blank=True)),
('comments', self.gf('ietf.nomcom.fields.EncryptedTextField')()),
('type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.FeedbackType'])),
('type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.FeedbackType'], null=True, blank=True)),
('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)),
('time', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
))
@ -332,15 +332,15 @@ class Migration(SchemaMigration):
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'nomcom.feedback': {
'Meta': {'object_name': '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']"}),
'nominee': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Nominee']"}),
'nominee': ('django.db.models.fields.related.ForeignKey', [], {'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'}),
'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.FeedbackType']"}),
'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': {

View file

@ -54,7 +54,7 @@ class Nomination(models.Model):
nominee = models.ForeignKey('Nominee')
comments = models.ForeignKey('Feedback')
nominator_email = models.EmailField(verbose_name='Nominator Email', blank=True)
user = models.ForeignKey(User)
user = models.ForeignKey(User, editable=False)
time = models.DateTimeField(auto_now_add=True)
class Meta:
@ -153,16 +153,16 @@ class Feedback(models.Model):
nomcom = models.ForeignKey('NomCom')
author = models.EmailField(verbose_name='Author', blank=True)
positions = models.ManyToManyField('Position', blank=True, null=True)
nominee = models.ForeignKey('Nominee')
nominee = models.ForeignKey('Nominee', blank=True, null=True)
comments = EncryptedTextField(verbose_name='Comments')
type = models.ForeignKey(FeedbackType)
user = models.ForeignKey(User, blank=True, null=True)
type = models.ForeignKey(FeedbackType, blank=True, null=True)
user = models.ForeignKey(User, editable=False, blank=True, null=True)
time = models.DateTimeField(auto_now_add=True)
objects = FeedbackManager()
def __unicode__(self):
return u"%s - %s" % (self.author, self.nominee)
return u"from %s to %s" % (self.author, self.nominee)
class Meta:
ordering = ['time']

View file

@ -258,7 +258,29 @@ class NomcomViewsTest(TestCase):
self.client.logout()
def feedback_view(self, *args, **kwargs):
pass
public = kwargs.pop('public', True)
nominee_email = kwargs.pop('nominee_email', u'nominee@example.com')
position_name = kwargs.pop('position', 'IAOC')
if public:
nominate_url = self.public_feedback_url
else:
nominate_url = self.private_feedback_url
response = self.client.get(nominate_url)
self.assertEqual(response.status_code, 200)
nomcom = get_nomcom_by_year(self.year)
if not nomcom.public_key:
self.assertNotContains(response, "feedbackform")
# save the cert file in tmp
nomcom.public_key.storage.location = tempfile.gettempdir()
nomcom.public_key.save('cert', File(open(self.cert_file.name, 'r')))
response = self.client.get(nominate_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, "feedbackform")
def test_public_nominate(self):
login_testing_unauthorized(self, COMMUNITY_USER, self.public_nominate_url)

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/pending/$', 'view_feedback_pending', name='nomcom_view_feedback_pending'),
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'),

View file

@ -8,6 +8,7 @@ from django.template import RequestContext
from django.template.loader import render_to_string
from django.utils import simplejson
from django.db.models import Count
from django.forms.models import modelformset_factory
from ietf.utils.mail import send_mail
@ -17,7 +18,8 @@ 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,
NomComTemplateForm, PositionForm, PrivateKeyForm)
NomComTemplateForm, PositionForm, PrivateKeyForm,
BaseFeedbackFormSet)
from ietf.nomcom.models import Position, NomineePosition, Nominee, Feedback
from ietf.nomcom.utils import (get_nomcom_by_year, HOME_TEMPLATE,
retrieve_nomcom_private_key,
@ -315,6 +317,30 @@ def view_feedback(request, year):
'nomcom': nomcom}, RequestContext(request))
@member_required(role='chair')
@private_key_required
def view_feedback_pending(request, year):
nomcom = get_nomcom_by_year(year)
message = None
FeedbackFormSet = modelformset_factory(Feedback,
formset=BaseFeedbackFormSet,
exclude=('nomcom', 'comments'),
extra=0)
if request.method == 'POST':
formset = FeedbackFormSet(request.POST)
if formset.is_valid():
formset.save()
message = ('success', 'The feedbacks has been saved.')
else:
formset = FeedbackFormSet()
return render_to_response('nomcom/view_feedback_pending.html',
{'year': year,
'selected': 'view_feedback',
'formset': formset,
'message': message,
'nomcom': nomcom}, RequestContext(request))
@member_required(role='member')
@private_key_required
def view_feedback_nominee(request, year, nominee_id):

View file

@ -6,6 +6,8 @@
{% block nomcom_content %}
<p><a href="{% url nomcom_view_feedback_pending year %}">Feedbak pending</a></p>
<h2>List of Nominees</h2>
<table class="ietf-table ietf-doctable">
@ -17,7 +19,7 @@
</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><a href="{% url nomcom_view_feedback_nominee year nominee.id %}#comment">{{ 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>

View file

@ -20,24 +20,33 @@
<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>
<li><a href="#{{ ft.slug }}"><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 id="#{{ ft.slug }}">
{% ifequal ft.slug "comment" %}
<b>Number of comments: {{ nominee.feedback_set.comments.count|default:"0" }}</b>
{% endifequal %}
{% ifequal ft.slug "questio" %}
<b>Number of questionnaires: {{ nominee.feedback_set.questionaires.count|default:"0" }}</b>
{% endifequal %}
{% ifequal ft.slug "nomina" %}
<b>Number of nominations: {{ nominee.feedback_set.nominations.count|default:"0" }}</b>
{% endifequal %}
{% 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>

View file

@ -0,0 +1,37 @@
{% extends "nomcom/nomcom_private_base.html" %}
{% load nomcom_tags %}
{% block subtitle %} - Feeback pending{% endblock %}
{% block nomcom_content %}
<p>Back to <a href="{% url nomcom_view_feedback year %}">feedback index</a></p>
<h2>Feedback pending from email list</h2>
{% if message %}
<div class="info-message-{{ message.0 }}">{{ message.1 }}</div>
{% endif %}
<div>
<form id="feedbackformset" action="" method="post">{% csrf_token %}
{{ formset.management_form }}
{% for form in formset.forms %}
<div class="ietf-divider"></div>
<div>
{% for field in form %}
<div>
{{ field.label_tag }}: {{ field }}
</div>
{% endfor %}
{% decrypt form.instance.comments request year %}
</div>
{% endfor %}
<div class="ietf-divider"></div>
<input type="submit" value="Submit" />
</form>
</div>
{% endblock %}