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)