From bf0747a8e9d90bb37bee8dcdf36fa5ee8420e872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Jim=C3=A9nez?= Date: Tue, 15 Jan 2013 16:14:00 +0000 Subject: [PATCH] Add duplicated field for nominees, it is necesary when chair marks duplicate nominations Change questionnaires field in NomineePosition model to manytomany, becouse it is necessary whe chair marks duplicate nominations. Add timestamp in NomineePosition objects to see wich nomineeposition object is the last one. Better merge nominations, update questionnaires and state of primary nomineposition object See #930 - Legacy-Id: 5187 --- ietf/nomcom/forms.py | 31 +++++++++++++++++------ ietf/nomcom/migrations/0001_initial.py | 34 +++++++++++++++++++------- ietf/nomcom/models.py | 10 +++++--- ietf/nomcom/test_data.py | 9 +++++-- ietf/nomcom/tests.py | 13 ++++++---- 5 files changed, 70 insertions(+), 27 deletions(-) diff --git a/ietf/nomcom/forms.py b/ietf/nomcom/forms.py index 032f7df9d..428ff2b78 100644 --- a/ietf/nomcom/forms.py +++ b/ietf/nomcom/forms.py @@ -203,7 +203,7 @@ class MergeForm(BaseNomcomForm, forms.Form): def clean_primary_email(self): email = self.cleaned_data['primary_email'] nominees = Nominee.objects.filter(email__address=email, - nomine_position__nomcom=self.nomcom) + nominee_position__nomcom=self.nomcom) if not nominees: msg = "Does not exist a nomiee with this email" self._errors["primary_email"] = self.error_class([msg]) @@ -215,7 +215,7 @@ class MergeForm(BaseNomcomForm, forms.Form): emails = get_list(data) for email in emails: nominees = Nominee.objects.filter(email__address=email, - nomine_position__nomcom=self.nomcom) + nominee_position__nomcom=self.nomcom) if not nominees: msg = "Does not exist a nomiee with email %s" % email self._errors["primary_email"] = self.error_class([msg]) @@ -237,9 +237,9 @@ class MergeForm(BaseNomcomForm, forms.Form): secondary_emails = get_list(self.cleaned_data.get("secondary_emails")) primary_nominee = Nominee.objects.get(email__address=primary_email, - nomine_position__nomcom=self.nomcom) + nominee_position__nomcom=self.nomcom) secondary_nominees = Nominee.objects.filter(email__address__in=secondary_emails, - nomine_position__nomcom=self.nomcom) + nominee_position__nomcom=self.nomcom) for nominee in secondary_nominees: # move nominations nominee.nomination_set.all().update(nominee=primary_nominee) @@ -247,13 +247,30 @@ class MergeForm(BaseNomcomForm, forms.Form): nominee.feedback_set.all().update(nominee=primary_nominee) # move nomineepositions for nominee_position in nominee.nomineeposition_set.all(): - if not NomineePosition.objects.filter(position=nominee_position.position, - nominee=primary_nominee): + primary_nominee_positions = NomineePosition.objects.filter(position=nominee_position.position, + nominee=primary_nominee) + primary_nominee_position = primary_nominee_positions and primary_nominee_positions[0] or None + if primary_nominee_position: + # if already a nomineeposition object for a position and nominee, + # update the nomineepostion of primary nominee with the state and questionnaire + if nominee_position.time > primary_nominee_position.time: + primary_nominee_position.state = nominee_position.state + primary_nominee_position.save() + questionnaires = nominee_position.questionnaires.all() + if questionnaires: + primary_nominee_position.questionnaires.add(*questionnaires) + + else: + # It is not allowed two or more nomineeposition objects with same position and nominee + # move nominee_position object to primary nominee nominee_position.nominee = primary_nominee nominee_position.save() - secondary_nominees.delete() + nominee.duplicated = primary_nominee + nominee.save() + + secondary_nominees.update(duplicated=primary_nominee) class NominateForm(BaseNomcomForm, forms.ModelForm): diff --git a/ietf/nomcom/migrations/0001_initial.py b/ietf/nomcom/migrations/0001_initial.py index 326a03cc3..b73456db4 100644 --- a/ietf/nomcom/migrations/0001_initial.py +++ b/ietf/nomcom/migrations/0001_initial.py @@ -1,13 +1,13 @@ # encoding: utf-8 +import datetime from south.db import db from south.v2 import SchemaMigration from django.db import models - class Migration(SchemaMigration): def forwards(self, orm): - + # Adding model 'NomCom' db.create_table('nomcom_nomcom', ( ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), @@ -34,6 +34,7 @@ class Migration(SchemaMigration): db.create_table('nomcom_nominee', ( ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), ('email', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['person.Email'])), + ('duplicated', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['nomcom.Nominee'], null=True, blank=True)), )) db.send_create_signal('nomcom', ['Nominee']) @@ -43,13 +44,21 @@ class Migration(SchemaMigration): ('position', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['nomcom.Position'])), ('nominee', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['nomcom.Nominee'])), ('state', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.NomineePositionState'])), - ('questionnaire', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='questionnaire', null=True, to=orm['nomcom.Feedback'])), + ('time', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), )) db.send_create_signal('nomcom', ['NomineePosition']) # Adding unique constraint on 'NomineePosition', fields ['position', 'nominee'] db.create_unique('nomcom_nomineeposition', ['position_id', 'nominee_id']) + # Adding M2M table for field questionnaires on 'NomineePosition' + db.create_table('nomcom_nomineeposition_questionnaires', ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('nomineeposition', models.ForeignKey(orm['nomcom.nomineeposition'], null=False)), + ('feedback', models.ForeignKey(orm['nomcom.feedback'], null=False)) + )) + db.create_unique('nomcom_nomineeposition_questionnaires', ['nomineeposition_id', 'feedback_id']) + # Adding M2M table for field feedback on 'NomineePosition' db.create_table('nomcom_nomineeposition_feedback', ( ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), @@ -75,7 +84,7 @@ class Migration(SchemaMigration): # Adding model 'Feedback' db.create_table('nomcom_feedback', ( ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('author', self.gf('django.db.models.fields.EmailField')(max_length=75)), + ('author', self.gf('django.db.models.fields.EmailField')(max_length=75, blank=True)), ('position', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['nomcom.Position'])), ('nominee', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['nomcom.Nominee'])), ('comments', self.gf('ietf.nomcom.fields.EncryptedTextField')()), @@ -84,8 +93,9 @@ class Migration(SchemaMigration): )) db.send_create_signal('nomcom', ['Feedback']) - def backwards(self, orm): + def backwards(self, orm): + # Removing unique constraint on 'NomineePosition', fields ['position', 'nominee'] db.delete_unique('nomcom_nomineeposition', ['position_id', 'nominee_id']) @@ -101,6 +111,9 @@ class Migration(SchemaMigration): # Deleting model 'NomineePosition' db.delete_table('nomcom_nomineeposition') + # Removing M2M table for field questionnaires on 'NomineePosition' + db.delete_table('nomcom_nomineeposition_questionnaires') + # Removing M2M table for field feedback on 'NomineePosition' db.delete_table('nomcom_nomineeposition_feedback') @@ -110,6 +123,7 @@ class Migration(SchemaMigration): # Deleting model 'Feedback' db.delete_table('nomcom_feedback') + models = { 'auth.group': { 'Meta': {'object_name': 'Group'}, @@ -327,7 +341,7 @@ class Migration(SchemaMigration): }, 'nomcom.feedback': { 'Meta': {'object_name': 'Feedback'}, - 'author': ('django.db.models.fields.EmailField', [], {'max_length': '75'}), + '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'}), 'nominee': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Nominee']"}), @@ -355,9 +369,10 @@ class Migration(SchemaMigration): }, 'nomcom.nominee': { 'Meta': {'object_name': 'Nominee'}, + 'duplicated': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Nominee']", 'null': 'True', 'blank': 'True'}), 'email': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'nomine_position': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['nomcom.Position']", 'through': "orm['nomcom.NomineePosition']", 'symmetrical': 'False'}) + 'nominee_position': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['nomcom.Position']", 'through': "orm['nomcom.NomineePosition']", 'symmetrical': 'False'}) }, 'nomcom.nomineeposition': { 'Meta': {'unique_together': "(('position', 'nominee'),)", 'object_name': 'NomineePosition'}, @@ -365,8 +380,9 @@ class Migration(SchemaMigration): 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'nominee': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Nominee']"}), 'position': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['nomcom.Position']"}), - 'questionnaire': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'questionnaire'", 'null': 'True', 'to': "orm['nomcom.Feedback']"}), - 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.NomineePositionState']"}) + 'questionnaires': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'questionnaires'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['nomcom.Feedback']"}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.NomineePositionState']"}), + 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}) }, 'nomcom.position': { 'Meta': {'object_name': 'Position'}, diff --git a/ietf/nomcom/models.py b/ietf/nomcom/models.py index a1e53bccd..5de305562 100644 --- a/ietf/nomcom/models.py +++ b/ietf/nomcom/models.py @@ -62,7 +62,8 @@ class Nomination(models.Model): class Nominee(models.Model): email = models.ForeignKey(Email) - nomine_position = models.ManyToManyField('Position', through='NomineePosition') + nominee_position = models.ManyToManyField('Position', through='NomineePosition') + duplicated = models.ForeignKey('Nominee', blank=True, null=True) class Meta: verbose_name_plural = 'Nominees' @@ -76,10 +77,11 @@ class NomineePosition(models.Model): position = models.ForeignKey('Position') nominee = models.ForeignKey('Nominee') state = models.ForeignKey(NomineePositionState) - questionnaire = models.ForeignKey('Feedback', - related_name='questionnaire', - blank=True, null=True) + questionnaires = models.ManyToManyField('Feedback', + related_name='questionnaires', + blank=True, null=True) feedback = models.ManyToManyField('Feedback', blank=True, null=True) + time = models.DateTimeField(auto_now_add=True) class Meta: verbose_name = 'Nominee position' diff --git a/ietf/nomcom/test_data.py b/ietf/nomcom/test_data.py index 6742d3230..f0e344ee6 100644 --- a/ietf/nomcom/test_data.py +++ b/ietf/nomcom/test_data.py @@ -2,6 +2,7 @@ import tempfile import os from django.contrib.auth.models import User +from django.core.files import File from django.conf import settings from ietf.utils.pipe import pipe @@ -15,6 +16,7 @@ CHAIR_USER = 'chair' MEMBER_USER = 'member' SECRETARIAT_USER = 'secretariat' EMAIL_DOMAIN = '@example.com' +NOMCOM_YEAR = "2013" USERS = [COMMUNITY_USER, CHAIR_USER, MEMBER_USER, SECRETARIAT_USER] @@ -98,10 +100,13 @@ def nomcom_test_data(): group, created = Group.objects.get_or_create(name='IAB/IESG Nominating Committee 2013/2014', state_id='active', type_id='nomcom', - acronym='nomcom2013') + acronym='nomcom%s' % NOMCOM_YEAR) nomcom, created = NomCom.objects.get_or_create(group=group) - secretariat, created = Group.objects.get_or_create(name="Secretariat", + cert_file, privatekey_file = generate_cert() + nomcom.public_key.save('cert', File(open(cert_file.name, 'r'))) + + secretariat, created = Group.objects.get_or_create(name=u'IETF Secretariat', acronym="secretariat", state_id="active", type_id="ietf", diff --git a/ietf/nomcom/tests.py b/ietf/nomcom/tests.py index 64f7fed27..62a97bcdf 100644 --- a/ietf/nomcom/tests.py +++ b/ietf/nomcom/tests.py @@ -14,7 +14,7 @@ from ietf.person.models import Email, Person from ietf.nomcom.test_data import nomcom_test_data, generate_cert, check_comments, \ COMMUNITY_USER, CHAIR_USER, \ - MEMBER_USER, SECRETARIAT_USER, EMAIL_DOMAIN + MEMBER_USER, SECRETARIAT_USER, EMAIL_DOMAIN, NOMCOM_YEAR from ietf.nomcom.models import NomineePosition, Position, Nominee, \ NomineePositionState, Feedback, FeedbackType, \ Nomination @@ -33,7 +33,7 @@ class NomcomViewsTest(TestCase): def setUp(self): nomcom_test_data() self.cert_file, self.privatekey_file = generate_cert() - self.year = 2013 + self.year = NOMCOM_YEAR # private urls self.private_index_url = reverse('nomcom_private_index', kwargs={'year': self.year}) @@ -133,9 +133,12 @@ class NomcomViewsTest(TestCase): self.assertEqual(response.status_code, 200) self.assertContains(response, "info-message-success") - self.assertEqual(Nominee.objects.filter(email__address='nominee2@example.com').count(), 0) - self.assertEqual(Nominee.objects.filter(email__address='nominee3@example.com').count(), 0) - self.assertEqual(Nominee.objects.filter(email__address='nominee4@example.com').count(), 0) + self.assertEqual(Nominee.objects.filter(email__address='nominee2@example.com', + duplicated__isnull=False).count(), 1) + self.assertEqual(Nominee.objects.filter(email__address='nominee3@example.com', + duplicated__isnull=False).count(), 1) + self.assertEqual(Nominee.objects.filter(email__address='nominee4@example.com', + duplicated__isnull=False).count(), 1) nominee = Nominee.objects.get(email__address='nominee@example.com') self.assertEqual(Nomination.objects.filter(nominee=nominee).count(), 4)