From 394a16662cc15bfefb5c9af5a248c9dab767cf3a Mon Sep 17 00:00:00 2001
From: Ben Adida <ben@adida.net>
Date: Thu, 15 May 2014 17:48:35 -0700
Subject: [PATCH] added field for determining when to release a result

---
 ...__add_field_election_result_released_at.py | 148 ++++++++++++++++++
 helios/models.py                              |   3 +
 2 files changed, 151 insertions(+)
 create mode 100644 helios/migrations/0012_auto__add_field_election_result_released_at.py

diff --git a/helios/migrations/0012_auto__add_field_election_result_released_at.py b/helios/migrations/0012_auto__add_field_election_result_released_at.py
new file mode 100644
index 0000000..0cc6853
--- /dev/null
+++ b/helios/migrations/0012_auto__add_field_election_result_released_at.py
@@ -0,0 +1,148 @@
+# -*- coding: 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 field 'Election.result_released_at'
+        db.add_column('helios_election', 'result_released_at',
+                      self.gf('django.db.models.fields.DateTimeField')(default=None, null=True),
+                      keep_default=False)
+
+
+    def backwards(self, orm):
+        # Deleting field 'Election.result_released_at'
+        db.delete_column('helios_election', 'result_released_at')
+
+
+    models = {
+        'helios.auditedballot': {
+            'Meta': {'object_name': 'AuditedBallot'},
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'raw_vote': ('django.db.models.fields.TextField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'helios.castvote': {
+            'Meta': {'object_name': 'CastVote'},
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'invalidated_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'quarantined_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'released_from_quarantine_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'verified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'vote': ('helios.datatypes.djangofield.LDObjectField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'vote_tinyhash': ('django.db.models.fields.CharField', [], {'max_length': '50', 'unique': 'True', 'null': 'True'}),
+            'voter': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Voter']"})
+        },
+        'helios.election': {
+            'Meta': {'object_name': 'Election'},
+            'admin': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']"}),
+            'archived_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'cast_url': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
+            'complaint_period_ends_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'datatype': ('django.db.models.fields.CharField', [], {'default': "'legacy/Election'", 'max_length': '250'}),
+            'description': ('django.db.models.fields.TextField', [], {}),
+            'election_info_url': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'}),
+            'election_type': ('django.db.models.fields.CharField', [], {'default': "'election'", 'max_length': '250'}),
+            'eligibility': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'encrypted_tally': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'featured_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'frozen_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'help_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
+            'openreg': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'private_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'private_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'public_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'questions': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'randomize_answer_order': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'registration_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'result': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'result_proof': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'result_released_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'short_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'tallies_combined_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_finished_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'use_advanced_audit_features': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'use_voter_aliases': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'voters_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voting_ended_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_ends_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_extended_until': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'})
+        },
+        'helios.electionlog': {
+            'Meta': {'object_name': 'ElectionLog'},
+            'at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'log': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+        },
+        'helios.trustee': {
+            'Meta': {'unique_together': "(('election', 'email'),)", 'object_name': 'Trustee'},
+            'decryption_factors': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'decryption_proofs': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'pok': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'public_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'public_key_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'helios.voter': {
+            'Meta': {'unique_together': "(('election', 'voter_login_id'),)", 'object_name': 'Voter'},
+            'alias': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']", 'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'vote': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_email': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True'}),
+            'voter_login_id': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'voter_password': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
+        },
+        'helios.voterfile': {
+            'Meta': {'object_name': 'VoterFile'},
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'num_voters': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'processing_finished_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'processing_started_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'voter_file': ('django.db.models.fields.files.FileField', [], {'max_length': '250', 'null': 'True'}),
+            'voter_file_content': ('django.db.models.fields.TextField', [], {'null': 'True'})
+        },
+        'helios_auth.user': {
+            'Meta': {'unique_together': "(('user_type', 'user_id'),)", 'object_name': 'User'},
+            'admin_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'info': ('helios_auth.jsonfield.JSONField', [], {}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'token': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'user_id': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'user_type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        }
+    }
+
+    complete_apps = ['helios']
\ No newline at end of file
diff --git a/helios/models.py b/helios/models.py
index 3df75bb..e338bbd 100644
--- a/helios/models.py
+++ b/helios/models.py
@@ -120,6 +120,9 @@ class Election(HeliosModel):
   tallying_finished_at = models.DateTimeField(auto_now_add=False, default=None, null=True)
   tallies_combined_at = models.DateTimeField(auto_now_add=False, default=None, null=True)
 
+  # we want to explicitly release results
+  result_released_at = models.DateTimeField(auto_now_add=False, default=None, null=True)
+
   # the hash of all voters (stored for large numbers)
   voters_hash = models.CharField(max_length=100, null=True)
   
-- 
GitLab