diff --git a/ietf/nomcom/forms.py b/ietf/nomcom/forms.py index 303ab6c12..e87695f2e 100644 --- a/ietf/nomcom/forms.py +++ b/ietf/nomcom/forms.py @@ -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', )), diff --git a/ietf/nomcom/migrations/0001_initial.py b/ietf/nomcom/migrations/0001_initial.py index 80ab434ec..e25e3543d 100644 --- a/ietf/nomcom/migrations/0001_initial.py +++ b/ietf/nomcom/migrations/0001_initial.py @@ -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': { diff --git a/ietf/nomcom/models.py b/ietf/nomcom/models.py index 721a5857e..97bf56f0d 100644 --- a/ietf/nomcom/models.py +++ b/ietf/nomcom/models.py @@ -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'] diff --git a/ietf/nomcom/tests.py b/ietf/nomcom/tests.py index f928c132f..b0f773276 100644 --- a/ietf/nomcom/tests.py +++ b/ietf/nomcom/tests.py @@ -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) diff --git a/ietf/nomcom/urls.py b/ietf/nomcom/urls.py index 2e39de3d9..c907d9e8a 100644 --- a/ietf/nomcom/urls.py +++ b/ietf/nomcom/urls.py @@ -8,6 +8,7 @@ urlpatterns = patterns('ietf.nomcom.views', url(r'^(?P\d{4})/private/nominate/$', 'private_nominate', name='nomcom_private_nominate'), url(r'^(?P\d{4})/private/feedback/$', 'private_feedback', name='nomcom_private_feedback'), url(r'^(?P\d{4})/private/view-feedback/$', 'view_feedback', name='nomcom_view_feedback'), + url(r'^(?P\d{4})/private/view-feedback/pending/$', 'view_feedback_pending', name='nomcom_view_feedback_pending'), url(r'^(?P\d{4})/private/view-feedback/nominee/(?P\d+)$', 'view_feedback_nominee', name='nomcom_view_feedback_nominee'), url(r'^(?P\d{4})/private/merge/$', 'private_merge', name='nomcom_private_merge'), url(r'^(?P\d{4})/private/send-reminder-mail/$', 'send_reminder_mail', name='nomcom_send_reminder_mail'), diff --git a/ietf/nomcom/views.py b/ietf/nomcom/views.py index 5efd904f9..449d54258 100644 --- a/ietf/nomcom/views.py +++ b/ietf/nomcom/views.py @@ -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): diff --git a/ietf/templates/nomcom/view_feedback.html b/ietf/templates/nomcom/view_feedback.html index 93e1952c9..293bebef6 100644 --- a/ietf/templates/nomcom/view_feedback.html +++ b/ietf/templates/nomcom/view_feedback.html @@ -6,6 +6,8 @@ {% block nomcom_content %} +

Feedbak pending

+

List of Nominees

@@ -17,7 +19,7 @@ {% for nominee in nominees %} - + diff --git a/ietf/templates/nomcom/view_feedback_nominee.html b/ietf/templates/nomcom/view_feedback_nominee.html index 357c81daf..1486267ad 100644 --- a/ietf/templates/nomcom/view_feedback_nominee.html +++ b/ietf/templates/nomcom/view_feedback_nominee.html @@ -20,24 +20,33 @@
Pick the feedback type to view from the list immediately above
{% for ft in feedback_types %} -
- {% for feedback in nominee.feedback_set.all %} - {% ifequal feedback.type.slug ft.slug %} -
-

From {{ feedback.author|get_person|default:"Anonymous" }} ({{ feedback.time|date:"Y-m-d" }})

- Positions: {{ feedback.positions.all|join:"," }} -

- {% decrypt feedback.comments request year %} -

-
- {% endifequal %} - {% endfor %} +
+ {% ifequal ft.slug "comment" %} + Number of comments: {{ nominee.feedback_set.comments.count|default:"0" }} + {% endifequal %} + {% ifequal ft.slug "questio" %} + Number of questionnaires: {{ nominee.feedback_set.questionaires.count|default:"0" }} + {% endifequal %} + {% ifequal ft.slug "nomina" %} + Number of nominations: {{ nominee.feedback_set.nominations.count|default:"0" }} + {% endifequal %} + {% for feedback in nominee.feedback_set.all %} + {% ifequal feedback.type.slug ft.slug %} +
+

From {{ feedback.author|get_person|default:"Anonymous" }} ({{ feedback.time|date:"Y-m-d" }})

+ Positions: {{ feedback.positions.all|join:"," }} +

+ {% decrypt feedback.comments request year %} +

+
+ {% endifequal %} + {% endfor %}
{% endfor %}
diff --git a/ietf/templates/nomcom/view_feedback_pending.html b/ietf/templates/nomcom/view_feedback_pending.html new file mode 100644 index 000000000..eb183c292 --- /dev/null +++ b/ietf/templates/nomcom/view_feedback_pending.html @@ -0,0 +1,37 @@ +{% extends "nomcom/nomcom_private_base.html" %} + +{% load nomcom_tags %} + + +{% block subtitle %} - Feeback pending{% endblock %} + +{% block nomcom_content %} + +

Back to feedback index

+ +

Feedback pending from email list

+ +{% if message %} +
{{ message.1 }}
+{% endif %} + +
+
{% csrf_token %} + {{ formset.management_form }} + {% for form in formset.forms %} +
+
+ {% for field in form %} +
+ {{ field.label_tag }}: {{ field }} +
+ {% endfor %} + {% decrypt form.instance.comments request year %} +
+ {% endfor %} +
+ + +
+ +{% endblock %} \ No newline at end of file
{{ nominee.email.person.name }}{{ nominee.email.person.name }} {{ nominee.feedback_set.nominations.count }} {{ nominee.feedback_set.comments.count }} {{ nominee.feedback_set.questionnaires.count }}